From d5253286397ad1810022784e029f3db7a2bceabd Mon Sep 17 00:00:00 2001 From: Dzejkop Date: Tue, 4 Jun 2024 15:04:59 +0200 Subject: [PATCH] Get tx --- src/db.rs | 7 +- src/db/data.rs | 81 +-------------------- src/new_server.rs | 30 ++++++-- src/server/routes/transaction.rs | 5 +- src/types.rs | 44 ++++++++++++ src/types/wrappers/h256.rs | 117 +++++++++++++++++++++++++++++++ src/types/wrappers/hex_bytes.rs | 6 ++ 7 files changed, 202 insertions(+), 88 deletions(-) diff --git a/src/db.rs b/src/db.rs index 688547b..25574ee 100644 --- a/src/db.rs +++ b/src/db.rs @@ -11,12 +11,13 @@ use tracing::instrument; use crate::broadcast_utils::gas_estimation::FeesEstimate; use crate::config::DatabaseConfig; -use crate::types::{RelayerInfo, NetworkInfo, RelayerUpdate, TransactionPriority}; +use crate::types::wrappers::h256::H256Wrapper; +use crate::types::{NetworkInfo, RelayerInfo, RelayerUpdate, TransactionPriority, TxStatus}; pub mod data; -use self::data::{BlockFees, H256Wrapper, NetworkStats, ReadTxData, RpcKind}; -pub use self::data::{TxForEscalation, TxStatus, UnsentTx}; +use self::data::{BlockFees, NetworkStats, ReadTxData, RpcKind}; +pub use self::data::{TxForEscalation, UnsentTx}; // Statically link in migration files static MIGRATOR: Migrator = sqlx::migrate!("db/migrations"); diff --git a/src/db/data.rs b/src/db/data.rs index ca65aec..b92f1c8 100644 --- a/src/db/data.rs +++ b/src/db/data.rs @@ -1,14 +1,12 @@ -use ethers::types::{H256, U256}; +use ethers::types::U256; use serde::{Deserialize, Serialize}; -use sqlx::database::{HasArguments, HasValueRef}; -use sqlx::postgres::{PgHasArrayType, PgTypeInfo}; use sqlx::prelude::FromRow; -use sqlx::Database; use crate::broadcast_utils::gas_estimation::FeesEstimate; use crate::types::wrappers::address::AddressWrapper; +use crate::types::wrappers::h256::H256Wrapper; use crate::types::wrappers::hex_u256::HexU256; -use crate::types::TransactionPriority; +use crate::types::{TransactionPriority, TxStatus}; #[derive(Debug, Clone, FromRow)] pub struct UnsentTx { @@ -78,79 +76,6 @@ pub struct BlockFees { pub gas_price: U256, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct H256Wrapper(pub H256); - -impl<'r, DB> sqlx::Decode<'r, DB> for H256Wrapper -where - DB: Database, - [u8; 32]: sqlx::Decode<'r, DB>, -{ - fn decode( - value: >::ValueRef, - ) -> Result { - let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; - - let value = H256::from_slice(&bytes); - - Ok(Self(value)) - } -} - -impl<'q, DB> sqlx::Encode<'q, DB> for H256Wrapper -where - DB: Database, - [u8; 32]: sqlx::Encode<'q, DB>, -{ - fn encode_by_ref( - &self, - buf: &mut >::ArgumentBuffer, - ) -> sqlx::encode::IsNull { - <[u8; 32] as sqlx::Encode>::encode_by_ref(&self.0 .0, buf) - } -} - -impl PgHasArrayType for H256Wrapper { - fn array_type_info() -> PgTypeInfo { - <[u8; 32] as PgHasArrayType>::array_type_info() - } -} - -impl sqlx::Type for H256Wrapper -where - [u8; 32]: sqlx::Type, -{ - fn type_info() -> DB::TypeInfo { - <[u8; 32] as sqlx::Type>::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - *ty == Self::type_info() - } -} - -#[derive( - Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, sqlx::Type, -)] -#[sqlx(rename_all = "camelCase")] -#[sqlx(type_name = "tx_status")] -#[serde(rename_all = "camelCase")] -pub enum TxStatus { - Pending, - Mined, - Finalized, -} - -impl TxStatus { - pub fn previous(self) -> Self { - match self { - Self::Pending => Self::Pending, - Self::Mined => Self::Pending, - Self::Finalized => Self::Mined, - } - } -} - #[derive( Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, sqlx::Type, )] diff --git a/src/new_server.rs b/src/new_server.rs index 776a48a..bc1d75a 100644 --- a/src/new_server.rs +++ b/src/new_server.rs @@ -18,8 +18,8 @@ use crate::server::routes::relayer::CreateApiKeyResponse; use crate::service::Service; use crate::task_runner::TaskRunner; use crate::types::{ - CreateRelayerRequest, CreateRelayerResponse, NetworkInfo, NewNetworkInfo, - RelayerInfo, RelayerUpdate, SendTxRequest, SendTxResponse, + CreateRelayerRequest, CreateRelayerResponse, GetTxResponse, NetworkInfo, + NewNetworkInfo, RelayerInfo, RelayerUpdate, SendTxRequest, SendTxResponse, }; mod security; @@ -318,10 +318,32 @@ impl RelayerApi { Data(app): Data<&Arc>, Path(api_token): Path, Path(tx_id): Path, - ) -> Result> { + ) -> Result> { api_token.validate(app).await?; - todo!() + let tx = app.db.read_tx(&tx_id).await?.ok_or_else(|| { + poem::error::Error::from_string( + "Transaction not found".to_string(), + StatusCode::NOT_FOUND, + ) + })?; + + let get_tx_response = GetTxResponse { + tx_id: tx.tx_id, + to: tx.to, + data: if tx.data.is_empty() { + None + } else { + Some(tx.data.into()) + }, + value: tx.value.into(), + gas_limit: tx.gas_limit.into(), + nonce: tx.nonce, + tx_hash: tx.tx_hash, + status: tx.status, + }; + + Ok(Json(get_tx_response)) } /// Get Transactions diff --git a/src/server/routes/transaction.rs b/src/server/routes/transaction.rs index 57c8b30..40569f4 100644 --- a/src/server/routes/transaction.rs +++ b/src/server/routes/transaction.rs @@ -1,16 +1,15 @@ use std::sync::Arc; use axum::extract::{Json, Path, Query, State}; -use ethers::types::{Address, Bytes, H256, U256}; +use ethers::types::{Address, Bytes, H256}; use eyre::Result; use serde::{Deserialize, Serialize}; use crate::api_key::ApiKey; use crate::app::App; -use crate::db::TxStatus; use crate::server::ApiError; use crate::types::wrappers::decimal_u256::DecimalU256; -use crate::types::TransactionPriority; +use crate::types::{TransactionPriority, TxStatus}; #[derive(Debug, Default, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] diff --git a/src/types.rs b/src/types.rs index 93b492d..99e6692 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use sqlx::prelude::FromRow; use wrappers::address::AddressWrapper; use wrappers::decimal_u256::DecimalU256; +use wrappers::h256::H256Wrapper; use wrappers::hex_bytes::HexBytes; use wrappers::hex_u256::HexU256; @@ -151,6 +152,49 @@ pub struct SendTxResponse { pub tx_id: String, } +#[derive(Debug, Clone, Serialize, Deserialize, Object)] +#[serde(rename_all = "camelCase")] +#[oai(rename_all = "camelCase")] +pub struct GetTxResponse { + pub tx_id: String, + pub to: AddressWrapper, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub data: Option, + pub value: DecimalU256, + pub gas_limit: DecimalU256, + pub nonce: u64, + + // Sent tx data + #[serde(default, skip_serializing_if = "Option::is_none")] + pub tx_hash: Option, + #[serde(default)] + #[oai(default)] + pub status: Option, +} + +#[derive( + Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, sqlx::Type, Enum +)] +#[sqlx(rename_all = "camelCase")] +#[sqlx(type_name = "tx_status")] +#[serde(rename_all = "camelCase")] +#[oai(rename_all = "camelCase")] +pub enum TxStatus { + Pending, + Mined, + Finalized, +} + +impl TxStatus { + pub fn previous(self) -> Self { + match self { + Self::Pending => Self::Pending, + Self::Mined => Self::Pending, + Self::Finalized => Self::Mined, + } + } +} + impl RelayerUpdate { pub fn with_relayer_name(mut self, relayer_name: String) -> Self { self.relayer_name = Some(relayer_name); diff --git a/src/types/wrappers/h256.rs b/src/types/wrappers/h256.rs index e69de29..0052996 100644 --- a/src/types/wrappers/h256.rs +++ b/src/types/wrappers/h256.rs @@ -0,0 +1,117 @@ +use ethers::types::H256; +use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; +use poem_openapi::types::{ParseFromJSON, ToJSON}; +use serde::{Deserialize, Serialize}; +use sqlx::database::{HasArguments, HasValueRef}; +use sqlx::postgres::{PgHasArrayType, PgTypeInfo}; +use sqlx::Database; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct H256Wrapper(pub H256); + +impl<'r, DB> sqlx::Decode<'r, DB> for H256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; + + let value = H256::from_slice(&bytes); + + Ok(Self(value)) + } +} + +impl<'q, DB> sqlx::Encode<'q, DB> for H256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Encode<'q, DB>, +{ + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer, + ) -> sqlx::encode::IsNull { + <[u8; 32] as sqlx::Encode>::encode_by_ref(&self.0 .0, buf) + } +} + +impl PgHasArrayType for H256Wrapper { + fn array_type_info() -> PgTypeInfo { + <[u8; 32] as PgHasArrayType>::array_type_info() + } +} + +impl sqlx::Type for H256Wrapper +where + [u8; 32]: sqlx::Type, +{ + fn type_info() -> DB::TypeInfo { + <[u8; 32] as sqlx::Type>::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + *ty == Self::type_info() + } +} + +impl poem_openapi::types::Type for H256Wrapper { + const IS_REQUIRED: bool = true; + + type RawValueType = Self; + + type RawElementValueType = Self; + + fn name() -> std::borrow::Cow<'static, str> { + "string(h256)".into() + } + + fn schema_ref() -> MetaSchemaRef { + let mut schema_ref = MetaSchema::new_with_format("string", "h256"); + + schema_ref.example = Some(serde_json::Value::String( + "0x46239dbfe5502b9f82c3dff992927d8d9b3168e732b4fd5771288569f5a1813d".to_string(), + )); + schema_ref.default = Some(serde_json::Value::String( + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + )); + schema_ref.title = Some("H256".to_string()); + schema_ref.description = Some("A hex encoded 256-bit hash"); + + MetaSchemaRef::Inline(Box::new(schema_ref)) + } + + fn as_raw_value(&self) -> Option<&Self::RawValueType> { + Some(self) + } + + fn raw_element_iter<'a>( + &'a self, + ) -> Box + 'a> { + Box::new(self.as_raw_value().into_iter()) + } +} + +impl ParseFromJSON for H256Wrapper { + fn parse_from_json( + value: Option, + ) -> poem_openapi::types::ParseResult { + // TODO: Better error handling + let value = value + .ok_or_else(|| poem_openapi::types::ParseError::expected_input())?; + + let inner = serde_json::from_value(value) + .map_err(|_| poem_openapi::types::ParseError::expected_input())?; + + Ok(Self(inner)) + } +} + +impl ToJSON for H256Wrapper { + fn to_json(&self) -> Option { + serde_json::to_value(self.0).ok() + } +} \ No newline at end of file diff --git a/src/types/wrappers/hex_bytes.rs b/src/types/wrappers/hex_bytes.rs index 66a7813..1e1d4f6 100644 --- a/src/types/wrappers/hex_bytes.rs +++ b/src/types/wrappers/hex_bytes.rs @@ -13,6 +13,12 @@ impl From for HexBytes { } } +impl From> for HexBytes { + fn from(value: Vec) -> Self { + Self(Bytes::from(value)) + } +} + impl poem_openapi::types::Type for HexBytes { const IS_REQUIRED: bool = true;