Skip to content

Commit ac23127

Browse files
committed
feat(node): periodically revalidate pending stake and unstake transactions to detect invalidated transactions
1 parent fe9754f commit ac23127

File tree

1 file changed

+84
-4
lines changed

1 file changed

+84
-4
lines changed

node/src/actors/chain_manager/handlers.rs

+84-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ use witnet_data_structures::{
2525
},
2626
transaction_factory::{self, NodeBalance},
2727
types::LastBeacon,
28-
utxo_pool::{get_utxo_info, UtxoInfo},
28+
utxo_pool::{get_utxo_info, UtxoDiff, UtxoInfo},
2929
};
3030
use witnet_util::timestamp::get_timestamp;
31-
use witnet_validations::validations::{block_reward, total_block_reward, validate_rad_request};
31+
use witnet_validations::validations::{
32+
block_reward, total_block_reward, validate_rad_request, validate_stake_transaction,
33+
validate_unstake_transaction,
34+
};
3235

3336
use crate::{
3437
actors::{
@@ -232,10 +235,87 @@ impl Handler<EpochNotification<EveryEpochPayload>> for ChainManager {
232235
self.candidates.clear();
233236
self.seen_candidates.clear();
234237

238+
// Periodically revalidate pending stake transactions since they can become invalid
239+
if get_protocol_version(Some(current_epoch)) >= ProtocolVersion::V1_8
240+
&& current_epoch % 10 == 0
241+
{
242+
let utxo_diff = UtxoDiff::new(
243+
&self.chain_state.unspent_outputs_pool,
244+
self.chain_state.block_number(),
245+
);
246+
let min_stake = self
247+
.consensus_constants_wit2
248+
.get_validator_min_stake_nanowits(current_epoch);
249+
let max_stake = self
250+
.consensus_constants_wit2
251+
.get_validator_max_stake_nanowits(current_epoch);
252+
253+
let mut invalid_stake_transactions = Vec::<Hash>::new();
254+
for st_tx in self.transactions_pool.st_iter() {
255+
if let Err(e) = validate_stake_transaction(
256+
st_tx,
257+
&utxo_diff,
258+
current_epoch,
259+
self.epoch_constants.unwrap(),
260+
&mut vec![],
261+
&self.chain_state.stakes,
262+
min_stake,
263+
max_stake,
264+
) {
265+
log::debug!(
266+
"Removing stake transaction {} as it became invalid: {}",
267+
st_tx.hash(),
268+
e
269+
);
270+
invalid_stake_transactions.push(st_tx.hash());
271+
continue;
272+
}
273+
}
274+
275+
self.transactions_pool
276+
.remove_invalid_stake_transactions(invalid_stake_transactions);
277+
}
278+
279+
// Periodically revalidate pending unstake transactions since they can become invalid
280+
if get_protocol_version(Some(current_epoch)) >= ProtocolVersion::V2_0
281+
&& current_epoch % 10 == 0
282+
{
283+
let min_stake = self
284+
.consensus_constants_wit2
285+
.get_validator_min_stake_nanowits(current_epoch);
286+
let unstake_delay = self
287+
.consensus_constants_wit2
288+
.get_unstaking_delay_seconds(current_epoch);
289+
290+
let mut invalid_unstake_transactions = Vec::<Hash>::new();
291+
for ut_tx in self.transactions_pool.ut_iter() {
292+
if let Err(e) = validate_unstake_transaction(
293+
ut_tx,
294+
current_epoch,
295+
&self.chain_state.stakes,
296+
min_stake,
297+
unstake_delay,
298+
) {
299+
log::debug!(
300+
"Removing unstake transaction {} as it became invalid: {}",
301+
ut_tx.hash(),
302+
e
303+
);
304+
invalid_unstake_transactions.push(ut_tx.hash());
305+
continue;
306+
}
307+
}
308+
309+
self.transactions_pool
310+
.remove_invalid_unstake_transactions(invalid_unstake_transactions);
311+
}
312+
235313
log::debug!(
236-
"Transactions pool size: {} value transfer, {} data request",
314+
"Transactions pool size: {} value transfer, {} data request, {} stake, {} unstake",
237315
self.transactions_pool.vt_len(),
238-
self.transactions_pool.dr_len()
316+
self.transactions_pool.dr_len(),
317+
self.transactions_pool.st_len(),
318+
self.transactions_pool.ut_len()
239319
);
240320
}
241321

0 commit comments

Comments
 (0)