Skip to content
Open
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: 2 additions & 2 deletions magicblock-aperture/src/geyser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl GeyserPluginManager {
) -> Result<(), GeyserPluginError> {
check_if_enabled!(self);
let blockhash = block.blockhash.to_string();
let parent_blockhash = block.parent_blockhash.to_string();
let rewards = solana_transaction_status::RewardsAndNumPartitions {
rewards: Vec::new(),
num_partitions: None,
Expand All @@ -165,8 +166,7 @@ impl GeyserPluginManager {
block_height: Some(block.slot),
rewards: &rewards,
block_time: Some(block.clock.unix_timestamp),
// TODO(bmuddha): register proper values with the new ledger
parent_blockhash: "11111111111111111111111111111111",
parent_blockhash: &parent_blockhash,
executed_transaction_count: 0,
entry_count: 0,
};
Expand Down
21 changes: 21 additions & 0 deletions magicblock-ledger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct LatestBlockInner {
pub slot: u64,
pub blockhash: Hash,
pub clock: Clock,
pub parent_blockhash: Hash,
}

/// Atomically updated, shared, latest block information
Expand Down Expand Up @@ -45,6 +46,26 @@ impl LatestBlockInner {
slot,
blockhash,
clock,
parent_blockhash: Hash::default(),
}
}

pub fn new_with_parent(
slot: u64,
blockhash: Hash,
timestamp: i64,
parent_blockhash: Hash,
) -> Self {
let clock = Clock {
slot: slot + 1,
unix_timestamp: timestamp,
..Default::default()
};
Self {
slot,
blockhash,
clock,
parent_blockhash,
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions magicblock-ledger/tests/get_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,39 @@ fn test_get_block_meta() {
assert_eq!(slot_2_block.blockhash, slot_2_hash.to_string());
}

#[test]
fn test_write_block_stores_parent_blockhash() {
init_logger!();
let ledger = setup();

let slot_0_hash = Hash::new_unique();
ledger
.write_block(LatestBlockInner::new(0, slot_0_hash, 1))
.unwrap();
assert_eq!(
ledger.latest_block().load().parent_blockhash,
Hash::default()
);

let slot_1_hash = Hash::new_unique();
ledger
.write_block(LatestBlockInner::new_with_parent(
1,
slot_1_hash,
2,
slot_0_hash,
))
.unwrap();

let latest = ledger.latest_block().load();
assert_eq!(latest.slot, 1);
assert_eq!(latest.blockhash, slot_1_hash);
assert_eq!(latest.parent_blockhash, slot_0_hash);

let slot_1_block = get_block(&ledger, 1);
assert_eq!(slot_1_block.previous_blockhash, slot_0_hash.to_string());
}

#[test]
fn test_get_block_transactions() {
init_logger!();
Expand Down
25 changes: 22 additions & 3 deletions magicblock-processor/src/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,18 @@ impl TransactionScheduler {
.await
.map_err(|_| "scheduler semaphore closed".to_string())?;

let block =
LatestBlockInner::new(block.slot, block.hash, block.timestamp);
// once write_block runs, latest_block is overwritten with the block that's being applied
let parent_blockhash = Self::initial_blockhash(
&self.accountsdb,
&self.ledger.latest_block(),
);
let block = LatestBlockInner::new_with_parent(
block.slot,
block.hash,
block.timestamp,
parent_blockhash,
);

self.verify_block_as_replica(&block);
self.ledger
.write_block(block.clone())
Expand Down Expand Up @@ -575,6 +585,10 @@ impl TransactionScheduler {
/// Prepares block as primary: computes blockhash and broadcasts to replicas.
async fn prepare_block_as_primary(&mut self) -> LatestBlockInner {
let blockhash = (*self.hasher.finalize().as_bytes()).into();
let parent_blockhash = Self::initial_blockhash(
&self.accountsdb,
&self.ledger.latest_block(),
);
// NOTE:
// As we have a single node network, we have no
// option but to use the time from host machine
Expand All @@ -584,7 +598,12 @@ impl TransactionScheduler {
// NOTE: since we can tick very frequently, a lot
// of blocks might have identical timestamps
.as_secs() as i64;
let block = LatestBlockInner::new(self.slot, blockhash, timestamp);
let block = LatestBlockInner::new_with_parent(
self.slot,
blockhash,
timestamp,
parent_blockhash,
);
let msg = Message::Block(replication::Block {
slot: block.slot,
hash: block.blockhash,
Expand Down
10 changes: 9 additions & 1 deletion magicblock-processor/tests/replica_ordering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,10 @@ async fn test_replay_block_waits_for_queued_transactions() {
.expect("failed to apply replayed block");

assert_eq!(env.get_account(acc).data()[0], 77);
assert_eq!(env.ledger.latest_block().load().slot, slot);
let latest = env.ledger.latest_block().load();
assert_eq!(latest.slot, slot);
assert_eq!(latest.blockhash, hash);
assert_eq!(latest.parent_blockhash, prev_hash);
assert_eq!(env.accountsdb.slot(), slot);
}

Expand Down Expand Up @@ -255,6 +258,11 @@ async fn test_replica_replayed_superblock_takes_snapshot_without_publishing() {
.await
.expect("failed to apply replayed superblock boundary");

let latest = env.ledger.latest_block().load();
assert_eq!(latest.slot, slot);
assert_eq!(latest.blockhash, hash);
assert_eq!(latest.parent_blockhash, prev_hash);

timeout(Duration::from_secs(5), async {
while !snapshot.exists() {
sleep(Duration::from_millis(10)).await;
Expand Down
24 changes: 24 additions & 0 deletions magicblock-processor/tests/scheduling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,3 +527,27 @@ async fn test_wait_for_idle_coordination() {
.await
.expect("should acquire permit quickly when scheduler is idle");
}

#[tokio::test]
async fn test_primary_slot_transition_sets_parent_blockhash() {
let mut env = setup_env(1);
let parent_hash = env.ledger.latest_block().load().blockhash;
let initial_slot = env.ledger.latest_block().load().slot;

env.run_scheduler();
env.yield_to_scheduler().await;

// Wait for the first primary slot tick to finalize the in-progress slot.
timeout(TIMEOUT, async {
loop {
let latest = env.ledger.latest_block().load();
if latest.slot > initial_slot {
assert_eq!(latest.parent_blockhash, parent_hash);
return;
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
})
.await
.expect("timed out waiting for primary slot transition");
}