Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9b92e7c
Add constructors
d0cd Mar 15, 2025
de65282
Add program checksum and edition to stack
d0cd Mar 15, 2025
341078d
Adjust operand
d0cd Mar 15, 2025
0f19c3a
Load operand
d0cd Mar 15, 2025
5906dfe
Set edition to default
d0cd Mar 15, 2025
8f97617
Implement constructors, add basic tests
d0cd Mar 18, 2025
0710e19
Fix and add test
d0cd Mar 18, 2025
091f43f
Fix expectation
d0cd Mar 18, 2025
b28c317
Fix comment
d0cd Mar 18, 2025
9f2e8e0
Cleanup
d0cd Mar 19, 2025
1277470
Feedback
d0cd Mar 20, 2025
d032476
Update good_constructor test, allow other FinalizeOperations
d0cd Mar 20, 2025
2ca3f04
Fine-grained pricing for constructors
d0cd Mar 20, 2025
e2c4f75
Feedback
d0cd Mar 20, 2025
5da640e
Feedback
d0cd Mar 20, 2025
9646b02
Feedback
d0cd Mar 20, 2025
60784ef
Feedback
d0cd Mar 20, 2025
b2dcf99
Feedback
d0cd Mar 20, 2025
8179ffb
Feedback
d0cd Mar 20, 2025
2f35cf9
Feedback
d0cd Mar 20, 2025
ede2b81
Feedback
d0cd Mar 20, 2025
f4aa8a2
Merge branch 'feat/constructors-and-operands' into review/constructor…
d0cd Mar 21, 2025
542adb7
Merge pull request #2658 from ProvableHQ/review/constructors-and-oper…
d0cd Mar 21, 2025
cb1ea9f
Feedback
d0cd Mar 21, 2025
83b319e
Feedback
d0cd Mar 21, 2025
56f27ad
Feedback
d0cd Mar 27, 2025
e0d0882
Remove edition and checksum as keywords
d0cd Mar 27, 2025
fd173bc
Feedback
d0cd Mar 28, 2025
3e0b08c
Removed constructor from reserved keywords
d0cd Apr 15, 2025
01e228e
Merge branch 'staging' into feat/constructors-and-operands
d0cd Apr 18, 2025
c4e8c3b
Merge branch 'staging' into feat/constructors-and-operands
d0cd May 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion console/network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ pub trait Network:
const STARTING_SUPPLY: u64 = 1_500_000_000_000_000; // 1.5B credits
/// The cost in microcredits per byte for the deployment transaction.
const DEPLOYMENT_FEE_MULTIPLIER: u64 = 1_000; // 1 millicredit per byte
/// The multiplier in microcredits for each command in the constructor.
const CONSTRUCTOR_FEE_MULTIPLIER: u64 = 100; // 100x per command
/// The constant that divides the storage polynomial.
const EXECUTION_STORAGE_FEE_SCALING_FACTOR: u64 = 5000;
/// The maximum size execution transactions can be before a quadratic storage penalty applies.
Expand All @@ -141,7 +143,7 @@ pub trait Network:
const MAX_DEPLOYMENT_CONSTRAINTS: u64 = 1 << 20; // 1,048,576 constraints
/// The maximum number of microcredits that can be spent as a fee.
const MAX_FEE: u64 = 1_000_000_000_000_000;
/// The maximum number of microcredits that can be spent on a transaction's finalize scope.
/// The maximum number of microcredits that can be spent on a constructor or finalize scope.
const TRANSACTION_SPEND_LIMIT: u64 = 100_000_000;

/// The anchor height, defined as the expected number of blocks to reach the coinbase target.
Expand Down
2 changes: 1 addition & 1 deletion ledger/block/src/transaction/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ impl<N: Network> Transaction<N> {
// Ensure the number of functions is within the allowed range.
ensure!(
num_transitions < Self::MAX_TRANSITIONS, // Note: Observe we hold back 1 for the fee.
"Execution must contain less than {num_transitions} transitions, found {}",
"Execution must contain less than {} transitions, found {num_transitions}",
Self::MAX_TRANSITIONS,
);
Ok(())
Expand Down
45 changes: 30 additions & 15 deletions ledger/block/src/transactions/confirmed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ pub type NumFinalizeSize = u16;
#[derive(Clone, PartialEq, Eq)]
pub enum ConfirmedTransaction<N: Network> {
/// The accepted deploy transaction is composed of `(index, deploy_transaction, finalize_operations)`.
/// The finalize operations may contain operations from the executing the constructor and fee transition.
AcceptedDeploy(u32, Transaction<N>, Vec<FinalizeOperation<N>>),
/// The accepted execute transaction is composed of `(index, execute_transaction, finalize_operations)`.
/// The finalize operations can contain operations from the executing the finalize scope and fee transition.
AcceptedExecute(u32, Transaction<N>, Vec<FinalizeOperation<N>>),
/// The rejected deploy transaction is composed of `(index, fee_transaction, rejected_deployment, finalize_operations)`.
/// The finalize operations can contain operations from the fee transition.
RejectedDeploy(u32, Transaction<N>, Rejected<N>, Vec<FinalizeOperation<N>>),
/// The rejected execute transaction is composed of `(index, fee_transaction, rejected_execution, finalize_operations)`.
/// The finalize operations can contain operations from the fee transition.
RejectedExecute(u32, Transaction<N>, Rejected<N>, Vec<FinalizeOperation<N>>),
}

Expand All @@ -51,20 +55,22 @@ impl<N: Network> ConfirmedTransaction<N> {
}
};

// Count the number of `InitializeMapping` and `UpdateKeyValue` finalize operations.
let (num_initialize_mappings, num_update_key_values) =
finalize_operations.iter().try_fold((0, 0), |(init, update), operation| match operation {
FinalizeOperation::InitializeMapping(..) => Ok((init + 1, update)),
FinalizeOperation::UpdateKeyValue(..) => Ok((init, update + 1)),
// Count the number of `InitializeMapping` and `*KeyValue` finalize operations.
let (num_initialize_mappings, num_key_values) =
finalize_operations.iter().try_fold((0, 0), |(init, key_value), operation| match operation {
FinalizeOperation::InitializeMapping(..) => Ok((init + 1, key_value)),
FinalizeOperation::InsertKeyValue(..) // At the time of writing, `InsertKeyValue` is only used in tests. However, it is added for completeness, as it is a valid operation.
| FinalizeOperation::RemoveKeyValue(..)
| FinalizeOperation::UpdateKeyValue(..) => Ok((init, key_value + 1)),
op => {
bail!("Transaction '{}' (deploy) contains an invalid finalize operation ({op})", transaction.id())
}
})?;

// Perform safety checks on the finalize operations.
{
// Ensure the number of finalize operations matches the number of 'InitializeMapping' and 'UpdateKeyValue' finalize operations.
if num_initialize_mappings + num_update_key_values != finalize_operations.len() {
// Ensure the number of finalize operations matches the number of 'InitializeMapping' and '*KeyValue' finalize operations.
if num_initialize_mappings + num_key_values != finalize_operations.len() {
bail!(
"Transaction '{}' (deploy) must contain '{}' operations",
transaction.id(),
Expand All @@ -79,14 +85,23 @@ impl<N: Network> ConfirmedTransaction<N> {
program.mappings().len(),
)
}
// Ensure the number of finalize operations matches the number of 'UpdateKeyValue' finalize operations.
if num_update_key_values != fee.num_finalize_operations() {
bail!(
"Transaction '{}' (deploy) must contain {} 'UpdateKeyValue' operations (found '{num_update_key_values}')",
transaction.id(),
fee.num_finalize_operations()
);
}
// Ensure the number of fee finalize operations lower bounds the number of '*KeyValue' finalize operations.
// The lower bound is due to the fact that constructors can issue '*KeyValue' operations as part of the deployment.
ensure!(
fee.num_finalize_operations() <= num_key_values,
"Transaction '{}' (deploy) must contain at least {} '*KeyValue' operations (found '{num_key_values}')",
transaction.id(),
fee.num_finalize_operations()
);
// Ensure the number of fee finalize operations and the number of "write" operations in the constructor upper bounds the number of '*KeyValue' finalize operations.
// This is an upper bound because a constructor may contain `branch.*` commands so that a subset of writes are executed.
let num_constructor_writes = usize::from(program.constructor().map(|c| c.num_writes()).unwrap_or_default());
ensure!(
fee.num_finalize_operations().saturating_add(num_constructor_writes) >= num_key_values,
"Transaction '{}' (deploy) must contain at most {} '*KeyValue' operations (found '{num_key_values}')",
transaction.id(),
fee.num_finalize_operations().saturating_add(num_constructor_writes)
);
}

// Return the accepted deploy transaction.
Expand Down
7 changes: 6 additions & 1 deletion ledger/store/src/program/finalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,11 +590,16 @@ impl<N: Network, P: FinalizeStorage<N>> FinalizeStore<N, P> {
}

impl<N: Network, P: FinalizeStorage<N>> FinalizeStoreTrait<N> for FinalizeStore<N, P> {
/// Returns `true` if the given `program ID` and `mapping name` exist.
/// Returns `true` if the given `program ID` and `mapping name` is confirmed to exist.
fn contains_mapping_confirmed(&self, program_id: &ProgramID<N>, mapping_name: &Identifier<N>) -> Result<bool> {
self.storage.contains_mapping_confirmed(program_id, mapping_name)
}

/// Returns `true` if the given `program ID` and `mapping name` exist.
fn contains_mapping_speculative(&self, program_id: &ProgramID<N>, mapping_name: &Identifier<N>) -> Result<bool> {
self.storage.contains_mapping_speculative(program_id, mapping_name)
}

/// Returns `true` if the given `program ID`, `mapping name`, and `key` exist.
fn contains_key_speculative(
&self,
Expand Down
Loading