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: initial siloing of incoming notes to pxe / pxe database #7533

Closed
wants to merge 1 commit into from

Conversation

sklppy88
Copy link
Contributor

Please read contributing guidelines and remove this line.

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @sklppy88 and the rest of your teammates on Graphite Graphite

@sklppy88 sklppy88 changed the title init feat: initial siloing ofincoming notes to pxe / pxe database Jul 19, 2024
@sklppy88 sklppy88 changed the title feat: initial siloing ofincoming notes to pxe / pxe database feat: initial siloing of incoming notes to pxe / pxe database Jul 19, 2024
@sklppy88 sklppy88 force-pushed the ek/feat/silo-notes-to-account-in-pxe branch 8 times, most recently from 68388da to b8ed79f Compare July 22, 2024 22:38
@AztecBot
Copy link
Collaborator

AztecBot commented Jul 22, 2024

Benchmark results

Metrics with a significant change:

  • app_circuit_witness_generation_time_in_ms (GasToken:deploy): 574 (+18%)
  • app_circuit_input_size_in_bytes (Token:transfer_public (avm)): 42,914 (-23%)
  • app_circuit_input_size_in_bytes (FPC:pay_refund (avm)): 32,835 (+19%)
  • protocol_circuit_simulation_time_in_ms (private-kernel-inner): 228 (+33%)
  • protocol_circuit_simulation_time_in_ms (private-kernel-tail): 1,164 (+217%)
  • protocol_circuit_simulation_time_in_ms (base-rollup): 4,226 (+29%)
  • protocol_circuit_simulation_time_in_ms (public-kernel-setup): 195 (+91%)
  • protocol_circuit_simulation_time_in_ms (public-kernel-app-logic): 150 (+42%)
  • protocol_circuit_simulation_time_in_ms (public-kernel-tail): 889 (+40%)
  • protocol_circuit_simulation_time_in_ms (private-kernel-reset-tiny): 301 (+29%)
  • protocol_circuit_simulation_time_in_ms (private-kernel-tail-to-public): 6,794 (+69%)
  • protocol_circuit_simulation_time_in_ms (public-kernel-teardown): 141 (+55%)
  • avm_simulation_time_ms (FPC:prepare_fee): 127 (-51%)
  • avm_simulation_time_ms (FPC:pay_refund): 121 (+64%)
  • avm_simulation_time_ms (Benchmarking:increment_balance): 1,339 (+33%)
  • avm_simulation_time_ms (Token:_increase_public_balance): 84.5 (-44%)
  • avm_simulation_time_ms (FPC:pay_refund_with_shielded_rebate): 109 (+66%)
  • avm_simulation_bytecode_size_in_bytes (Token:transfer_public): 31,218 (-29%)
  • avm_simulation_bytecode_size_in_bytes (FPC:pay_refund): 21,266 (+33%)
  • avm_simulation_bytecode_size_in_bytes (FPC:pay_refund_with_shielded_rebate): 22,361 (+31%)
  • protocol_circuit_witness_generation_time_in_ms (private-kernel-tail-to-public): 2,963 (+114%)
  • protocol_circuit_witness_generation_time_in_ms (private-kernel-tail): 2,480 (+187%)
  • protocol_circuit_witness_generation_time_in_ms (base-parity): 833 (+23%)
  • protocol_circuit_proving_time_in_ms (base-parity): 1,954 (+45%)
  • protocol_circuit_num_public_inputs (base-parity): 3.00 (-84%)
  • protocol_circuit_num_public_inputs (base-rollup): 28.0 (-36%)
  • protocol_circuit_num_public_inputs (root-parity): 3.00 (-84%)
  • protocol_circuit_num_public_inputs (root-rollup): 26.0 (-38%)
  • app_circuit_proving_time_in_ms (FPC:prepare_fee (avm)): 1,983 (-17%)
  • app_circuit_proving_time_in_ms (Token:transfer_public (avm)): 2,781 (-56%)
  • app_circuit_proving_time_in_ms (FPC:pay_refund (avm)): 8,550 (+136%)
  • l2_block_building_time_in_ms (4): 13,209 (+28%)
  • l2_block_building_time_in_ms (8): 26,027 (+29%)
  • l2_block_building_time_in_ms (16): 50,900 (+28%)
  • l2_block_rollup_simulation_time_in_ms (4): 13,209 (+28%)
  • l2_block_rollup_simulation_time_in_ms (8): 26,027 (+29%)
  • l2_block_rollup_simulation_time_in_ms (16): 50,900 (+28%)
  • l2_block_public_tx_process_time_in_ms (4): 11,044 (+29%)
  • l2_block_public_tx_process_time_in_ms (8): 23,662 (+29%)
  • l2_block_public_tx_process_time_in_ms (16): 48,512 (+29%)
  • pxe_database_size_in_bytes (3): 7,456 (-54%)
  • pxe_database_size_in_bytes (5): 12,128 (-55%)
Detailed results

All benchmarks are run on txs on the Benchmarking contract on the repository. Each tx consists of a batch call to create_note and increment_balance, which guarantees that each tx has a private call, a nested private call, a public call, and a nested public call, as well as an emitted private note, an unencrypted log, and public storage read and write.

This benchmark source data is available in JSON format on S3 here.

Proof generation

Each column represents the number of threads used in proof generation.

Metric 1 threads 4 threads 16 threads 32 threads 64 threads
proof_construction_time_sha256_ms 5,711 1,537 700 (-7%) 768 (+3%) 776
proof_construction_time_sha256_30_ms 12,250 (+3%) 3,132 (-1%) 1,448 (+3%) 1,423 (-1%) 1,459 (-2%)
proof_construction_time_sha256_100_ms 44,981 (+2%) 11,826 5,413 (-1%) 5,387 5,456 (+2%)
proof_construction_time_poseidon_hash_ms 77.0 34.0 34.0 (-3%) 58.0 (-2%) 87.0
proof_construction_time_poseidon_hash_30_ms 1,516 (-2%) 420 (+1%) 202 (+1%) 224 (+1%) 267 (-1%)
proof_construction_time_poseidon_hash_100_ms 6,336 (+13%) 1,515 677 727 (+2%) 747

L2 block published to L1

Each column represents the number of txs on an L2 block published to L1.

Metric 4 txs 8 txs 16 txs
l1_rollup_calldata_size_in_bytes 708 708 708
l1_rollup_calldata_gas 6,588 6,586 6,588
l1_rollup_execution_gas 583,050 583,199 583,352
l2_block_processing_time_in_ms 760 1,418 2,720
l2_block_building_time_in_ms ⚠️ 13,209 (+28%) ⚠️ 26,027 (+29%) ⚠️ 50,900 (+28%)
l2_block_rollup_simulation_time_in_ms ⚠️ 13,209 (+28%) ⚠️ 26,027 (+29%) ⚠️ 50,900 (+28%)
l2_block_public_tx_process_time_in_ms ⚠️ 11,044 (+29%) ⚠️ 23,662 (+29%) ⚠️ 48,512 (+29%)

L2 chain processing

Each column represents the number of blocks on the L2 chain where each block has 8 txs.

Metric 3 blocks 5 blocks
node_history_sync_time_in_ms 7,170 (+1%) 9,953
node_database_size_in_bytes 12,443,728 (-2%) 16,511,056 (-2%)
pxe_database_size_in_bytes ⚠️ 7,456 (-54%) ⚠️ 12,128 (-55%)

Circuits stats

Stats on running time and I/O sizes collected for every kernel circuit run across all benchmarks.

Circuit simulation_time_in_ms witness_generation_time_in_ms input_size_in_bytes output_size_in_bytes proving_time_in_ms proof_size_in_bytes num_public_inputs size_in_gates
private-kernel-init 118 (+26%) 402 (+2%) 21,732 54,085 N/A N/A N/A N/A
private-kernel-inner ⚠️ 228 (+33%) 722 (+4%) 81,199 54,264 N/A N/A N/A N/A
private-kernel-tail ⚠️ 1,164 (+217%) ⚠️ 2,480 (+187%) 61,568 62,127 N/A N/A N/A N/A
base-parity 6.50 (-1%) ⚠️ 833 (+23%) 160 96.0 ⚠️ 1,954 (+45%) 12,676 (-4%) ⚠️ 3.00 (-84%) 131,072
root-parity 108 (-2%) 124 (+9%) 64,860 (-3%) 96.0 30,616 (+9%) 12,676 (-4%) ⚠️ 3.00 (-84%) 4,194,304
base-rollup ⚠️ 4,226 (+29%) 5,006 (-1%) 181,083 632 44,000 (+8%) 13,476 (-4%) ⚠️ 28.0 (-36%) 4,194,304
root-rollup 153 (-2%) 124 (+7%) 51,261 (-3%) 652 28,620 (+12%) 13,412 (-4%) ⚠️ 26.0 (-38%) 4,194,304
public-kernel-setup ⚠️ 195 (+91%) 2,446 (+4%) 113,048 80,822 17,833 (+13%) 119,428 3,339 2,097,152
public-kernel-app-logic ⚠️ 150 (+42%) 3,379 (+2%) 113,048 80,822 10,109 (+14%) 119,428 3,339 1,048,576
public-kernel-tail ⚠️ 889 (+40%) 24,173 (+4%) 410,181 10,814 66,433 (+8%) 25,860 (-2%) 415 (-4%) 8,388,608
private-kernel-reset-tiny ⚠️ 301 (+29%) 1,010 (+6%) 77,007 53,954 N/A N/A N/A N/A
private-kernel-tail-to-public ⚠️ 6,794 (+69%) ⚠️ 2,963 (+114%) 773,262 1,632 N/A N/A N/A N/A
public-kernel-teardown ⚠️ 141 (+55%) 3,341 (+2%) 113,048 80,822 18,252 (+12%) 119,428 3,339 2,097,152
merge-rollup 57.5 (-2%) N/A 33,566 (-3%) 632 N/A N/A N/A N/A
undefined N/A N/A N/A N/A 164,519 (+8%) N/A N/A N/A

Stats on running time collected for app circuits

Function input_size_in_bytes output_size_in_bytes witness_generation_time_in_ms proof_size_in_bytes proving_time_in_ms
ContractClassRegisterer:register 1,312 9,344 394 (+12%) N/A N/A
ContractInstanceDeployer:deploy 1,376 9,344 25.1 (-1%) N/A N/A
MultiCallEntrypoint:entrypoint 1,888 9,344 641 (+13%) N/A N/A
GasToken:deploy 1,344 9,344 ⚠️ 574 (+18%) N/A N/A
SchnorrAccount:constructor 1,280 9,344 459 (+5%) N/A N/A
SchnorrAccount:entrypoint 2,272 9,344 818 (+12%) N/A N/A
Token:privately_mint_private_note 1,248 9,344 541 (+2%) N/A N/A
FPC:fee_entrypoint_public 1,312 9,344 100 (-5%) N/A N/A
Token:transfer 1,280 9,344 1,533 (+15%) N/A N/A
AuthRegistry:set_authorized (avm) 19,222 N/A N/A 95,392 1,978 (-13%)
FPC:prepare_fee (avm) 22,670 N/A N/A 95,456 ⚠️ 1,983 (-17%)
Token:transfer_public (avm) ⚠️ 42,914 (-23%) N/A N/A 95,456 ⚠️ 2,781 (-56%)
AuthRegistry:consume (avm) 33,100 N/A N/A 95,424 2,456 (-14%)
FPC:pay_refund (avm) ⚠️ 32,835 (+19%) N/A N/A 95,424 ⚠️ 8,550 (+136%)
Benchmarking:create_note 1,312 9,344 452 (+6%) N/A N/A
SchnorrAccount:verify_private_authwit 1,248 9,344 48.9 (+18%) N/A N/A
Token:unshield 1,344 9,344 1,230 (+7%) N/A N/A
FPC:fee_entrypoint_private 1,344 9,344 1,602 (+6%) N/A N/A

AVM Simulation

Time to simulate various public functions in the AVM.

Function time_ms bytecode_size_in_bytes
GasToken:_increase_public_balance 102 (+2%) 13,790
GasToken:set_portal 12.7 (+12%) 3,339
Token:constructor 123 (-2%) 23,692
FPC:constructor 93.6 (-2%) 13,592
GasToken:mint_public 81.8 (-2%) 10,158
Token:mint_public 55.9 (-8%) 19,034
Token:assert_minter_and_mint 87.1 (-7%) 12,925
AuthRegistry:set_authorized 49.4 (+4%) 7,812
FPC:prepare_fee ⚠️ 127 (-51%) 11,068
Token:transfer_public 43.1 (+14%) ⚠️ 31,218 (-29%)
FPC:pay_refund ⚠️ 121 (+64%) ⚠️ 21,266 (+33%)
Benchmarking:increment_balance ⚠️ 1,339 (+33%) 11,281
Token:_increase_public_balance ⚠️ 84.5 (-44%) 15,006
FPC:pay_refund_with_shielded_rebate ⚠️ 109 (+66%) ⚠️ 22,361 (+31%)

Public DB Access

Time to access various public DBs.

Function time_ms
get-nullifier-index 0.164 (+5%)

Tree insertion stats

The duration to insert a fixed batch of leaves into each tree type.

Metric 1 leaves 16 leaves 64 leaves 128 leaves 256 leaves 512 leaves 1024 leaves
batch_insert_into_append_only_tree_16_depth_ms 10.4 (-1%) 16.7 (-1%) N/A N/A N/A N/A N/A
batch_insert_into_append_only_tree_16_depth_hash_count 16.8 31.7 N/A N/A N/A N/A N/A
batch_insert_into_append_only_tree_16_depth_hash_ms 0.599 (-1%) 0.514 (-1%) N/A N/A N/A N/A N/A
batch_insert_into_append_only_tree_32_depth_ms N/A N/A 48.3 76.0 (+1%) 131 (+1%) 246 471
batch_insert_into_append_only_tree_32_depth_hash_count N/A N/A 95.9 159 287 543 1,055
batch_insert_into_append_only_tree_32_depth_hash_ms N/A N/A 0.493 0.468 (+1%) 0.452 (+1%) 0.445 0.440 (+1%)
batch_insert_into_indexed_tree_20_depth_ms N/A N/A 59.8 111 183 (+1%) 352 (-1%) 693
batch_insert_into_indexed_tree_20_depth_hash_count N/A N/A 109 207 355 691 1,363
batch_insert_into_indexed_tree_20_depth_hash_ms N/A N/A 0.504 (-1%) 0.500 0.481 0.476 (-1%) 0.476
batch_insert_into_indexed_tree_40_depth_ms N/A N/A 72.8 N/A N/A N/A N/A
batch_insert_into_indexed_tree_40_depth_hash_count N/A N/A 133 N/A N/A N/A N/A
batch_insert_into_indexed_tree_40_depth_hash_ms N/A N/A 0.518 N/A N/A N/A N/A

Miscellaneous

Transaction sizes based on how many contract classes are registered in the tx.

Metric 0 registered classes 1 registered classes
tx_size_in_bytes 77,341 668,542

Transaction size based on fee payment method

| Metric | |
| - | |

@sklppy88 sklppy88 force-pushed the ek/feat/silo-notes-to-account-in-pxe branch from b8ed79f to 95464a1 Compare July 23, 2024 20:31
Copy link
Contributor

github-actions bot commented Jul 23, 2024

Changes to circuit sizes

Generated at commit: a3c54b938595378556354fe575630054ff99136c, compared to commit: 2633aa91a97684f481a861aee0be8756c956135a

🧾 Summary (100% most significant diffs)

Program ACIR opcodes (+/-) % Circuit size (+/-) %
public_kernel_tail +597 ❌ +0.06% +389 ❌ +0.01%
rollup_base +148 ❌ +0.04% -139 ✅ -0.00%
public_kernel_teardown -48 ✅ -0.02% -256 ✅ -0.02%
public_kernel_setup -48 ✅ -0.03% -256 ✅ -0.02%
parity_root -144 ✅ -2.94% -944 ✅ -0.02%
rollup_root -112 ✅ -2.67% -720 ✅ -0.02%
rollup_merge -80 ✅ -2.88% -496 ✅ -0.02%
private_kernel_empty -48 ✅ -2.58% -273 ✅ -0.03%

Full diff report 👇
Program ACIR opcodes (+/-) % Circuit size (+/-) %
public_kernel_tail 965,693 (+597) +0.06% 4,645,487 (+389) +0.01%
rollup_base 341,542 (+148) +0.04% 3,836,142 (-139) -0.00%
public_kernel_teardown 241,730 (-48) -0.02% 1,618,002 (-256) -0.02%
public_kernel_setup 183,195 (-48) -0.03% 1,554,056 (-256) -0.02%
parity_root 4,749 (-144) -2.94% 4,171,794 (-944) -0.02%
rollup_root 4,081 (-112) -2.67% 3,144,641 (-720) -0.02%
rollup_merge 2,702 (-80) -2.88% 2,092,160 (-496) -0.02%
private_kernel_empty 1,811 (-48) -2.58% 1,041,821 (-273) -0.03%

@sklppy88 sklppy88 force-pushed the ek/feat/silo-notes-to-account-in-pxe branch 3 times, most recently from 918203b to 7d1deb0 Compare July 23, 2024 21:22
addNote(note: ExtendedNote): Promise<void> {
return this.pxe.addNote(note);
addNote(note: ExtendedNote, account: AztecAddress): Promise<void> {
return this.pxe.addNote(note, account);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird and a prime example on why we should expose PXE directly: add a note to this siloed storage shouldn't be the wallet's responsability

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtendedNote does have an owner, which seems to be related to the incoming keys used. So we could go with that initially. If the note had an npk, then the owner of the npk sounds perhaps more conceptually correct (assuming they were not the same). And if there's no npk and no encryption, then who knows.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire flow seems quite incomplete due to the partial implementation of keys, especially key rotation. So this would definitely need reviewing later on. But it does sound in principle like the notion of notes being 'owned' makes sense.

Copy link
Contributor

@nventuro nventuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your work on this PR! I see a lot of effort went into it and the multiple e2e tests 😅

As we discussed, I'm concerned that introducing this change in this manner might result in excessive API pollution, affecting many parts of PXE with the extra account parameter. The large diff shows a significant impact on numerous callsites.

Given we're still exploring the best implementation, it might be challenging to roll back these changes if needed. I was thinking we could start with something more contained within PXE to minimize the impact on callsites. Since the callers are quite basic (raw test calls, barebones wallet, etc.), they might not handle this additional complexity well, leading to more plumbing to their callers.

At this early experimental stage, I'd suggest we explore different siloing methods (extending keys, using distinct databases, applying filters on top of the data layer, etc.). We could assess the tradeoffs (performance, attack surface size, multi-account access) and cosnider a path forward that:
a) avoids making the e2e setup overly complicated, using escape hatches if needed
b) acknowledges it will take time to develop a proper wallet using the full-fledged feature, and so allows for intermediate milestones
c) allows for some back-and-forth as we refine our decisions

@@ -73,7 +73,8 @@ export class BatchCall extends BaseContractInteraction {

const unconstrainedCalls = unconstrained.map(async indexedCall => {
const call = indexedCall[0];
return [await this.wallet.simulateUnconstrained(call.name, call.args, call.to, options?.from), indexedCall[1]];
// This is weird
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be useful if these kind of comments were expanded some more, e.g. what it is that's weird, how it might be desirable to do it, why it might not be possible, etc.

addNote(note: ExtendedNote): Promise<void> {
return this.pxe.addNote(note);
addNote(note: ExtendedNote, account: AztecAddress): Promise<void> {
return this.pxe.addNote(note, account);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtendedNote does have an owner, which seems to be related to the incoming keys used. So we could go with that initially. If the note had an npk, then the owner of the npk sounds perhaps more conceptually correct (assuming they were not the same). And if there's no npk and no encryption, then who knows.

@@ -57,7 +57,7 @@ async function main() {
TokenContract.notes.TransparentNote.id,
receipt.txHash,
);
await pxe.addNote(extendedNote);
await pxe.addNote(extendedNote, alice.address);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to the above, see how here alice was the owner of the note being stored.

addNote(note: ExtendedNote): Promise<void> {
return this.pxe.addNote(note);
addNote(note: ExtendedNote, account: AztecAddress): Promise<void> {
return this.pxe.addNote(note, account);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire flow seems quite incomplete due to the partial implementation of keys, especially key rotation. So this would definitely need reviewing later on. But it does sound in principle like the notion of notes being 'owned' makes sense.

Comment on lines +249 to +252
getIncomingNotes(filter: IncomingNotesFilter, account: AztecAddress): Promise<IncomingNoteDao[]> {
console.log('GETTING INCOMING NOTES FROM KV PXE DATABASE WITH ACCOUNT', account);
console.log(filter);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the source of most of my confusion. filter already has an owner element - could we not simply use that?

@@ -246,15 +260,17 @@ export class KVPxeDatabase implements PxeDatabase {

candidateNoteSources.push({
ids: publicKey
? this.#notesByIvpkM.getValues(publicKey.toString())
? this.#notesByIvpkM.getValues(`${account.toString()}:${publicKey.toString()}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't doing things this way mean that we always access one account at a time? So if e.g. multiple accounts were unlocked for whatever reason, we'd need to loop over all of them every time we fetch anything, which seems to lead to a lot of duplicated effort. Is there no way we can avoid this?

@@ -227,7 +227,7 @@ export class NoteProcessor {
const incomingNotes = blocksAndNotes.flatMap(b => b.incomingNotes);
const outgoingNotes = blocksAndNotes.flatMap(b => b.outgoingNotes);
if (incomingNotes.length || outgoingNotes.length) {
await this.db.addNotes(incomingNotes, outgoingNotes);
await this.db.addNotes(incomingNotes, outgoingNotes, this.account);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this is interesting, I thought the note processor would be handling multiple sets of keys, but it looks like each account gets their own note processor. This seems different from other pieces of the stack, where we are handling many accounts at once (like when fetching notes, they're all in the same database).

@sklppy88 sklppy88 force-pushed the ek/feat/silo-notes-to-account-in-pxe branch from 7d1deb0 to dda9474 Compare July 24, 2024 22:16
@sklppy88 sklppy88 force-pushed the ek/feat/silo-notes-to-account-in-pxe branch from dda9474 to 8b0d182 Compare July 25, 2024 11:20
@sklppy88
Copy link
Contributor Author

sklppy88 commented Aug 9, 2024

Closed in favor of #7710 and #7749.

@sklppy88 sklppy88 closed this Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants