Skip to content

Commit a6d918e

Browse files
authored
Merge pull request #1777 from mintlayer/fix/add_missing_reorg_test
Improve simulation and add missing test
2 parents 0e90372 + ce472fd commit a6d918e

File tree

20 files changed

+733
-77
lines changed

20 files changed

+733
-77
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chainstate/src/detail/ban_score.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ impl BanScore for pos_accounting::Error {
521521
E::DelegationDeletionFailedBalanceNonZero => 100,
522522
E::DelegationDeletionFailedPoolsShareNonZero => 100,
523523
E::DelegationDeletionFailedPoolStillExists => 100,
524+
E::InvariantErrorNonZeroBalanceForNonExistingDelegation => 100,
524525
}
525526
}
526527
}
@@ -614,6 +615,7 @@ impl BanScore for tokens_accounting::Error {
614615
tokens_accounting::Error::CannotLockFrozenToken(_) => 100,
615616
tokens_accounting::Error::CannotChangeAuthorityForFrozenToken(_) => 100,
616617
tokens_accounting::Error::CannotUndoChangeAuthorityForFrozenToken(_) => 100,
618+
tokens_accounting::Error::InvariantErrorNonZeroSupplyForNonExistingToken => 100,
617619
tokens_accounting::Error::ViewFail => 0,
618620
tokens_accounting::Error::StorageWrite => 0,
619621
}

chainstate/src/detail/error_classification.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,8 @@ impl BlockProcessingErrorClassification for tokens_accounting::Error {
722722
| Error::CannotUndoFreezeTokenThatIsNotFrozen(_)
723723
| Error::CannotUndoUnfreezeTokenThatIsFrozen(_)
724724
| Error::CannotChangeAuthorityForFrozenToken(_)
725-
| Error::CannotUndoChangeAuthorityForFrozenToken(_) => {
725+
| Error::CannotUndoChangeAuthorityForFrozenToken(_)
726+
| Error::InvariantErrorNonZeroSupplyForNonExistingToken => {
726727
BlockProcessingErrorClass::BadBlock
727728
}
728729

@@ -830,7 +831,8 @@ impl BlockProcessingErrorClassification for pos_accounting::Error {
830831
| Error::IncreaseStakerRewardsOfNonexistingPool
831832
| Error::StakerBalanceOverflow
832833
| Error::InvariantErrorIncreasePledgeUndoFailedPoolBalanceNotFound
833-
| Error::InvariantErrorIncreaseStakerRewardUndoFailedPoolBalanceNotFound => {
834+
| Error::InvariantErrorIncreaseStakerRewardUndoFailedPoolBalanceNotFound
835+
| Error::InvariantErrorNonZeroBalanceForNonExistingDelegation => {
834836
BlockProcessingErrorClass::BadBlock
835837
}
836838

chainstate/test-framework/src/key_manager.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use common::{
3737
use crypto::key::{KeyKind, PrivateKey, PublicKey};
3838
use randomness::{CryptoRng, Rng};
3939

40+
#[derive(Clone)]
4041
struct Multisig {
4142
keys: Vec<(PrivateKey, PublicKey)>,
4243
min_required_signatures: NonZeroU8,
@@ -53,6 +54,7 @@ impl Multisig {
5354
}
5455
}
5556

57+
#[derive(Clone)]
5658
pub struct KeyManager {
5759
public_key_hashes: BTreeMap<PublicKeyHash, PrivateKey>,
5860
public_keys: BTreeMap<PublicKey, PrivateKey>,

chainstate/test-framework/src/transaction_builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use common::{
2323
use rstest::rstest;
2424

2525
/// The transaction builder.
26+
#[derive(Clone)]
2627
pub struct TransactionBuilder {
2728
flags: u128,
2829
inputs: Vec<TxInput>,

chainstate/test-suite/src/tests/fungible_tokens_v1.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5351,3 +5351,163 @@ fn reorg_tokens_tx_with_simple_tx(#[case] seed: Seed) {
53515351
let new_chain_block_id = tf.create_chain(&tf.genesis().get_id().into(), 2, &mut rng).unwrap();
53525352
assert_eq!(new_chain_block_id, tf.best_block_id());
53535353
}
5354+
5355+
#[rstest]
5356+
#[trace]
5357+
#[case(Seed::from_entropy())]
5358+
fn issue_same_token_alternative_pos_chain(#[case] seed: Seed) {
5359+
use chainstate_test_framework::create_stake_pool_data_with_all_reward_to_staker;
5360+
use common::{
5361+
chain::{config::create_unit_test_config, PoolId},
5362+
primitives::H256,
5363+
};
5364+
use crypto::vrf::{VRFKeyKind, VRFPrivateKey};
5365+
5366+
utils::concurrency::model(move || {
5367+
let mut rng = make_seedable_rng(seed);
5368+
let (vrf_sk, vrf_pk) = VRFPrivateKey::new_from_rng(&mut rng, VRFKeyKind::Schnorrkel);
5369+
5370+
let genesis_pool_id = PoolId::new(H256::random_using(&mut rng));
5371+
let amount_to_stake = create_unit_test_config().min_stake_pool_pledge();
5372+
5373+
let (stake_pool_data, staking_sk) = create_stake_pool_data_with_all_reward_to_staker(
5374+
&mut rng,
5375+
amount_to_stake,
5376+
vrf_pk.clone(),
5377+
);
5378+
5379+
let chain_config = chainstate_test_framework::create_chain_config_with_staking_pool(
5380+
&mut rng,
5381+
(amount_to_stake * 2).unwrap(),
5382+
genesis_pool_id,
5383+
stake_pool_data,
5384+
)
5385+
.build();
5386+
let target_block_time = chain_config.target_block_spacing();
5387+
let mut tf = TestFramework::builder(&mut rng).with_chain_config(chain_config).build();
5388+
tf.progress_time_seconds_since_epoch(target_block_time.as_secs());
5389+
5390+
let genesis_block_id = tf.genesis().get_id();
5391+
let token_supply_change_fee =
5392+
tf.chainstate.get_chain_config().token_supply_change_fee(BlockHeight::zero());
5393+
5394+
//issue a token
5395+
let issuance = make_issuance(
5396+
&mut rng,
5397+
TokenTotalSupply::Fixed(Amount::from_atoms(100)),
5398+
IsTokenFreezable::No,
5399+
);
5400+
let issue_token_tx = TransactionBuilder::new()
5401+
.add_input(
5402+
TxInput::from_utxo(genesis_block_id.into(), 0),
5403+
InputWitness::NoSignature(None),
5404+
)
5405+
.add_output(TxOutput::Transfer(
5406+
OutputValue::Coin(token_supply_change_fee),
5407+
Destination::AnyoneCanSpend,
5408+
))
5409+
.add_output(TxOutput::IssueFungibleToken(Box::new(issuance.clone())))
5410+
.build();
5411+
let token_id = make_token_id(issue_token_tx.transaction().inputs()).unwrap();
5412+
let tx_id = issue_token_tx.transaction().get_id();
5413+
tf.make_pos_block_builder()
5414+
.with_stake_pool_id(genesis_pool_id)
5415+
.with_stake_spending_key(staking_sk.clone())
5416+
.with_vrf_key(vrf_sk.clone())
5417+
.add_transaction(issue_token_tx)
5418+
.build_and_process(&mut rng)
5419+
.unwrap();
5420+
5421+
// Mint some tokens to increase circulating supply
5422+
let mint_block_index = tf
5423+
.make_pos_block_builder()
5424+
.with_stake_pool_id(genesis_pool_id)
5425+
.with_stake_spending_key(staking_sk.clone())
5426+
.with_vrf_key(vrf_sk.clone())
5427+
.add_transaction(
5428+
TransactionBuilder::new()
5429+
.add_input(
5430+
TxInput::from_command(
5431+
AccountNonce::new(0),
5432+
AccountCommand::MintTokens(token_id, Amount::from_atoms(5)),
5433+
),
5434+
InputWitness::NoSignature(None),
5435+
)
5436+
.add_input(
5437+
UtxoOutPoint::new(tx_id.into(), 0).into(),
5438+
InputWitness::NoSignature(None),
5439+
)
5440+
.add_output(TxOutput::Transfer(
5441+
OutputValue::TokenV1(token_id, Amount::from_atoms(5)),
5442+
Destination::AnyoneCanSpend,
5443+
))
5444+
.build(),
5445+
)
5446+
.build_and_process(&mut rng)
5447+
.unwrap()
5448+
.unwrap();
5449+
assert_eq!(
5450+
Id::<GenBlock>::from(*mint_block_index.block_id()),
5451+
tf.best_block_id()
5452+
);
5453+
5454+
// issue same token in alternative chain
5455+
let alt_block_a = tf
5456+
.make_pos_block_builder()
5457+
.with_parent(genesis_block_id.into())
5458+
.with_stake_pool_id(genesis_pool_id)
5459+
.with_stake_spending_key(staking_sk.clone())
5460+
.with_vrf_key(vrf_sk.clone())
5461+
.add_transaction(
5462+
TransactionBuilder::new()
5463+
.add_input(
5464+
TxInput::from_utxo(genesis_block_id.into(), 0),
5465+
InputWitness::NoSignature(None),
5466+
)
5467+
.add_output(TxOutput::Transfer(
5468+
OutputValue::Coin((token_supply_change_fee * 2).unwrap()),
5469+
Destination::AnyoneCanSpend,
5470+
))
5471+
.add_output(TxOutput::IssueFungibleToken(Box::new(issuance)))
5472+
.build(),
5473+
)
5474+
.build(&mut rng);
5475+
let alt_block_a_id = alt_block_a.get_id();
5476+
tf.process_block(alt_block_a, BlockSource::Local).unwrap();
5477+
5478+
assert_ne!(Id::<GenBlock>::from(alt_block_a_id), tf.best_block_id());
5479+
assert_eq!(
5480+
Id::<GenBlock>::from(*mint_block_index.block_id()),
5481+
tf.best_block_id()
5482+
);
5483+
5484+
let alt_block_b = tf
5485+
.make_pos_block_builder()
5486+
.with_parent(alt_block_a_id.into())
5487+
.with_stake_pool_id(genesis_pool_id)
5488+
.with_stake_spending_key(staking_sk.clone())
5489+
.with_vrf_key(vrf_sk.clone())
5490+
.build(&mut rng);
5491+
let alt_block_b_id = alt_block_b.get_id();
5492+
tf.process_block(alt_block_b, BlockSource::Local).unwrap();
5493+
5494+
assert_ne!(Id::<GenBlock>::from(alt_block_b_id), tf.best_block_id());
5495+
assert_eq!(
5496+
Id::<GenBlock>::from(*mint_block_index.block_id()),
5497+
tf.best_block_id()
5498+
);
5499+
5500+
// Trigger a reorg
5501+
let alt_block_c = tf
5502+
.make_pos_block_builder()
5503+
.with_parent(alt_block_b_id.into())
5504+
.with_stake_pool_id(genesis_pool_id)
5505+
.with_stake_spending_key(staking_sk.clone())
5506+
.with_vrf_key(vrf_sk.clone())
5507+
.build(&mut rng);
5508+
let alt_block_c_id = alt_block_c.get_id();
5509+
tf.process_block(alt_block_c, BlockSource::Local).unwrap();
5510+
5511+
assert_eq!(Id::<GenBlock>::from(alt_block_c_id), tf.best_block_id());
5512+
});
5513+
}

0 commit comments

Comments
 (0)