Skip to content

Commit

Permalink
more cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay committed Oct 1, 2024
1 parent e14d439 commit ad33d52
Showing 1 changed file with 103 additions and 133 deletions.
236 changes: 103 additions & 133 deletions src/api/block.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,85 @@
use anyhow::Result;
use mesh::models::{
AccountIdentifier, Block, BlockIdentifier, Currency, Operation, OperationIdentifier, Transaction,
TransactionIdentifier,
AccountIdentifier, Block, BlockIdentifier, Operation, OperationIdentifier, Transaction, TransactionIdentifier,
};
pub use mesh::models::{Amount, BlockRequest, BlockResponse, PartialBlockIdentifier};
pub use mesh::models::{BlockRequest, BlockResponse, PartialBlockIdentifier};
use serde::Serialize;
use sqlx::FromRow;

use crate::{ChainStatus, CommandType, MinaMesh, MinaMeshError, TransactionStatus, Wrapper};

/// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/block.ml#L7
impl MinaMesh {
pub async fn block(&self, request: BlockRequest) -> Result<BlockResponse, MinaMeshError> {
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())),
};
let parent_block_metadata = match &metadata.parent_id {
Some(parent_id) => {
sqlx::query_file_as!(BlockMetadata, "sql/query_id.sql", parent_id).fetch_optional(&self.pg_pool).await?
}
None => None,
};
let block_identifier = BlockIdentifier::new(metadata.height, metadata.state_hash.clone());
let parent_block_identifier = match parent_block_metadata {
Some(block_metadata) => BlockIdentifier::new(block_metadata.height, block_metadata.state_hash),
None => block_identifier.clone(),
};
let user_commands = self.user_commands(&metadata).await?;
Ok(BlockResponse {
block: Some(Box::new(Block::new(
block_identifier,
parent_block_identifier,
metadata.timestamp.parse()?,
user_commands,
))),
other_transactions: None,
})
}

// TODO: use default token value, check how to best handle this
pub async fn user_commands(&self, metadata: &BlockMetadata) -> Result<Vec<Transaction>, MinaMeshError> {
Ok(
sqlx::query_file_as!(
UserCommandMetadata,
"sql/user_commands.sql",
metadata.id,
// cspell:disable-next-line
"wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"
)
.fetch_all(&self.pg_pool)
.await?
.into_iter()
.map(|item| Transaction::new(TransactionIdentifier::new(item.hash.clone()), Wrapper(&item).into()))
.collect(),
)
}

pub async fn block_metadata(
&self,
PartialBlockIdentifier { index, hash }: &PartialBlockIdentifier,
) -> Result<Option<BlockMetadata>, sqlx::Error> {
if let (Some(index), Some(hash)) = (&index, &hash) {
sqlx::query_file_as!(BlockMetadata, "sql/query_both.sql", hash.to_string(), index)
.fetch_optional(&self.pg_pool)
.await
} else if let Some(index) = index {
let record = sqlx::query_file!("sql/max_canonical_height.sql").fetch_one(&self.pg_pool).await?;
if index <= &record.max_canonical_height.unwrap() {
sqlx::query_file_as!(BlockMetadata, "sql/query_canonical.sql", index).fetch_optional(&self.pg_pool).await
} else {
sqlx::query_file_as!(BlockMetadata, "sql/query_pending.sql", index).fetch_optional(&self.pg_pool).await
}
} else if let Some(hash) = &hash {
sqlx::query_file_as!(BlockMetadata, "sql/query_hash.sql", hash).fetch_optional(&self.pg_pool).await
} else {
sqlx::query_file_as!(BlockMetadata, "sql/query_best.sql").fetch_optional(&self.pg_pool).await
}
}
}

#[derive(Debug, PartialEq, Eq, FromRow, Serialize)]
pub struct BlockMetadata {
id: i32,
Expand Down Expand Up @@ -57,63 +128,8 @@ pub struct UserCommandMetadata {
creation_fee: Option<String>,
}

/// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/block.ml#L7
impl MinaMesh {
// pub async fn block(&self, request: BlockRequest) -> Result<BlockResponse,
// MinaMeshError> {
pub async fn block(&self, request: BlockRequest) -> Result<BlockResponse, MinaMeshError> {
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())),
};
let parent_block_metadata = match &metadata.parent_id {
Some(parent_id) => {
sqlx::query_file_as!(BlockMetadata, "sql/query_id.sql", parent_id).fetch_optional(&self.pg_pool).await?
}
None => None,
};
let block_identifier = BlockIdentifier::new(metadata.height, metadata.state_hash.clone());
let parent_block_identifier = match parent_block_metadata {
Some(block_metadata) => BlockIdentifier::new(block_metadata.height, block_metadata.state_hash),
None => block_identifier.clone(),
};
let user_commands = self.user_commands(&metadata).await?;
Ok(BlockResponse {
block: Some(Box::new(Block::new(
block_identifier,
parent_block_identifier,
metadata.timestamp.parse()?,
user_commands,
))),
other_transactions: None,
})

// // TODO: what else here?:
// // - fetch user commands from the database
// // - SQL command -> Rosetta/mesh transaction
// // - Each command will originate multiple atomic Rosetta/mesh
// operations

// let transactions = user_commands
// .into_iter()
// .map(|user_commands|
// Transaction::new(TransactionIdentifier::new(user_commands.hash.0),
// vec![])) .collect();

// Ok(BlockResponse {
// block: Some(Box::new(Block::new(
// BlockIdentifier::new(metadata.height, metadata.state_hash),
// // TODO: parent block height
// BlockIdentifier::new(0, metadata.parent_hash),
// metadata.timestamp.parse()?,
// transactions,
// ))),
// other_transactions: Some(vec![]),
// })
}

fn user_command_metadata_to_operations(metadata: &UserCommandMetadata) -> Vec<Operation> {
impl From<Wrapper<&UserCommandMetadata>> for Vec<Operation> {
fn from(Wrapper(metadata): Wrapper<&UserCommandMetadata>) -> Self {
let mut operations = Vec::new();
if metadata.fee != "0" {
operations.push(Operation {
Expand All @@ -127,36 +143,35 @@ impl MinaMesh {
metadata: None, // TODO: get the correct metadata
});
}
match &metadata.failure_reason {
Some(_failure_reason) => {}
None => {
if let Some(creation_fee) = &metadata.creation_fee {
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(metadata.status.to_string()),
related_operations: None,
coin_change: None,
r#type: "".to_string(), // TODO: get the correct type
metadata: None, // TODO: get the correct metadata
});
}
match metadata.command_type {
CommandType::Delegation => {
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()))),
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: None,
account: Some(Box::new(AccountIdentifier::new(metadata.source.clone()))),
status: Some(metadata.status.to_string()),
related_operations: None,
coin_change: None,
r#type: "".to_string(), // TODO: get the correct type
metadata: None, // TODO: get the correct metadata
});
}
match metadata.command_type {
CommandType::Delegation => {
operations.push(Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: None,
account: Some(Box::new(AccountIdentifier::new(metadata.source.clone()))),
status: Some(metadata.status.to_string()),
related_operations: None,
coin_change: None,
r#type: "".to_string(), // TODO: get the correct type
metadata: None, // TODO: get the correct metadata
});
}
CommandType::Payment => {
operations.push(Operation {
CommandType::Payment => {
operations.extend_from_slice(&[
Operation {
operation_identifier: Box::new(OperationIdentifier::new(2)),
amount: Wrapper(metadata.amount.clone()).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.source.clone()))),
Expand All @@ -165,8 +180,8 @@ impl MinaMesh {
coin_change: None,
r#type: "".to_string(), // TODO: get the correct type
metadata: None, // TODO: get the correct metadata
});
operations.push(Operation {
},
Operation {
operation_identifier: Box::new(OperationIdentifier::new(3)),
amount: Wrapper(metadata.amount.clone()).into(),
account: Some(Box::new(AccountIdentifier::new(metadata.receiver.clone()))),
Expand All @@ -175,56 +190,11 @@ impl MinaMesh {
coin_change: None,
r#type: "".to_string(), // TODO: get the correct type
metadata: None, // TODO: get the correct metadata
});
}
};
}
},
]);
}
};
}
operations
}

// Do we also need internal and zkapps commands?
pub async fn user_commands(&self, metadata: &BlockMetadata) -> Result<Vec<Transaction>, MinaMeshError> {
Ok(
sqlx::query_file_as!(
UserCommandMetadata,
"sql/user_commands.sql",
metadata.id,
"wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf" /* TODO: use default token value, check how to best
* handle this */
)
.fetch_all(&self.pg_pool)
.await?
.into_iter()
.map(|item| {
Transaction::new(
TransactionIdentifier::new(item.hash.clone()),
Self::user_command_metadata_to_operations(&item),
)
})
.collect(),
)
}

pub async fn block_metadata(
&self,
PartialBlockIdentifier { index, hash }: &PartialBlockIdentifier,
) -> Result<Option<BlockMetadata>, sqlx::Error> {
if let (Some(index), Some(hash)) = (&index, &hash) {
sqlx::query_file_as!(BlockMetadata, "sql/query_both.sql", hash.to_string(), index)
.fetch_optional(&self.pg_pool)
.await
} else if let Some(index) = index {
let record = sqlx::query_file!("sql/max_canonical_height.sql").fetch_one(&self.pg_pool).await?;
if index <= &record.max_canonical_height.unwrap() {
sqlx::query_file_as!(BlockMetadata, "sql/query_canonical.sql", index).fetch_optional(&self.pg_pool).await
} else {
sqlx::query_file_as!(BlockMetadata, "sql/query_pending.sql", index).fetch_optional(&self.pg_pool).await
}
} else if let Some(hash) = &hash {
sqlx::query_file_as!(BlockMetadata, "sql/query_hash.sql", hash).fetch_optional(&self.pg_pool).await
} else {
sqlx::query_file_as!(BlockMetadata, "sql/query_best.sql").fetch_optional(&self.pg_pool).await
}
}
}

0 comments on commit ad33d52

Please sign in to comment.