Skip to content

Commit

Permalink
Merge branch 'feat/rbac-registration' into feat/registration-chain
Browse files Browse the repository at this point in the history
  • Loading branch information
bkioshn authored Nov 29, 2024
2 parents 672a1d6 + a1cea39 commit 1fd155a
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 104 deletions.
2 changes: 1 addition & 1 deletion rust/cardano-chain-follower/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cardano-chain-follower"
version = "0.0.4"
version = "0.0.5"
edition.workspace = true
authors.workspace = true
homepage.workspace = true
Expand Down
185 changes: 182 additions & 3 deletions rust/cardano-chain-follower/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,38 @@ impl Network {
///
/// The Slot does not have to be a valid slot present in the blockchain.
#[must_use]
pub fn time_to_slot(&self, _time: DateTime<Utc>) -> Option<u64> {
// TODO: Implement this, for now just return None.
None
pub fn time_to_slot(&self, time: DateTime<Utc>) -> Option<u64> {
let genesis = self.genesis_values();

let byron_start_time = i64::try_from(genesis.byron_known_time)
.map(|time| DateTime::<Utc>::from_timestamp(time, 0))
.ok()??;
let shelley_start_time = i64::try_from(genesis.shelley_known_time)
.map(|time| DateTime::<Utc>::from_timestamp(time, 0))
.ok()??;

// determine if the given time is in Byron or Shelley era.
if time < byron_start_time {
return None;
}

if time < shelley_start_time {
// Byron era
let time_diff = time - byron_start_time;
let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.byron_slot_length);

u64::try_from(elapsed_slots)
.map(|elapsed_slots| Some(genesis.byron_known_slot + elapsed_slots))
.ok()?
} else {
// Shelley era
let time_diff = time - shelley_start_time;
let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.shelley_slot_length);

u64::try_from(elapsed_slots)
.map(|elapsed_slots| Some(genesis.shelley_known_slot + elapsed_slots))
.ok()?
}
}
}

Expand All @@ -191,6 +220,7 @@ mod tests {
use std::str::FromStr;

use anyhow::Ok;
use chrono::{TimeZone, Utc};

use super::*;

Expand All @@ -214,4 +244,153 @@ mod tests {

Ok(())
}

#[test]
fn test_time_to_slot_before_blockchain() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let before_blockchain = Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap() - 1, 0)
.unwrap();

assert_eq!(network.time_to_slot(before_blockchain), None);
}

#[test]
fn test_time_to_slot_byron_era() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let byron_start_time = Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0)
.unwrap();
let byron_slot_length = i64::from(genesis.byron_slot_length);

// a time in the middle of the Byron era.
let time = byron_start_time + chrono::Duration::seconds(byron_slot_length * 100);
let expected_slot = genesis.byron_known_slot + 100;

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}

#[test]
fn test_time_to_slot_transition_to_shelley() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let shelley_start_time = Utc
.timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0)
.unwrap();
let byron_slot_length = i64::from(genesis.byron_slot_length);

// a time just before Shelley era starts.
let time = shelley_start_time - chrono::Duration::seconds(1);
let elapsed_slots = (time
- Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0)
.unwrap())
.num_seconds()
/ byron_slot_length;
let expected_slot = genesis.byron_known_slot + u64::try_from(elapsed_slots).unwrap();

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}

#[test]
fn test_time_to_slot_shelley_era() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let shelley_start_time = Utc
.timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0)
.unwrap();
let shelley_slot_length = i64::from(genesis.shelley_slot_length);

// a time in the middle of the Shelley era.
let time = shelley_start_time + chrono::Duration::seconds(shelley_slot_length * 200);
let expected_slot = genesis.shelley_known_slot + 200;

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}

#[test]
fn test_slot_to_time_to_slot_consistency() {
let network = Network::Mainnet;

// a few arbitrary slots in different ranges.
let slots_to_test = vec![0, 10_000, 1_000_000, 50_000_000];

for slot in slots_to_test {
let time = network.slot_to_time(slot);
let calculated_slot = network.time_to_slot(time);

assert_eq!(calculated_slot, Some(slot), "Failed for slot: {slot}");
}
}

#[test]
#[allow(clippy::panic)]
fn test_time_to_slot_to_time_consistency() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

// Byron, Shelley, and Conway.
let times_to_test = vec![
Utc.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap() + 100, 0)
.unwrap(),
Utc.timestamp_opt(
i64::try_from(genesis.shelley_known_time).unwrap() + 1_000,
0,
)
.unwrap(),
Utc.timestamp_opt(
i64::try_from(genesis.shelley_known_time).unwrap() + 10_000_000,
0,
)
.unwrap(),
];

for time in times_to_test {
if let Some(slot) = network.time_to_slot(time) {
let calculated_time = network.slot_to_time(slot);

assert_eq!(
calculated_time.timestamp(),
time.timestamp(),
"Failed for time: {time}"
);
} else {
panic!("time_to_slot returned None for a valid time: {time}");
}
}
}

#[test]
fn test_conway_era_time_to_slot_and_back() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

// a very late time, far in the Conway era.
let conway_time = Utc
.timestamp_opt(
i64::try_from(genesis.shelley_known_time).unwrap() + 20_000_000,
0,
)
.unwrap();

let slot = network.time_to_slot(conway_time);
assert!(
slot.is_some(),
"Failed to calculate slot for Conway era time"
);

let calculated_time = network.slot_to_time(slot.unwrap());

assert_eq!(
calculated_time.timestamp(),
conway_time.timestamp(),
"Inconsistency for Conway era time"
);
}
}
38 changes: 1 addition & 37 deletions rust/rbac-registration/src/cardano/cip509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ impl Cip509 {
for role in role_set {
if role.role_number == 0 {
stake_key_validate =
validate_stake_public_key(self, txn, txn_idx, validation_report)
.unwrap_or(false);
validate_stake_public_key(self, txn, validation_report).unwrap_or(false);
payment_key_validate =
validate_payment_key(txn, txn_idx, role, validation_report)
.unwrap_or(false);
Expand All @@ -221,38 +220,3 @@ impl Cip509 {
&& signing_key
}
}

#[cfg(test)]
mod tests {

use super::*;

#[test]
fn test_decode_cip509() {
// This data is from conway_1.block
let cip_509 = "a50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c0150226d126819472b7afad7d0b8c7b89aa20258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b9458401b03060066006fd5b67002167882eac0b5f2b11da40788a39bfa0324c494f7003a6b4c1c4bac378e322cb280230a4002f5b2754e863806f7e524afc99996aa28584032f02b600cbf04c6a09e05100880a09ee59b6627dc78d68175469b8c5b1fac141a6da5c6c2ea446597b6f0b6efea00a04ac0c1756455589908a5e089ba604a1258405917d6ee2b2535959d806c00eb2958929ababb40d681b5245751538e915d3d90f561ddcaa9aaa9cd78a30882a22a99c742c4f7610b43750a0d6651e8640a8d4c58402167427cfa933d6430c026640888210cd0c4e93e7015100300dcaef47b9c155ea4ccb27773c27f5d6a44fbf98065a14e5f0eca530e57082a971cbf22fa9065585840ae72e2a061eb558d3fd7727e87a8f07b5faf0d3cedf8d99ab6e0c845f5dd3ce78d31d7365c523b5a4dfe5d35bfafaefb2f60dd7473cbe8d6aa6bf557b1fbdf775840bf96bcd3ffdbfc7d20b65be7f5c7dba1cf635e3b449bb644bdfc73e0e49a5db73edddc7ed331220ba732f62f3aee8503f5c6f9bd5f7fedb37dc6580196052e50584027fdd7e8bfe9146561ad1ebc79ecef0ee1df7081cf9cd1fd929569ef3d55972d5b7ff882ce2213f789fc08787164f14aa86d55e98e332b220a07fa464aaa7c335840ce4bcfb268ed577f72e87fdea4442107bf2da93fe05121d5befa7ae5aecc5f3f9c732e82108003166380198c0146b0e214114a31d7c62b0ec18afd5834034c2b58402b2c515b350d8980a16932071b6d8d125ea1eb53dc28a8aee1787a1670b9e8c4c8cb00c726f3515a39ca1689f870295752820a64721e05e1a234710583416316584031d80291ac9a2b66a04cba844b85f9928a4a04a9928b2805124a25b3aaa4422e45e5d422a9b88a028ba4a5123ac244b8b472164b86085ac21357c3aae7696be25840f1104878009b03813d9e6c53255722402090206058a009d2b808aff772fb712d75f1dea09507fd83838e045dd9ce3eb59e4554f5ed02b8aeb60700f4b39dd9fe584064e1d5a137de0fa4c6cccfd71f831bee372756d72990b357a44e2f9eaf3854db65379db466cfcb55517ba71550acade564f4b7efd1fd95fa57228cee6fa9ae3458405ce1ae79b77f7cd5bdecfcb800fbdb7eaf720eae5995176d94a07c326c71aaf5e6f8439e577edb2d1ed64959324b5a7476e9159bf37bdf226edb747787b79b9e5840bc6ab5b84714eefa4a8c2df4aba37a36757d8b39dd79ec41b4a2f3ee96eabdc0e1f65b37264bdbfdf79eebbc820a7deab4e39f7e1cbf6610402fd8fb55fbef3d584038226e4d37c42970c830184b2e1c5026eadb9677ae8f6d300975ca6ceec5c8920382e827c1f636f7dd9f8d492737f4520a944bfeebba5ca2d5efa80ad453a43f584004c357ecccfc4dab75ce560b0300db9092ced52625d0c8df6fc89da9a45b6dc9c2461f21e6ee7b7afd877fbd8c1a1fa7ff38fa506e14749ebb68e24571c6220c584004208c284d628c2148b252f91b8b50014b080b040554095b52ca862bb974218222d412112ae5d2584c54584ae157f22b183cb4ba9c5fc42ba6894ad074ffe0875840c69ee921211d0ce4cd0f89b7e708163b3ab9286fe26a8c68ed85930cabc5dbfed7f9681c535dbdbfeb56f7a2b32d1f43de1dbcc934676edefacb3df7c1210067584064a1b8d94448b7f22a77dc736edb12f7c2c52b2eb8d4a80b78147d89f9a3a0659c03e10bbb336e391b3961f1afbfa08af3de2a817fceddea0cb57f438b0f8947581e9782ee92e890df65636d835d2d465cc5521c0ec05470e002800015eecf5818635840e0427f23196c17cf13f030595335343030c11d914bc7a84b56af7040930af4110fd4ca29b0bc0e83789adb8668ea2ef28c1dd10dc1fd35ea6ae8c06ee769540d";
let binding = hex::decode(cip_509).unwrap();
let mut decoder = Decoder::new(binding.as_slice());
let decoded_cip509 = Cip509::decode(&mut decoder, &mut ()).unwrap();

let purpose: [u8; 16] = hex::decode("ca7a1457ef9f4c7f9c747f8c4a4cfa6c")
.unwrap()
.try_into()
.unwrap();
let txn_inputs_hash: [u8; 16] = hex::decode("226d126819472b7afad7d0b8c7b89aa2")
.unwrap()
.try_into()
.unwrap();
let prv_tx_id: [u8; 32] =
hex::decode("4d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c2")
.unwrap()
.try_into()
.unwrap();
let validation_signature = hex::decode("e0427f23196c17cf13f030595335343030c11d914bc7a84b56af7040930af4110fd4ca29b0bc0e83789adb8668ea2ef28c1dd10dc1fd35ea6ae8c06ee769540d").unwrap();

assert_eq!(decoded_cip509.purpose, UuidV4(purpose));
assert_eq!(decoded_cip509.txn_inputs_hash, TxInputHash(txn_inputs_hash));
assert_eq!(decoded_cip509.prv_tx_id, Some(prv_tx_id.into()));
assert_eq!(decoded_cip509.validation_signature, validation_signature);
}
}
5 changes: 4 additions & 1 deletion rust/rbac-registration/src/cardano/cip509/rbac/pub_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ impl Decode<'_, ()> for SimplePublicKeyType {
ed25519.copy_from_slice(&bytes);
Ok(Self::Ed25519(Ed25519PublicKey(ed25519)))
} else {
Err(decode::Error::message("Invalid length for Ed25519 key"))
Err(decode::Error::message(format!(
"Invalid length for Ed25519 key, got {}",
bytes.len()
)))
}
},
_ => Err(decode::Error::message("Unknown tag for Self")),
Expand Down
20 changes: 6 additions & 14 deletions rust/rbac-registration/src/cardano/cip509/rbac/role_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub struct RoleData {
/// Role number.
pub role_number: u8,
/// Optional role signing key.
pub role_signing_key: Option<Vec<KeyLocalRef>>,
pub role_signing_key: Option<KeyLocalRef>,
/// Optional role encryption key.
pub role_encryption_key: Option<Vec<KeyLocalRef>>,
pub role_encryption_key: Option<KeyLocalRef>,
/// Optional payment key.
pub payment_key: Option<i16>,
/// Optional role extended data keys.
Expand Down Expand Up @@ -56,20 +56,12 @@ impl Decode<'_, ()> for RoleData {
role_data.role_number = decode_helper(d, "RoleNumber in RoleData", ctx)?;
},
RoleDataInt::RoleSigningKey => {
let arr_len = decode_array_len(d, "RoleSigningKey")?;
let mut role_signing_key = Vec::new();
for _ in 0..arr_len {
role_signing_key.push(KeyLocalRef::decode(d, ctx)?);
}
role_data.role_signing_key = Some(role_signing_key);
decode_array_len(d, "RoleSigningKey")?;
role_data.role_signing_key = Some(KeyLocalRef::decode(d, ctx)?);
},
RoleDataInt::RoleEncryptionKey => {
let arr_len = decode_array_len(d, "RoleEncryptionKey")?;
let mut role_encryption_key = Vec::new();
for _ in 0..arr_len {
role_encryption_key.push(KeyLocalRef::decode(d, ctx)?);
}
role_data.role_encryption_key = Some(role_encryption_key);
decode_array_len(d, "RoleEncryptionKey")?;
role_data.role_encryption_key = Some(KeyLocalRef::decode(d, ctx)?);
},
RoleDataInt::PaymentKey => {
role_data.payment_key =
Expand Down
Loading

0 comments on commit 1fd155a

Please sign in to comment.