Skip to content

Commit

Permalink
Testing and adjustments for /account/balance (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-iohk authored Dec 4, 2024
1 parent 5431840 commit 3fbb2a2
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 98 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion sql/queries/maybe_account_balance_info.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ SELECT
b.global_slot_since_genesis AS block_global_slot_since_genesis,
balance,
nonce,
timing_id
timing_id,
t.value AS token_id
FROM
blocks b
INNER JOIN accounts_accessed ac ON ac.block_id=b.id
Expand Down
88 changes: 50 additions & 38 deletions src/api/account_balance.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use coinbase_mesh::models::{
AccountBalanceRequest, AccountBalanceResponse, AccountIdentifier, Amount, BlockIdentifier, Currency,
PartialBlockIdentifier,
AccountBalanceRequest, AccountBalanceResponse, AccountIdentifier, Amount, BlockIdentifier, PartialBlockIdentifier,
};
use cynic::QueryBuilder;

use crate::{
graphql::{Account, AnnotatedBalance, Balance, Length, QueryBalance, QueryBalanceVariables, StateHash},
create_currency,
graphql::{
Account, AccountNonce, AnnotatedBalance, Balance, Length, QueryBalance, QueryBalanceVariables, StateHash, TokenId,
},
util::Wrapper,
MinaMesh, MinaMeshError,
};
Expand Down Expand Up @@ -42,22 +44,25 @@ impl MinaMesh {
.fetch_optional(&self.pg_pool)
.await?;
match maybe_account_balance_info {
None => {
Ok(AccountBalanceResponse::new(BlockIdentifier { hash: block.state_hash, index: block.height }, vec![Amount {
currency: Box::new(Currency {
symbol: "MINA".into(), // TODO: Use actual currency symbol / custom tokens
decimals: 9,
metadata: None,
}),
None => Ok(AccountBalanceResponse {
block_identifier: Box::new(BlockIdentifier { hash: block.state_hash, index: block.height }),
balances: vec![Amount {
currency: Box::new(create_currency(None)),
value: "0".to_string(),
metadata: Some(serde_json::json!({
"locked_balance": "0".to_string(),
"liquid_balance": "0".to_string(),
"total_balance": "0".to_string()
"locked_balance": 0,
"liquid_balance": 0,
"total_balance": 0
})),
}]))
}
}],
metadata: Some(serde_json::json!({
"created_via_historical_lookup": true,
"nonce": "0"
})),
}),
Some(account_balance_info) => {
let token_id = account_balance_info.token_id;
let nonce = account_balance_info.nonce;
let last_relevant_command_balance = account_balance_info.balance.parse::<u64>()?;
let timing_info = sqlx::query_file!("sql/queries/timing_info.sql", account_balance_info.timing_id)
.fetch_optional(&self.pg_pool)
Expand All @@ -79,19 +84,22 @@ impl MinaMesh {
};
let total_balance = last_relevant_command_balance;
let locked_balance = total_balance - liquid_balance;
Ok(AccountBalanceResponse::new(BlockIdentifier { hash: block.state_hash, index: block.height }, vec![Amount {
currency: Box::new(Currency {
symbol: "MINA".into(), // TODO: Use actual currency symbol / custom tokens
decimals: 9,
metadata: None,
}),
value: liquid_balance.to_string(),
Ok(AccountBalanceResponse {
block_identifier: Box::new(BlockIdentifier { hash: block.state_hash, index: block.height }),
balances: vec![Amount {
currency: Box::new(create_currency(Some(&token_id))),
value: liquid_balance.to_string(),
metadata: Some(serde_json::json!({
"locked_balance": locked_balance,
"liquid_balance": liquid_balance,
"total_balance": total_balance
})),
}],
metadata: Some(serde_json::json!({
"locked_balance": locked_balance.to_string(),
"liquid_balance": liquid_balance.to_string(),
"total_balance": total_balance.to_string()
"created_via_historical_lookup": true,
"nonce": format!("{}", nonce)
})),
}]))
})
}
}
}
Expand All @@ -111,26 +119,30 @@ impl MinaMesh {
liquid: Some(Balance(liquid_raw)),
total: Balance(total_raw),
},
..
nonce: Some(AccountNonce(nonce)),
token_id: TokenId(token_id),
}),
} = result
{
let total = total_raw.parse::<u64>()?;
let liquid = liquid_raw.parse::<u64>()?;
let index = index_raw.parse::<i64>()?;
Ok(AccountBalanceResponse::new(BlockIdentifier { hash, index }, vec![Amount {
currency: Box::new(Currency {
symbol: "MINA".into(), // TODO: Use actual currency symbol / custom tokens
decimals: 9,
metadata: None,
}),
value: total_raw,
Ok(AccountBalanceResponse {
block_identifier: Box::new(BlockIdentifier { hash, index }),
balances: vec![Amount {
currency: Box::new(create_currency(Some(&token_id))),
value: total_raw,
metadata: Some(serde_json::json!({
"locked_balance": (total - liquid),
"liquid_balance": liquid,
"total_balance": total
})),
}],
metadata: Some(serde_json::json!({
"locked_balance": (total - liquid).to_string(),
"liquid_balance": liquid.to_string(),
"total_balance": total.to_string()
"created_via_historical_lookup": false,
"nonce": format!("{}", nonce)
})),
}]))
})
} else {
Err(MinaMeshError::AccountNotFound(public_key))
}
Expand Down
20 changes: 10 additions & 10 deletions src/create_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{playground::handle_playground, util::Wrapper, MinaMesh, MinaMeshErro

pub fn create_router(mina_mesh: MinaMesh, playground: bool) -> Router {
let mut router = Router::new()
.route("/available_endpoints", get(handle_available_endpoints))
.route("/account/balance", post(handle_account_balance))
.route("/block", post(handle_block))
.route("/call", post(handle_call))
Expand All @@ -24,7 +25,6 @@ pub fn create_router(mina_mesh: MinaMesh, playground: bool) -> Router {
.route("/construction/payloads", post(handle_construction_payloads))
.route("/construction/preprocess", post(handle_construction_preprocess))
.route("/construction/submit", post(handle_construction_submit))
.route("/implemented_methods", get(handle_implemented_methods))
.route("/mempool", post(handle_mempool))
.route("/mempool/transaction", post(handle_mempool_transaction))
.route("/network/list", post(handle_network_list))
Expand Down Expand Up @@ -77,15 +77,15 @@ create_handler!(network_status, NetworkRequest);
create_handler!(search_transactions, SearchTransactionsRequest);

#[debug_handler]
async fn handle_implemented_methods() -> impl IntoResponse {
async fn handle_available_endpoints() -> impl IntoResponse {
Json([
"account_balance",
"block",
"mempool",
"mempool_transaction",
"network_list",
"network_options",
"network_status",
"search_transactions",
"/account/balance",
"/block",
"/mempool",
"/mempool/transaction",
"/network/list",
"/network/options",
"/network/status",
"/search/transactions",
])
}
1 change: 1 addition & 0 deletions src/graphql/balance.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ query QueryBalance($publicKey: PublicKey!) {
total
}
nonce
tokenId
}
}
25 changes: 13 additions & 12 deletions src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ use serde_json::json;

use crate::{util::DEFAULT_TOKEN_ID, OperationStatus, OperationType, TransactionStatus};

/// Creates a `Currency` based on the token provided.
/// If the token is `DEFAULT_TOKEN_ID`, it creates a MINA currency.
/// Otherwise, it creates a MINA+ currency with the token ID in metadata.
pub fn create_currency(token: Option<&String>) -> Currency {
match token {
Some(token_id) if token_id != DEFAULT_TOKEN_ID => {
Currency { symbol: "MINA+".to_owned(), decimals: 9, metadata: Some(json!({ "token_id": token_id })) }
}
_ => Currency::new("MINA".to_owned(), 9),
}
}

#[allow(clippy::too_many_arguments)]
pub fn operation(
ident: i64,
Expand All @@ -15,18 +27,7 @@ pub fn operation(
metadata: Option<&serde_json::Value>,
token: Option<&String>,
) -> Operation {
// if token is provided and different from DEFAULT_TOKEN_ID, then create a new
// currency with the token else create a new currency with "MINA"
let currency = token
.map(|token_id| {
if token_id != DEFAULT_TOKEN_ID {
Currency { symbol: "MINA+".to_owned(), decimals: 9, metadata: Some(json!({ "token_id": token_id })) }
} else {
Currency::new("MINA".to_owned(), 9)
}
})
.unwrap_or(Currency::new("MINA".to_owned(), 9));

let currency = create_currency(token);
Operation {
operation_identifier: Box::new(OperationIdentifier::new(ident)),
amount: amount.map(|value| Box::new(Amount::new(value.to_owned(), currency))),
Expand Down
12 changes: 12 additions & 0 deletions tests/compare_to_ocaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,15 @@ async fn mempool_transaction() -> Result<()> {
let (subpath, reqs) = fixtures::mempool_transaction();
assert_responses_contain(subpath, &reqs, "\"message\": \"Transaction not found").await
}

#[tokio::test]
async fn account_balance() -> Result<()> {
let (subpath, reqs) = fixtures::account_balance();
assert_responses_eq(subpath, &reqs).await
}

#[tokio::test]
async fn account_balance_not_exists() -> Result<()> {
let (subpath, reqs) = fixtures::account_balance_not_exists();
assert_responses_contain(subpath, &reqs, "\"message\": \"Account not found").await
}
26 changes: 17 additions & 9 deletions tests/fixtures/account_balance.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use mina_mesh::models::{AccountBalanceRequest, AccountIdentifier, NetworkIdentifier, PartialBlockIdentifier};
use mina_mesh::models::{AccountBalanceRequest, AccountIdentifier, PartialBlockIdentifier};

use super::CompareGroup;
use super::{network_id, CompareGroup};

#[allow(dead_code)]
pub fn account_balance<'a>() -> CompareGroup<'a> {
("/account/balance", vec![
// historical lookups
Box::new(AccountBalanceRequest {
account_identifier: Box::new(AccountIdentifier::new(
"B62qmo4nfFemr9hFtvz8F5h4JFSCxikVNsUJmZcfXQ9SGJ4abEC1RtH".to_string(),
)),
block_identifier: Some(Box::new(PartialBlockIdentifier { index: Some(100), hash: None })),
network_identifier: Box::new(NetworkIdentifier::new("mina".to_string(), "devnet".to_string())),
network_identifier: Box::new(network_id()),
currencies: None,
}),
Box::new(AccountBalanceRequest {
Expand All @@ -21,11 +21,19 @@ pub fn account_balance<'a>() -> CompareGroup<'a> {
}),
block_identifier: Some(Box::new(PartialBlockIdentifier { index: Some(6265), hash: None })),
currencies: None,
network_identifier: Box::new(NetworkIdentifier {
blockchain: "mina".into(),
network: "devnet".into(),
sub_network_identifier: None,
}),
network_identifier: Box::new(network_id()),
}),
// current lookups
Box::new(AccountBalanceRequest::new(
network_id(),
AccountIdentifier::new("B62qkYHGYmws5CYa3phYEKoZvrENTegEhUJYMhzHUQe5UZwCdWob8zv".to_string()),
)),
])
}

pub fn account_balance_not_exists<'a>() -> CompareGroup<'a> {
("/account/balance", vec![Box::new(AccountBalanceRequest::new(
network_id(),
AccountIdentifier::new("B62qiW9Qwv9UnKfNKdBm6hRLNDobv46rVhX1trGdB35YCNT33CSCVt5".to_string()),
))])
}
8 changes: 4 additions & 4 deletions tests/fixtures/block.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use mina_mesh::models::{BlockRequest, NetworkIdentifier, PartialBlockIdentifier};
use mina_mesh::models::{BlockRequest, PartialBlockIdentifier};

use super::CompareGroup;
use super::{network_id, CompareGroup};

#[allow(dead_code)]
pub fn block<'a>() -> CompareGroup<'a> {
("/block", vec![
Box::new(BlockRequest {
network_identifier: Box::new(NetworkIdentifier::new("mina".to_string(), "devnet".to_string())),
network_identifier: Box::new(network_id()),
block_identifier: Box::new(PartialBlockIdentifier::new()),
}),
Box::new(BlockRequest {
network_identifier: Box::new(NetworkIdentifier::new("mina".to_string(), "devnet".to_string())),
network_identifier: Box::new(network_id()),
block_identifier: Box::new(PartialBlockIdentifier { index: Some(52676), hash: None }),
}),
])
Expand Down
8 changes: 2 additions & 6 deletions tests/fixtures/mempool.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use mina_mesh::models::{MempoolTransactionRequest, NetworkIdentifier, NetworkRequest, TransactionIdentifier};
use mina_mesh::models::{MempoolTransactionRequest, NetworkRequest, TransactionIdentifier};

use super::CompareGroup;
use super::{network_id, CompareGroup};

pub fn mempool<'a>() -> CompareGroup<'a> {
("/mempool", vec![Box::new(NetworkRequest::new(network_id()))])
Expand All @@ -12,7 +12,3 @@ pub fn mempool_transaction<'a>() -> CompareGroup<'a> {
TransactionIdentifier::new("hash_not_exists".to_string()),
))])
}

fn network_id() -> NetworkIdentifier {
NetworkIdentifier::new("mina".to_string(), "devnet".to_string())
}
10 changes: 9 additions & 1 deletion tests/fixtures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@ mod mempool;
mod network;
mod search_transactions;

#[allow(unused_imports)]
pub use account_balance::*;
#[allow(unused_imports)]
pub use block::*;
pub use mempool::*;
use mina_mesh::models::{NetworkIdentifier, NetworkRequest};
pub use network::*;
pub use search_transactions::*;

pub type CompareGroup<'a> = (&'a str, Vec<Box<dyn ErasedSerialize>>);

pub fn network_id() -> NetworkIdentifier {
NetworkIdentifier::new("mina".to_string(), "devnet".to_string())
}

pub fn network_request() -> NetworkRequest {
NetworkRequest::new(network_id())
}
Loading

0 comments on commit 3fbb2a2

Please sign in to comment.