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

feat(BlockRecord): add new fields #195

Merged
merged 3 commits into from
Mar 25, 2022
Merged
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
4 changes: 4 additions & 0 deletions src/mapper/byron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ impl EventWriter {
hash: hash.to_hex(),
number: source.header.consensus_data.2[0],
slot: source.header.consensus_data.0.to_abs_slot(),
epoch: Some(source.header.consensus_data.0.epoch),
epoch_slot: Some(source.header.consensus_data.0.slot),
previous_hash: source.header.prev_block.to_hex(),
cbor_hex: match self.config.include_block_cbor {
true => hex::encode(cbor).into(),
Expand Down Expand Up @@ -201,6 +203,8 @@ impl EventWriter {
tx_count: 0,
number: source.header.consensus_data.difficulty[0],
slot: source.header.to_abs_slot(),
epoch: Some(source.header.consensus_data.epoch_id),
epoch_slot: Some(0),
previous_hash: source.header.prev_block.to_hex(),
cbor_hex: match self.config.include_block_cbor {
true => hex::encode(cbor).into(),
Expand Down
9 changes: 9 additions & 0 deletions src/mapper/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::model::{
StakeCredential, TransactionRecord, TxInputRecord, TxOutputRecord,
};

use crate::utils::time::TimeProvider;
use crate::Error;

use super::EventWriter;
Expand Down Expand Up @@ -359,6 +360,12 @@ impl EventWriter {
cbor: &[u8],
era: Era,
) -> Result<BlockRecord, Error> {
let relative_epoch = self
.utils
.time
.as_ref()
.map(|time| time.absolute_slot_to_relative(source.header.header_body.slot));

Ok(BlockRecord {
era,
body_size: source.header.header_body.block_body_size as usize,
Expand All @@ -367,6 +374,8 @@ impl EventWriter {
hash: hex::encode(hash),
number: source.header.header_body.block_number,
slot: source.header.header_body.slot,
epoch: relative_epoch.map(|(epoch, _)| epoch),
epoch_slot: relative_epoch.map(|(_, epoch_slot)| epoch_slot),
previous_hash: hex::encode(source.header.header_body.prev_hash),
cbor_hex: match self.config.include_block_cbor {
true => hex::encode(cbor).into(),
Expand Down
2 changes: 2 additions & 0 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ pub enum StakeCredential {
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct BlockRecord {
pub era: Era,
pub epoch: Option<u64>,
pub epoch_slot: Option<u64>,
pub body_size: usize,
pub issuer_vkey: String,
pub tx_count: usize,
Expand Down
6 changes: 6 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ impl SwallowResult for Result<(), Error> {
/// values.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ChainWellKnownInfo {
pub byron_epoch_length: u32,
pub byron_slot_length: u32,
pub byron_known_slot: u64,
pub byron_known_hash: String,
pub byron_known_time: u64,
pub shelley_epoch_length: u32,
pub shelley_slot_length: u32,
pub shelley_known_slot: u64,
pub shelley_known_hash: String,
Expand All @@ -67,11 +69,13 @@ impl ChainWellKnownInfo {
/// Hardcoded values for mainnet
pub fn mainnet() -> Self {
ChainWellKnownInfo {
byron_epoch_length: 432000,
byron_slot_length: 20,
byron_known_slot: 0,
byron_known_time: 1506203091,
byron_known_hash: "f0f7892b5c333cffc4b3c4344de48af4cc63f55e44936196f365a9ef2244134f"
.to_string(),
shelley_epoch_length: 432000,
shelley_slot_length: 1,
shelley_known_slot: 4492800,
shelley_known_hash: "aa83acbf5904c0edfe4d79b3689d3d00fcfc553cf360fd2229b98d464c28e9de"
Expand All @@ -84,11 +88,13 @@ impl ChainWellKnownInfo {
/// Hardcoded values for testnet
pub fn testnet() -> Self {
ChainWellKnownInfo {
byron_epoch_length: 432000,
byron_slot_length: 20,
byron_known_slot: 0,
byron_known_time: 1564010416,
byron_known_hash: "8f8602837f7c6f8b8867dd1cbc1842cf51a27eaed2c70ef48325d00f8efb320f"
.to_string(),
shelley_epoch_length: 432000,
shelley_slot_length: 1,
shelley_known_slot: 1598400,
shelley_known_hash: "02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f"
Expand Down
97 changes: 83 additions & 14 deletions src/utils/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::utils::ChainWellKnownInfo;
pub(crate) trait TimeProvider {
/// Maps between slots and wallclock
fn slot_to_wallclock(&self, slot: u64) -> u64;
fn absolute_slot_to_relative(&self, slot: u64) -> (u64, u64);
}

/// A naive, standalone implementation of a time provider
Expand All @@ -17,11 +18,33 @@ pub(crate) trait TimeProvider {
/// logic from a well-known configured point in the chain, assuming homogeneous
/// slot length from that point forward.
#[derive(Clone)]
pub(crate) struct NaiveProvider(ChainWellKnownInfo);
pub(crate) struct NaiveProvider {
config: ChainWellKnownInfo,
shelley_start_epoch: u64,
}

impl NaiveProvider {
pub fn new(config: ChainWellKnownInfo) -> Self {
NaiveProvider(config)
assert!(
config.byron_epoch_length > 0,
"byron epoch length needs to be greater than zero"
);

assert!(
config.shelley_epoch_length > 0,
"shelley epoch length needs to be greater than zero"
);

let (shelley_start_epoch, _) = compute_era_epoch(
config.shelley_known_slot,
config.byron_slot_length as u64,
config.byron_epoch_length as u64,
);

NaiveProvider {
config,
shelley_start_epoch,
}
}
}

Expand All @@ -35,9 +58,17 @@ fn compute_linear_timestamp(
known_time + (query_slot - known_slot) * slot_length
}

#[inline]
fn compute_era_epoch(era_slot: u64, era_slot_length: u64, era_epoch_length: u64) -> (u64, u64) {
let epoch = (era_slot * era_slot_length) / era_epoch_length;
let reminder = era_slot % era_epoch_length;

(epoch, reminder)
}

impl TimeProvider for NaiveProvider {
fn slot_to_wallclock(&self, slot: u64) -> u64 {
let NaiveProvider(config) = self;
let NaiveProvider { config, .. } = self;

if slot < config.shelley_known_slot {
compute_linear_timestamp(
Expand All @@ -55,16 +86,50 @@ impl TimeProvider for NaiveProvider {
)
}
}

fn absolute_slot_to_relative(&self, slot: u64) -> (u64, u64) {
let NaiveProvider {
config,
shelley_start_epoch,
} = self;

if slot < config.shelley_known_slot {
compute_era_epoch(
slot,
config.byron_slot_length as u64,
config.byron_epoch_length as u64,
)
} else {
let era_slot = slot - config.shelley_known_slot;

let (era_epoch, reminder) = compute_era_epoch(
era_slot,
config.shelley_slot_length as u64,
config.shelley_epoch_length as u64,
);

(shelley_start_epoch + era_epoch, reminder)
}
}
}

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

fn assert_slot_matches_timestamp(provider: &NaiveProvider, slot: u64, ts: u64) {
fn assert_slot_matches_timestamp(
provider: &NaiveProvider,
slot: u64,
expected_ts: u64,
expected_epoch: u64,
expected_epoch_slot: u64,
) {
let wallclock = provider.slot_to_wallclock(slot);
assert_eq!(wallclock, expected_ts);

assert_eq!(wallclock, ts);
let (epoch, epoch_slot) = provider.absolute_slot_to_relative(slot);
assert_eq!(epoch, expected_epoch);
assert_eq!(epoch_slot, expected_epoch_slot);
}

#[test]
Expand All @@ -73,19 +138,23 @@ mod tests {

// Byron start, value copied from:
// https://explorer.cardano.org/en/block?id=f0f7892b5c333cffc4b3c4344de48af4cc63f55e44936196f365a9ef2244134f
assert_slot_matches_timestamp(&provider, 0, 1506203091);
assert_slot_matches_timestamp(&provider, 0, 1506203091, 0, 0);

// Byron middle, value copied from:
// https://explorer.cardano.org/en/block?id=c1b57d58761af4dc3c6bdcb3542170cec6db3c81e551cd68012774d1c38129a3
assert_slot_matches_timestamp(&provider, 2160007, 1549403231);
assert_slot_matches_timestamp(&provider, 2160007, 1549403231, 100, 7);

// Shelley start, value copied from:
// https://explorer.cardano.org/en/block?id=aa83acbf5904c0edfe4d79b3689d3d00fcfc553cf360fd2229b98d464c28e9de
assert_slot_matches_timestamp(&provider, 4492800, 1596059091);
assert_slot_matches_timestamp(&provider, 4492800, 1596059091, 208, 0);

// Shelly middle, value copied from:
// https://explorer.cardano.org/en/block?id=ca60833847d0e70a1adfa6b7f485766003cf7d96d28d481c20d4390f91b76d68
assert_slot_matches_timestamp(&provider, 51580240, 1643146531);
assert_slot_matches_timestamp(&provider, 51580240, 1643146531, 316, 431440);

// Shelly middle, value copied from:
// https://explorer.cardano.org/en/block?id=ec07c6f74f344062db5340480e5b364aac8bb40768d184c1b1491e05c5bec4c4
assert_slot_matches_timestamp(&provider, 54605026, 1646171317, 324, 226);
}

#[test]
Expand All @@ -94,22 +163,22 @@ mod tests {

// Byron origin, value copied from:
// https://explorer.cardano-testnet.iohkdev.io/en/block?id=8f8602837f7c6f8b8867dd1cbc1842cf51a27eaed2c70ef48325d00f8efb320f
assert_slot_matches_timestamp(&provider, 0, 1564010416);
assert_slot_matches_timestamp(&provider, 0, 1564010416, 0, 0);

// Byron start, value copied from:
// https://explorer.cardano-testnet.iohkdev.io/en/block?id=388a82f053603f3552717d61644a353188f2d5500f4c6354cc1ad27a36a7ea91
assert_slot_matches_timestamp(&provider, 1031, 1564031036);
assert_slot_matches_timestamp(&provider, 1031, 1564031036, 0, 1031);

// Byron middle, value copied from:
// https://explorer.cardano-testnet.iohkdev.io/en/block?id=66102c0b80e1eebc9cddf9cab43c1bf912e4f1963d6f3b8ff948952f8409e779
assert_slot_matches_timestamp(&provider, 561595, 1575242316);
assert_slot_matches_timestamp(&provider, 561595, 1575242316, 25, 129595);

// Shelley start, value copied from:
// https://explorer.cardano-testnet.iohkdev.io/en/block?id=02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f
assert_slot_matches_timestamp(&provider, 1598400, 1595967616);
assert_slot_matches_timestamp(&provider, 1598400, 1595967616, 74, 0);

// Shelley middle, value copied from:
// https://explorer.cardano-testnet.iohkdev.io/en/block?id=26a1b5a649309c0c8dd48f3069d9adea5a27edf5171dfb941b708acaf2d76dcd
assert_slot_matches_timestamp(&provider, 48783593, 1643152809);
assert_slot_matches_timestamp(&provider, 48783593, 1643152809, 183, 97193);
}
}