Skip to content

Commit f2dce1b

Browse files
tmpolaczykaesedepece
authored andcommitted
refactor: improve update_utxo_diff function and add tests
1 parent 85fa5f1 commit f2dce1b

File tree

3 files changed

+184
-24
lines changed

3 files changed

+184
-24
lines changed

node/src/actors/chain_manager/mining.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,8 @@ pub fn build_block(
862862
if new_vt_weight <= max_vt_weight {
863863
update_utxo_diff(
864864
&mut utxo_diff,
865-
vt_tx.body.inputs.iter().collect(),
866-
vt_tx.body.outputs.iter().collect(),
865+
vt_tx.body.inputs.iter(),
866+
vt_tx.body.outputs.iter(),
867867
vt_tx.hash(),
868868
);
869869
value_transfer_txns.push(vt_tx.clone());
@@ -967,8 +967,8 @@ pub fn build_block(
967967
if new_dr_weight <= max_dr_weight {
968968
update_utxo_diff(
969969
&mut utxo_diff,
970-
dr_tx.body.inputs.iter().collect(),
971-
dr_tx.body.outputs.iter().collect(),
970+
dr_tx.body.inputs.iter(),
971+
dr_tx.body.outputs.iter(),
972972
dr_tx.hash(),
973973
);
974974

validations/src/tests/mod.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,48 @@ pub fn generate_unspent_outputs_pool(
217217
unspent_outputs
218218
}
219219

220+
fn get_vtis_from_utxo_set(
221+
utxo_set: &UnspentOutputsPool,
222+
vtos: &[ValueTransferOutput],
223+
) -> Vec<Input> {
224+
let mut utxos_list: Vec<_> = utxo_set.iter().collect();
225+
let mut vtis = vec![];
226+
227+
for vto in vtos {
228+
// Search for this output in the list
229+
let found_index = utxos_list
230+
.iter()
231+
.position(|(_output_pointer, (output, _block_number))| output == vto)
232+
.expect("failed to find vto in utxo set");
233+
// Remove UTXO from list
234+
let (output_pointer, (_output, _block_number)) = utxos_list.remove(found_index);
235+
vtis.push(Input::new(output_pointer));
236+
}
237+
238+
vtis
239+
}
240+
241+
fn get_block_numbers_from_utxo_set(
242+
utxo_set: &UnspentOutputsPool,
243+
vtos: &[ValueTransferOutput],
244+
) -> Vec<u32> {
245+
let mut utxos_list: Vec<_> = utxo_set.iter().collect();
246+
let mut vtis = vec![];
247+
248+
for vto in vtos {
249+
// Search for this output in the list
250+
let found_index = utxos_list
251+
.iter()
252+
.position(|(_output_pointer, (output, _block_number))| output == vto)
253+
.expect("failed to find vto in utxo set");
254+
// Remove UTXO from list
255+
let (_output_pointer, (_output, block_number)) = utxos_list.remove(found_index);
256+
vtis.push(block_number);
257+
}
258+
259+
vtis
260+
}
261+
220262
// Validate transactions in block
221263
#[test]
222264
fn mint_mismatched_reward() {
@@ -10605,6 +10647,109 @@ fn validate_commit_transactions_included_in_utxo_diff() {
1060510647
assert_eq!(utxos, expected_utxos);
1060610648
}
1060710649

10650+
#[test]
10651+
fn validate_update_utxo_diff() {
10652+
let pkh1 = MY_PKH_1.parse().unwrap();
10653+
let pkh2 = MY_PKH_2.parse().unwrap();
10654+
10655+
// For the get_vtis_from_utxo_set function to work correctly, all the vtos here need to be different, so they have different value
10656+
let vto1 = ValueTransferOutput {
10657+
pkh: pkh1,
10658+
value: 1000,
10659+
time_lock: 0,
10660+
};
10661+
let vto2 = ValueTransferOutput {
10662+
pkh: pkh1,
10663+
value: 1001,
10664+
time_lock: 0,
10665+
};
10666+
let vto3 = ValueTransferOutput {
10667+
pkh: pkh2,
10668+
value: 1002,
10669+
time_lock: 0,
10670+
};
10671+
let mut utxo_set = build_utxo_set_with_mint(vec![vto1.clone(), vto3.clone()], None, vec![]);
10672+
let vto2_ptr = "2222222222222222222222222222222222222222222222222222222222222222:0"
10673+
.parse()
10674+
.unwrap();
10675+
utxo_set.insert(vto2_ptr, vto2.clone(), 999);
10676+
10677+
let vtis = get_vtis_from_utxo_set(&utxo_set, &[vto1, vto2, vto3]);
10678+
let vti0 = vtis[0];
10679+
let vti1 = vtis[1];
10680+
let vti2 = vtis[2];
10681+
10682+
let block_number = 1000;
10683+
let tx_hash = Hash::default();
10684+
10685+
let test_diff_block_numbers =
10686+
|inputs: &[Input], outputs: &[ValueTransferOutput], block_numbers: &[u32]| {
10687+
let mut utxo_diff = UtxoDiff::new(&utxo_set, block_number);
10688+
10689+
update_utxo_diff(&mut utxo_diff, inputs, outputs, tx_hash);
10690+
10691+
let diff = utxo_diff.take_diff();
10692+
10693+
let mut utxo_set_copy = utxo_set.clone();
10694+
diff.apply(&mut utxo_set_copy);
10695+
let utxo_block_numbers = get_block_numbers_from_utxo_set(&utxo_set_copy, outputs);
10696+
10697+
assert_eq!(utxo_block_numbers, block_numbers);
10698+
};
10699+
10700+
let vto4 = ValueTransferOutput {
10701+
pkh: pkh1,
10702+
value: 100,
10703+
time_lock: 0,
10704+
};
10705+
let vto5 = ValueTransferOutput {
10706+
pkh: pkh1,
10707+
value: 101,
10708+
time_lock: 0,
10709+
};
10710+
let vto6 = ValueTransferOutput {
10711+
pkh: pkh2,
10712+
value: 102,
10713+
time_lock: 0,
10714+
};
10715+
10716+
// 1 input and 1 output with same PKH: keep block number
10717+
test_diff_block_numbers(&[vti0], &[vto4.clone()], &[0]);
10718+
10719+
// 2 inputs and 1 output with same PKH: keep block number of max input
10720+
test_diff_block_numbers(&[vti0, vti1], &[vto4.clone()], &[999]);
10721+
10722+
// 1 input and 2 outputs with same PKH: keep block number
10723+
test_diff_block_numbers(&[vti0], &[vto4.clone(), vto5.clone()], &[0, 0]);
10724+
10725+
// 2 inputs and 2 outputs with same PKH: keep block number of max input
10726+
test_diff_block_numbers(&[vti0, vti1], &[vto4.clone(), vto5], &[999, 999]);
10727+
10728+
// No inputs: reset block number
10729+
test_diff_block_numbers(&[], &[vto4.clone()], &[1000]);
10730+
10731+
// 1 input and 1 output with different PKH: reset block number
10732+
test_diff_block_numbers(&[vti0], &[vto6.clone()], &[1000]);
10733+
10734+
// 2 inputs with different PKH: reset block number for all outputs
10735+
test_diff_block_numbers(&[vti0, vti2], &[vto4.clone()], &[1000]);
10736+
10737+
// 2 inputs with different PKH: reset block number for all outputs
10738+
test_diff_block_numbers(&[vti0, vti2], &[vto6.clone()], &[1000]);
10739+
10740+
// 2 inputs with different PKH: reset block number for all outputs
10741+
test_diff_block_numbers(&[vti0, vti2], &[vto4.clone(), vto6.clone()], &[1000, 1000]);
10742+
10743+
// 2 outputs with different PKH: reset the block number of the new PKH only
10744+
test_diff_block_numbers(&[vti0], &[vto4.clone(), vto6.clone()], &[0, 1000]);
10745+
10746+
// 2 outputs with different PKH: the order of the outputs does not matter
10747+
test_diff_block_numbers(&[vti0], &[vto6.clone(), vto4.clone()], &[1000, 0]);
10748+
10749+
// 2 outputs with different PKH: reset the block number of the new PKH only
10750+
test_diff_block_numbers(&[vti0, vti1], &[vto4, vto6], &[999, 1000]);
10751+
}
10752+
1060810753
#[test]
1060910754
fn validate_required_tally_not_found() {
1061010755
let dr_pointer = Hash::default();

validations/src/validations.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,32 +1308,47 @@ fn increment_witnesses_counter<S: ::std::hash::BuildHasher>(
13081308
.current += 1;
13091309
}
13101310

1311-
/// Update UTXO diff with the provided inputs and outputs
1312-
pub fn update_utxo_diff(
1311+
/// Update UTXO diff with the provided inputs and outputs.
1312+
///
1313+
/// If all the inputs have the same PKH, the outputs with that PKH will keep the maximum
1314+
/// (most recent) block number of the inputs. Outputs with different PKH have the block number reset.
1315+
/// And in case one of the inputs has a different PKH from another input, the block number of all the outputs is reset.
1316+
pub fn update_utxo_diff<'a, IterInputs, IterOutputs>(
13131317
utxo_diff: &mut UtxoDiff<'_>,
1314-
inputs: Vec<&Input>,
1315-
outputs: Vec<&ValueTransferOutput>,
1318+
inputs: IterInputs,
1319+
outputs: IterOutputs,
13161320
tx_hash: Hash,
1317-
) {
1318-
let mut input_pkh = inputs
1319-
.first()
1320-
.and_then(|first| utxo_diff.get(first.output_pointer()).map(|vt| vt.pkh));
1321-
1321+
) where
1322+
IterInputs: IntoIterator<Item = &'a Input>,
1323+
IterOutputs: IntoIterator<Item = &'a ValueTransferOutput>,
1324+
{
1325+
let mut input_pkh = None;
13221326
let mut block_number_input = 0;
1327+
let mut first = true;
1328+
13231329
for input in inputs {
1324-
// Obtain the OuputPointer of each input and remove it from the utxo_diff
1330+
// Obtain the OutputPointer of each input and remove it from the utxo_diff
13251331
let output_pointer = input.output_pointer();
13261332

1327-
// Returns the input PKH in case that all PKHs are the same
1328-
if input_pkh != utxo_diff.get(output_pointer).map(|vt| vt.pkh) {
1333+
if !first && input_pkh.is_none() {
1334+
// No need to check PKH and block number, there is more than one distinct input PKH
1335+
} else if !first && input_pkh != utxo_diff.get(output_pointer).map(|vt| vt.pkh) {
1336+
// PKH of this input is different from the previous input, no need to check block number
13291337
input_pkh = None;
1338+
} else {
1339+
// All inputs up until this one have the same PKH
1340+
if first {
1341+
first = false;
1342+
// Store the PKH of the first element
1343+
input_pkh = utxo_diff.get(output_pointer).map(|vt| vt.pkh);
1344+
}
1345+
// Update block number to max of inputs
1346+
let block_number = utxo_diff
1347+
.included_in_block_number(output_pointer)
1348+
.unwrap_or(0);
1349+
block_number_input = std::cmp::max(block_number, block_number_input);
13301350
}
13311351

1332-
let block_number = utxo_diff
1333-
.included_in_block_number(output_pointer)
1334-
.unwrap_or(0);
1335-
block_number_input = std::cmp::max(block_number, block_number_input);
1336-
13371352
utxo_diff.remove_utxo(*output_pointer);
13381353
}
13391354

@@ -1481,8 +1496,8 @@ pub fn validate_block_transactions(
14811496
increment_witnesses_counter(&mut commits_number, &dr_pointer, u32::from(dr_witnesses));
14821497

14831498
let (inputs, outputs) = (
1484-
transaction.body.collateral.iter().collect(),
1485-
transaction.body.outputs.iter().collect(),
1499+
transaction.body.collateral.iter(),
1500+
transaction.body.outputs.iter(),
14861501
);
14871502
update_utxo_diff(&mut utxo_diff, inputs, outputs, transaction.hash());
14881503

@@ -1657,7 +1672,7 @@ pub fn validate_block_transactions(
16571672
update_utxo_diff(
16581673
&mut utxo_diff,
16591674
vec![],
1660-
block.txns.mint.outputs.iter().collect(),
1675+
block.txns.mint.outputs.iter(),
16611676
block.txns.mint.hash(),
16621677
);
16631678
}

0 commit comments

Comments
 (0)