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

[RPC server] - add get transaction endpoint #1447

Merged
merged 7 commits into from
Apr 19, 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
2 changes: 1 addition & 1 deletion sui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ toml = "0.5.8"
strum = "0.24.0"
strum_macros = "0.24.0"
num_cpus = "1.13.1"
base64 = "0.13.0"
base64ct = { version = "1.5.0", features = ["alloc"] }
ed25519-dalek = { version = "1.0.1", features = ["batch", "serde"] }
rocksdb = "0.18.0"
hex = "0.4.3"
Expand Down
23 changes: 20 additions & 3 deletions sui/src/rest_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use anyhow::anyhow;
use async_trait::async_trait;
use base64ct::{Base64, Encoding};
use dropshot::HttpErrorResponseBody;
use http::StatusCode;
use move_core_types::identifier::Identifier;
Expand All @@ -15,7 +16,7 @@ use serde_json::json;
use sui_core::gateway_state::gateway_responses::TransactionResponse;
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::messages::{CertifiedTransaction, Transaction, TransactionData};
use sui_types::object::ObjectRead;

use crate::rest_gateway::requests::{
Expand Down Expand Up @@ -114,7 +115,10 @@ impl GatewayAPI for RestGatewayClient {
.map(|object_id| object_id.to_hex())
.collect();

let pure_arguments = pure_arguments.iter().map(base64::encode).collect();
let pure_arguments = pure_arguments
.iter()
.map(|s| Base64::encode_string(s))
.collect();

let request = CallRequest {
signer: encode_bytes_hex(&signer),
Expand All @@ -139,7 +143,10 @@ impl GatewayAPI for RestGatewayClient {
gas_object_ref: ObjectRef,
gas_budget: u64,
) -> Result<TransactionData, anyhow::Error> {
let package_bytes = package_bytes.iter().map(base64::encode).collect::<Vec<_>>();
let package_bytes = package_bytes
.iter()
.map(|s| Base64::encode_string(s))
.collect::<Vec<_>>();
let request = PublishRequest {
sender: encode_bytes_hex(&signer),
compiled_modules: package_bytes,
Expand Down Expand Up @@ -230,6 +237,16 @@ impl GatewayAPI for RestGatewayClient {
// TODO: Implement this.
Ok(vec![])
}

async fn get_transaction(
&self,
digest: TransactionDigest,
) -> Result<CertifiedTransaction, anyhow::Error> {
let hex_digest = encode_bytes_hex(&digest);
let url = format!("{}/api/tx?digest={}", self.url, hex_digest);
let response = reqwest::blocking::get(url)?;
Ok(response.json()?)
}
}

impl RestGatewayClient {
Expand Down
7 changes: 7 additions & 0 deletions sui/src/rest_gateway/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,10 @@ pub struct SyncRequest {
/// Required; Hex code as string representing the address
pub address: String,
}

/// Query string containing the digest of the transaction to be retrieved.
#[derive(Deserialize, Serialize, JsonSchema)]
pub struct GetTransactionDetailsRequest {
/// Required; hex string encoding a 32 byte transaction digest
pub digest: String,
}
12 changes: 8 additions & 4 deletions sui/src/rest_gateway/responses.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use anyhow::anyhow;
use base64ct::{Base64, Encoding};
use std::env;

use dropshot::{ApiEndpointResponse, HttpError, HttpResponse, CONTENT_TYPE_JSON};
Expand Down Expand Up @@ -41,15 +43,15 @@ impl NamedObjectRef {
Self {
object_id: object_id.to_hex(),
version: version.value(),
digest: base64::encode(digest),
digest: Base64::encode_string(digest.as_ref()),
}
}

pub fn to_object_ref(self) -> Result<ObjectRef, anyhow::Error> {
Ok((
ObjectID::try_from(self.object_id)?,
SequenceNumber::from(self.version),
ObjectDigest::try_from(&*base64::decode(self.digest)?)?,
ObjectDigest::try_from(&*Base64::decode_vec(&self.digest).map_err(|e| anyhow!(e))?)?,
))
}
}
Expand Down Expand Up @@ -84,12 +86,14 @@ pub struct TransactionBytes {
impl TransactionBytes {
pub fn new(data: TransactionData) -> Self {
Self {
tx_bytes: base64::encode(data.to_bytes()),
tx_bytes: Base64::encode_string(&data.to_bytes()),
}
}

pub fn to_data(self) -> Result<TransactionData, anyhow::Error> {
TransactionData::from_signable_bytes(&base64::decode(self.tx_bytes)?)
TransactionData::from_signable_bytes(
&Base64::decode_vec(&self.tx_bytes).map_err(|e| anyhow!(e))?,
)
}
}

Expand Down
69 changes: 58 additions & 11 deletions sui/src/rest_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::str::FromStr;
use std::sync::Arc;

use anyhow::anyhow;
use base64ct::{Base64, Encoding};
use clap::*;
use dropshot::{endpoint, Query, TypedBody};
use dropshot::{
Expand All @@ -25,8 +26,9 @@ use serde::{Deserialize, Serialize};
use sui::config::PersistedConfig;
use sui::gateway::GatewayConfig;
use sui::rest_gateway::requests::{
CallRequest, GetObjectInfoRequest, GetObjectSchemaRequest, GetObjectsRequest, MergeCoinRequest,
PublishRequest, SignedTransaction, SplitCoinRequest, SyncRequest, TransferTransactionRequest,
CallRequest, GetObjectInfoRequest, GetObjectSchemaRequest, GetObjectsRequest,
GetTransactionDetailsRequest, MergeCoinRequest, PublishRequest, SignedTransaction,
SplitCoinRequest, SyncRequest, TransferTransactionRequest,
};
use sui::rest_gateway::responses::{
custom_http_error, HttpResponseOk, JsonResponse, NamedObjectRef, ObjectResponse,
Expand All @@ -36,9 +38,9 @@ use sui::{sui_config_dir, SUI_GATEWAY_CONFIG};
use sui_core::gateway_state::gateway_responses::TransactionResponse;
use sui_core::gateway_state::{GatewayClient, GatewayState};
use sui_types::base_types::*;
use sui_types::crypto;
use sui_types::crypto::SignableBytes;
use sui_types::messages::{Transaction, TransactionData};
use sui_types::crypto::{self};
use sui_types::messages::{CertifiedTransaction, Transaction, TransactionData};
use sui_types::object::Object as SuiObject;
use sui_types::object::ObjectRead;

Expand Down Expand Up @@ -127,6 +129,7 @@ fn create_api() -> ApiDescription<ServerContext> {
api.register(move_call).unwrap();
api.register(sync_account_state).unwrap();
api.register(execute_transaction).unwrap();
api.register(get_transaction_details).unwrap();

api
}
Expand Down Expand Up @@ -492,11 +495,12 @@ async fn execute_transaction(
let gateway = ctx.context().gateway.lock().await;

let response: Result<_, anyhow::Error> = async {
let data = base64::decode(response.tx_bytes)?;
let data = Base64::decode_vec(&response.tx_bytes).map_err(|e| anyhow!(e))?;
let data = TransactionData::from_signable_bytes(&data)?;

let mut signature_bytes = base64::decode(response.signature)?;
let mut pub_key_bytes = base64::decode(response.pub_key)?;
let mut signature_bytes =
Base64::decode_vec(&response.signature).map_err(|e| anyhow!(e))?;
let mut pub_key_bytes = Base64::decode_vec(&response.pub_key).map_err(|e| anyhow!(e))?;
signature_bytes.append(&mut pub_key_bytes);
let signature = crypto::Signature::from_bytes(&*signature_bytes)?;
gateway
Expand Down Expand Up @@ -544,8 +548,9 @@ async fn handle_publish(
let compiled_modules = publish_params
.compiled_modules
.iter()
.map(base64::decode)
.collect::<Result<Vec<_>, _>>()?;
.map(|s| Base64::decode_vec(s))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| anyhow!(e))?;

let gas_budget = publish_params.gas_budget;
let gas_object_id = ObjectID::try_from(publish_params.gas_object_id)?;
Expand Down Expand Up @@ -589,8 +594,9 @@ async fn handle_move_call(
let pure_arguments = call_params
.pure_arguments
.iter()
.map(base64::decode)
.collect::<Result<_, _>>()?;
.map(|s| Base64::decode_vec(s))
.collect::<Result<_, _>>()
.map_err(|e| anyhow!(e))?;

let shared_object_arguments = call_params
.shared_object_arguments
Expand All @@ -613,3 +619,44 @@ async fn handle_move_call(
)
.await
}

/// on all objects owned by each address that is managed by this client state.
#[endpoint {
method = GET,
path = "/api/tx",
tags = [ "API" ]
}]
async fn get_transaction_details(
ctx: Arc<RequestContext<ServerContext>>,
query: Query<GetTransactionDetailsRequest>,
) -> Result<HttpResponseOk<JsonResponse<CertifiedTransaction>>, HttpError> {
let gateway = ctx.context().gateway.lock().await;
let query: GetTransactionDetailsRequest = query.into_inner();

println!("{}", query.digest);
let digest = Base64::decode_vec(&query.digest)
.map_err(|e| custom_http_error(StatusCode::BAD_REQUEST, format!("{}", e)))?;
let mut digest_fixu8 = [0u8; 32];
digest_fixu8.copy_from_slice(digest.as_slice());
let digest = TransactionDigest::new(digest_fixu8);

let result = match get_transaction(&gateway, digest).await {
Ok(tx_env) => tx_env,
Err(err) => return Err(err),
};

Ok(HttpResponseOk(JsonResponse(result)))
}

async fn get_transaction(
gateway: &GatewayClient,
digest: TransactionDigest,
) -> Result<CertifiedTransaction, HttpError> {
match gateway.get_transaction(digest).await {
Ok(tx_env) => Ok(tx_env),
Err(err) => Err(custom_http_error(
StatusCode::NOT_FOUND,
format!("Error while getting transaction details: {err:?}"),
)),
}
}
9 changes: 8 additions & 1 deletion sui/src/rpc_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use sui_core::gateway_state::{GatewayClient, GatewayState, GatewayTxSeqNumber};
use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest};
use sui_types::crypto;
use sui_types::crypto::SignableBytes;
use sui_types::messages::{Transaction, TransactionData};
use sui_types::messages::{CertifiedTransaction, Transaction, TransactionData};
use sui_types::object::ObjectRead;

use crate::config::PersistedConfig;
Expand Down Expand Up @@ -115,6 +115,9 @@ pub trait RpcGateway {
&self,
count: u64,
) -> RpcResult<Vec<(GatewayTxSeqNumber, TransactionDigest)>>;

#[method(name = "getTransaction")]
async fn get_transaction(&self, digest: TransactionDigest) -> RpcResult<CertifiedTransaction>;
}

pub struct RpcGatewayImpl {
Expand Down Expand Up @@ -341,6 +344,10 @@ impl RpcGatewayServer for RpcGatewayImpl {
) -> RpcResult<Vec<(GatewayTxSeqNumber, TransactionDigest)>> {
Ok(self.gateway.get_recent_transactions(count)?)
}

async fn get_transaction(&self, digest: TransactionDigest) -> RpcResult<CertifiedTransaction> {
Ok(self.gateway.get_transaction(digest).await?)
}
}

#[serde_as]
Expand Down
9 changes: 8 additions & 1 deletion sui/src/rpc_gateway_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use move_core_types::language_storage::TypeTag;
use sui_core::gateway_state::gateway_responses::TransactionResponse;
use sui_core::gateway_state::{GatewayAPI, GatewayTxSeqNumber};
use sui_types::base_types::{ObjectID, ObjectRef, SuiAddress, TransactionDigest};
use sui_types::messages::{Transaction, TransactionData};
use sui_types::messages::{CertifiedTransaction, Transaction, TransactionData};
use sui_types::object::ObjectRead;
use tokio::runtime::Handle;

Expand Down Expand Up @@ -193,4 +193,11 @@ impl GatewayAPI for RpcGatewayClient {
self.client.get_recent_transactions(count),
)?)
}

async fn get_transaction(
&self,
digest: TransactionDigest,
) -> Result<CertifiedTransaction, Error> {
Ok(self.client.get_transaction(digest).await?)
}
}
4 changes: 3 additions & 1 deletion sui/src/sui_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{anyhow, bail};
use base64ct::{Base64, Encoding};
use clap::*;
use futures::future::join_all;
use move_binary_format::CompiledModule;
Expand Down Expand Up @@ -192,7 +193,8 @@ impl SuiCommand {
let keystore = SuiKeystore::load_or_create(&keystore_path)?;
info!("Data to sign : {}", data);
info!("Address : {}", address);
let signature = keystore.sign(address, &base64::decode(data)?)?;
let message = Base64::decode_vec(data).map_err(|e| anyhow!(e))?;
let signature = keystore.sign(address, &message)?;
// Separate pub key and signature string, signature and pub key are concatenated with an '@' symbol.
let signature_string = format!("{:?}", signature);
let sig_split = signature_string.split('@').collect::<Vec<_>>();
Expand Down
8 changes: 8 additions & 0 deletions sui_core/src/authority/authority_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,14 @@ impl<const ALL_OBJ_VER: bool, S: Eq + Serialize + for<'de> Deserialize<'de>>
Ok(transaction)
}

pub fn get_certified_transaction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously this worked without modifying the authority store - did something change that requires this ?

&self,
transaction_digest: &TransactionDigest,
) -> SuiResult<Option<CertifiedTransaction>> {
let transaction = self.certificates.get(transaction_digest)?;
Ok(transaction)
}

#[cfg(test)]
/// Provide read access to the `schedule` table (useful for testing).
pub fn get_schedule(&self, object_id: &ObjectID) -> SuiResult<Option<SequenceNumber>> {
Expand Down
Loading