Skip to content

Commit

Permalink
Merge branch 'main' into feat/1412-yesNoChoiceComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
LynxLynxx authored Jan 14, 2025
2 parents 5d6dbf9 + eb15954 commit 7e1a18a
Show file tree
Hide file tree
Showing 24 changed files with 738 additions and 679 deletions.
2 changes: 2 additions & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,5 @@ xpub
xpublic
xvfb
yoroi
stake1u94ullc9nj9gawc08990nx8hwgw80l9zpmr8re44kydqy9cdjq6rq
invalid1u9nlq5nmuzthw3vhgakfpxyq4r0zl2c0p8uqy24gpyjsa6c3df4h6
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SELECT
stake_address,vote_key
FROM cip36_registration;
13 changes: 12 additions & 1 deletion catalyst-gateway/bin/src/db/index/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rbac::{
get_role0_chain_root::GetRole0ChainRootQuery,
};
use registrations::{
get_all_stakes_and_vote_keys::GetAllStakesAndVoteKeysQuery,
get_from_stake_addr::GetRegistrationQuery, get_from_stake_hash::GetStakeAddrQuery,
get_from_vote_key::GetStakeAddrFromVoteKeyQuery, get_invalid::GetInvalidRegistrationQuery,
};
Expand Down Expand Up @@ -96,6 +97,8 @@ pub(crate) enum PreparedSelectQuery {
RegistrationsByChainRoot,
/// Get chain root by role0 key
ChainRootByRole0Key,
/// Get all stake and vote keys for snapshot (`stake_pub_key,vote_key`)
GetAllStakesAndVoteKeys,
}

/// All prepared UPSERT query statements (inserts/updates a single value of data).
Expand Down Expand Up @@ -157,6 +160,8 @@ pub(crate) struct PreparedQueries {
registrations_by_chain_root_query: PreparedStatement,
/// Get chain root by role0 key
chain_root_by_role0_key_query: PreparedStatement,
/// Get all stake and vote keys (`stake_key,vote_key`) for snapshot
get_all_stakes_and_vote_keys_query: PreparedStatement,
}

/// An individual query response that can fail
Expand Down Expand Up @@ -193,7 +198,9 @@ impl PreparedQueries {
let chain_root_by_stake_address = GetChainRootQuery::prepare(session.clone()).await;
let registrations_by_chain_root =
GetRegistrationsByChainRootQuery::prepare(session.clone()).await;
let chain_root_by_role0_key = GetRole0ChainRootQuery::prepare(session).await;
let chain_root_by_role0_key = GetRole0ChainRootQuery::prepare(session.clone()).await;
let get_all_stakes_and_vote_keys_query =
GetAllStakesAndVoteKeysQuery::prepare(session).await;

let (
txo_insert_queries,
Expand Down Expand Up @@ -241,6 +248,7 @@ impl PreparedQueries {
chain_root_by_stake_address_query: chain_root_by_stake_address?,
registrations_by_chain_root_query: registrations_by_chain_root?,
chain_root_by_role0_key_query: chain_root_by_role0_key?,
get_all_stakes_and_vote_keys_query: get_all_stakes_and_vote_keys_query?,
})
}

Expand Down Expand Up @@ -331,6 +339,9 @@ impl PreparedQueries {
&self.registrations_by_chain_root_query
},
PreparedSelectQuery::ChainRootByRole0Key => &self.chain_root_by_role0_key_query,
PreparedSelectQuery::GetAllStakesAndVoteKeys => {
&self.get_all_stakes_and_vote_keys_query
},
};

session
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Get all stake and vote keys (`stake_pub_key,vote_key`)
//! Result is used to compose various query registrations for snapshot.
use std::sync::Arc;

use scylla::{
prepared_statement::PreparedStatement, transport::iterator::TypedRowStream, DeserializeRow,
SerializeRow, Session,
};
use tracing::error;

use crate::db::index::{
queries::{PreparedQueries, PreparedSelectQuery},
session::CassandraSession,
};

/// Get all (`stake_addr,vote` keys)
/// [(`stake_addr,vote_key`)]
const GET_ALL_STAKES_AND_VOTE_KEYS: &str = include_str!("../cql/get_all_stake_addrs.cql");

/// Get all stake and vote keys from cip36 registration
#[derive(SerializeRow)]
pub(crate) struct GetAllStakesAndVoteKeysParams {}

/// Get stakes and vote keys for snapshot.
#[derive(DeserializeRow)]
pub(crate) struct GetAllStakesAndVoteKeysQuery {
/// Full Stake Address (not hashed, 32 byte ED25519 Public key).
pub stake_address: Vec<u8>,
/// Voting Public Key
pub vote_key: Vec<u8>,
}

impl GetAllStakesAndVoteKeysQuery {
/// Prepares get all `stake_addr` paired with vote keys [(`stake_addr,vote_key`)]
pub(crate) async fn prepare(session: Arc<Session>) -> anyhow::Result<PreparedStatement> {
let get_all_stake_and_vote_keys = PreparedQueries::prepare(
session,
GET_ALL_STAKES_AND_VOTE_KEYS,
scylla::statement::Consistency::All,
true,
)
.await;

get_all_stake_and_vote_keys.inspect_err(
|error| error!(error=%error, "Failed to prepare get all (stake addrs, vote_keys)"),
)
}

/// Executes get all `stake_addr` paired with vote keys [(`stake_addr,vote_key`)]
pub(crate) async fn execute(
session: &CassandraSession, params: GetAllStakesAndVoteKeysParams,
) -> anyhow::Result<TypedRowStream<GetAllStakesAndVoteKeysQuery>> {
let iter = session
.execute_iter(PreparedSelectQuery::GetAllStakesAndVoteKeys, params)
.await?
.rows_stream::<GetAllStakesAndVoteKeysQuery>()?;

Ok(iter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ pub(crate) struct GetRegistrationParams {
pub stake_address: Vec<u8>,
}

impl From<&ed25519_dalek::VerifyingKey> for GetRegistrationParams {
fn from(value: &ed25519_dalek::VerifyingKey) -> Self {
impl From<Vec<u8>> for GetRegistrationParams {
fn from(value: Vec<u8>) -> Self {
GetRegistrationParams {
stake_address: value.as_bytes().to_vec(),
stake_address: value,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ use scylla::{
};
use tracing::error;

use crate::db::index::{
queries::{PreparedQueries, PreparedSelectQuery},
session::CassandraSession,
use crate::{
db::index::{
queries::{PreparedQueries, PreparedSelectQuery},
session::CassandraSession,
},
service::common::types::cardano::slot_no::SlotNo,
};

/// Get invalid registrations from stake addr query.
Expand All @@ -28,12 +31,10 @@ pub(crate) struct GetInvalidRegistrationParams {

impl GetInvalidRegistrationParams {
/// Create a new instance of [`GetInvalidRegistrationParams`]
pub(crate) fn new(
stake_address: Vec<u8>, slot_no: num_bigint::BigInt,
) -> GetInvalidRegistrationParams {
pub(crate) fn new(stake_address: Vec<u8>, slot_no: SlotNo) -> GetInvalidRegistrationParams {
Self {
stake_address,
slot_no,
slot_no: slot_no.into(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Registration related queries.
pub(crate) mod get_all_stakes_and_vote_keys;
pub(crate) mod get_from_stake_addr;
pub(crate) mod get_from_stake_hash;
pub(crate) mod get_from_vote_key;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- Index of CIP-36 registrations searchable by Stake Address.
-- Full registration data needs to be queried from the man cip36 registration tables.
-- Full registration data needs to be queried from the main cip36 registration tables.
-- Includes both Valid and Invalid registrations.
CREATE TABLE IF NOT EXISTS cip36_registration_for_vote_key (
-- Primary Key Data
Expand Down
23 changes: 13 additions & 10 deletions catalyst-gateway/bin/src/db/index/tests/scylla_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
use futures::StreamExt;

use super::*;
use crate::db::index::queries::{
rbac::{get_chain_root::*, get_registrations::*, get_role0_chain_root::*},
registrations::{
get_from_stake_addr::*, get_from_stake_hash::*, get_from_vote_key::*, get_invalid::*,
use crate::{
db::index::queries::{
rbac::{get_chain_root::*, get_registrations::*, get_role0_chain_root::*},
registrations::{
get_from_stake_addr::*, get_from_stake_hash::*, get_from_vote_key::*, get_invalid::*,
},
staked_ada::{
get_assets_by_stake_address::*, get_txi_by_txn_hash::*, get_txo_by_stake_address::*,
update_txo_spent::*,
},
sync_status::update::*,
},
staked_ada::{
get_assets_by_stake_address::*, get_txi_by_txn_hash::*, get_txo_by_stake_address::*,
update_txo_spent::*,
},
sync_status::update::*,
service::common::types::cardano::slot_no::SlotNo,
};

#[ignore = "An integration test which requires a running Scylla node instance, disabled from `testunit` CI run"]
Expand Down Expand Up @@ -58,7 +61,7 @@ async fn test_get_invalid_registration_w_stake_addr() {

let mut row_stream = GetInvalidRegistrationQuery::execute(
&session,
GetInvalidRegistrationParams::new(vec![], num_bigint::BigInt::from(i64::MAX)),
GetInvalidRegistrationParams::new(vec![], SlotNo::from(u64::MAX)),
)
.await
.unwrap();
Expand Down
72 changes: 60 additions & 12 deletions catalyst-gateway/bin/src/service/api/cardano/cip36/endpoint.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,77 @@
//! Implementation of the GET `/cardano/cip36` endpoint
use std::time::Duration;

use poem::http::HeaderMap;
use tokio::time::sleep;
use tracing::error;

use self::cardano::{hash28::HexEncodedHash28, query::stake_or_voter::StakeAddressOrPublicKey};
use super::{
cardano::{self},
response, NoneOrRBAC, SlotNo,
filter::{get_registration_given_stake_key_hash, get_registration_given_vote_key, snapshot},
response, SlotNo,
};
use crate::{
db::index::session::CassandraSession,
service::{
api::cardano::cip36::response::AllRegistration,
common::{self, types::headers::retry_after::RetryAfterOption},
},
};
use crate::service::common::{self};

/// Process the endpoint operation
pub(crate) async fn cip36_registrations(
_lookup: Option<cardano::query::stake_or_voter::StakeOrVoter>, _asat: Option<SlotNo>,
lookup: Option<cardano::query::stake_or_voter::StakeOrVoter>, asat: Option<SlotNo>,
_page: common::types::generic::query::pagination::Page,
_limit: common::types::generic::query::pagination::Limit, _auth: NoneOrRBAC,
_headers: &HeaderMap,
_limit: common::types::generic::query::pagination::Limit, _headers: &HeaderMap,
) -> response::AllRegistration {
// Dummy sleep, remove it
sleep(Duration::from_millis(1)).await;
let Some(session) = CassandraSession::get(true) else {
error!("Failed to acquire db session");
return AllRegistration::service_unavailable(
&anyhow::anyhow!("Failed to acquire db session"),
RetryAfterOption::Default,
);
};

if let Some(stake_or_voter) = lookup {
match StakeAddressOrPublicKey::from(stake_or_voter) {
StakeAddressOrPublicKey::Address(cip19_stake_address) => {
// Typically, a stake address will start with 'stake1',
// We need to convert this to a stake hash as per our data model to then find the,
// Full Stake Public Key (32 byte Ed25519 Public key, not hashed).
// We then get the latest registration or from a specific time as optionally
// specified in the query parameter. This can be represented as either
// the blockchains slot number or a unix timestamp.
let stake_hash: HexEncodedHash28 = match cip19_stake_address.try_into() {
Ok(stake_hash) => stake_hash,
Err(err) => {
return AllRegistration::handle_error(&anyhow::anyhow!(
"Given stake pub key is corrupt {:?}",
err
));
},
};

// Todo: refactor the below into a single operation here.
return get_registration_given_stake_key_hash(stake_hash, session, asat).await;
},
StakeAddressOrPublicKey::PublicKey(ed25519_hex_encoded_public_key) => {
// As above...
// Except using a voting key.
return get_registration_given_vote_key(
ed25519_hex_encoded_public_key,
session,
asat,
)
.await;
},
StakeAddressOrPublicKey::All =>
// As above...
// Snapshot replacement, returns all registrations or returns a
// subset of registrations if constrained by a given time.
{
return snapshot(session, asat).await
},
};
};

// If _asat is None, then get the latest slot number from the chain follower and use that.
// If _for is not defined, use the stake addresses defined for Role0 in the _auth
// parameter. _auth not yet implemented, so put placeholder for that, and return not
// found until _auth is implemented.
Expand Down
Loading

0 comments on commit 7e1a18a

Please sign in to comment.