Skip to content

Commit

Permalink
Merge branch 'mm/eccvm-work' of github.com:AztecProtocol/aztec-packag…
Browse files Browse the repository at this point in the history
…es into mm/eccvm-work
  • Loading branch information
maramihali committed May 28, 2024
2 parents d53f8a8 + fea7c51 commit ce88bb0
Show file tree
Hide file tree
Showing 18 changed files with 148 additions and 103 deletions.
14 changes: 0 additions & 14 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,6 @@ jobs:
command: cond_spot_run_build barretenberg-wasm-linux-clang 128
aztec_manifest_key: barretenberg-wasm-linux-clang

barretenberg-x86_64-linux-gcc:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Build"
command: cond_spot_run_build barretenberg-x86_64-linux-gcc 128
aztec_manifest_key: barretenberg-x86_64-linux-gcc

barretenberg-x86_64-linux-clang:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -505,7 +493,6 @@ workflows:
- avm-transpiler: *defaults

# Barretenberg
- barretenberg-x86_64-linux-gcc: *defaults
- barretenberg-x86_64-linux-clang: *defaults
- barretenberg-x86_64-linux-clang-assert: *defaults
# - barretenberg-x86_64-linux-clang-fuzzing: *defaults
Expand Down Expand Up @@ -555,7 +542,6 @@ workflows:
# Everything that must complete before deployment.
- end:
requires:
- barretenberg-x86_64-linux-gcc
- barretenberg-x86_64-linux-clang
- barretenberg-x86_64-linux-clang-assert
# - barretenberg-x86_64-linux-clang-fuzzing
Expand Down
1 change: 0 additions & 1 deletion barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ template <typename Flavor> class SumcheckVerifier {
bool checked = false;
//! [Final Verification Step]
if constexpr (IsRecursiveFlavor<Flavor>) {
full_honk_relation_purported_value.assert_equal(round.target_total_sum);
checked = (full_honk_relation_purported_value.get_value() == round.target_total_sum.get_value());
} else {
checked = (full_honk_relation_purported_value == round.target_total_sum);
Expand Down
6 changes: 0 additions & 6 deletions build_manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ barretenberg-x86_64-linux-clang-fuzzing:
dockerfile: dockerfiles/Dockerfile.x86_64-linux-clang-fuzzing
rebuildPatterns: .rebuild_patterns

# Builds all of barretenberg with gcc. Ensures compiler compatibility.
barretenberg-x86_64-linux-gcc:
buildDir: barretenberg/cpp
dockerfile: dockerfiles/Dockerfile.x86_64-linux-gcc
rebuildPatterns: .rebuild_patterns

# Builds barretenberg.wasm (single and multithreaded builds).
barretenberg-wasm-linux-clang:
buildDir: barretenberg/cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export abstract class BaseContractInteraction {
* @param request - Request to execute for this interaction.
* @returns Fee options for the actual transaction.
*/
protected async getFeeOptions(request: ExecutionRequestInit) {
protected async getFeeOptionsFromEstimatedGas(request: ExecutionRequestInit) {
const fee = request.fee;
if (fee) {
const txRequest = await this.wallet.createTxExecutionRequest(request);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/contract/batch_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class BatchCall extends BaseContractInteraction {
public async create(opts?: SendMethodOptions): Promise<TxExecutionRequest> {
if (!this.txRequest) {
const calls = this.calls;
const fee = opts?.estimateGas ? await this.getFeeOptions({ calls, fee: opts?.fee }) : opts?.fee;
const fee = opts?.estimateGas ? await this.getFeeOptionsFromEstimatedGas({ calls, fee: opts?.fee }) : opts?.fee;
this.txRequest = await this.wallet.createTxExecutionRequest({ calls, fee });
}
return this.txRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class ContractFunctionInteraction extends BaseContractInteraction {
}
if (!this.txRequest) {
const calls = [this.request()];
const fee = opts?.estimateGas ? await this.getFeeOptions({ calls, fee: opts?.fee }) : opts?.fee;
const fee = opts?.estimateGas ? await this.getFeeOptionsFromEstimatedGas({ calls, fee: opts?.fee }) : opts?.fee;
this.txRequest = await this.wallet.createTxExecutionRequest({ calls, fee });
}
return this.txRequest;
Expand Down
20 changes: 17 additions & 3 deletions yarn-project/aztec.js/src/contract/deploy_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
public async create(options: DeployOptions = {}): Promise<TxExecutionRequest> {
if (!this.txRequest) {
this.txRequest = await this.wallet.createTxExecutionRequest(await this.request(options));
// TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined?
await this.wallet.registerContract({ artifact: this.artifact, instance: this.instance! });
}
return this.txRequest;
}
Expand All @@ -98,6 +96,14 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
*/
public async request(options: DeployOptions = {}): Promise<ExecutionRequestInit> {
if (!this.functionCalls) {
// TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined?
// Note that we need to run this registerContract here so it's available when computeFeeOptionsFromEstimatedGas
// runs, since it needs the contract to have been registered in order to estimate gas for its initialization,
// in case the initializer is public. This hints at the need of having "transient" contracts scoped to a
// simulation, so we can run the simulation with a set of contracts, but only "commit" them to the wallet
// once this tx has gone through.
await this.wallet.registerContract({ artifact: this.artifact, instance: this.getInstance(options) });

const deployment = await this.getDeploymentFunctionCalls(options);
const bootstrap = await this.getInitializeFunctionCalls(options);

Expand All @@ -113,7 +119,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
};

if (options.estimateGas) {
request.fee = await this.getFeeOptions(request);
request.fee = await this.getFeeOptionsFromEstimatedGas(request);
}

this.functionCalls = request;
Expand Down Expand Up @@ -233,6 +239,14 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
return super.prove(options);
}

/**
* Estimates gas cost for this deployment operation.
* @param options - Options.
*/
public override estimateGas(options?: Omit<DeployOptions, 'estimateGas' | 'skipPublicSimulation'>) {
return super.estimateGas(options);
}

/** Return this deployment address. */
public get address() {
return this.instance?.address;
Expand Down
12 changes: 6 additions & 6 deletions yarn-project/aztec.js/src/wallet/signerless_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,26 @@ export class SignerlessWallet extends BaseWallet {
}

getChainId(): Fr {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method getChainId not implemented.');
}

getVersion(): Fr {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method getVersion not implemented.');
}

getPublicKeysHash(): Fr {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method getPublicKeysHash not implemented.');
}

getCompleteAddress(): CompleteAddress {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method getCompleteAddress not implemented.');
}

createAuthWit(_messageHash: Fr): Promise<AuthWitness> {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method createAuthWit not implemented.');
}

rotateNullifierKeys(_newNskM: Fq): Promise<void> {
throw new Error('Method not implemented.');
throw new Error('SignerlessWallet: Method rotateNullifierKeys not implemented.');
}
}
9 changes: 9 additions & 0 deletions yarn-project/circuit-types/src/tx/tx_hash.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { randomBytes } from '@aztec/foundation/crypto';
import { BufferReader, deserializeBigInt, serializeBigInt } from '@aztec/foundation/serialize';

/**
Expand Down Expand Up @@ -105,4 +106,12 @@ export class TxHash {
public static fromString(str: string): TxHash {
return new TxHash(Buffer.from(str, 'hex'));
}

/**
* Generates a random TxHash.
* @returns A new TxHash object.
*/
public static random(): TxHash {
return new TxHash(Buffer.from(randomBytes(TxHash.SIZE)));
}
}
23 changes: 23 additions & 0 deletions yarn-project/circuit-types/src/tx/tx_receipt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { TxHash } from './tx_hash.js';
import { TxReceipt, TxStatus } from './tx_receipt.js';

describe('TxReceipt', () => {
it('serializes and deserializes from json', () => {
const receipt = new TxReceipt(
TxHash.random(),
TxStatus.SUCCESS,
'error',
BigInt(1),
Buffer.from('blockHash'),
undefined,
);

expect(TxReceipt.fromJSON(receipt.toJSON())).toEqual(receipt);
});

it('serializes and deserializes from json with undefined fields', () => {
const receipt = new TxReceipt(TxHash.random(), TxStatus.DROPPED, 'error', undefined, undefined, undefined);

expect(TxReceipt.fromJSON(receipt.toJSON())).toEqual(receipt);
});
});
3 changes: 2 additions & 1 deletion yarn-project/circuit-types/src/tx/tx_receipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class TxReceipt {
error: this.error,
blockHash: this.blockHash?.toString('hex'),
blockNumber: this.blockNumber,
transactionFee: this.transactionFee?.toString(),
};
}

Expand All @@ -78,7 +79,7 @@ export class TxReceipt {
const txHash = TxHash.fromString(obj.txHash);
const status = obj.status as TxStatus;
const error = obj.error;
const transactionFee = obj.transactionFee;
const transactionFee = obj.transactionFee ? BigInt(obj.transactionFee) : undefined;
const blockHash = obj.blockHash ? Buffer.from(obj.blockHash, 'hex') : undefined;
const blockNumber = obj.blockNumber ? Number(obj.blockNumber) : undefined;
return new TxReceipt(txHash, status, error, transactionFee, blockHash, blockNumber);
Expand Down
50 changes: 48 additions & 2 deletions yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
PublicFeePaymentMethod,
} from '@aztec/aztec.js';
import { GasFees, type GasSettings } from '@aztec/circuits.js';
import { type TokenContract as BananaCoin, type FPCContract } from '@aztec/noir-contracts.js';
import { type Logger } from '@aztec/foundation/log';
import { TokenContract as BananaCoin, type FPCContract } from '@aztec/noir-contracts.js';

import { inspect } from 'util';

import { FeesTest } from './fees_test.js';

Expand All @@ -18,6 +21,7 @@ describe('e2e_fees gas_estimation', () => {
let bananaFPC: FPCContract;
let gasSettings: GasSettings;
let teardownFixedFee: bigint;
let logger: Logger;

const t = new FeesTest('gas_estimation');

Expand All @@ -26,7 +30,7 @@ describe('e2e_fees gas_estimation', () => {
await t.applyFPCSetupSnapshot();
await t.applyFundAliceWithBananas();
await t.applyFundAliceWithGasToken();
({ aliceWallet, aliceAddress, bobAddress, bananaCoin, bananaFPC, gasSettings } = await t.setup());
({ aliceWallet, aliceAddress, bobAddress, bananaCoin, bananaFPC, gasSettings, logger } = await t.setup());

teardownFixedFee = gasSettings.teardownGasLimits.computeFee(GasFees.default()).toBigInt();
});
Expand All @@ -51,9 +55,17 @@ describe('e2e_fees gas_estimation', () => {
.add(estimatedGas.teardownGasLimits.computeFee(GasFees.default()))
.toBigInt();

const logGasEstimate = (estimatedGas: Pick<GasSettings, 'gasLimits' | 'teardownGasLimits'>) =>
logger.info(`Estimated gas at`, {
gasLimits: inspect(estimatedGas.gasLimits),
teardownGasLimits: inspect(estimatedGas.teardownGasLimits),
});

it('estimates gas with native fee payment method', async () => {
const paymentMethod = new NativeFeePaymentMethod(aliceAddress);
const estimatedGas = await makeTransferRequest().estimateGas({ fee: { gasSettings, paymentMethod } });
logGasEstimate(estimatedGas);

const [withEstimate, withoutEstimate] = await sendTransfers(paymentMethod);
const actualFee = withEstimate.transactionFee!;

Expand All @@ -75,6 +87,8 @@ describe('e2e_fees gas_estimation', () => {
it('estimates gas with public payment method', async () => {
const paymentMethod = new PublicFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet);
const estimatedGas = await makeTransferRequest().estimateGas({ fee: { gasSettings, paymentMethod } });
logGasEstimate(estimatedGas);

const [withEstimate, withoutEstimate] = await sendTransfers(paymentMethod);
const actualFee = withEstimate.transactionFee!;

Expand All @@ -93,4 +107,36 @@ describe('e2e_fees gas_estimation', () => {
expect(feeFromEstimatedGas).toBeLessThan(actualFee * 3n);
expect(feeFromEstimatedGas).toBeGreaterThanOrEqual(actualFee);
});

it('estimates gas for public contract initialization with native fee payment method', async () => {
const paymentMethod = new NativeFeePaymentMethod(aliceAddress);
const deployMethod = () => BananaCoin.deploy(aliceWallet, aliceAddress, 'TKN', 'TKN', 8);
const deployOpts = { fee: { gasSettings, paymentMethod }, skipClassRegistration: true };
const estimatedGas = await deployMethod().estimateGas(deployOpts);
logGasEstimate(estimatedGas);

const [withEstimate, withoutEstimate] = await Promise.all([
deployMethod()
.send({ ...deployOpts, estimateGas: true })
.wait(),
deployMethod()
.send({ ...deployOpts, estimateGas: false })
.wait(),
]);

// Estimation should yield that teardown has no cost, so should send the tx with zero for teardown
const actualFee = withEstimate.transactionFee!;
expect(actualFee + teardownFixedFee).toEqual(withoutEstimate.transactionFee!);

// Check that estimated gas for teardown are zero
expect(estimatedGas.teardownGasLimits.l2Gas).toEqual(0);
expect(estimatedGas.teardownGasLimits.daGas).toEqual(0);

// Check that the estimate was close to the actual gas used by recomputing the tx fee from it
const feeFromEstimatedGas = getFeeFromEstimatedGas(estimatedGas);

// The actual fee should be under the estimate, but not too much
expect(feeFromEstimatedGas).toBeLessThan(actualFee * 2n);
expect(feeFromEstimatedGas).toBeGreaterThanOrEqual(actualFee);
});
});
2 changes: 2 additions & 0 deletions yarn-project/foundation/src/serialize/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ export function toFriendlyJSON(obj: object): string {
).toFriendlyJSON
) {
return value.toFriendlyJSON();
} else if (value && value.type && ['Fr', 'Fq', 'AztecAddress'].includes(value.type)) {
return value.value;
} else {
return value;
}
Expand Down
35 changes: 3 additions & 32 deletions yarn-project/simulator/src/client/client_execution_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
type AuthWitness,
type AztecNode,
EncryptedL2Log,
EncryptedL2NoteLog,
L1NotePayload,
Note,
type NoteStatus,
Expand All @@ -29,7 +28,7 @@ import { type NoteData, toACVMWitness } from '../acvm/index.js';
import { type PackedValuesCache } from '../common/packed_values_cache.js';
import { type DBOracle } from './db_oracle.js';
import { type ExecutionNoteCache } from './execution_note_cache.js';
import { CountedLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
import { CountedLog, type CountedNoteLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
import { pickNotes } from './pick_notes.js';
import { executePrivateFunction } from './private_execution.js';
import { ViewDataOracle } from './view_data_oracle.js';
Expand Down Expand Up @@ -57,7 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle {
*/
private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
private nullifiedNoteHashCounters: Map<number, number> = new Map();
private noteEncryptedLogs: CountedLog<EncryptedL2NoteLog>[] = [];
private noteEncryptedLogs: CountedNoteLog[] = [];
private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
private unencryptedLogs: CountedLog<UnencryptedL2Log>[] = [];
private nestedExecutions: ExecutionResult[] = [];
Expand Down Expand Up @@ -137,33 +136,6 @@ export class ClientExecutionContext extends ViewDataOracle {
return this.noteEncryptedLogs;
}

/**
* Sometimes notes can be chopped after a nested execution is complete.
* This means finished nested executions still hold transient logs. This method removes them.
* TODO(Miranda): is there a cleaner solution?
*/
public chopNoteEncryptedLogs() {
// Do not return logs that have been chopped in the cache
const allNoteLogs = this.noteCache.getLogs();
this.noteEncryptedLogs = this.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
const chop = (thing: any) =>
thing.nestedExecutions.forEach((result: ExecutionResult) => {
if (!result.noteEncryptedLogs[0]?.isEmpty()) {
// The execution has note logs
result.noteEncryptedLogs = result.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
}
chop(result);
});
chop(this);
}

/**
* Return the note encrypted logs emitted during this execution and nested executions.
*/
public getAllNoteEncryptedLogs() {
return this.noteCache.getLogs();
}

/**
* Return the encrypted logs emitted during this execution.
*/
Expand Down Expand Up @@ -382,9 +354,8 @@ export class ClientExecutionContext extends ViewDataOracle {
* @param counter - The effects counter.
*/
public override emitEncryptedNoteLog(noteHash: Fr, encryptedNote: Buffer, counter: number) {
const encryptedLog = new CountedLog(new EncryptedL2NoteLog(encryptedNote), counter);
const encryptedLog = this.noteCache.addNewLog(encryptedNote, counter, noteHash);
this.noteEncryptedLogs.push(encryptedLog);
this.noteCache.addNewLog(encryptedLog, noteHash);
}

/**
Expand Down
Loading

0 comments on commit ce88bb0

Please sign in to comment.