Skip to content

Commit 10ea1fa

Browse files
committed
Merge branch 'main' into fix/cip36-assets-indexing
2 parents efd993b + 6cf4587 commit 10ea1fa

File tree

128 files changed

+5169
-2035
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+5169
-2035
lines changed

.config/dictionaries/project.dic

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ loguru
192192
lovelace
193193
lovelaces
194194
LTRB
195+
ltwh
195196
LynxLynxx
196197
Lynxx
197198
mdlint
@@ -259,6 +260,7 @@ pytest
259260
qrcode
260261
rapidoc
261262
ratelimit
263+
RGBO
262264
redoc
263265
reloadable
264266
Replayability
@@ -361,6 +363,7 @@ vsync
361363
wallclock
362364
wasmtime
363365
Wconditional
366+
webos
364367
Werror
365368
Wireframes
366369
Wmissing

catalyst-gateway/bin/Cargo.toml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ repository.workspace = true
1515
workspace = true
1616

1717
[dependencies]
18-
cardano-chain-follower = { version = "0.0.8", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
19-
rbac-registration = { version = "0.0.4", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
20-
catalyst-types = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
21-
cardano-blockchain-types = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
22-
catalyst-signed-doc = { version = "0.0.4", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
23-
c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250325-00" }
18+
cardano-chain-follower = { version = "0.0.8", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250331-01" }
19+
rbac-registration = { version = "0.0.4", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250331-01" }
20+
catalyst-types = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250331-01" }
21+
cardano-blockchain-types = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250331-01" }
22+
catalyst-signed-doc = { version = "0.0.4", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250331-01" }
2423

2524
pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
2625
pallas-traverse = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
@@ -66,7 +65,7 @@ futures = "0.3.31"
6665
rand = "0.8.5"
6766
moka = { version = "0.12.8", features = ["future"] }
6867
crossbeam-skiplist = "0.1.3"
69-
poem = { version = "3.1.6", features = ["embed", "prometheus", "compression"] }
68+
poem = { version = "=3.1.6", features = ["embed", "prometheus", "compression"] }
7069
poem-openapi = { version = "=5.1.5", features = [
7170
"openapi-explorer",
7271
"rapidoc",
@@ -98,19 +97,19 @@ stats_alloc = "0.1.10"
9897
memory-stats = "1.0.0"
9998
derive_more = { version = "2.0.1", default-features = false, features = ["from", "into"] }
10099
rayon = "1.10"
101-
oid-registry = "0.7.1"
102-
x509-cert = "0.2.5"
103100

104101
# Its a transitive dependency of the "poem-openapi" crate,
105102
# but its breaks API after version "5.1.8".
106103
poem-openapi-derive = { version = "=5.1.4" }
104+
# Its a transitive dependency of the "poem-openapi-derive" crate,
105+
# but its breaks API after version "0.20.11".
106+
darling = { version = "=0.20.10" }
107107

108108
[dev-dependencies]
109-
x509-cert = { version = "0.2.5", features = ["builder"] }
110109

111110
[build-dependencies]
112111
build-info-build = "0.0.39"
113112

114113
[package.metadata.cargo-machete]
115114
# remove that after fixing issues with latest crates
116-
ignored = ["poem-openapi-derive"]
115+
ignored = ["poem-openapi-derive", "darling"]

catalyst-gateway/bin/src/service/api/documents/post_document_index_query/mod.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Document Index Query
22
3-
use std::future;
3+
use std::collections::HashMap;
44

5-
use dashmap::DashMap;
65
use futures::TryStreamExt;
76
use poem_openapi::{payload::Json, ApiResponse};
87
use query_filter::DocumentIndexQueryFilter;
@@ -55,7 +54,7 @@ pub(crate) async fn endpoint(
5554
Err(e) => return AllResponses::handle_error(&e),
5655
};
5756

58-
let (docs, counts) = tokio::join!(
57+
let (fetched_docs, total_doc_count) = tokio::join!(
5958
fetch_docs(&conditions, &query_limits),
6059
SignedDocBody::retrieve_count(&conditions)
6160
);
@@ -64,7 +63,7 @@ pub(crate) async fn endpoint(
6463
let page = page.unwrap_or_default();
6564
let limit = limit.unwrap_or_default();
6665

67-
let total: u32 = match counts {
66+
let total: u32 = match total_doc_count {
6867
Ok(total) => {
6968
match total.try_into() {
7069
Ok(t) => t,
@@ -76,13 +75,8 @@ pub(crate) async fn endpoint(
7675
Err(e) => return AllResponses::handle_error(&e),
7776
};
7877

79-
match docs {
80-
Ok(docs) => {
81-
let doc_count: u32 = match docs.len().try_into() {
82-
Ok(d) => d,
83-
Err(e) => return AllResponses::handle_error(&e.into()),
84-
};
85-
78+
match fetched_docs {
79+
Ok((docs, doc_count)) => {
8680
let remaining = Remaining::calculate(page.into(), limit.into(), total, doc_count);
8781

8882
Responses::Ok(Json(DocumentIndexListDocumented(DocumentIndexList {
@@ -103,16 +97,23 @@ pub(crate) async fn endpoint(
10397
/// Fetch documents from the event db
10498
async fn fetch_docs(
10599
conditions: &DocsQueryFilter, query_limits: &QueryLimits,
106-
) -> anyhow::Result<Vec<IndexedDocumentDocumented>> {
100+
) -> anyhow::Result<(Vec<IndexedDocumentDocumented>, u32)> {
107101
let docs_stream = SignedDocBody::retrieve(conditions, query_limits).await?;
108-
let indexed_docs = DashMap::new();
109102

110-
docs_stream
111-
.try_for_each(|doc: SignedDocBody| {
112-
let id = *doc.id();
113-
indexed_docs.entry(id).or_insert_with(Vec::new).push(doc);
114-
future::ready(Ok(()))
115-
})
103+
let (indexed_docs, total_fetched_doc_count) = docs_stream
104+
.try_fold(
105+
(HashMap::new(), 0u32),
106+
|(mut indexed_docs, mut total_fetched_doc_count), doc| {
107+
async move {
108+
let id = *doc.id();
109+
indexed_docs.entry(id).or_insert_with(Vec::new).push(doc);
110+
total_fetched_doc_count = total_fetched_doc_count
111+
.checked_add(1)
112+
.ok_or(anyhow::anyhow!("Fetched Signed Documents overflow"))?;
113+
Ok((indexed_docs, total_fetched_doc_count))
114+
}
115+
},
116+
)
116117
.await?;
117118

118119
let docs = indexed_docs
@@ -130,5 +131,5 @@ async fn fetch_docs(
130131
}))
131132
})
132133
.collect::<Result<_, _>>()?;
133-
Ok(docs)
134+
Ok((docs, total_fetched_doc_count))
134135
}

catalyst-gateway/bin/src/service/common/auth/rbac/scheme.rs

Lines changed: 7 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,19 @@
22
use std::{env, error::Error, sync::LazyLock, time::Duration};
33

44
use anyhow::{anyhow, Context};
5-
use c509_certificate::c509::C509;
65
use cardano_blockchain_types::{Network, Point, Slot, TxnIndex};
76
use cardano_chain_follower::ChainFollower;
87
use catalyst_types::id_uri::IdUri;
9-
use ed25519_dalek::{VerifyingKey, PUBLIC_KEY_LENGTH};
8+
use ed25519_dalek::VerifyingKey;
109
use futures::{TryFutureExt, TryStreamExt};
1110
use moka::future::Cache;
12-
use oid_registry::{Oid, OID_SIG_ED25519};
1311
use poem::{error::ResponseError, http::StatusCode, IntoResponse, Request};
1412
use poem_openapi::{auth::Bearer, payload::Json, SecurityScheme};
1513
use rbac_registration::{
16-
cardano::cip509::{Cip509, LocalRefInt, RoleNumber},
14+
cardano::cip509::{Cip509, RoleNumber},
1715
registration::cardano::RegistrationChain,
1816
};
1917
use tracing::{error, warn};
20-
use x509_cert::Certificate;
2118

2219
use super::token::CatalystRBACTokenV1;
2320
use crate::{
@@ -161,6 +158,7 @@ async fn checker_api_catalyst_auth(
161158
// }
162159

163160
// Step 8: get the latest stable signing certificate registered for Role 0.
161+
164162
let public_key = last_signing_key(token.network(), &registrations)
165163
.await
166164
.map_err(|e| {
@@ -233,41 +231,10 @@ async fn last_signing_key(
233231
let chain = registration_chain(network, indexed_registrations)
234232
.await
235233
.context("Failed to build registration chain")?;
236-
let key_ref = chain
237-
.role_data()
238-
.get(&RoleNumber::ROLE_0)
239-
.context("Missing role 0 data")?
240-
.data()
241-
.signing_key()
242-
.context("Missing signing key")?;
243-
match key_ref.local_ref {
244-
LocalRefInt::X509Certs => {
245-
let cert = &chain
246-
.x509_certs()
247-
.get(&key_ref.key_offset)
248-
.context("Missing X509 role 0 certificate")?
249-
.last()
250-
.and_then(|p| p.data().as_ref())
251-
.context("Unable to get last X509 role 0 certificate")?;
252-
x509_key(cert)
253-
},
254-
LocalRefInt::C509Certs => {
255-
let cert = &chain
256-
.c509_certs()
257-
.get(&key_ref.key_offset)
258-
.context("Missing C509 role 0 certificate")?
259-
.last()
260-
.and_then(|p| p.data().as_ref())
261-
.context("Unable to get last C509 role 0 certificate")?;
262-
c509_key(cert)
263-
},
264-
LocalRefInt::PubKeys => {
265-
// We check this during Cip509 validation.
266-
Err(anyhow!(
267-
"Invalid signing key for role 0: it must reference a certificate, not public key"
268-
))
269-
},
270-
}
234+
chain
235+
.get_latest_signing_pk_for_role(&RoleNumber::ROLE_0)
236+
.ok_or(anyhow!("Cannot find latest role 0 public key"))
237+
.map(|(pk, _)| pk)
271238
}
272239

273240
/// Build a registration chain from the given indexed data.
@@ -328,68 +295,3 @@ async fn registration(network: Network, slot: Slot, txn_index: TxnIndex) -> anyh
328295
.context("Invalid RBAC registration")?
329296
.context("No RBAC registration at this block and txn index")
330297
}
331-
332-
/// Returns `VerifyingKey` from the given X509 certificate.
333-
fn x509_key(cert: &Certificate) -> anyhow::Result<VerifyingKey> {
334-
let oid: Oid = cert
335-
.tbs_certificate
336-
.subject_public_key_info
337-
.algorithm
338-
.oid
339-
.to_string()
340-
.parse()
341-
// `Context` cannot be used here because `OidParseError` doesn't implement `std::Error`.
342-
.map_err(|e| anyhow!("Invalid signature algorithm OID: {e:?}"))?;
343-
check_signature_algorithm(&oid)?;
344-
let extended_public_key = cert
345-
.tbs_certificate
346-
.subject_public_key_info
347-
.subject_public_key
348-
.as_bytes()
349-
.context("Invalid subject_public_key value (has unused bits)")?;
350-
verifying_key(extended_public_key).context("Unable to get verifying key from X509 certificate")
351-
}
352-
353-
/// Returns `VerifyingKey` from the given C509 certificate.
354-
fn c509_key(cert: &C509) -> anyhow::Result<VerifyingKey> {
355-
let oid = cert
356-
.tbs_cert()
357-
.subject_public_key_algorithm()
358-
.algo_identifier()
359-
.oid();
360-
check_signature_algorithm(oid)?;
361-
verifying_key(cert.tbs_cert().subject_public_key())
362-
.context("Unable to get verifying key from C509 certificate")
363-
}
364-
365-
/// Checks that the signature algorithm is supported.
366-
fn check_signature_algorithm(oid: &Oid) -> anyhow::Result<()> {
367-
// Currently the only supported signature algorithm is ED25519.
368-
if *oid != OID_SIG_ED25519 {
369-
return Err(anyhow!("Unsupported signature algorithm: {oid}"));
370-
}
371-
Ok(())
372-
}
373-
374-
// TODO: The very similar logic exists in the `rbac-registration` crate. It should be
375-
// moved somewhere and reused. See https://github.com/input-output-hk/catalyst-voices/issues/1952
376-
/// Creates `VerifyingKey` from the given extended public key.
377-
fn verifying_key(extended_public_key: &[u8]) -> anyhow::Result<VerifyingKey> {
378-
/// An extender public key length in bytes.
379-
const EXTENDED_PUBLIC_KEY_LENGTH: usize = 64;
380-
381-
if extended_public_key.len() != EXTENDED_PUBLIC_KEY_LENGTH {
382-
return Err(anyhow!(
383-
"Unexpected extended public key length in certificate: {}, expected {EXTENDED_PUBLIC_KEY_LENGTH}",
384-
extended_public_key.len()
385-
));
386-
}
387-
// This should never fail because of the check above.
388-
let public_key = extended_public_key
389-
.get(0..PUBLIC_KEY_LENGTH)
390-
.context("Unable to get public key part")?;
391-
let bytes: &[u8; PUBLIC_KEY_LENGTH] = public_key
392-
.try_into()
393-
.context("Invalid public key length in X509 certificate")?;
394-
VerifyingKey::from_bytes(bytes).context("Invalid public key in X509 certificate")
395-
}

catalyst-gateway/tests/api_tests/Earthfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
VERSION 0.8
22

33
IMPORT github.com/input-output-hk/catalyst-ci/earthly/python:v3.3.1 AS python-ci
4-
IMPORT github.com/input-output-hk/catalyst-libs/rust:r20250227-00 AS cat-libs-rust
4+
IMPORT github.com/input-output-hk/catalyst-libs/rust:r20250330-00 AS cat-libs-rust
55

66
builder:
77
FROM python-ci+python-base

0 commit comments

Comments
 (0)