Skip to content

Commit

Permalink
fix(cat-gateway): Fix native asset indexing to be more flexible (#1150)
Browse files Browse the repository at this point in the history
* refactor: rename schema to asset

* refactor: vector asset

* chore: rename asset fields

* refactor: object mapping structs

* chore: minor rename

* fix: update operation cql

* fix: schema version

* chore: change asset_id back to policy_id

* chore: find rename

* fix: schema version

* fix: i128

* feat: asset value from i128

* refactor: change &[u8] for asset name

* refactor: try from asset value

* fix: import

* chore: fmtfix

* Update catalyst-gateway/bin/src/db/index/block/txo/insert_txo_asset.rs

Co-authored-by: Steven Johnson <stevenj@users.noreply.github.com>

* revert: i128 to bigint

* fix: unused import

* feat: api test

* chore: cspell fix

* chore: cspell fix

* chore: fmtfix

---------

Co-authored-by: Oleksandr Prokhorenko <djminikin@gmail.com>
Co-authored-by: Steven Johnson <stevenj@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 29, 2024
1 parent 880b04b commit 43b9b58
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ INSERT INTO txo_assets_by_stake (
txn,
txo,
policy_id,
policy_name,
asset_name,
value
) VALUES (
:stake_address,
:slot_no,
:txn,
:txo,
:policy_id,
:policy_name,
:asset_name,
:value
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ INSERT INTO unstaked_txo_assets_by_txn_hash (
txn_hash,
txo,
policy_id,
policy_name,
asset_name,
slot_no,
txn,
value
) VALUES (
:txn_hash,
:txo,
:policy_id,
:policy_name,
:asset_name,
:slot_no,
:txn,
:value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub(super) struct Params {
txo: i16,
/// Policy hash of the asset
policy_id: Vec<u8>,
/// Policy name of the asset
policy_name: String,
/// Name of the asset, within the Policy.
asset_name: Vec<u8>,
/// Value of the asset
value: num_bigint::BigInt,
}
Expand All @@ -41,15 +41,15 @@ impl Params {
#[allow(clippy::too_many_arguments)]
pub(super) fn new(
stake_address: &[u8], slot_no: u64, txn: i16, txo: i16, policy_id: &[u8],
policy_name: &str, value: i128,
asset_name: &[u8], value: i128,
) -> Self {
Self {
stake_address: stake_address.to_vec(),
slot_no: slot_no.into(),
txn,
txo,
policy_id: policy_id.to_vec(),
policy_name: policy_name.to_owned(),
asset_name: asset_name.to_vec(),
value: value.into(),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub(super) struct Params {
/// Policy hash of the asset
policy_id: Vec<u8>,
/// Policy name of the asset
policy_name: String,
asset_name: Vec<u8>,
/// Block Slot Number
slot_no: num_bigint::BigInt,
/// Transaction Offset inside the block.
Expand All @@ -40,14 +40,14 @@ impl Params {
/// values.
#[allow(clippy::too_many_arguments)]
pub(super) fn new(
txn_hash: &[u8], txo: i16, policy_id: &[u8], policy_name: &str, slot_no: u64, txn: i16,
txn_hash: &[u8], txo: i16, policy_id: &[u8], asset_name: &[u8], slot_no: u64, txn: i16,
value: i128,
) -> Self {
Self {
txn_hash: txn_hash.to_vec(),
txo,
policy_id: policy_id.to_vec(),
policy_name: policy_name.to_owned(),
asset_name: asset_name.to_vec(),
slot_no: slot_no.into(),
txn,
value: value.into(),
Expand Down
12 changes: 3 additions & 9 deletions catalyst-gateway/bin/src/db/index/block/txo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl TxoInsertQuery {
let policy_id = asset.policy().to_vec();
for policy_asset in asset.assets() {
if policy_asset.is_output() {
let policy_name = policy_asset.to_ascii_name().unwrap_or_default();
let asset_name = policy_asset.name();
let value = policy_asset.any_coin();

if staked {
Expand All @@ -191,19 +191,13 @@ impl TxoInsertQuery {
txn,
txo_index,
&policy_id,
&policy_name,
asset_name,
value,
);
self.staked_txo_asset.push(params);
} else {
let params = insert_unstaked_txo_asset::Params::new(
txn_hash,
txo_index,
&policy_id,
&policy_name,
slot_no,
txn,
value,
txn_hash, txo_index, &policy_id, asset_name, slot_no, txn, value,
);
self.unstaked_txo_asset.push(params);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SELECT
txo,
slot_no,
policy_id,
policy_name,
asset_name,
value
FROM txo_assets_by_stake
WHERE stake_address = :stake_address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ mod result {
/// Asset hash.
pub policy_id: Vec<u8>,
/// Asset name.
pub policy_name: String,
pub asset_name: Vec<u8>,
/// Asset value.
pub value: num_bigint::BigInt,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ CREATE TABLE IF NOT EXISTS txo_assets_by_stake (
txn smallint, -- Which Transaction in the Slot is the TXO.
txo smallint, -- offset in the txo list of the transaction the txo is in.
policy_id blob, -- asset policy hash (id) (28 byte binary hash)
policy_name text, -- name of the policy (UTF8) TODO: https://github.com/input-output-hk/catalyst-voices/issues/1121
asset_name blob, -- name of the asset policy (UTF8) (32 bytes)


-- None Key Data of the asset.
value varint, -- Value of the asset (i128)

PRIMARY KEY (stake_address, slot_no, txn, txo, policy_id, policy_name)
PRIMARY KEY (stake_address, slot_no, txn, txo, policy_id, asset_name)
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS unstaked_txo_assets_by_txn_hash (
txn_hash blob, -- 32 byte hash of this transaction.
txo smallint, -- offset in the txo list of the transaction the txo is in.
policy_id blob, -- asset policy hash (id) (28 byte binary hash)
policy_name text, -- name of the policy (UTF8)
asset_name blob, -- name of the policy (UTF8) (32 bytes)

-- Secondary Location information for the transaction.
slot_no varint, -- slot number the txo was created in.
Expand All @@ -13,5 +13,5 @@ CREATE TABLE IF NOT EXISTS unstaked_txo_assets_by_txn_hash (
-- Value of the asset.
value varint, -- Value of the asset (u64)

PRIMARY KEY (txn_hash, txo, policy_id, policy_name)
PRIMARY KEY (txn_hash, txo, policy_id, asset_name)
);
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/src/db/index/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{settings::cassandra_db, utils::blake2b_hash::generate_uuid_string_fr
/// change accidentally, and is NOT to be used directly to set the schema version of the
/// table namespaces.
#[allow(dead_code)]
const SCHEMA_VERSION: &str = "08193dfe-698a-8177-bdf8-20c5691a06e7";
const SCHEMA_VERSION: &str = "75ae6ac9-ddd8-8472-8a7a-8676d04f8679";

/// Keyspace Create (Templated)
const CREATE_NAMESPACE_CQL: &str = include_str!("./cql/namespace.cql");
Expand Down
30 changes: 17 additions & 13 deletions catalyst-gateway/bin/src/service/api/cardano/staking/assets_get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
stake_info::{FullStakeInfo, StakeInfo, StakedNativeTokenInfo},
},
responses::WithErrorResponses,
types::cardano::cip19_stake_address::Cip19StakeAddress,
types::cardano::{asset_name::AssetName, cip19_stake_address::Cip19StakeAddress},
},
};

Expand Down Expand Up @@ -79,8 +79,7 @@ struct TxoAssetInfo {
/// Asset hash.
id: Vec<u8>,
/// Asset name.
// TODO: https://github.com/input-output-hk/catalyst-voices/issues/1121
name: String,
name: AssetName,
/// Asset amount.
amount: num_bigint::BigInt,
}
Expand All @@ -100,8 +99,7 @@ struct TxoInfo {
/// Whether the TXO was spent.
spent_slot_no: Option<num_bigint::BigInt>,
/// TXO assets.
// TODO: https://github.com/input-output-hk/catalyst-voices/issues/1121
assets: HashMap<Vec<u8>, TxoAssetInfo>,
assets: HashMap<Vec<u8>, Vec<TxoAssetInfo>>,
}

/// Calculate the stake info for a given stake address.
Expand Down Expand Up @@ -186,12 +184,18 @@ async fn get_txo_by_txn(
let entry = txo_info
.assets
.entry(row.policy_id.clone())
.or_insert(TxoAssetInfo {
id: row.policy_id,
name: row.policy_name,
amount: num_bigint::BigInt::ZERO,
});
entry.amount += row.value;
.or_insert_with(Vec::new);

match entry.iter_mut().find(|item| item.id == row.policy_id) {
Some(item) => item.amount += row.value,
None => {
entry.push(TxoAssetInfo {
id: row.policy_id,
name: row.asset_name.into(),
amount: row.value,
});
},
}
}

let mut txos_by_txn = HashMap::new();
Expand Down Expand Up @@ -274,10 +278,10 @@ fn build_stake_info(
stake_info.ada_amount +=
i64::try_from(txo_info.value).map_err(|err| anyhow!(err))?;

for asset in txo_info.assets.into_values() {
for asset in txo_info.assets.into_values().flatten() {
stake_info.native_tokens.push(StakedNativeTokenInfo {
policy_hash: asset.id.try_into()?,
asset_name: asset.name.into(),
asset_name: asset.name,
amount: asset.amount.try_into()?,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ impl Example for AssetName {
}
}

// TODO: https://github.com/input-output-hk/catalyst-voices/issues/1121
impl From<Vec<u8>> for AssetName {
fn from(value: Vec<u8>) -> Self {
match String::from_utf8(value.clone()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub(crate) const PATTERN: &str = concatcp!(
/// Length of the encoded address.
const ENCODED_ADDR_LEN: usize = 53;
/// Length of the decoded address.
const DECODED_ADDR_LEN: usize = 28;
const DECODED_ADDR_LEN: usize = 29;
/// Minimum length
pub(crate) const MIN_LENGTH: usize = PROD_STAKE.len() + 1 + ENCODED_ADDR_LEN;
/// Minimum length
Expand Down Expand Up @@ -150,3 +150,34 @@ impl Example for Cip19StakeAddress {
Self(EXAMPLE.to_owned())
}
}

#[cfg(test)]
mod tests {
use super::*;

// cspell: disable
const VALID_PROD_STAKE_ADDRESS: &str =
"stake1u94ullc9nj9gawc08990nx8hwgw80l9zpmr8re44kydqy9cdjq6rq";
const VALID_TEST_STAKE_ADDRESS: &str =
"stake_test1uqehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gssrtvn";
const INVALID_STAKE_ADDRESS: &str =
"invalid1u9nlq5nmuzthw3vhgakfpxyq4r0zl2c0p8uqy24gpyjsa6c3df4h6";
// cspell: enable

#[test]
fn test_valid_stake_address_from_string() {
let stake_address_prod = Cip19StakeAddress::try_from(VALID_PROD_STAKE_ADDRESS.to_string());
let stake_address_test = Cip19StakeAddress::try_from(VALID_TEST_STAKE_ADDRESS.to_string());

assert!(stake_address_prod.is_ok());
assert!(stake_address_test.is_ok());
assert_eq!(stake_address_prod.unwrap().0, VALID_PROD_STAKE_ADDRESS);
assert_eq!(stake_address_test.unwrap().0, VALID_TEST_STAKE_ADDRESS);
}

#[test]
fn test_invalid_stake_address_from_string() {
let stake_address = Cip19StakeAddress::try_from(INVALID_STAKE_ADDRESS.to_string());
assert!(stake_address.is_err());
}
}
15 changes: 15 additions & 0 deletions catalyst-gateway/tests/api_tests/api_tests/get_cardano_assets.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Get staked ADA amount: zero assets
GET http://localhost:3030/api/draft/cardano/assets/stake_test1ursne3ndzr4kz8gmhmstu5026erayrnqyj46nqkkfcn0ufss2t7vt
HTTP 200
{"persistent":{"ada_amount":9809147618,"native_tokens":[],"slot_number":76323283},"volatile":{"ada_amount":0,"native_tokens":[],"slot_number":0}}

# Get staked ADA amount: single asset
GET http://localhost:3030/api/draft/cardano/assets/stake_test1uq7cnze6az9f8ffjrvkxx4ad77jz088frkhzupxcc7y4x8q5x808s
HTTP 200
{"persistent":{"ada_amount":8870859858,"native_tokens":[{"amount":3,"asset_name":"GoldRelic","policy_hash":"0x2862c9b33e98096107e2d8b8c072070834db9c91c0d2f3743e75df65"}],"slot_number":76572358},"volatile":{"ada_amount":0,"native_tokens":[],"slot_number":0}}

# Get staked ADA amount: multiple assets
GET http://localhost:3030/api/draft/cardano/assets/stake_test1ur66dds0pkf3j5tu7py9tqf7savpv7pgc5g3dd74xy0x2vsldf2mx
HTTP 200
[Asserts]
jsonpath "$.persistent.native_tokens" count == 9

0 comments on commit 43b9b58

Please sign in to comment.