Skip to content

Commit

Permalink
feat!: Include contract class id in deployment info (#4223)
Browse files Browse the repository at this point in the history
**Breaking changes:**
- Aztec.js `Contract` object and generated ts wrappers now hold a
`ContractInstance` instead of a `CompleteAddress`.
- Updated `addContract` CLI command to require initHash and salt instead
of partialAddress, needed to generate the ContractInstance

**Other changes:**
- Updated contract deployment data, contract deployment event, new
contract data, and other structs to include the contract class id.
- `ContractDao` now holds a `ContractInstance` reference instead of a
`CompleteAddress`.
- Moved functions to compute address to a separate module within
circuits.js.
- Killed `DeploymentInfo` struct in favor of `ContractInstance`
- Updated types in `noir-protocol-circuit` to handle new structures for
new contract data, and updated address computation.

**Comments**
- CompleteAddress still around, meant to let a user receive funds
without registering themselves, and has public key in plain.
- Unclear whether to store initiHash+salt+portal or just saltedInitHash
in instances in the node.
- Unclear if portal should be part of saltedInitHash also.

Fixes #4054
  • Loading branch information
spalladino committed Jan 30, 2024
1 parent e99a882 commit 0ed4126
Show file tree
Hide file tree
Showing 96 changed files with 1,482 additions and 1,292 deletions.
18 changes: 9 additions & 9 deletions l1-contracts/src/periphery/ContractDeploymentEmitter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ contract ContractDeploymentEmitter is IContractDeploymentEmitter {
* @param _aztecAddress - The address of the L2 counterparty
* @param _portalAddress - The address of the L1 counterparty
* @param _l2BlockHash - The hash of the L2 block that this is related to
* @param _partialAddress - The partial address of the deployed contract
* @param _pubKeyX - The x coordinate of the contract's public key
* @param _pubKeyY - The y coordinate of the contract's public key
* @param _contractClassId - The contract class id
* @param _saltedInitializationHash - Salted init hash
* @param _publicKeyHash - Public key hash
* @param _acir - The acir bytecode of the L2 contract
* @dev See the link bellow for more info on partial address and public key:
* https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys
Expand All @@ -32,19 +32,19 @@ contract ContractDeploymentEmitter is IContractDeploymentEmitter {
bytes32 _aztecAddress,
address _portalAddress,
bytes32 _l2BlockHash,
bytes32 _partialAddress,
bytes32 _pubKeyX,
bytes32 _pubKeyY,
bytes32 _contractClassId,
bytes32 _saltedInitializationHash,
bytes32 _publicKeyHash,
bytes calldata _acir
) external override(IContractDeploymentEmitter) {
emit ContractDeployment(
_l2BlockNum,
_aztecAddress,
_portalAddress,
_l2BlockHash,
_partialAddress,
_pubKeyX,
_pubKeyY,
_contractClassId,
_saltedInitializationHash,
_publicKeyHash,
_acir
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ interface IContractDeploymentEmitter {
* @param aztecAddress - The address of the L2 counterparty
* @param portalAddress - The address of the L1 counterparty
* @param l2BlockHash - The hash of the L2 block that this is related to
* @param partialAddress - The partial address of the deployed contract
* @param pubKeyX - The x coordinate of the contract's public key
* @param pubKeyY - The y coordinate of the contract's public key
* @param contractClassId - The contract class id
* @param saltedInitializationHash - Salted init hash
* @param publicKeyHash - Public key hash
* @param acir - The acir bytecode of the L2 contract
* @dev See the link bellow for more info on partial address and public key:
* https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys
Expand All @@ -28,9 +28,9 @@ interface IContractDeploymentEmitter {
bytes32 indexed aztecAddress,
address indexed portalAddress,
bytes32 l2BlockHash,
bytes32 partialAddress,
bytes32 pubKeyX,
bytes32 pubKeyY,
bytes32 contractClassId,
bytes32 saltedInitializationHash,
bytes32 publicKeyHash,
bytes acir
);

Expand All @@ -39,9 +39,9 @@ interface IContractDeploymentEmitter {
bytes32 _aztecAddress,
address _portalAddress,
bytes32 _l2BlockHash,
bytes32 _partialAddress,
bytes32 _pubKeyX,
bytes32 _pubKeyY,
bytes32 _contractClassId,
bytes32 _saltedInitializationHash,
bytes32 _publicKeyHash,
bytes calldata _acir
) external;
}
10 changes: 5 additions & 5 deletions yarn-project/accounts/src/ecdsa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@
*/
import { AccountManager, Salt } from '@aztec/aztec.js/account';
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
import { CompleteAddress, GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { AztecAddress } from '@aztec/circuits.js';

import { EcdsaAccountContract } from './account_contract.js';

export { EcdsaAccountContract };
export { EcdsaAccountContractArtifact } from './artifact.js';
export { EcdsaAccountContract };

/**
* Creates an Account that relies on an ECDSA signing key for authentication.
* @param pxe - An PXE server instance.
* @param encryptionPrivateKey - Grumpkin key used for note encryption.
* @param signingPrivateKey - Secp256k1 key used for signing transactions.
* @param saltOrAddress - Deployment salt or complete address if account contract is already deployed.
* @param salt - Deployment salt.
*/
export function getEcdsaAccount(
pxe: PXE,
encryptionPrivateKey: GrumpkinPrivateKey,
signingPrivateKey: Buffer,
saltOrAddress?: Salt | CompleteAddress,
salt?: Salt,
): AccountManager {
return new AccountManager(pxe, encryptionPrivateKey, new EcdsaAccountContract(signingPrivateKey), saltOrAddress);
return new AccountManager(pxe, encryptionPrivateKey, new EcdsaAccountContract(signingPrivateKey), salt);
}

/**
Expand Down
8 changes: 4 additions & 4 deletions yarn-project/accounts/src/schnorr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { AccountManager, Salt } from '@aztec/aztec.js/account';
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
import { CompleteAddress, GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { AztecAddress } from '@aztec/circuits.js';

import { SchnorrAccountContract } from './account_contract.js';
Expand All @@ -20,15 +20,15 @@ export { SchnorrAccountContractArtifact } from './artifact.js';
* @param pxe - An PXE server instance.
* @param encryptionPrivateKey - Grumpkin key used for note encryption.
* @param signingPrivateKey - Grumpkin key used for signing transactions.
* @param saltOrAddress - Deployment salt or complete address if account contract is already deployed.
* @param salt - Deployment salt.
*/
export function getSchnorrAccount(
pxe: PXE,
encryptionPrivateKey: GrumpkinPrivateKey,
signingPrivateKey: GrumpkinPrivateKey,
saltOrAddress?: Salt | CompleteAddress,
salt?: Salt,
): AccountManager {
return new AccountManager(pxe, encryptionPrivateKey, new SchnorrAccountContract(signingPrivateKey), saltOrAddress);
return new AccountManager(pxe, encryptionPrivateKey, new SchnorrAccountContract(signingPrivateKey), salt);
}

/**
Expand Down
11 changes: 5 additions & 6 deletions yarn-project/accounts/src/single_key/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { AccountManager, Salt } from '@aztec/aztec.js/account';
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
import { CompleteAddress, GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
import { AztecAddress } from '@aztec/circuits.js';

import { SingleKeyAccountContract } from './account_contract.js';
Expand All @@ -19,18 +19,18 @@ export { SchnorrSingleKeyAccountContractArtifact as SingleKeyAccountContractArti
* Creates an Account that uses the same Grumpkin key for encryption and authentication.
* @param pxe - An PXE server instance.
* @param encryptionAndSigningPrivateKey - Grumpkin key used for note encryption and signing transactions.
* @param saltOrAddress - Deployment salt or complete address if account contract is already deployed.
* @param salt - Deployment salt .
*/
export function getSingleKeyAccount(
pxe: PXE,
encryptionAndSigningPrivateKey: GrumpkinPrivateKey,
saltOrAddress?: Salt | CompleteAddress,
salt?: Salt,
): AccountManager {
return new AccountManager(
pxe,
encryptionAndSigningPrivateKey,
new SingleKeyAccountContract(encryptionAndSigningPrivateKey),
saltOrAddress,
salt,
);
}

Expand All @@ -49,5 +49,4 @@ export function getSingleKeyWallet(
return getWallet(pxe, address, new SingleKeyAccountContract(signingKey));
}

export { getSingleKeyAccount as getUnsafeSchnorrAccount };
export { getSingleKeyWallet as getUnsafeSchnorrWallet };
export { getSingleKeyAccount as getUnsafeSchnorrAccount, getSingleKeyWallet as getUnsafeSchnorrWallet };
8 changes: 4 additions & 4 deletions yarn-project/acir-simulator/src/acvm/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ export function toACVMCallContext(callContext: CallContext): ACVMField[] {
*/
export function toACVMContractDeploymentData(contractDeploymentData: ContractDeploymentData): ACVMField[] {
return [
toACVMField(contractDeploymentData.deployerPublicKey.x),
toACVMField(contractDeploymentData.deployerPublicKey.y),
toACVMField(contractDeploymentData.constructorVkHash),
toACVMField(contractDeploymentData.functionTreeRoot),
toACVMField(contractDeploymentData.publicKey.x),
toACVMField(contractDeploymentData.publicKey.y),
toACVMField(contractDeploymentData.initializationHash),
toACVMField(contractDeploymentData.contractClassId),
toACVMField(contractDeploymentData.contractAddressSalt),
toACVMField(contractDeploymentData.portalContractAddress),
];
Expand Down
6 changes: 3 additions & 3 deletions yarn-project/archiver/src/archiver/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,9 @@ function makeContractDeploymentEvent(l1BlockNum: bigint, l2Block: L2Block) {
aztecAddress: extendedContractData.contractData.contractAddress.toString(),
portalAddress: extendedContractData.contractData.portalContractAddress.toString(),
l2BlockHash: `0x${l2Block.getCalldataHash().toString('hex')}`,
partialAddress: extendedContractData.partialAddress.toString(),
pubKeyX: extendedContractData.publicKey.x.toString(),
pubKeyY: extendedContractData.publicKey.y.toString(),
contractClassId: extendedContractData.contractClassId.toString(),
saltedInitializationHash: extendedContractData.saltedInitializationHash.toString(),
publicKeyHash: extendedContractData.publicKeyHash.toString(),
acir: '0x' + acir,
},
transactionHash: `0x${l2Block.number}`,
Expand Down
17 changes: 11 additions & 6 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
LogType,
TxHash,
} from '@aztec/circuit-types';
import { FunctionSelector, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, getContractClassId } from '@aztec/circuits.js';
import { FunctionSelector, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js';
import { createEthereumChain } from '@aztec/ethereum';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { padArrayEnd } from '@aztec/foundation/collection';
Expand Down Expand Up @@ -471,7 +471,12 @@ export class Archiver implements ArchiveSource {
}
}

/** Converts ExtendedContractData into contract classes and instances. */
/**
* Converts ExtendedContractData into contract classes and instances.
* Note that the conversion is not correct, since there is some data missing from the broadcasted ExtendedContractData.
* The archiver will trust the ids broadcasted instead of trying to recompute them.
* Eventually this function and ExtendedContractData altogether will be removed.
*/
function extendedContractDataToContractClassAndInstance(
data: ExtendedContractData,
): [ContractClassWithId, ContractInstanceWithAddress] {
Expand All @@ -486,14 +491,14 @@ function extendedContractDataToContractClassAndInstance(
privateFunctions: [],
packedBytecode: data.bytecode,
};
const contractClassId = getContractClassId(contractClass);
const contractClassId = data.contractClassId;
const contractInstance: ContractInstance = {
version: 1,
salt: Fr.ZERO,
salt: data.saltedInitializationHash,
contractClassId,
initializationHash: Fr.ZERO,
initializationHash: data.saltedInitializationHash,
portalContractAddress: data.contractData.portalContractAddress,
publicKeysHash: data.partialAddress,
publicKeysHash: data.publicKeyHash,
};
const address = data.contractData.contractAddress;
return [
Expand Down
15 changes: 7 additions & 8 deletions yarn-project/archiver/src/archiver/eth_log_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@aztec/circuit-types';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr, Point } from '@aztec/foundation/fields';
import { Fr } from '@aztec/foundation/fields';
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts';

Expand Down Expand Up @@ -195,17 +195,16 @@ export function processContractDeploymentLogs(
continue;
}
const publicFnsReader = BufferReader.asReader(Buffer.from(log.args.acir.slice(2), 'hex'));
const partialAddress = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.partialAddress)));
const publicKey = new Point(
Fr.fromBuffer(Buffer.from(hexToBytes(log.args.pubKeyX))),
Fr.fromBuffer(Buffer.from(hexToBytes(log.args.pubKeyY))),
);
const contractClassId = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.contractClassId)));
const saltedInitializationHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.saltedInitializationHash)));
const publicKeyHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.publicKeyHash)));

const contractData = new ExtendedContractData(
new ContractData(AztecAddress.fromString(log.args.aztecAddress), EthAddress.fromString(log.args.portalAddress)),
publicFnsReader.readVector(EncodedContractFunction),
partialAddress,
publicKey,
contractClassId,
saltedInitializationHash,
publicKeyHash,
);
if (extendedContractData[i]) {
extendedContractData[i][0].push(contractData);
Expand Down
6 changes: 3 additions & 3 deletions yarn-project/aztec-nr/aztec/src/context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,12 @@ impl PrivateContext {
unencrypted_log_preimages_length: reader.read(),
historical_header: reader.read_struct(Header::deserialize),
contract_deployment_data: ContractDeploymentData {
deployer_public_key: GrumpkinPoint {
public_key: GrumpkinPoint {
x: reader.read(),
y: reader.read()
},
constructor_vk_hash : reader.read(),
function_tree_root : reader.read(),
initialization_hash : reader.read(),
contract_class_id : reader.read(),
contract_address_salt : reader.read(),
portal_contract_address : EthAddress::from_field(reader.read()),
},
Expand Down
45 changes: 24 additions & 21 deletions yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use dep::protocol_types::{
abis::{
complete_address::CompleteAddress,
new_contract_data::NewContractData as ContractLeafPreimage,
},
address::{AztecAddress, EthAddress},
Expand All @@ -22,40 +21,44 @@ use crate::{
// it is what it expects. The constructor param check is the reason of why we pass in the preimage of contract's
// aztec address instead of just the address.
pub fn prove_contract_inclusion(
deployer_public_key: GrumpkinPoint,
public_key: GrumpkinPoint,
contract_address_salt: Field,
function_tree_root: Field,
constructor_hash: Field,
contract_class_id: Field,
initialization_hash: Field,
portal_contract_address: EthAddress,
block_number: u32, // The block at which we'll prove that the public value exists
context: PrivateContext
) -> AztecAddress {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let header = context.get_header_at(block_number);
// let block_header = context.get_header.at(block_number);

// 2) Compute the contract address
let contract_address = CompleteAddress::compute(
deployer_public_key,
let contract_address = AztecAddress::compute_from_public_key(
public_key,
contract_class_id,
contract_address_salt,
function_tree_root,
constructor_hash
).address;
initialization_hash,
portal_contract_address
);

// 3) Form the contract tree leaf preimage
let preimage = ContractLeafPreimage { contract_address, portal_contract_address, function_tree_root };
// TODO(@spalladino): Use initialization and/or deployment nullifier for this proof.
// Consider splitting this into 2 methods, one for initialization and one for public deployment.

// 3) Form the contract tree leaf preimage
// let preimage = ContractLeafPreimage { contract_address, portal_contract_address, contract_class_id };
//
// 4) Get the contract tree leaf by hashing the preimage
let contract_leaf = preimage.hash();

// let contract_leaf = preimage.hash();
//
// 5) Get the membership witness of the leaf in the contract tree
let witness = get_contract_membership_witness(block_number, contract_leaf);

// let witness = get_contract_membership_witness(block_number, contract_leaf);
//
// 6) Prove that the leaf is in the contract tree
assert(
header.state.partial.contract_tree.root
== compute_merkle_root(contract_leaf, witness.index, witness.path), "Proving contract inclusion failed"
);

// assert(
// block_header.partial.contract_tree.root
// == compute_merkle_root(contract_leaf, witness.index, witness.path), "Proving contract inclusion failed"
// );
//
// --> Now we have traversed the trees all the way up to archive root.

contract_address
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/aztec-nr/aztec/src/oracle/get_public_key.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use dep::protocol_types::{
address::{
AztecAddress,
PartialAddress,
PublicKeysHash,
},
grumpkin_point::GrumpkinPoint,
};
Expand All @@ -18,7 +19,7 @@ pub fn get_public_key(address: AztecAddress) -> GrumpkinPoint {
let pub_key = GrumpkinPoint::new(result[0], result[1]);
let partial_address = PartialAddress::from_field(result[2]);

let calculated_address = AztecAddress::compute(pub_key, partial_address);
let calculated_address = AztecAddress::compute(PublicKeysHash::compute(pub_key), partial_address);
assert(calculated_address.eq(address));

pub_key
Expand Down

0 comments on commit 0ed4126

Please sign in to comment.