mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-07-15 18:29:38 +00:00
145 lines
5.0 KiB
Rust
145 lines
5.0 KiB
Rust
use common::test_utils::produce_dummy_block;
|
|
use lee::{Account, AccountId};
|
|
use tempfile::tempdir;
|
|
|
|
use super::*;
|
|
|
|
fn marker_id() -> AccountId {
|
|
AccountId::new([1; 32])
|
|
}
|
|
|
|
/// A state distinguishable by the marker account's balance, so tests can tell
|
|
/// which snapshot a write persisted.
|
|
///
|
|
/// TODO: is this a bit too much of a hot-fix for test snapshot?
|
|
fn state_with_balance(balance: u128) -> V03State {
|
|
V03State::new().with_public_accounts([(
|
|
marker_id(),
|
|
Account {
|
|
balance,
|
|
..Account::default()
|
|
},
|
|
)])
|
|
}
|
|
|
|
fn dbio_with_genesis(path: &Path) -> (RocksDBIO, Block) {
|
|
let genesis = produce_dummy_block(1, None, vec![]);
|
|
let dbio = RocksDBIO::create(path, &genesis, &state_with_balance(100)).unwrap();
|
|
(dbio, genesis)
|
|
}
|
|
|
|
fn stored_balance(dbio: &RocksDBIO) -> u128 {
|
|
dbio.get_lee_state()
|
|
.unwrap()
|
|
.get_account_by_id(marker_id())
|
|
.balance
|
|
}
|
|
|
|
#[test]
|
|
fn store_followed_block_persists_new_block_and_state() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let (dbio, genesis) = dbio_with_genesis(temp_dir.path());
|
|
|
|
let block2 = produce_dummy_block(2, Some(genesis.header.hash), vec![]);
|
|
dbio.store_followed_block(&block2, &state_with_balance(200), false)
|
|
.unwrap();
|
|
|
|
let stored = dbio.get_block(2).unwrap().expect("block 2 is stored");
|
|
assert_eq!(stored.header.hash, block2.header.hash);
|
|
assert!(matches!(stored.bedrock_status, BedrockStatus::Pending));
|
|
assert_eq!(dbio.latest_block_meta().unwrap().id, 2);
|
|
assert_eq!(stored_balance(&dbio), 200);
|
|
}
|
|
|
|
#[test]
|
|
fn store_followed_block_finalized_marks_block() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let (dbio, genesis) = dbio_with_genesis(temp_dir.path());
|
|
|
|
let block2 = produce_dummy_block(2, Some(genesis.header.hash), vec![]);
|
|
dbio.store_followed_block(&block2, &state_with_balance(200), true)
|
|
.unwrap();
|
|
|
|
let stored = dbio.get_block(2).unwrap().expect("block 2 is stored");
|
|
assert!(matches!(stored.bedrock_status, BedrockStatus::Finalized));
|
|
}
|
|
|
|
#[test]
|
|
fn store_followed_block_redelivery_is_a_noop_and_keeps_finalized() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let (dbio, genesis) = dbio_with_genesis(temp_dir.path());
|
|
|
|
let block2 = produce_dummy_block(2, Some(genesis.header.hash), vec![]);
|
|
dbio.store_followed_block(&block2, &state_with_balance(200), true)
|
|
.unwrap();
|
|
dbio.store_followed_block(&block2, &state_with_balance(300), false)
|
|
.unwrap();
|
|
|
|
let stored = dbio.get_block(2).unwrap().expect("block 2 is stored");
|
|
assert!(
|
|
matches!(stored.bedrock_status, BedrockStatus::Finalized),
|
|
"re-delivery must not demote a finalized block"
|
|
);
|
|
assert_eq!(
|
|
stored_balance(&dbio),
|
|
200,
|
|
"re-delivery must not overwrite the persisted state"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn store_followed_blocks_batch_lands_meta_and_state_on_last_block() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let (dbio, genesis) = dbio_with_genesis(temp_dir.path());
|
|
|
|
// Block 2 is already stored (own production); one update then finalizes it
|
|
// and adopts block 3.
|
|
let block2 = produce_dummy_block(2, Some(genesis.header.hash), vec![]);
|
|
dbio.store_followed_block(&block2, &state_with_balance(200), false)
|
|
.unwrap();
|
|
|
|
let block3 = produce_dummy_block(3, Some(block2.header.hash), vec![]);
|
|
dbio.store_followed_blocks(
|
|
&[(&block2, true), (&block3, false)],
|
|
&state_with_balance(300),
|
|
)
|
|
.unwrap();
|
|
|
|
let stored2 = dbio.get_block(2).unwrap().expect("block 2 is stored");
|
|
assert!(matches!(stored2.bedrock_status, BedrockStatus::Finalized));
|
|
let stored3 = dbio.get_block(3).unwrap().expect("block 3 is stored");
|
|
assert!(matches!(stored3.bedrock_status, BedrockStatus::Pending));
|
|
|
|
// Meta and state land together on the last block of the batch.
|
|
let meta = dbio.latest_block_meta().unwrap();
|
|
assert_eq!(meta.id, 3);
|
|
assert_eq!(meta.hash, block3.header.hash);
|
|
assert_eq!(stored_balance(&dbio), 300);
|
|
}
|
|
|
|
#[test]
|
|
fn store_followed_block_overwrites_competing_block_at_same_id() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let (dbio, genesis) = dbio_with_genesis(temp_dir.path());
|
|
|
|
let block2a = produce_dummy_block(2, Some(genesis.header.hash), vec![]);
|
|
dbio.store_followed_block(&block2a, &state_with_balance(200), false)
|
|
.unwrap();
|
|
|
|
// A reorg replaces block 2: the competing block wins the slot.
|
|
let block2b = produce_dummy_block(2, Some(HashType([9; 32])), vec![]);
|
|
dbio.store_followed_block(&block2b, &state_with_balance(300), false)
|
|
.unwrap();
|
|
|
|
let stored = dbio.get_block(2).unwrap().expect("block 2 is stored");
|
|
assert_eq!(stored.header.hash, block2b.header.hash);
|
|
assert!(matches!(stored.bedrock_status, BedrockStatus::Pending));
|
|
assert_eq!(stored_balance(&dbio), 300);
|
|
|
|
// The tip meta must follow the reorg winner, or a restart seeds the chain
|
|
// from the orphaned block's hash.
|
|
let meta = dbio.latest_block_meta().unwrap();
|
|
assert_eq!(meta.id, 2);
|
|
assert_eq!(meta.hash, block2b.header.hash);
|
|
}
|