Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/rbac indexing #1367

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions catalyst-gateway/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ description = "The Catalyst Data Gateway"
keywords = ["cardano", "catalyst", "gateway"]
categories = ["command-line-utilities"]
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -21,7 +21,7 @@ rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-

pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
pallas-traverse = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
#pallas-crypto = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
pallas-crypto = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }

clap = { version = "4.5.20", features = ["derive", "env"] }
tracing = { version = "0.1.40", features = ["log"] }
Expand Down Expand Up @@ -94,9 +94,13 @@ jsonschema = "0.26.1"
bech32 = "0.11.0"
const_format = "0.2.33"
regex = "1.11.1"
as-slice = "0.2.1"
to_vec = "0.1.0"
minicbor = { version = "0.25.1", features = ["std"] }

[dev-dependencies]
proptest = "1.5.0"
x509-cert = { version = "0.2.5", features = ["builder"] }

[build-dependencies]
build-info-build = "0.0.39"
1 change: 1 addition & 0 deletions catalyst-gateway/bin/src/cardano/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
};

// pub(crate) mod cip36_registration_obsolete;
pub(crate) mod types;
pub(crate) mod util;

/// Blocks batch length that will trigger the blocks buffer to be written to the database.
Expand Down
11 changes: 11 additions & 0 deletions catalyst-gateway/bin/src/cardano/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Simple Cardano Types not defined by Pallas
//!
//! Note: We should not redefine types already defined by Pallas, but use those types.

use pallas_crypto::hash::Hash;

/// Transaction Hash - Blake2b-256 Hash of a transaction
pub(crate) type TransactionHash = Hash<32>;

/// Public Key Hash - Raw Blake2b-224 Hash of a Ed25519 Public Key (Has no discriminator, just the hash)
pub(crate) type PubKeyHash = Hash<28>;
1 change: 0 additions & 1 deletion catalyst-gateway/bin/src/db/index/block/cip36/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ impl Cip36InsertQuery {
&mut self, txn: usize, txn_index: i16, slot_no: u64, block: &MultiEraBlock,
) {
if let Some(decoded_metadata) = block.txn_metadata(txn, Metadata::cip36::LABEL) {
#[allow(irrefutable_let_patterns)]
if let Metadata::DecodedMetadataValues::Cip36(cip36) = &decoded_metadata.value {
// Check if we are indexing a valid or invalid registration.
// Note, we ONLY care about catalyst, we should only have 1 voting key, if not, call
Expand Down
6 changes: 3 additions & 3 deletions catalyst-gateway/bin/src/db/index/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) async fn index_block(block: &MultiEraBlock) -> anyhow::Result<()> {
for (txn_index, txs) in block_data.txs().iter().enumerate() {
let txn = from_saturating(txn_index);

let txn_hash = txs.hash().to_vec();
let txn_hash = txs.hash();

// Index the TXIs.
txi_index.index(txs, slot_no);
Expand All @@ -54,10 +54,10 @@ pub(crate) async fn index_block(block: &MultiEraBlock) -> anyhow::Result<()> {
cert_index.index(txs, slot_no, txn, block);

// Index the TXOs.
txo_index.index(txs, slot_no, &txn_hash, txn);
txo_index.index(txs, slot_no, txn_hash, txn);

// Index RBAC 509 inside the transaction.
rbac509_index.index(&txn_hash, txn_index, txn, slot_no, block);
rbac509_index.index(&session, txn_hash, txn_index, slot_no, block);
}

// We then execute each batch of data from the block.
Expand Down
141 changes: 141 additions & 0 deletions catalyst-gateway/bin/src/db/index/block/rbac509/chain_root.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//! Chain Root

use std::sync::{Arc, LazyLock};

use cardano_chain_follower::Metadata::cip509::Cip509;
use futures::StreamExt;
use moka::{policy::EvictionPolicy, sync::Cache};
use pallas::ledger::addresses::StakeAddress;
use pallas_crypto::hash::Hash;
use tracing::{error, warn};

use crate::{
cardano::types::TransactionHash,
db::index::{
block::from_saturating,
queries::rbac::{self, get_chain_root},
},
service::{common::auth::rbac::role0_kid::Role0Kid, utilities::convert::big_uint_to_u64},
};

use self::rbac::{
get_chain_root_from_stake_addr::cache_for_stake_addr, get_role0_chain_root::cache_for_role0_kid,
};

use super::CassandraSession;

/// Chain Root Id - Hash of the first transaction in an RBAC Chain.
pub(crate) type ChainRootId = TransactionHash;

/// The Chain Root for an RBAC Key Chain.
#[derive(Debug, Clone)]
pub(crate) struct ChainRoot {
/// Transaction hash of the Chain Root itself
pub txn_hash: ChainRootId,
/// What slot# the Chain root is found in on the blockchain
pub slot: u64,
/// What transaction in the block holds the chain root.
pub idx: usize,
}

pub(crate) const LRU_MAX_CAPACITY: usize = 1024;

/// Cached Chain Root By Transaction ID.
static CHAIN_ROOT_BY_TXN_HASH_CACHE: LazyLock<Cache<TransactionHash, ChainRoot>> =
LazyLock::new(|| {
Cache::builder()
// Set Eviction Policy to `LRU`
.eviction_policy(EvictionPolicy::lru())
// Set the initial capacity
.initial_capacity(LRU_MAX_CAPACITY)
// Set the maximum number of LRU entries
.max_capacity(LRU_MAX_CAPACITY as u64)
// Create the cache.
.build()
});

impl ChainRoot {
/// Create a new ChainRoot record
pub(crate) fn new(chain_root: TransactionHash, slot_no: u64, txn_idx: usize) -> Self {
Self {
txn_hash: chain_root,
slot: slot_no,
idx: txn_idx,
}
}

/// Gets a new `ChainRoot` from the given Transaction and its metadata.
///
/// Will try and get it from the cache first, and fall back to the Index DB if not found.
pub(crate) async fn get(
session: &Arc<CassandraSession>, txn_hash: Hash<32>, txn_index: usize, slot_no: u64,
cip509: &Cip509,
) -> Option<ChainRoot> {
if let Some(prv_tx_id) = cip509.cip509.prv_tx_id {
match CHAIN_ROOT_BY_TXN_HASH_CACHE.get(&prv_tx_id) {
Some(chain_root) => Some(chain_root), // Cached
None => {
// Not cached, need to see if its in the DB.
if let Ok(mut result) = get_chain_root::Query::execute(
session,
get_chain_root::QueryParams {
transaction_id: prv_tx_id.to_vec(),
},
)
.await
{
if let Some(row_res) = result.next().await {
let row = match row_res {
Ok(row) => row,
Err(err) => {
error!(error = ?err, "Failed to parse get chain root by transaction id query row");
return None;
},
};

let txn_hash = Hash::<32>::from(row.chain_root.as_slice());

let new_root = Self {
txn_hash,
slot: big_uint_to_u64(&row.slot_no),
idx: from_saturating(row.txn),
};

// Add the new Chain root to the cache.
CHAIN_ROOT_BY_TXN_HASH_CACHE.insert(txn_hash, new_root.clone());

Some(new_root)
} else {
error!(prv_tx_id = ?prv_tx_id, "No data for chain root for prv_tx_id");
None
}
} else {
warn!(prev_txn_id=%prv_tx_id, "Chain root not found.");
None
}
},
}
} else {
let new_root = Self {
txn_hash,
idx: txn_index,
slot: slot_no,
};

// Add the new Chain root to the cache.
CHAIN_ROOT_BY_TXN_HASH_CACHE.insert(txn_hash, new_root.clone());

Some(new_root)
}
}

/// Update the cache when a rbac registration is indexed.
pub(crate) fn cache_for_stake_addr(&self, stake: &StakeAddress) {
cache_for_stake_addr(stake, self);
}

/// Update the cache when a rbac registration is indexed.
pub(crate) fn cache_for_role0_kid(&self, kid: Role0Kid) {
cache_for_role0_kid(kid, self);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Index of Chain Root For Role0 Key. RBAC 509 registrations.
INSERT INTO rbac_chain_root_for_role0_key (
role0_kid,
slot_no,
txn,
chain_root,
chain_root_slot,
chain_root_txn,
signature_alg,
public_key
) VALUES (
:role0_kid,
:slot_no,
:txn,
:chain_root,
:chain_root_slot,
:chain_root_txn,
:signature_alg,
:public_key
);
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
-- Index of Chain Root For Stake Address. RBAC 509 registrations.
INSERT INTO chain_root_for_stake_addr (
INSERT INTO rbac_chain_root_for_stake_addr (
stake_addr,
slot_no,
txn,
chain_root
chain_root,
chain_root_slot,
chain_root_txn
) VALUES (
:stake_addr,
:slot_no,
:txn,
:chain_root
:chain_root,
:chain_root_slot,
:chain_root_txn
);
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
-- Index of Chain Root For TX ID. RBAC 509 registrations.
INSERT INTO chain_root_for_txn_id (
INSERT INTO rbac_chain_root_for_txn_id (
transaction_id,
chain_root
chain_root,
slot_no,
txn_idx
) VALUES (
:transaction_id,
:chain_root
:chain_root,
:slot_no,
:txn_idx
);
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
-- Index RBAC 509 Registrations (Valid)
INSERT INTO RBAC509_registration (
INSERT INTO rbac_registration (
chain_root,
transaction_id,
slot_no,
txn,
transaction_id,
purpose,
prv_txn_id
purpose,
) VALUES (
:chain_root,
:transaction_id,
:slot_no,
:txn,
:transaction_id,
:purpose,
:prv_txn_id
:purpose,
);
Loading
Loading