Skip to content

Commit 085cf65

Browse files
Merge pull request #1170 from mintlayer/feat/incentivise_pledging
Incentivize pledging in consensus
2 parents 1bb9912 + e850857 commit 085cf65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2135
-294
lines changed

blockprod/src/detail/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,18 @@ fn generate_finalize_block_data(
593593
.add_int_seconds(chain_config.max_future_block_time_offset().as_secs())
594594
.ok_or(ConsensusPoSError::TimestampOverflow)?;
595595

596+
let pledge_amount = chainstate_handle
597+
.get_stake_pool_data(pos_input_data.pool_id())
598+
.map_err(|_| {
599+
ConsensusPoSError::PropertyQueryError(
600+
PropertyQueryError::StakePoolDataReadError(pos_input_data.pool_id()),
601+
)
602+
})?
603+
.ok_or(ConsensusPoSError::PropertyQueryError(
604+
PropertyQueryError::StakePoolDataNotFound(pos_input_data.pool_id()),
605+
))?
606+
.pledge_amount();
607+
596608
let pool_balance = chainstate_handle
597609
.get_stake_pool_balance(pos_input_data.pool_id())
598610
.map_err(|_| {
@@ -612,6 +624,7 @@ fn generate_finalize_block_data(
612624
epoch_index,
613625
sealed_epoch_randomness,
614626
max_block_timestamp,
627+
pledge_amount,
615628
pool_balance,
616629
)))
617630
}

blockprod/src/detail/tests.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use common::{
2323
stakelock::StakePoolData,
2424
transaction::TxInput,
2525
ConsensusUpgrade, Destination, GenBlock, Genesis, NetUpgrades, OutPointSourceId,
26-
PoSChainConfig, PoolId, RequiredConsensus, TxOutput, UpgradeVersion,
26+
PoSChainConfig, PoSConsensusVersion, PoolId, RequiredConsensus, TxOutput, UpgradeVersion,
2727
},
2828
primitives::{per_thousand::PerThousand, time, Amount, BlockHeight, Id, H256},
2929
time_getter::TimeGetter,
@@ -1245,6 +1245,7 @@ mod produce_block {
12451245
2000.into(),
12461246
5,
12471247
PerThousand::new(1).expect("must be valid"),
1248+
PoSConsensusVersion::V1,
12481249
)
12491250
.expect("Valid PoS config values");
12501251

@@ -1254,7 +1255,7 @@ mod produce_block {
12541255
initial_difficulty: Uint256::MAX.into(),
12551256
},
12561257
ConsensusUpgrade::PoS {
1257-
initial_difficulty: Uint256::MAX.into(),
1258+
initial_difficulty: Some(Uint256::MAX.into()),
12581259
config: easy_pos_config,
12591260
},
12601261
];

blockprod/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ mod tests {
126126
chain::{
127127
block::timestamp::BlockTimestamp,
128128
config::{create_unit_test_config, Builder, ChainConfig, ChainType},
129-
create_unittest_pos_config, initial_difficulty,
129+
create_unittest_pos_config, pos_initial_difficulty,
130130
stakelock::StakePoolData,
131131
Block, ConsensusUpgrade, Destination, Genesis, NetUpgrades, TxOutput, UpgradeVersion,
132132
},
@@ -295,7 +295,7 @@ mod tests {
295295
(
296296
BlockHeight::new(1),
297297
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
298-
initial_difficulty: initial_difficulty(ChainType::Regtest).into(),
298+
initial_difficulty: Some(pos_initial_difficulty(ChainType::Regtest).into()),
299299
config: create_unittest_pos_config(),
300300
}),
301301
),

chainstate/src/detail/ban_score.rs

+5
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ impl BanScore for ConsensusPoSError {
364364
ConsensusPoSError::FutureTimestampInThePast => 0,
365365
ConsensusPoSError::FailedToSignKernel => 0,
366366
ConsensusPoSError::PoSBlockTimeStrictOrderInvalid(_) => 100,
367+
ConsensusPoSError::FiniteTotalSupplyIsRequired => 100,
368+
ConsensusPoSError::UnsupportedConsensusVersion => 100,
369+
ConsensusPoSError::EffectivePoolBalanceError(_) => 100,
370+
ConsensusPoSError::EmptyTimespan => 100,
371+
ConsensusPoSError::FailedToCalculateCappedBalance => 100,
367372
}
368373
}
369374
}

chainstate/test-framework/src/pos_block_builder.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -274,18 +274,19 @@ impl<'f> PoSBlockBuilder<'f> {
274274
);
275275

276276
let new_block_height = parent_block_index.block_height().next_height();
277-
let current_difficulty = match self
277+
let pos_status = match self
278278
.framework
279279
.chainstate
280280
.get_chain_config()
281281
.net_upgrade()
282282
.consensus_status(new_block_height)
283283
{
284-
RequiredConsensus::PoS(status) => status.get_chain_config().target_limit(),
284+
RequiredConsensus::PoS(status) => status,
285285
RequiredConsensus::PoW(_) | RequiredConsensus::IgnoreConsensus => {
286286
panic!("Invalid consensus")
287287
}
288288
};
289+
let current_difficulty = pos_status.get_chain_config().target_limit();
289290
let chain_config = self.framework.chainstate.get_chain_config().as_ref();
290291
let epoch_index = chain_config.epoch_index_from_height(&new_block_height);
291292

@@ -297,18 +298,17 @@ impl<'f> PoSBlockBuilder<'f> {
297298
None => PoSRandomness::new(chain_config.initial_randomness()),
298299
}
299300
});
300-
let pool_balance = self.stake_pool_balance.unwrap_or_else(|| {
301-
self.framework.chainstate.get_stake_pool_balance(staking_pool).unwrap().unwrap()
302-
});
303301

304302
pos_mine(
303+
&self.framework.storage,
304+
pos_status.get_chain_config(),
305305
BlockTimestamp::from_duration_since_epoch(self.framework.current_time()),
306306
kernel_input_outpoint,
307307
InputWitness::Standard(kernel_sig),
308308
&self.staker_vrf_sk,
309309
randomness,
310310
staking_pool,
311-
pool_balance,
311+
chain_config.final_supply().unwrap(),
312312
epoch_index,
313313
current_difficulty.into(),
314314
)

chainstate/test-framework/src/utils.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::num::NonZeroU64;
1717

1818
use crate::{framework::BlockOutputs, TestChainstate, TestFramework};
1919
use chainstate::chainstate_interface::ChainstateInterface;
20+
use chainstate_storage::{BlockchainStorageRead, TipStorageTag};
2021
use chainstate_types::pos_randomness::PoSRandomness;
2122
use common::{
2223
chain::{
@@ -30,9 +31,9 @@ use common::{
3031
},
3132
stakelock::StakePoolData,
3233
tokens::{TokenData, TokenTransfer},
33-
Block, ChainConfig, ConsensusUpgrade, Destination, GenBlock, Genesis, NetUpgrades,
34-
OutPointSourceId, PoolId, RequiredConsensus, TxInput, TxOutput, UpgradeVersion,
35-
UtxoOutPoint,
34+
Block, ChainConfig, ConsensusUpgrade, Destination, GenBlock, Genesis, Mlt, NetUpgrades,
35+
OutPointSourceId, PoSChainConfig, PoolId, RequiredConsensus, TxInput, TxOutput,
36+
UpgradeVersion, UtxoOutPoint,
3637
},
3738
primitives::{per_thousand::PerThousand, Amount, BlockHeight, Compact, Id, Idable, H256},
3839
Uint256,
@@ -42,6 +43,7 @@ use crypto::{
4243
random::{CryptoRng, Rng},
4344
vrf::{VRFPrivateKey, VRFPublicKey},
4445
};
46+
use pos_accounting::{PoSAccountingDB, PoSAccountingView};
4547
use test_utils::nft_utils::*;
4648

4749
pub fn empty_witness(rng: &mut impl Rng) -> InputWitness {
@@ -357,7 +359,7 @@ pub fn create_chain_config_with_staking_pool(
357359
(
358360
BlockHeight::new(1),
359361
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
360-
initial_difficulty: Uint256::MAX.into(),
362+
initial_difficulty: Some(Uint256::MAX.into()),
361363
config: create_unittest_pos_config(),
362364
}),
363365
),
@@ -408,20 +410,27 @@ pub fn produce_kernel_signature(
408410
.unwrap()
409411
}
410412

413+
// TODO: consider replacing this function with consensus::pos::stake
411414
#[allow(clippy::too_many_arguments)]
412415
pub fn pos_mine(
416+
storage: &impl BlockchainStorageRead,
417+
pos_config: &PoSChainConfig,
413418
initial_timestamp: BlockTimestamp,
414419
kernel_outpoint: UtxoOutPoint,
415420
kernel_witness: InputWitness,
416421
vrf_sk: &VRFPrivateKey,
417422
sealed_epoch_randomness: PoSRandomness,
418423
pool_id: PoolId,
419-
pool_balance: Amount,
424+
final_supply: Mlt,
420425
epoch_index: EpochIndex,
421426
target: Compact,
422427
) -> Option<(PoSData, BlockTimestamp)> {
423-
let mut timestamp = initial_timestamp;
428+
let pos_db = PoSAccountingDB::<_, TipStorageTag>::new(&storage);
429+
430+
let pool_balance = pos_db.get_pool_balance(pool_id).unwrap().unwrap();
431+
let pledge_amount = pos_db.get_pool_data(pool_id).unwrap().unwrap().pledge_amount();
424432

433+
let mut timestamp = initial_timestamp;
425434
for _ in 0..1000 {
426435
let transcript = chainstate_types::vrf_tools::construct_transcript(
427436
epoch_index,
@@ -440,12 +449,15 @@ pub fn pos_mine(
440449

441450
let vrf_pk = VRFPublicKey::from_private_key(vrf_sk);
442451
if consensus::check_pos_hash(
452+
pos_config.consensus_version(),
443453
epoch_index,
444454
&sealed_epoch_randomness,
445455
&pos_data,
446456
&vrf_pk,
447457
timestamp,
458+
pledge_amount,
448459
pool_balance,
460+
final_supply.to_amount_atoms(),
449461
)
450462
.is_ok()
451463
{

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

+72
Original file line numberDiff line numberDiff line change
@@ -688,3 +688,75 @@ fn spend_share_then_decommission_then_cleanup_delegations(#[case] seed: Seed) {
688688
assert!(delegation_data.is_none());
689689
});
690690
}
691+
692+
// Create a pool, create delegation id and delegate staking in different transactions in the same blocks
693+
#[rstest]
694+
#[trace]
695+
#[case(Seed::from_entropy())]
696+
fn create_pool_and_delegation_and_delegate_same_block(#[case] seed: Seed) {
697+
utils::concurrency::model(move || {
698+
let mut rng = make_seedable_rng(seed);
699+
let mut tf = TestFramework::builder(&mut rng).build();
700+
701+
let (_, vrf_pk) = VRFPrivateKey::new_from_rng(&mut rng, VRFKeyKind::Schnorrkel);
702+
let min_stake_pool_pledge =
703+
tf.chainstate.get_chain_config().min_stake_pool_pledge().into_atoms();
704+
let amount_to_stake =
705+
Amount::from_atoms(rng.gen_range(min_stake_pool_pledge..(min_stake_pool_pledge * 10)));
706+
let (stake_pool_data, _) =
707+
create_stake_pool_data_with_all_reward_to_owner(&mut rng, amount_to_stake, vrf_pk);
708+
709+
let genesis_outpoint = UtxoOutPoint::new(
710+
OutPointSourceId::BlockReward(tf.genesis().get_id().into()),
711+
0,
712+
);
713+
let pool_id = pos_accounting::make_pool_id(&genesis_outpoint);
714+
715+
let tx1 = TransactionBuilder::new()
716+
.add_input(genesis_outpoint.into(), empty_witness(&mut rng))
717+
.add_output(TxOutput::CreateStakePool(
718+
pool_id,
719+
Box::new(stake_pool_data),
720+
))
721+
.add_output(TxOutput::Transfer(
722+
OutputValue::Coin(amount_to_stake),
723+
Destination::AnyoneCanSpend,
724+
))
725+
.build();
726+
let tx1_source_id = OutPointSourceId::Transaction(tx1.transaction().get_id());
727+
let tx_1_kernel0_outpoint = UtxoOutPoint::new(tx1_source_id, 1);
728+
729+
let delegation_id = pos_accounting::make_delegation_id(&tx_1_kernel0_outpoint);
730+
let tx2 = TransactionBuilder::new()
731+
.add_input(tx_1_kernel0_outpoint.into(), empty_witness(&mut rng))
732+
.add_output(TxOutput::CreateDelegationId(
733+
Destination::AnyoneCanSpend,
734+
pool_id,
735+
))
736+
.add_output(TxOutput::Transfer(
737+
OutputValue::Coin(amount_to_stake),
738+
Destination::AnyoneCanSpend,
739+
))
740+
.build();
741+
let tx2_source_id = OutPointSourceId::Transaction(tx2.transaction().get_id());
742+
743+
let tx3 = TransactionBuilder::new()
744+
.add_input(
745+
UtxoOutPoint::new(tx2_source_id, 1).into(),
746+
empty_witness(&mut rng),
747+
)
748+
.add_output(TxOutput::DelegateStaking(amount_to_stake, delegation_id))
749+
.build();
750+
751+
tf.make_block_builder()
752+
.with_transactions(vec![tx1, tx2, tx3])
753+
.build_and_process()
754+
.unwrap()
755+
.unwrap();
756+
757+
assert_eq!(
758+
tf.chainstate.get_stake_delegation_balance(delegation_id).unwrap(),
759+
Some(amount_to_stake)
760+
);
761+
});
762+
}

chainstate/test-suite/src/tests/helpers/pos.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use chainstate_test_framework::TestFramework;
1818
use common::{
1919
chain::{
2020
block::timestamp::BlockTimestamp, output_value::OutputValue, stakelock::StakePoolData,
21-
Destination, Genesis, RequiredConsensus, TxOutput,
21+
Destination, Genesis, Mlt, RequiredConsensus, TxOutput,
2222
},
2323
primitives::{per_thousand::PerThousand, Amount, BlockHeight, Compact, H256},
2424
};
@@ -32,7 +32,7 @@ use crypto::{
3232
use super::block_index_handle_impl::TestBlockIndexHandle;
3333

3434
pub fn calculate_new_target(
35-
tf: &mut TestFramework,
35+
tf: &TestFramework,
3636
block_height: BlockHeight,
3737
) -> Result<Compact, ConsensusPoSError> {
3838
let pos_status =
@@ -81,7 +81,7 @@ pub fn create_custom_genesis_with_stake_pool(
8181
staker_pk: PublicKey,
8282
vrf_pk: VRFPublicKey,
8383
) -> Genesis {
84-
let initial_amount = Amount::from_atoms(100_000_000_000 * common::chain::Mlt::ATOMS_PER_MLT);
84+
let initial_amount = Mlt::from_mlt(100_000_000).to_amount_atoms();
8585
let initial_pool_amount = (initial_amount / 3).unwrap();
8686
let mint_output_amount = (initial_amount - initial_pool_amount).unwrap();
8787

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

+10-6
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use common::{
2121
chain::{
2222
config::Builder as ConfigBuilder, output_value::OutputValue, stakelock::StakePoolData,
2323
timelock::OutputTimeLock, AccountNonce, AccountOutPoint, AccountSpending, ConsensusUpgrade,
24-
Destination, NetUpgrades, OutPointSourceId, PoSChainConfig, TxInput, TxOutput,
25-
UpgradeVersion, UtxoOutPoint,
24+
Destination, NetUpgrades, OutPointSourceId, PoSChainConfig, PoSConsensusVersion, TxInput,
25+
TxOutput, UpgradeVersion, UtxoOutPoint,
2626
},
2727
primitives::{per_thousand::PerThousand, Amount, BlockHeight, Idable},
2828
Uint256,
@@ -50,29 +50,31 @@ fn decommission_maturity_setting_follows_netupgrade(#[case] seed: Seed) {
5050
(
5151
BlockHeight::new(1),
5252
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
53-
initial_difficulty: Uint256::MAX.into(),
53+
initial_difficulty: Some(Uint256::MAX.into()),
5454
config: PoSChainConfig::new(
5555
Uint256::MAX,
5656
1,
5757
100.into(),
5858
1.into(),
5959
5,
6060
PerThousand::new(100).unwrap(),
61+
PoSConsensusVersion::V1,
6162
)
6263
.unwrap(),
6364
}),
6465
),
6566
(
6667
BlockHeight::new(3),
6768
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
68-
initial_difficulty: Uint256::MAX.into(),
69+
initial_difficulty: None,
6970
config: PoSChainConfig::new(
7071
Uint256::MAX,
7172
1,
7273
50.into(), // decrease maturity setting
7374
1.into(),
7475
5,
7576
PerThousand::new(100).unwrap(),
77+
PoSConsensusVersion::V1,
7678
)
7779
.unwrap(),
7880
}),
@@ -198,29 +200,31 @@ fn spend_share_maturity_setting_follows_netupgrade(#[case] seed: Seed) {
198200
(
199201
BlockHeight::new(1),
200202
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
201-
initial_difficulty: Uint256::MAX.into(),
203+
initial_difficulty: Some(Uint256::MAX.into()),
202204
config: PoSChainConfig::new(
203205
Uint256::MAX,
204206
1,
205207
1.into(),
206208
100.into(),
207209
5,
208210
PerThousand::new(100).unwrap(),
211+
PoSConsensusVersion::V1,
209212
)
210213
.unwrap(),
211214
}),
212215
),
213216
(
214217
BlockHeight::new(3),
215218
UpgradeVersion::ConsensusUpgrade(ConsensusUpgrade::PoS {
216-
initial_difficulty: Uint256::MAX.into(),
219+
initial_difficulty: None,
217220
config: PoSChainConfig::new(
218221
Uint256::MAX,
219222
1,
220223
1.into(),
221224
50.into(), // decrease maturity setting
222225
5,
223226
PerThousand::new(100).unwrap(),
227+
PoSConsensusVersion::V1,
224228
)
225229
.unwrap(),
226230
}),

0 commit comments

Comments
 (0)