Skip to content

Commit

Permalink
feat(validations): validate withdrawer uniqueness for an existing val…
Browse files Browse the repository at this point in the history
…idator
  • Loading branch information
drcpu-github committed Jun 16, 2024
1 parent f1aad73 commit 059b6aa
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 0 deletions.
9 changes: 9 additions & 0 deletions data_structures/src/staking/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ where
/// A withdrawer address.
withdrawer: Address,
},
/// Tried to add stake to a validator with a different withdrawer than the one initially set.
#[fail(
display = "Validator {} already has a different withdrawer set",
validator
)]
DifferentWithdrawer {
/// A validator address.
validator: Address,
},
/// Tried to query for a stake entry without providing a validator or a withdrawer address.
#[fail(
display = "Tried to query a stake entry without providing a validator or a withdrawer address"
Expand Down
15 changes: 15 additions & 0 deletions data_structures/src/staking/stakes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,21 @@ where
}
}

/// Query stakes to check existing validator / withdrawer pair.
pub fn check_validator_withdrawer(
&self,
validator: Address,
withdrawer: Address,
) -> StakesResult<(), Address, Coins, Epoch> {
for stake_key in self.by_key.keys() {
if stake_key.validator == validator && stake_key.withdrawer != withdrawer {
return Err(StakesError::DifferentWithdrawer { validator });
}
}

Ok(())
}

/// Query stakes by stake key.
#[inline(always)]
fn query_by_key(&self, key: StakeKey<Address>) -> StakesResult<Coins, Address, Coins, Epoch> {
Expand Down
3 changes: 3 additions & 0 deletions node/src/actors/chain_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,7 @@ impl ChainManager {
required_reward_collateral_ratio,
&active_wips,
chain_info.consensus_constants.superblock_period,
&self.chain_state.stakes,
))
.into_actor(self)
.and_then(|fee, act, _ctx| {
Expand Down Expand Up @@ -2108,6 +2109,7 @@ impl ChainManager {
&consensus_constants,
&active_wips,
None,
&act.chain_state.stakes,
);
async {
// Short-circuit if validation failed
Expand Down Expand Up @@ -2916,6 +2918,7 @@ pub fn process_validations(
consensus_constants,
active_wips,
transaction_visitor,
stakes,
)?;

if !resynchronizing {
Expand Down
11 changes: 11 additions & 0 deletions validations/src/validations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,7 @@ pub fn validate_stake_transaction<'a>(
epoch: Epoch,
epoch_constants: EpochConstants,
signatures_to_verify: &mut Vec<SignaturesToVerify>,
stakes: &Stakes<PublicKeyHash, Wit, u32, u64>,
) -> Result<ValidatedStakeTransaction<'a>, failure::Error> {
// Check that the amount of coins to stake is equal or greater than the minimum allowed
if st_tx.body.output.value < MIN_STAKE_NANOWITS {
Expand All @@ -1221,6 +1222,12 @@ pub fn validate_stake_transaction<'a>(
})?;
}

// A stake transaction can only stake on an existing validator if the withdrawer address is the same
stakes.check_validator_withdrawer(
st_tx.body.output.key.validator,
st_tx.body.output.key.withdrawer,
)?;

validate_transaction_signature(
&st_tx.signatures,
&st_tx.body.inputs,
Expand Down Expand Up @@ -1621,6 +1628,7 @@ pub fn validate_block_transactions(
consensus_constants: &ConsensusConstants,
active_wips: &ActiveWips,
mut visitor: Option<&mut dyn Visitor<Visitable = (Transaction, u64, u32)>>,
stakes: &Stakes<PublicKeyHash, Wit, u32, u64>,
) -> Result<Diff, failure::Error> {
let epoch = block.block_header.beacon.checkpoint;
let is_genesis = block.is_genesis(&consensus_constants.genesis_hash);
Expand Down Expand Up @@ -1923,6 +1931,7 @@ pub fn validate_block_transactions(
epoch,
epoch_constants,
signatures_to_verify,
stakes,
)?;

total_fee += fee;
Expand Down Expand Up @@ -2178,6 +2187,7 @@ pub fn validate_new_transaction(
required_reward_collateral_ratio: u64,
active_wips: &ActiveWips,
superblock_period: u16,
stakes: &Stakes<PublicKeyHash, Wit, u32, u64>,
) -> Result<u64, failure::Error> {
let utxo_diff = UtxoDiff::new(unspent_outputs_pool, block_number);

Expand Down Expand Up @@ -2230,6 +2240,7 @@ pub fn validate_new_transaction(
current_epoch,
epoch_constants,
signatures_to_verify,
stakes,
)
.map(|(_, _, fee, _, _)| fee),
_ => Err(TransactionError::NotValidTransaction.into()),
Expand Down

0 comments on commit 059b6aa

Please sign in to comment.