Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay committed Oct 3, 2024
1 parent b9f40eb commit 5fd6108
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 169 deletions.
19 changes: 0 additions & 19 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,3 @@ mod network_health_check;
mod network_list;
mod network_options;
mod network_status;
mod types;

pub use account_balance::*;
pub use block::*;
pub use call::*;
pub use construction_combine::*;
pub use construction_derive::*;
pub use construction_hash::*;
pub use construction_metadata::*;
pub use construction_parse::*;
pub use construction_payloads::*;
pub use construction_preprocess::*;
pub use construction_submit::*;
pub use mempool::*;
pub use mempool_transaction::*;
pub use network_list::*;
pub use network_options::*;
pub use network_status::*;
pub use types::*;
194 changes: 75 additions & 119 deletions src/api/block.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use anyhow::Result;
use convert_case::{Case, Casing};
use mesh::models::{
AccountIdentifier, Block, BlockIdentifier, BlockRequest, BlockResponse, Operation, OperationIdentifier,
PartialBlockIdentifier, Transaction, TransactionIdentifier,
AccountIdentifier, Amount, Block, BlockIdentifier, BlockRequest, BlockResponse, Currency, Operation,
OperationIdentifier, PartialBlockIdentifier, Transaction, TransactionIdentifier,
};
use serde::Serialize;
use sqlx::FromRow;

use crate::{
ChainStatus, InternalCommandType, MinaMesh, MinaMeshError, OperationStatus, OperationType, TransactionStatus,
UserCommandType, Wrapper,
UserCommandType,
};

/// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/block.ml#L7
Expand All @@ -17,7 +18,7 @@ impl MinaMesh {
let partial_block_identifier = *request.block_identifier;
let metadata = match self.block_metadata(&partial_block_identifier).await? {
Some(metadata) => metadata,
None => return Err(MinaMeshError::BlockMissing(Wrapper(&partial_block_identifier).to_string())),
None => return Err(MinaMeshError::BlockMissing(serde_json::to_string(&partial_block_identifier)?)),
};
let parent_block_metadata = match &metadata.parent_id {
Some(parent_id) => {
Expand All @@ -30,8 +31,9 @@ impl MinaMesh {
Some(block_metadata) => BlockIdentifier::new(block_metadata.height, block_metadata.state_hash),
None => block_identifier.clone(),
};
let user_commands = self.user_commands(&metadata).await?;
// let internal_commands = self.internal_commands(&metadata).await?;
let (mut user_commands, internal_commands) =
tokio::try_join!(self.user_commands(&metadata), self.internal_commands(&metadata))?;
user_commands.extend(internal_commands.into_iter());
Ok(BlockResponse {
block: Some(Box::new(Block::new(
block_identifier,
Expand All @@ -58,18 +60,18 @@ impl MinaMesh {
}

pub async fn internal_commands(&self, metadata: &BlockMetadata) -> Result<Vec<Transaction>, MinaMeshError> {
// let metadata =
// sqlx::query_file_as!(InternalCommandMetadata, "sql/internal_commands.sql",
// metadata.id, DEFAULT_TOKEN_ID) .fetch_all(&self.pg_pool)
// .await?;
// let transactions = metadata
// .into_iter()
// .map(|item| {
// Transaction::new(TransactionIdentifier::new(item.hash.clone()),
// internal_command_metadata_to_operation(&item)) })
// .collect();
// Ok(transactions)
unimplemented!();
let metadata =
sqlx::query_file_as!(InternalCommandMetadata, "sql/internal_commands.sql", metadata.id, DEFAULT_TOKEN_ID)
.fetch_all(&self.pg_pool)
.await?;
let transactions = metadata
.into_iter()
.map(|item| {
internal_command_metadata_to_operation(&item)
.map(|operation| Transaction::new(TransactionIdentifier::new(item.hash.clone()), operation))
})
.collect::<Result<Vec<Transaction>, MinaMeshError>>()?;
Ok(transactions)
}

pub async fn block_metadata(
Expand Down Expand Up @@ -154,65 +156,38 @@ pub struct InternalCommandMetadata {
fn user_command_metadata_to_operations(metadata: &UserCommandMetadata) -> Vec<Operation> {
let mut operations = Vec::new();
if metadata.fee != "0" {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(0)),
amount: Wrapper(Some(metadata.fee.clone())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.fee_payer.clone()))),
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::FeePayment).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(0, Some(&metadata.fee), &metadata.fee_payer, OperationType::FeePayment, None));
}
if metadata.failure_reason.is_none() {
if let Some(creation_fee) = &metadata.creation_fee {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(1)),
amount: Wrapper(Some(creation_fee.to_owned())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))),
status: Some(OperationStatus::from(metadata.status.clone()).to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::AccountCreationFeeViaPayment).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(
1,
Some(creation_fee),
&metadata.receiver,
OperationType::AccountCreationFeeViaPayment,
Some(&metadata.status),
));
}
match metadata.command_type {
UserCommandType::Delegation => {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: None,
account: Some(Box::new(AccountIdentifier::new(metadata.source.clone()))),
status: Some(OperationStatus::from(metadata.status.clone()).to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::DelegateChange).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(2, None, &metadata.source, OperationType::DelegateChange, Some(&metadata.status)));
}
UserCommandType::Payment => {
operations.extend_from_slice(&[
Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: Wrapper(metadata.amount.clone()).into(), // TODO: negate value
account: Some(Box::new(AccountIdentifier::new(metadata.source.clone()))),
status: Some(OperationStatus::from(metadata.status.clone()).to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::PaymentSourceDec).to_snake_case(),
metadata: None, // TODO: get the correct metadata
},
Operation {
operation_identifier: Box::new(OperationIdentifier::new(3)),
amount: Wrapper(metadata.amount.clone()).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))),
status: Some(OperationStatus::from(metadata.status.clone()).to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::PaymentReceiverInc).to_snake_case(),
metadata: None, // TODO: get the correct metadata
},
operation(
2,
metadata.amount.as_ref(),
&metadata.source,
OperationType::PaymentSourceDec,
Some(&metadata.status),
),
operation(
3,
metadata.amount.as_ref(),
&metadata.receiver,
OperationType::PaymentReceiverInc,
Some(&metadata.status),
),
]);
}
};
Expand All @@ -223,65 +198,25 @@ fn user_command_metadata_to_operations(metadata: &UserCommandMetadata) -> Vec<Op
fn internal_command_metadata_to_operation(metadata: &InternalCommandMetadata) -> Result<Vec<Operation>, MinaMeshError> {
let mut operations = Vec::new();
if let Some(creation_fee) = &metadata.creation_fee {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(0)),
amount: Wrapper(Some(creation_fee.clone())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))),
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::AccountCreationFeeViaFeeReceiver).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(
0,
Some(creation_fee),
&metadata.receiver,
OperationType::AccountCreationFeeViaFeeReceiver,
None,
));
}

match metadata.command_type {
InternalCommandType::Coinbase => {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: Wrapper(Some(metadata.fee.clone())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))),
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::CoinbaseInc).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(2, Some(&metadata.fee), &metadata.receiver, OperationType::CoinbaseInc, None));
}
InternalCommandType::FeeTransfer => {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: Wrapper(Some(metadata.fee.clone())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))), // TODO: token id
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::FeeReceiverInc).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(2, Some(&metadata.fee), &metadata.receiver, OperationType::FeeReceiverInc, None));
}
InternalCommandType::FeeTransferViaCoinbase => {
if let Some(coinbase_receiver) = &metadata.coinbase_receiver {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: Wrapper(Some(metadata.fee.clone())).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))), // TODO: token id
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::FeeReceiverInc).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(3)),
amount: Wrapper(Some(metadata.fee.clone())).into(), // TODO: negate value
account: Some(Box::new(AccountIdentifier::new(coinbase_receiver.clone()))), // TODO: token id
status: Some(OperationStatus::Success.to_string()),
related_operations: None,
coin_change: None,
r#type: Wrapper(OperationType::FeePayerDec).to_snake_case(),
metadata: None, // TODO: get the correct metadata
});
operations.push(operation(2, Some(&metadata.fee), &metadata.receiver, OperationType::FeeReceiverInc, None));
operations.push(operation(3, Some(&metadata.fee), coinbase_receiver, OperationType::FeePayerDec, None));
} else {
return Err(MinaMeshError::InvariantViolation);
}
Expand All @@ -290,5 +225,26 @@ fn internal_command_metadata_to_operation(metadata: &InternalCommandMetadata) ->
Ok(operations)
}

fn operation(
ident: i64,
amount: Option<&String>,
account: &String,
operation_type: OperationType,
status: Option<&TransactionStatus>,
) -> Operation {
Operation {
operation_identifier: Box::new(OperationIdentifier::new(ident)),
amount: amount.map(|value| Box::new(Amount::new(value.to_owned(), Currency::new("mina".to_string(), 9)))),
account: Some(Box::new(AccountIdentifier::new(account.to_owned()))),
status: Some(
status.map(|item| OperationStatus::from(item.to_owned())).unwrap_or(OperationStatus::Success).to_string(),
),
related_operations: None,
coin_change: None,
r#type: operation_type.to_string().to_case(Case::Snake),
metadata: None, // TODO: get the correct metadata
}
}

// cspell:disable-next-line
static DEFAULT_TOKEN_ID: &str = "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf";
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::num::ParseIntError;

use cynic::http::CynicReqwestError;
use serde_json::Error as SerdeError;
use sqlx::Error as SqlxError;
use thiserror::Error;

Expand Down Expand Up @@ -137,3 +138,11 @@ impl From<CynicReqwestError> for MinaMeshError {
MinaMeshError::GraphqlMinaQuery(value.to_string())
}
}

// TODO: this isn't necessarily accurate, as we use this for a serialization
// errors as well.
impl From<SerdeError> for MinaMeshError {
fn from(value: SerdeError) -> Self {
MinaMeshError::JsonParse(Some(value.to_string()))
}
}
10 changes: 6 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ mod config;
mod error;
mod graphql;
mod playground;
mod types;
mod util;

pub use api::*;
pub use commands::*;
pub use config::*;
pub use error::*;
use graphql::GraphQLClient;
pub use mesh::models;
use mesh::models::BlockIdentifier;
use sqlx::PgPool;
pub(crate) use util::Wrapper;
pub use types::*;

#[derive(Debug)]
pub struct MinaMesh {
pub graphql_client: graphql::GraphQLClient,
pub graphql_client: GraphQLClient,
pub pg_pool: PgPool,
pub genesis_block_identifier: models::BlockIdentifier,
pub genesis_block_identifier: BlockIdentifier,
}
File renamed without changes.
27 changes: 0 additions & 27 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use convert_case::{Case, Casing};
use mesh::models::{Amount, Currency, PartialBlockIdentifier};
use serde::Serialize;

use crate::MinaMeshError;
Expand Down Expand Up @@ -35,28 +33,3 @@ impl Wrapper<Option<serde_json::Value>> {

// cspell:disable-next-line
const DEFAULT_TOKEN_ID: &str = "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf";

#[allow(clippy::to_string_trait_impl)]
impl ToString for Wrapper<&PartialBlockIdentifier> {
fn to_string(&self) -> String {
match &self.0.hash {
Some(hash) => hash.to_owned(),
None => match self.0.index {
Some(index) => index.to_string(),
None => "latest".to_string(),
},
}
}
}

impl From<Wrapper<Option<String>>> for Option<Box<Amount>> {
fn from(value: Wrapper<Option<String>>) -> Self {
value.0.map(|some| Box::new(Amount::new(some, Currency::new("mina".to_string(), 9))))
}
}

impl<T: ToString> Wrapper<T> {
pub fn to_snake_case(&self) -> String {
self.0.to_string().to_case(Case::Snake)
}
}
12 changes: 12 additions & 0 deletions tests/snapshots/block__specified.snap.new
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: tests/block.rs
assertion_line: 25
expression: maybe_prev
---
Some(
Err(
Sql(
"error occurred while decoding column 2: unexpected null; try decoding as an `Option`",
),
),
)

0 comments on commit 5fd6108

Please sign in to comment.