feat(aztec-nr)!: remove set_sender_for_tags oracle, use builder pattern for sender override#23619
Conversation
f599bd7 to
c919519
Compare
nventuro
left a comment
There was a problem hiding this comment.
Thank you for trying to make the world a better place.
|
|
||
| - unsafe { set_sender_for_tags(some_address) }; | ||
| - note.deliver(MessageDelivery::onchain_constrained()); | ||
| + note.deliver(MessageDelivery::onchain_constrained_with_sender(SenderForTags::explicit(some_address))); |
There was a problem hiding this comment.
This seems a bit verbose and ad-hoc. Two suggestions:
- Have a second method that just takes the param, avoiding the object, similar to
TestEnvironment.private_context_at, makes sense when some option is used often
note.deliver(MessageDelivery::onchain_constrained_from(some_address);- Have a more general options object and a variant that takes it, so that we can further extend these options in the future in backwards compatible ways (like
TestEnvironment::private_context_opts:
note.deliver(MessageDelivery::onchain_constrained_opts(DeliveryOpts::new().sender(some_address)));If you think we'll add more options in the future, I'd go with 2. If not 1 might be good enough.
There was a problem hiding this comment.
Actually in this case because the method is already deliver, what you could do instead is have deliver take the full options object and use a builder pattern. This would be more extensible and less verbose
struct DeliveryMethod {
variant: u8,
sender: Option<Address>,
}
impl DeliveryMethod {
fn onchain_constrained() -> Self {
Self { variant: ONCHAIN_CONST, sender: none() }
}
fn onchain_unconstrained() -> Self { ... }
fn with_sender(&mut self, sender: Addr) -> Self {
self.sender = some(sender);
self
}
}and you then do
msg.deliver(DeliveryMethod.onchain_constrained());
// or
msg.deliver(DeliveryMethod.onchain_unconstrained().with_sender(some_sender));If you want to forbid certain combinations (e.g. not allow with_sender for offchain delivery) then you can either add runtime checks to that fn, or compile time checks by having each delivery fn return a different type, which then each have different methods of their own (the config for each deli mechanism).
Note how in this case we're not exposing the internal types, the members of the struct etc., we just commit to the method chain. So we can freely add more stuff or change the internal repr with no breaking changes.
There was a problem hiding this comment.
I really liked this idea, I implemented it so that .offchain() couldn't be chained with .with_sender()
c919519 to
9c6cbd8
Compare
| }; | ||
|
|
||
| #[test] | ||
| fn constructors_produce_distinct_variants() { |
| /// Unlike [`MessageDelivery`] (which is returned by [`MessageDelivery::offchain`]), this type exposes | ||
| /// [`with_sender`](OnchainDelivery::with_sender), which overrides the sender address used for discovery tag | ||
| /// derivation. | ||
| pub struct OnchainDelivery { |
There was a problem hiding this comment.
Does this and MessageDelivery need to be pub?
There was a problem hiding this comment.
Eh it's not too bad I guess, as longs as the members are not pub (and so the thing cannot be constructed directly).
Introduce a dedicated OffchainDelivery type so the resolved delivery struct no longer doubles as its own builder, switch with_sender to &mut self, drop a redundant assert_constant, and clarify the related docstrings, error message, docs, and account-contract comments.
…/remove-set-sender-for-tags # Conflicts: # noir-projects/aztec-nr/aztec/src/standard_addresses.nr # noir-projects/noir-contracts/contracts/protocol/aztec_sublib/src/standard_addresses.nr # yarn-project/standard-contracts/src/standard_contract_data.ts
The merge brought in message-signing and fallback keys (#23510), which extended the contract instance (CONTRACT_INSTANCE_LENGTH 10 -> 12). The previously committed addresses were derived against a stale local TS build using the old instance layout. Regenerate against the rebuilt toolchain so the compile_all drift check passes.
Flakey Tests🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
Why we are doing this
The
set_sender_for_tagsoracle was a mutable, side-effectful call that contracts used to override which address is used for discovery tag derivation. The connection between theset_sender_for_tagscall and the later.deliver()call was non-obvious.Our fix
Replace the oracle with a
.with_sender(address)builder method onOnchainDelivery, making the sender selection explicit at the delivery call site.MessageDelivery::onchain_constrained()andonchain_unconstrained()now returnOnchainDelivery(which exposeswith_sender), whileoffchain()returnsMessageDeliverydirectly (no sender override, since offchain delivery does not use tags).A
MessageDeliveryBuildertrait letsdeliver()accept both types generically.Migration
The
set_sender_for_tagsoracle has been removed. Contracts that used it should pass the sender address via the.with_sender()builder on onchain delivery modes:Contracts that did not call
set_sender_for_tagsrequire no changes.