Skip to content
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
5 changes: 5 additions & 0 deletions crates/cardano/src/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ pub fn bootstrap_utxos<D: Domain>(
state_writer.commit()?;
index_writer.commit()?;

// A genesis bootstrap only happens on a fresh store, so every block the
// store will ever index flows through the apply path from here on. That
// makes the stake address log complete by construction.
indexes.mark_stake_log_ready()?;

Ok(())
}

Expand Down
51 changes: 49 additions & 2 deletions crates/cardano/src/indexes/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//! `IndexDelta` structures from Cardano block data.

use dolos_core::{
ArchiveIndexDelta, BlockSlot, ChainPoint, EraCbor, IndexDelta, Tag, TxoRef, UtxoIndexDelta,
UtxoSetDelta,
ArchiveIndexDelta, BlockSlot, ChainPoint, EraCbor, IndexDelta, StakeAddressAppearance, Tag,
TxoRef, UtxoIndexDelta, UtxoSetDelta,
};
use pallas::{
codec::minicbor,
Expand Down Expand Up @@ -283,6 +283,10 @@ impl CardanoIndexDeltaBuilder {

self.start_block(block.slot(), block.hash().to_vec(), Some(block.number()));

self.delta
.stake_addresses
.extend(stake_appearances_from_block(block));

for tx in block.txs() {
self.add_tx_hash(tx.hash().to_vec());

Expand Down Expand Up @@ -412,6 +416,49 @@ impl CardanoIndexDeltaBuilder {
}
}

/// Stake address log candidates in one block: every produced output that
/// carries a stake credential, ordered by transaction and output index.
///
/// Both the apply path (`index_block`) and the rollback path
/// (`compute_undo`) derive their log entries from this one function, so an
/// undo removes exactly what an apply inserted.
pub fn stake_appearances_from_block(
block: &pallas::ledger::traverse::MultiEraBlock<'_>,
) -> Vec<StakeAddressAppearance> {
let mut out = Vec::new();

for (tx_order, tx) in block.txs().iter().enumerate() {
for (output_order, output) in tx.produces() {
let Ok(address) = output.address() else {
continue;
};

let stake = match &address {
Address::Shelley(x) => {
pallas_extras::shelley_address_to_stake_address(x).map(|s| s.to_vec())
}
Address::Stake(x) => Some(x.to_vec()),
Address::Byron(_) => None,
};

let Some(stake) = stake else {
continue;
};

let order = ((tx_order as u32) << 16) | (output_order as u32 & 0xffff);

out.push(StakeAddressAppearance {
slot: block.slot(),
order,
stake,
address: address.to_vec(),
});
}
}

out
}

/// Build an `IndexDelta` from a `UtxoSetDelta` (for genesis/bulk import).
///
/// This creates an `IndexDelta` containing only UTxO filter changes,
Expand Down
4 changes: 3 additions & 1 deletion crates/cardano/src/indexes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ mod dimensions;
mod ext;
mod query;

pub use delta::{index_delta_from_utxo_delta, CardanoIndexDeltaBuilder};
pub use delta::{
index_delta_from_utxo_delta, stake_appearances_from_block, CardanoIndexDeltaBuilder,
};
pub use dimensions::{archive as archive_dimensions, utxo as utxo_dimensions};
pub use ext::CardanoIndexExt;
pub use query::{AsyncCardanoQueryExt, ScriptData, ScriptLanguage, SlotOrder};
7 changes: 6 additions & 1 deletion crates/cardano/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,12 @@ impl dolos_core::ChainLogic for CardanoLogic {
let utxo_delta = crate::utxoset::compute_undo_delta(blockv, &decoded_inputs)
.map_err(ChainError::from)?;

let index_delta = crate::indexes::index_delta_from_utxo_delta(point, &utxo_delta);
let mut index_delta = crate::indexes::index_delta_from_utxo_delta(point, &utxo_delta);

// The undo path never re-runs `index_block`, so the stake address
// log entries to remove are derived here from the same function the
// apply path used to insert them.
index_delta.stake_addresses = crate::indexes::stake_appearances_from_block(blockv);

let tx_hashes = blockv.txs().iter().map(|tx| tx.hash()).collect();

Expand Down
Loading
Loading