Skip to content

Commit 94a5f55

Browse files
authored
Merge pull request #3051 from ProvableHQ/feat/improve-register-index-error
[Refactor] Output record register check from V10
2 parents cf10c9d + af911b8 commit 94a5f55

File tree

5 files changed

+53
-31
lines changed

5 files changed

+53
-31
lines changed

synthesizer/process/src/stack/helpers/check_upgrade.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ impl<N: Network> Stack<N> {
3636
/// | finalize | ❌ | ✅ (logic) | ✅ |
3737
/// |-------------------|--------|--------------|-------|
3838
///
39+
/// There is one important caveat in that output register indices **MUST** remain the same.
40+
/// For example, changing `output r10 as <NAME>.record` into `output r11 as <NAME>.record` would not be a valid upgrade.
41+
/// This restriction is necessary because the output register index is instantiated as a constant in the caller circuit.
42+
/// This check is enforced in `check_transaction` in `synthesizer/src/vm/verify.rs`.
3943
#[inline]
4044
pub fn check_upgrade_is_valid(old_program: &Program<N>, new_program: &Program<N>) -> Result<()> {
4145
// Get the new program ID.

synthesizer/src/vm/helpers/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pub use history::*;
2323

2424
mod macros;
2525

26+
mod program;
27+
pub use program::*;
28+
2629
mod rewards;
2730
pub use rewards::*;
2831

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2019-2025 Provable Inc.
2+
// This file is part of the snarkVM library.
3+
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at:
7+
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
use console::{network::Network, program::ValueType};
17+
use snarkvm_synthesizer_program::Program;
18+
19+
use anyhow::{Result, bail, ensure};
20+
21+
/// Verifies that the existing output register indices are not changed in a new version of the program.
22+
// Note. This function is public so that depednent crates can cleanly surface this error to users.
23+
pub fn check_output_register_indices_unchanged<N: Network>(
24+
old_program: &Program<N>,
25+
new_program: &Program<N>,
26+
) -> Result<()> {
27+
for (id, function) in old_program.functions() {
28+
// Get the corresponding function in the new program.
29+
let Ok(new_function) = new_program.get_function(id) else { bail!("Missing function '{id}'") };
30+
// Ensure the record output registers match.
31+
let existing_output_registers =
32+
function.outputs().iter().filter(|output| matches!(output.value_type(), ValueType::Record(_)));
33+
let new_output_registers =
34+
new_function.outputs().iter().filter(|output| matches!(output.value_type(), ValueType::Record(_)));
35+
ensure!(
36+
existing_output_registers.eq(new_output_registers),
37+
"Function '{id}' has mismatched record output registers"
38+
);
39+
}
40+
Ok(())
41+
}

synthesizer/src/vm/mod.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,7 @@ use crate::{Restrictions, cast_mut_ref, cast_ref, convert, process};
2929
use console::{
3030
account::{Address, PrivateKey},
3131
network::prelude::*,
32-
program::{
33-
Argument,
34-
Identifier,
35-
Literal,
36-
Locator,
37-
Plaintext,
38-
ProgramID,
39-
ProgramOwner,
40-
Record,
41-
Response,
42-
Value,
43-
ValueType,
44-
},
32+
program::{Argument, Identifier, Literal, Locator, Plaintext, ProgramID, ProgramOwner, Record, Response, Value},
4533
types::{Field, Group, U16, U64},
4634
};
4735
use snarkvm_algorithms::snark::varuna::VarunaVersion;

synthesizer/src/vm/verify.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -350,24 +350,10 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
350350
);
351351
// If the consensus version is V10 or greater, then check that each function's **record** output registers match the existing program.
352352
if consensus_version >= ConsensusVersion::V10 {
353-
for (id, function) in existing_program.functions() {
354-
// Get the corresponding function in the new program.
355-
let Ok(new_function) = deployment.program().get_function(id) else {
356-
bail!("Invalid deployment transaction '{id}' - missing function '{id}'")
357-
};
358-
// Ensure the record output registers match.
359-
let existing_output_registers = function
360-
.outputs()
361-
.iter()
362-
.filter(|output| matches!(output.value_type(), ValueType::Record(_)));
363-
let new_output_registers = new_function
364-
.outputs()
365-
.iter()
366-
.filter(|output| matches!(output.value_type(), ValueType::Record(_)));
367-
ensure!(
368-
existing_output_registers.eq(new_output_registers),
369-
"Invalid deployment transaction '{id}' - function '{id}' has mismatched record output registers"
370-
);
353+
if let Err(e) =
354+
check_output_register_indices_unchanged(existing_program, deployment.program())
355+
{
356+
bail!("Invalid deployment transaction '{id}' - {e}")
371357
}
372358
}
373359
}

0 commit comments

Comments
 (0)