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: bridge l1 assets to l2 acvm #578

Merged
merged 43 commits into from
May 18, 2023
Merged

feat: bridge l1 assets to l2 acvm #578

merged 43 commits into from
May 18, 2023

Conversation

Maddiaa0
Copy link
Member

@Maddiaa0 Maddiaa0 commented May 15, 2023

Description

part of #522, #515

Overview

Adds a series of functionality to the acvm as well as a noir contract that can consume an l1 to l2 message and create a nullifier for it.

  1. Creates a cbind to recreate a secret message hash which has its own pedesen generator index.
  2. Create a small TokenPortal that is capable of holding assets and sending messages instructing tokens to be minted on the L2.
  3. ACVM oracle opcodes
  • getL1ToL2Message: The implementation of this is currently stubbed, but this opcode fetches a message based on its msgKey, and returns key information to the noir context, essentially the same info that is included within the solidity struct
  • emitData: This is a utility function to aid development, it allows us to log out values from noir when the acvm is simulating them. I found it useful for debugging and think it should be kept for other people to use too.
  1. Adds a test to consume an l1 to l2 message, mocking the stubbed getL1ToL2Message mentioned above
  2. Begins an e2e test that mints some tokens and has the scaffolding to make the corresponding noir call. however, in a following pr the sequencer side of this will be added.

Notes

  • Sha256 inside the circuit is unrolled, similar to lasse's implementation as the loops be quite slow
  • removes use of const p = prime_order from typescript and replaces it with the static field Fr.MODULO which is the same

Please provide a paragraph or two giving a summary of the change, including relevant motivation and context.

Checklist:

  • I have reviewed my diff in github, line by line.
  • Every change is related to the PR description.
  • I have linked this pull request to the issue(s) that it resolves.
  • There are no unexpected formatting changes, superfluous debug logs, or commented-out code.
  • The branch has been merged or rebased against the head of its merge target.
  • I'm happy for the PR to be merged at the reviewer's next convenience.

{
NT::fr message_secret;
read(secret, message_secret);
// TODO(sean): This is not using the generator correctly and is unsafe, update
Copy link
Contributor

Choose a reason for hiding this comment

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

wdym? does this have an issue we are tracking it in?

Copy link
Contributor

Choose a reason for hiding this comment

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

Think it is because Noir currently does not support the generators specified as we are doing in cpp. The message_secret is to be used in noir, so @Maddiaa0 using this method to have a hash that can be reproduced inside and outside noir.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's todo with not being able to use pedersen generator indexes natively inside noir yet.

  • [index, ...hashValues], is not the same as [hashValues], hashed under a different generator index.

Alvaro has added the functionality to noir but it has not made it into the aztec3 branch yet so cannot be used here, (branch: https://github.com/noir-lang/noir/tree/arv/pedersen_with_hash_index)

I've made an issue for this here: #610

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
Copy link
Contributor

Choose a reason for hiding this comment

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

why do you have 2 IInbox interfaces?

Copy link
Member Author

@Maddiaa0 Maddiaa0 May 17, 2023

Choose a reason for hiding this comment

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

Seems this was left over from the merge, as your previous pr had it in a different location it did not cop (me also) that they were really the same file.
This has been addressed and they have been removed


// Check that the message is in the inbox
IMessageBox.Entry memory entry = IInbox(inbox).get(entryKey);
assertEq(entry.count, 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit; you may also check if the corresponding event (MessageAdded) got fired

let recipientPk: Buffer;
let recipient: NoirPoint;

const buildMessage = async (content: Fr[], targetContract: AztecAddress, secret: Fr) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: rename this to buildL1ToL2Message

AztecAddress.random(),
contractAddress,
new FunctionData(Buffer.alloc(4), true, true),
// BUG: placing a fr in args will result in a fr wrapped in an fr
Copy link
Contributor

Choose a reason for hiding this comment

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

have you flagged this issue somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah I have not, but it is a known issue, #611 made this for tracking

Copy link
Contributor

Choose a reason for hiding this comment

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

If you put the issue in the comment would be neat 👍

@@ -216,6 +223,7 @@ export class PrivateFunctionExecution {
private writeInputs() {
const argsSize = this.abi.parameters.reduce((acc, param) => acc + sizeOfType(param.type), 0);

console.log('storage contract address: ', this.callContext.storageContractAddress);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: remove


global Nonce = 1;
global NoteHash = 2;
global NoteStorageSlot = 3;
global MappingStorageSlot = 4;
global Nullifier = 5;
global L1ToL2MessageSecret = 29;
Copy link
Contributor

Choose a reason for hiding this comment

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

I am out of the loop - why is this 29? is this the pedereson generator constant?

Copy link
Member Author

Choose a reason for hiding this comment

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

Its index 29 here:

secret: pub Field,
) -> pub [Field; dep::aztec3::abi::PUBLIC_INPUTS_LENGTH] {
let mut context = PrivateFunctionContext::new();
context.args = context.args.push_array([amount, owner.x, owner.y, msg_key, secret]);
Copy link
Contributor

Choose a reason for hiding this comment

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

damn is this how we create private vars in noir now?

Copy link
Member Author

@Maddiaa0 Maddiaa0 May 17, 2023

Choose a reason for hiding this comment

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

haha, nah its just to get around a noir mutability quirk when constructing the context for the kernel circuit


// Checks is a msg is within the l1Msg tree
#[oracle(getL1ToL2Message)]
fn get_l1_to_l2_msg_oracle(_msg_key: Field) -> [Field; L1_MESSAGE_ORACLE_CALL_LENGTH] {}
Copy link
Contributor

Choose a reason for hiding this comment

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

question so I understand this better -> how does this work?

Copy link
Member Author

@Maddiaa0 Maddiaa0 May 17, 2023

Choose a reason for hiding this comment

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

In the acvm you can register callbacks:

export interface ACIRCallback {

When making an oracle call, it will look for the callback with the given name, then inject into this function response / send the inputs to the ts context. You can see in the tests where you can mock what the function returns.

hash_bytes[30] = amount_bytes[30];
hash_bytes[31] = amount_bytes[31];

hash_bytes[0 + 32] = recipient_bytes[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

BAHAHHAHAH damn :/

Copy link
Member Author

Choose a reason for hiding this comment

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

fr fr

@Maddiaa0 Maddiaa0 changed the title feat: (wip) bridge l1 assets to l2 test feat: bridge l1 assets to l2 acvm May 17, 2023
@Maddiaa0 Maddiaa0 marked this pull request as ready for review May 17, 2023 16:31
@Maddiaa0 Maddiaa0 requested a review from rahul-kothari May 17, 2023 17:33
Copy link
Contributor

@LHerskind LHerskind left a comment

Choose a reason for hiding this comment

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

A bit inconsistenct on L1 or L1ToL2 naming, but nice job 👍

"@aztec/verifier/=lib/aztec-verifier-contracts/src/"
"@aztec/interfaces/=src/interfaces/",
"@aztec/verifier/=lib/aztec-verifier-contracts/src/",
"@aztec/mocks/=/src/mock/"
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems strange. Why is there both a mock and mocks now? And the interfaces don't seem to exist here, is in the core/interfaces?

@@ -9,6 +9,11 @@ import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";
import {MockVerifier} from "@aztec/mock/MockVerifier.sol";
import {Decoder} from "./Decoder.sol";

// Messaging
Copy link
Contributor

Choose a reason for hiding this comment

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

Think this needs a rebase to get the updates from #609

@@ -3,6 +3,9 @@
pragma solidity >=0.8.18;

library DataStructures {
// Prime field modulus
Copy link
Contributor

Choose a reason for hiding this comment

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

Think this is more fitting in a Constants.sol as it is not a data structure. In #552 I added one after your comment.

{
// Preamble
IInbox inbox = REGISTRY.getInbox();
DataStructures.L2Actor memory actor = DataStructures.L2Actor(_to, 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using the same _to here means that the messages is received by the same as will be receiving funds. Won't you just lock the funds forever in the rollup to belong to the token contract itself.

Think the L2Actor aztec address should not be specified by the user, but from storage in the contract, e.g., use an initialize function or something for making the "link" to the L2 contract and use that value for the actor, then the user passed in _to can be part of the content.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, this is correct

* @param msgKey - A buffer representing the message key.
* @returns The message data
*/
public async getL1ToL2Message(msgKey: Fr) {
Copy link
Contributor

Choose a reason for hiding this comment

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

A specified return type would be neat.

// Deposit tokens to the TokenPortal
const contractString = deployedContract.address.toString() as `0x${string}`;
const secretString = `0x${claimSecretHash.toBuffer().toString('hex')}` as `0x${string}`;
const deadline = 4_294_967_295 - 1; // max uint - 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you want max uint - 1? The maxuint is already 2**32 - 1

"noir:build:test": "(cd src/contracts/test_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts test",
"noir:build:parent": "(cd src/contracts/parent_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts parent",
"noir:build:child": "(cd src/contracts/child_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts child",
"noir:build:zk_token": "(cd src/contracts/zk_token_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts zk_token",
"noir:build:pub_token": "(cd src/contracts/public_token_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts public_token"
"noir:build:pub_token": "(cd src/contracts/public_token_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts public_token",
"noir:build:l1_token": "(cd src/contracts/non_native_token_contract && nargo compile main --contracts) && ts-node --esm src/scripts/copy_output.ts non_native_token"
Copy link
Contributor

Choose a reason for hiding this comment

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

Think you run into size limits.


// TODO: Still need to check that the secret hash -> note hash
// this should be another pedersen generator ?
global L1_MESSAGE_LEN = 8;
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency, think it would be nice if it is referred to as L1_TO_L2, generally for this file some places it is L1Message but and other L1ToL2.

}

fn compute_msg_hash(_self: Self) -> Field {
// Todo a sha256 hash of the message
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there an issue for this 👀?

Copy link
Member Author

Choose a reason for hiding this comment

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

Implementing in current interation

@Maddiaa0 Maddiaa0 merged commit a19c36e into master May 18, 2023
@Maddiaa0 Maddiaa0 deleted the md/scaffold-l1-l2-e2e branch May 18, 2023 15:06
ludamad pushed a commit that referenced this pull request Jul 14, 2023
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.

3 participants