Skip to content

Commit f8fd994

Browse files
authored
Merge pull request #3132 from ProvableHQ/feat/increase-program-size-2
Add safety checks for `MAX_WRITE` increase.
2 parents bd2990d + efab469 commit f8fd994

File tree

7 files changed

+251
-2099
lines changed

7 files changed

+251
-2099
lines changed

console/network/src/consensus_heights.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,11 @@ mod tests {
328328
assert!(*version > previous_version);
329329
previous_version = *version;
330330
}
331+
let mut previous_version = N::MAX_WRITES.first().unwrap().0;
332+
for (version, _) in N::MAX_WRITES.iter().skip(1) {
333+
assert!(*version > previous_version);
334+
previous_version = *version;
335+
}
331336
}
332337

333338
/// Ensure that consensus *heights* are unique and incrementing.
@@ -369,6 +374,12 @@ mod tests {
369374
// Double-check that consensus_config_value returns the correct value.
370375
assert_eq!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, height).unwrap(), *value);
371376
}
377+
for (version, value) in N::MAX_WRITES.iter() {
378+
// Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
379+
let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
380+
// Double-check that consensus_config_value returns the correct value.
381+
assert_eq!(consensus_config_value!(N, MAX_WRITES, height).unwrap(), *value);
382+
}
372383
}
373384

374385
/// Ensure that consensus_config_value returns a valid value for all consensus versions.
@@ -378,6 +389,7 @@ mod tests {
378389
assert!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, *height).is_some());
379390
assert!(consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).is_some());
380391
assert!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).is_some());
392+
assert!(consensus_config_value!(N, MAX_WRITES, *height).is_some());
381393
}
382394
}
383395

@@ -415,6 +427,7 @@ mod tests {
415427
let _ = [N1::TRANSACTION_SPEND_LIMIT, N2::TRANSACTION_SPEND_LIMIT, N3::TRANSACTION_SPEND_LIMIT];
416428
let _ = [N1::MAX_PROGRAM_SIZE, N2::MAX_PROGRAM_SIZE, N3::MAX_PROGRAM_SIZE];
417429
let _ = [N1::MAX_TRANSACTION_SIZE, N2::MAX_TRANSACTION_SIZE, N3::MAX_TRANSACTION_SIZE];
430+
let _ = [N1::MAX_WRITES, N2::MAX_WRITES, N3::MAX_WRITES];
418431
}
419432

420433
/// Ensure that `LATEST_MAX_*` functions return valid values without panicking.
@@ -426,6 +439,8 @@ mod tests {
426439
assert!(N::LATEST_MAX_PROGRAM_SIZE() > 0, "LATEST_MAX_PROGRAM_SIZE must be positive");
427440
// Verify LATEST_MAX_TRANSACTION_SIZE returns a positive value.
428441
assert!(N::LATEST_MAX_TRANSACTION_SIZE() > 0, "LATEST_MAX_TRANSACTION_SIZE must be positive");
442+
// Verify LATEST_MAX_WRITES returns a positive value.
443+
assert!(N::LATEST_MAX_WRITES() > 0, "LATEST_MAX_WRITES must be positive");
429444
}
430445

431446
#[test]

console/program/src/state_path/configuration/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ pub const BLOCKS_DEPTH: u8 = 32;
2121
/// The depth of the Merkle tree for the block header.
2222
pub const HEADER_DEPTH: u8 = 3;
2323
/// The depth of the Merkle tree for finalize operations in a transaction.
24-
pub const FINALIZE_ID_DEPTH: u8 = TRANSACTION_DEPTH + 4; // '+ 4' is to support 16 finalize operations per transition.
24+
/// A transaction can include at most `2^FINALIZE_ID_DEPTH` finalize operations total (across *all* transitions).
25+
/// Note that `MAX_WRITES * MAX_TRANSITIONS` can exceed that Merkle-tree capacity.
26+
pub const FINALIZE_ID_DEPTH: u8 = TRANSACTION_DEPTH + 4; // '+ 4' is to support an average of 16 finalize operations per transition.
2527
/// The depth of the Merkle tree for finalize operations in a block.
2628
pub const FINALIZE_OPERATIONS_DEPTH: u8 = TRANSACTIONS_DEPTH;
2729
/// The depth of the Merkle tree for the ratifications in a block.

synthesizer/program/src/lib.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ use console::{
103103
program::{Identifier, PlaintextType, ProgramID, RecordType, StructType},
104104
types::U8,
105105
};
106-
use snarkvm_utilities::cfg_iter;
106+
use snarkvm_utilities::{cfg_find_map, cfg_iter};
107107

108108
use indexmap::{IndexMap, IndexSet};
109109
use std::collections::BTreeSet;
@@ -1069,17 +1069,22 @@ impl<N: Network> ProgramCore<N> {
10691069
.ok_or(anyhow!("Failed to fetch maximum program size"))?;
10701070

10711071
// Check if the constructor exceeds the maximum number of writes.
1072-
let constructor_exceeds =
1073-
self.constructor().is_some_and(|constructor| constructor.num_writes() > max_num_writes);
1074-
1075-
// Check if any finalize logic exceeds the maximum number of writes.
1076-
let finalize_exceeds = cfg_iter!(self.functions()).any(|(_, function)| {
1077-
function.finalize_logic().is_some_and(|finalize| finalize.num_writes() > max_num_writes)
1078-
});
1072+
if self.constructor().is_some_and(|constructor| constructor.num_writes() > max_num_writes) {
1073+
bail!(
1074+
"Program constructor exceeds the maximum allowed writes ({max_num_writes}) for the current height {block_height} (consensus version {}).",
1075+
N::CONSENSUS_VERSION(block_height)?
1076+
);
1077+
}
10791078

1080-
if constructor_exceeds || finalize_exceeds {
1079+
// Find the first function whose finalize logic exceeds the maximum writes.
1080+
if let Some(name) = cfg_find_map!(self.functions(), |function| {
1081+
function
1082+
.finalize_logic()
1083+
.is_some_and(|finalize| finalize.num_writes() > max_num_writes)
1084+
.then(|| *function.name())
1085+
}) {
10811086
bail!(
1082-
"Program writes exceed the maximum allowed writes of {max_num_writes} for the current height {block_height} (consensus version {}).",
1087+
"Program function '{name}' exceeds the maximum allowed writes ({max_num_writes}) for the current height {block_height} (consensus version {}).",
10831088
N::CONSENSUS_VERSION(block_height)?
10841089
);
10851090
}

synthesizer/src/vm/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,19 @@ use crate::{Restrictions, cast_mut_ref, cast_ref, convert, process};
2929
use console::{
3030
account::{Address, PrivateKey},
3131
network::prelude::*,
32-
program::{Argument, Identifier, Literal, Locator, Plaintext, ProgramID, ProgramOwner, Record, Response, Value},
32+
program::{
33+
Argument,
34+
FINALIZE_ID_DEPTH,
35+
Identifier,
36+
Literal,
37+
Locator,
38+
Plaintext,
39+
ProgramID,
40+
ProgramOwner,
41+
Record,
42+
Response,
43+
Value,
44+
},
3345
types::{Field, Group, U16, U64},
3446
};
3547
use snarkvm_algorithms::snark::varuna::VarunaVersion;
@@ -73,6 +85,7 @@ use snarkvm_synthesizer_process::{
7385
execution_cost,
7486
};
7587
use snarkvm_synthesizer_program::{
88+
FinalizeCore,
7689
FinalizeGlobalState,
7790
FinalizeOperation,
7891
FinalizeStoreTrait,

0 commit comments

Comments
 (0)