Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: shared mutable configurable delays #6104

Merged
merged 25 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
df451ff
Add scheduled delay change, adjust shared mutable
nventuro Apr 30, 2024
d0fe460
Add some more tests
nventuro Apr 30, 2024
80a860e
Adapt auth contract
nventuro Apr 30, 2024
b400ba0
Adapt to type param
nventuro May 2, 2024
503aa01
Add initial delay tests
nventuro May 2, 2024
f921f93
Update Auth contract
nventuro May 2, 2024
381a1f1
Add helper to make tests shorter
nventuro May 2, 2024
c6b0fa1
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 2, 2024
b47e5db
Add notes on Option usage
nventuro May 3, 2024
73ac5f5
Add migration notes
nventuro May 3, 2024
a9e7c75
Added comments re. max_block_number coordination
nventuro May 3, 2024
c095daa
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 3, 2024
27e64d6
update shared private getter
nventuro May 3, 2024
ddf6d4e
Apply suggestions from code review
nventuro May 7, 2024
d004ca5
Improvements from code review
nventuro May 7, 2024
88b6040
Clarfy diagram
nventuro May 7, 2024
ca2b228
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 7, 2024
f95f434
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 7, 2024
ad7fcd6
Fix diagrams
nventuro May 8, 2024
9512976
Fix migration notes
nventuro May 8, 2024
bbc4a67
Clarify docs
nventuro May 8, 2024
ce8ea8a
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 8, 2024
d8e9810
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 9, 2024
9053239
Fix nargo formatting
nventuro May 9, 2024
4fed5d3
Merge branch 'master' into nv/shared-mutable-delay
nventuro May 9, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ While shared state variables are much less leaky than the assertion in public ap

The `max_block_number` transaction property will be set to a value close to the current block number plus the duration of the delay in blocks. The exact value depends on the historical block over which the private proof is constructed. For example, if the current block number is 100 and a shared state variable has a delay of 20 blocks, then transactions that read this value privately will set `max_block_number` to a value close to 120 (clients building proofs on older state will select a lower `max_block_number`). This implicitly leaks the duration of the delay.

Applications using similar delays will therefore be part of the same privacy set. It is expected for social coordination to result in small set of predetermined delays that developers choose from depending on their needs, as an example a viable set might be: 12 hours (for time-sensitive operations, such as emergency mechanisms), 5 days (for middle-of-the-road operations) and 2 weeks (for operations that require lengthy public scrutiny).
Applications using similar delays will therefore be part of the same privacy set. It is expected for social coordination to result in small set of predetermined delays that developers choose from depending on their needs, as an example a viable set might be: 12 hours (for time-sensitive operations, such as emergency mechanisms), 5 days (for middle-of-the-road operations) and 2 weeks (for operations that require lengthy public scrutiny). These delays can be changed during the contract lifetime as the application's needs evolve.

:::note
Shared state delays are currently hardcoded at compilation time and cannot be changed, but there are plans to make this a mutable value.
:::note
Additionally, users might choose to coordinate and constrain their transactions to use a common delay value and set `max_block_number` to a value lower than would be strictly needed by the applications they interact with (if any!), and by doing so prevent privacy leakage.
nventuro marked this conversation as resolved.
Show resolved Hide resolved

### Choosing Epochs

Expand Down
4 changes: 4 additions & 0 deletions docs/docs/misc/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Aztec is in full-speed development. Literally every version breaks compatibility

## 0.38.0

### Mutable delays in `SharedMutable`
nventuro marked this conversation as resolved.
Show resolved Hide resolved

The type signature for `SharedMutable` changed from `SharedMutable<T, DELAY>` to `SharedMutable<T, INITIAL_DELAY>`. The behavior is the same as before, except the delay can now be changed after deployment by calling `schedule_delay_change`.

### [Aztec.nr] Emmiting encrypted logs

The `emit_encrypted_log` function is now a context method.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod shared_mutable;
mod scheduled_delay_change;
mod scheduled_value_change;
mod shared_mutable_private_getter;

Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,76 @@ use dep::protocol_types::{hash::pedersen_hash, traits::FromField, address::Aztec
use crate::context::{PrivateContext, Context};
use crate::history::public_storage::public_storage_historical_read;
use crate::public_storage;
use crate::state_vars::{storage::Storage, shared_mutable::scheduled_value_change::ScheduledValueChange};
use crate::state_vars::{
storage::Storage,
shared_mutable::{scheduled_delay_change::ScheduledDelayChange, scheduled_value_change::ScheduledValueChange}
};

struct SharedMutablePrivateGetter<T, DELAY> {
struct SharedMutablePrivateGetter<T, INITIAL_DELAY> {
context: PrivateContext,
// The contract address of the contract we want to read from
other_contract_address: AztecAddress,
// The storage slot where the SharedMutable is stored on the other contract
storage_slot: Field,
// The _dummy variable forces DELAY to be interpreted as a numberic value. This is a workaround to
// The _dummy variable forces INITIAL_DELAY to be interpreted as a numberic value. This is a workaround to
// https://github.com/noir-lang/noir/issues/4633. Remove once resolved.
_dummy: [Field; DELAY],
_dummy: [Field; INITIAL_DELAY],
}

// We have this as a view-only interface to reading Shared Mutables in other contracts.
// Currently the Shared Mutable does not support this. We can adapt SharedMutable at a later date
impl<T, DELAY> SharedMutablePrivateGetter<T, DELAY> {
impl<T, INITIAL_DELAY> SharedMutablePrivateGetter<T, INITIAL_DELAY> {
pub fn new(
context: PrivateContext,
other_contract_address: AztecAddress,
storage_slot: Field
) -> Self {
assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
assert(other_contract_address.to_field() != 0, "Other contract address cannot be 0");
Self { context, other_contract_address, storage_slot, _dummy: [0; DELAY] }
Self { context, other_contract_address, storage_slot, _dummy: [0; INITIAL_DELAY] }
}

pub fn get_current_value_in_private(self) -> T where T: FromField {
let mut context = self.context;

let (scheduled_value_change, historical_block_number) = self.historical_read_from_public_storage(context);
let block_horizon = scheduled_value_change.get_block_horizon(historical_block_number, DELAY);
let (value_change, delay_change, historical_block_number) = self.historical_read_from_public_storage(context);
let effective_minimum_delay = delay_change.get_effective_minimum_delay_at(historical_block_number);
let block_horizon = value_change.get_block_horizon(historical_block_number, effective_minimum_delay);

// We prevent this transaction from being included in any block after the block horizon, ensuring that the
// historical public value matches the current one, since it can only change after the horizon.
context.set_tx_max_block_number(block_horizon);
scheduled_value_change.get_current_at(historical_block_number)
value_change.get_current_at(historical_block_number)
}

fn historical_read_from_public_storage(
self,
context: PrivateContext
) -> (ScheduledValueChange<T>, u32) where T: FromField {
let derived_slot = self.get_derived_storage_slot();

// Ideally the following would be simply public_storage::read_historical, but we can't implement that yet.
let mut raw_fields = [0; 3];
) -> (ScheduledValueChange<T>, ScheduledDelayChange<INITIAL_DELAY>, u32) where T: FromField {
let value_change_slot = self.get_value_change_storage_slot();
let mut raw_value_change_fields = [0; 3];
for i in 0..3 {
raw_fields[i] = public_storage_historical_read(
context,
derived_slot + i as Field,
self.other_contract_address
);
raw_value_change_fields[i] = public_storage_historical_read(
context,
value_change_slot + i as Field,
self.other_contract_address
);
}

let scheduled_value: ScheduledValueChange<T> = ScheduledValueChange::deserialize(raw_fields);
let delay_change_slot = self.get_delay_change_storage_slot();
let raw_delay_change_fields = [public_storage_historical_read(context, delay_change_slot, context.this_address())];

let value_change = ScheduledValueChange::deserialize(raw_value_change_fields);
let delay_change = ScheduledDelayChange::deserialize(raw_delay_change_fields);

let historical_block_number = context.historical_header.global_variables.block_number as u32;

(scheduled_value, historical_block_number)
(value_change, delay_change, historical_block_number)
}

fn get_derived_storage_slot(self) -> Field {
// Since we're actually storing three values (a ScheduledValueChange struct), we hash the storage slot to get a
// unique location in which we can safely store as much data as we need. This could be removed if we informed
// the slot allocator of how much space we need so that proper padding could be added.
// See https://github.com/AztecProtocol/aztec-packages/issues/5492
fn get_value_change_storage_slot(self) -> Field {
pedersen_hash([self.storage_slot, 0], 0)
}

fn get_delay_change_storage_slot(self) -> Field {
pedersen_hash([self.storage_slot, 1], 0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ contract Auth {
fn constructor(admin: AztecAddress) {
assert(!admin.is_zero(), "invalid admin");
storage.admin.initialize(admin);
// Note that we don't initialize authorized with any value: because storage defaults to 0 it'll have a 'post'
// value of 0 and block of change 0, meaning it is effectively autoinitialized at the zero address.
}

// docs:start:shared_mutable_schedule
Expand Down
Loading