Skip to content

Commit c54b65c

Browse files
author
dbanks12
committed
feat(avm): get contract instance now works e2e with avm proving
1 parent 0fc9677 commit c54b65c

16 files changed

Lines changed: 308 additions & 61 deletions

File tree

barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ inline void read(uint8_t const*& it, ExternalCallHint& hint)
6161
}
6262

6363
struct ContractInstanceHint {
64+
FF address;
6465
FF instance_found_in_address;
6566
FF salt;
6667
FF deployer_addr;
@@ -73,6 +74,7 @@ struct ContractInstanceHint {
7374
inline void read(uint8_t const*& it, ContractInstanceHint& hint)
7475
{
7576
using serialize::read;
77+
read(it, hint.address);
7678
read(it, hint.instance_found_in_address);
7779
read(it, hint.salt);
7880
read(it, hint.deployer_addr);
@@ -131,8 +133,6 @@ struct ExecutionHints {
131133
std::vector<std::pair<FF, FF>> note_hash_exists_hints;
132134
std::vector<std::pair<FF, FF>> nullifier_exists_hints;
133135
std::vector<std::pair<FF, FF>> l1_to_l2_message_exists_hints;
134-
// TODO(dbanks): not read yet.
135-
std::map<FF, ContractInstanceHint> contract_instance_hints;
136136

137137
using serialize::read;
138138
const auto* it = data.data();
@@ -144,6 +144,13 @@ struct ExecutionHints {
144144
std::vector<ExternalCallHint> externalcall_hints;
145145
read(it, externalcall_hints);
146146

147+
std::vector<ContractInstanceHint> contract_instance_hints_vec;
148+
read(it, contract_instance_hints_vec);
149+
std::map<FF, ContractInstanceHint> contract_instance_hints;
150+
for (const auto& instance : contract_instance_hints_vec) {
151+
contract_instance_hints[instance.address] = instance;
152+
}
153+
147154
return { std::move(storage_value_hints), std::move(note_hash_exists_hints),
148155
std::move(nullifier_exists_hints), std::move(l1_to_l2_message_exists_hints),
149156
std::move(externalcall_hints), std::move(contract_instance_hints) };

barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,6 +2548,7 @@ void AvmTraceBuilder::op_get_contract_instance(uint8_t indirect, uint32_t addres
25482548
// Read the contract instance
25492549
ContractInstanceHint contract_instance = execution_hints.contract_instance_hints.at(read_address.val);
25502550

2551+
// NOTE: we don't write the first entry (the contract instance's address/key) to memory
25512552
std::vector<FF> contract_instance_vec = { contract_instance.instance_found_in_address,
25522553
contract_instance.salt,
25532554
contract_instance.deployer_addr,

barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,11 +2002,12 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
20022002

20032003
// Generate Hint for call operation
20042004
ExecutionHints execution_hints = {};
2005-
ContractInstanceHint contract_instance_hint = { 1, 1, 2, 3, 4, 5 }; // The first one represents true
2005+
// Note: opcode does not write 'address' into memory
2006+
ContractInstanceHint contract_instance_hint = { address, 1, 2, 3, 4, 5, 6 }; // The first one represents true
20062007
execution_hints.contract_instance_hints.insert({ address, contract_instance_hint });
20072008

20082009
auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);
2009-
EXPECT_EQ(returndata, std::vector<FF>({ 1, 1, 2, 3, 4, 5 })); // The first one represents true
2010+
EXPECT_EQ(returndata, std::vector<FF>({ 1, 2, 3, 4, 5, 6 })); // The first one represents true
20102011

20112012
validate_trace(std::move(trace));
20122013
}

yarn-project/bb-prover/src/avm_proving.test.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,25 @@ import { computeVarArgsHash } from '@aztec/circuits.js/hash';
2929
import { padArrayEnd } from '@aztec/foundation/collection';
3030
import { Fr } from '@aztec/foundation/fields';
3131
import { createDebugLogger } from '@aztec/foundation/log';
32-
import { AvmSimulator, type PublicExecutionResult } from '@aztec/simulator';
33-
import { getAvmTestContractBytecode, initContext, initExecutionEnvironment } from '@aztec/simulator/avm/fixtures';
32+
import { AvmSimulator, type PublicContractsDB, type PublicExecutionResult } from '@aztec/simulator';
33+
import {
34+
getAvmTestContractBytecode,
35+
initContext,
36+
initExecutionEnvironment,
37+
initHostStorage,
38+
} from '@aztec/simulator/avm/fixtures';
3439

40+
import { mock } from 'jest-mock-extended';
3541
import fs from 'node:fs/promises';
3642
import { tmpdir } from 'node:os';
3743
import path from 'path';
3844

45+
import { AvmPersistableStateManager } from '../../simulator/src/avm/journal/journal.js';
3946
import {
4047
convertAvmResultsToPxResult,
4148
createPublicExecution,
4249
} from '../../simulator/src/public/transitional_adaptors.js';
50+
import { SerializableContractInstance } from '../../types/src/contracts/contract_instance.js';
4351
import { type BBSuccess, BB_RESULT, generateAvmProof, verifyAvmProof } from './bb/execute.js';
4452
import { extractVkData } from './verification_key/verification_key_data.js';
4553

@@ -69,6 +77,13 @@ describe('AVM WitGen, proof generation and verification', () => {
6977
},
7078
TIMEOUT,
7179
);
80+
it(
81+
'Should prove get contract instance opcode with hints',
82+
async () => {
83+
await proveAndVerifyAvmTestContract('test_get_contract_instance');
84+
},
85+
TIMEOUT,
86+
);
7287

7388
it(
7489
'Should prove new note hash',
@@ -130,7 +145,21 @@ describe('AVM WitGen, proof generation and verification', () => {
130145
const proveAndVerifyAvmTestContract = async (functionName: string, calldata: Fr[] = []) => {
131146
const startSideEffectCounter = 0;
132147
const environment = initExecutionEnvironment({ calldata });
133-
const context = initContext({ env: environment });
148+
149+
const contractsDb = mock<PublicContractsDB>();
150+
const contractInstance = new SerializableContractInstance({
151+
version: 1,
152+
salt: new Fr(0x123),
153+
deployer: new Fr(0x456),
154+
contractClassId: new Fr(0x789),
155+
initializationHash: new Fr(0x101112),
156+
publicKeysHash: new Fr(0x161718),
157+
}).withAddress(environment.address);
158+
contractsDb.getContractInstance.mockResolvedValue(Promise.resolve(contractInstance));
159+
160+
const hostStorage = initHostStorage({ contractsDb });
161+
const persistableState = new AvmPersistableStateManager(hostStorage);
162+
const context = initContext({ env: environment, persistableState });
134163

135164
const startGas = new Gas(context.machineState.gasLeft.daGas, context.machineState.gasLeft.l2Gas);
136165
const oldPublicExecution = createPublicExecution(startSideEffectCounter, environment, calldata);

yarn-project/circuits.js/src/structs/avm/avm.ts

Lines changed: 106 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export class AvmKeyValueHint {
5757
* @param buffer - Buffer or reader to read from.
5858
* @returns The deserialized instance.
5959
*/
60-
static fromBuffer(buff: Buffer | BufferReader): AvmKeyValueHint {
60+
static fromBuffer(buff: Buffer | BufferReader) {
6161
const reader = BufferReader.asReader(buff);
6262
return new AvmKeyValueHint(Fr.fromBuffer(reader), Fr.fromBuffer(reader));
6363
}
@@ -147,25 +147,124 @@ export class AvmExternalCallHint {
147147
}
148148
}
149149

150+
export class AvmContractInstanceHint {
151+
constructor(
152+
public readonly address: Fr,
153+
public readonly exists: Fr,
154+
public readonly salt: Fr,
155+
public readonly deployer: Fr,
156+
public readonly contractClassId: Fr,
157+
public readonly initializationHash: Fr,
158+
public readonly publicKeysHash: Fr,
159+
) {}
160+
/**
161+
* Serializes the inputs to a buffer.
162+
* @returns - The inputs serialized to a buffer.
163+
*/
164+
toBuffer() {
165+
return serializeToBuffer(...AvmContractInstanceHint.getFields(this));
166+
}
167+
168+
/**
169+
* Serializes the inputs to a hex string.
170+
* @returns The instance serialized to a hex string.
171+
*/
172+
toString() {
173+
return this.toBuffer().toString('hex');
174+
}
175+
176+
/**
177+
* Is the struct empty?
178+
* @returns whether all members are empty.
179+
*/
180+
isEmpty(): boolean {
181+
return (
182+
this.address.isZero() &&
183+
this.exists.isZero() &&
184+
this.salt.isZero() &&
185+
this.deployer.isZero() &&
186+
this.contractClassId.isZero() &&
187+
this.initializationHash.isZero() &&
188+
this.publicKeysHash.isZero()
189+
);
190+
}
191+
192+
/**
193+
* Creates a new instance from fields.
194+
* @param fields - Fields to create the instance from.
195+
* @returns A new AvmHint instance.
196+
*/
197+
static from(fields: FieldsOf<AvmContractInstanceHint>): AvmContractInstanceHint {
198+
return new AvmContractInstanceHint(...AvmContractInstanceHint.getFields(fields));
199+
}
200+
201+
/**
202+
* Extracts fields from an instance.
203+
* @param fields - Fields to create the instance from.
204+
* @returns An array of fields.
205+
*/
206+
static getFields(fields: FieldsOf<AvmContractInstanceHint>) {
207+
return [
208+
fields.address,
209+
fields.exists,
210+
fields.salt,
211+
fields.deployer,
212+
fields.contractClassId,
213+
fields.initializationHash,
214+
fields.publicKeysHash,
215+
] as const;
216+
}
217+
218+
/**
219+
* Deserializes from a buffer or reader.
220+
* @param buffer - Buffer or reader to read from.
221+
* @returns The deserialized instance.
222+
*/
223+
static fromBuffer(buff: Buffer | BufferReader): AvmContractInstanceHint {
224+
const reader = BufferReader.asReader(buff);
225+
return new AvmContractInstanceHint(
226+
Fr.fromBuffer(reader),
227+
Fr.fromBuffer(reader),
228+
Fr.fromBuffer(reader),
229+
Fr.fromBuffer(reader),
230+
Fr.fromBuffer(reader),
231+
Fr.fromBuffer(reader),
232+
Fr.fromBuffer(reader),
233+
);
234+
}
235+
236+
/**
237+
* Deserializes from a hex string.
238+
* @param str - Hex string to read from.
239+
* @returns The deserialized instance.
240+
*/
241+
static fromString(str: string): AvmContractInstanceHint {
242+
return AvmContractInstanceHint.fromBuffer(Buffer.from(str, 'hex'));
243+
}
244+
}
245+
150246
export class AvmExecutionHints {
151247
public readonly storageValues: Vector<AvmKeyValueHint>;
152248
public readonly noteHashExists: Vector<AvmKeyValueHint>;
153249
public readonly nullifierExists: Vector<AvmKeyValueHint>;
154250
public readonly l1ToL2MessageExists: Vector<AvmKeyValueHint>;
155251
public readonly externalCalls: Vector<AvmExternalCallHint>;
252+
public readonly contractInstances: Vector<AvmContractInstanceHint>;
156253

157254
constructor(
158255
storageValues: AvmKeyValueHint[],
159256
noteHashExists: AvmKeyValueHint[],
160257
nullifierExists: AvmKeyValueHint[],
161258
l1ToL2MessageExists: AvmKeyValueHint[],
162259
externalCalls: AvmExternalCallHint[],
260+
contractInstances: AvmContractInstanceHint[],
163261
) {
164262
this.storageValues = new Vector(storageValues);
165263
this.noteHashExists = new Vector(noteHashExists);
166264
this.nullifierExists = new Vector(nullifierExists);
167265
this.l1ToL2MessageExists = new Vector(l1ToL2MessageExists);
168266
this.externalCalls = new Vector(externalCalls);
267+
this.contractInstances = new Vector(contractInstances);
169268
}
170269

171270
/**
@@ -194,7 +293,8 @@ export class AvmExecutionHints {
194293
this.noteHashExists.items.length == 0 &&
195294
this.nullifierExists.items.length == 0 &&
196295
this.l1ToL2MessageExists.items.length == 0 &&
197-
this.externalCalls.items.length == 0
296+
this.externalCalls.items.length == 0 &&
297+
this.contractInstances.items.length == 0
198298
);
199299
}
200300

@@ -210,6 +310,7 @@ export class AvmExecutionHints {
210310
fields.nullifierExists.items,
211311
fields.l1ToL2MessageExists.items,
212312
fields.externalCalls.items,
313+
fields.contractInstances.items,
213314
);
214315
}
215316

@@ -225,18 +326,10 @@ export class AvmExecutionHints {
225326
fields.nullifierExists,
226327
fields.l1ToL2MessageExists,
227328
fields.externalCalls,
329+
fields.contractInstances,
228330
] as const;
229331
}
230332

231-
flat() {
232-
return [
233-
...this.storageValues.items,
234-
...this.noteHashExists.items,
235-
...this.nullifierExists.items,
236-
...this.l1ToL2MessageExists.items,
237-
];
238-
}
239-
240333
/**
241334
* Deserializes from a buffer or reader.
242335
* @param buffer - Buffer or reader to read from.
@@ -250,6 +343,7 @@ export class AvmExecutionHints {
250343
reader.readVector(AvmKeyValueHint),
251344
reader.readVector(AvmKeyValueHint),
252345
reader.readVector(AvmExternalCallHint),
346+
reader.readVector(AvmContractInstanceHint),
253347
);
254348
}
255349

@@ -267,7 +361,7 @@ export class AvmExecutionHints {
267361
* @returns The empty instance.
268362
*/
269363
static empty() {
270-
return new AvmExecutionHints([], [], [], [], []);
364+
return new AvmExecutionHints([], [], [], [], [], []);
271365
}
272366
}
273367

yarn-project/circuits.js/src/tests/factories.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
ARGS_LENGTH,
1818
AppendOnlyTreeSnapshot,
1919
AvmCircuitInputs,
20+
AvmContractInstanceHint,
2021
AvmExecutionHints,
2122
AvmExternalCallHint,
2223
AvmKeyValueHint,
@@ -1277,7 +1278,7 @@ export function makeAvmKeyValueHint(seed = 0): AvmKeyValueHint {
12771278
/**
12781279
* Makes arbitrary AvmExternalCallHint.
12791280
* @param seed - The seed to use for generating the state reference.
1280-
* @returns AvmKeyValueHint.
1281+
* @returns AvmExternalCallHint.
12811282
*/
12821283
export function makeAvmExternalCallHint(seed = 0): AvmExternalCallHint {
12831284
return new AvmExternalCallHint(
@@ -1287,6 +1288,23 @@ export function makeAvmExternalCallHint(seed = 0): AvmExternalCallHint {
12871288
);
12881289
}
12891290

1291+
/**
1292+
* Makes arbitrary AvmContractInstanceHint.
1293+
* @param seed - The seed to use for generating the state reference.
1294+
* @returns AvmContractInstanceHint.
1295+
*/
1296+
export function makeAvmContractInstanceHint(seed = 0): AvmContractInstanceHint {
1297+
return new AvmContractInstanceHint(
1298+
new Fr(seed),
1299+
new Fr(seed + 0x1),
1300+
new Fr(seed + 0x2),
1301+
new Fr(seed + 0x3),
1302+
new Fr(seed + 0x4),
1303+
new Fr(seed + 0x5),
1304+
new Fr(seed + 0x6),
1305+
);
1306+
}
1307+
12901308
/**
12911309
* Creates arbitrary AvmExecutionHints.
12921310
* @param seed - The seed to use for generating the hints.
@@ -1306,6 +1324,7 @@ export function makeAvmExecutionHints(
13061324
nullifierExists: makeVector(baseLength + 2, makeAvmKeyValueHint, seed + 0x4400),
13071325
l1ToL2MessageExists: makeVector(baseLength + 3, makeAvmKeyValueHint, seed + 0x4500),
13081326
externalCalls: makeVector(baseLength + 4, makeAvmExternalCallHint, seed + 0x4600),
1327+
contractInstances: makeVector(baseLength + 5, makeAvmContractInstanceHint, seed + 0x4700),
13091328
...overrides,
13101329
});
13111330
}

yarn-project/simulator/src/avm/fixtures/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address';
44
import { EthAddress } from '@aztec/foundation/eth-address';
55
import { Fr } from '@aztec/foundation/fields';
66
import { AvmNestedCallsTestContractArtifact, AvmTestContractArtifact } from '@aztec/noir-contracts.js';
7+
import { SerializableContractInstance } from '@aztec/types/contracts';
78

89
import { strict as assert } from 'assert';
910
import { mock } from 'jest-mock-extended';
@@ -16,6 +17,7 @@ import { AvmMachineState } from '../avm_machine_state.js';
1617
import { Field, Uint8 } from '../avm_memory_types.js';
1718
import { HostStorage } from '../journal/host_storage.js';
1819
import { AvmPersistableStateManager } from '../journal/journal.js';
20+
import { type TracedContractInstance } from '../journal/trace_types.js';
1921

2022
/**
2123
* Create a new AVM context with default values.
@@ -145,3 +147,14 @@ export function getAvmNestedCallsTestContractBytecode(functionName: string): Buf
145147
);
146148
return artifact.bytecode;
147149
}
150+
151+
export function randomTracedContractInstance(): TracedContractInstance {
152+
const instance = SerializableContractInstance.random();
153+
const address = AztecAddress.random();
154+
return { exists: true, ...instance, address };
155+
}
156+
157+
export function emptyTracedContractInstance(withAddress?: AztecAddress): TracedContractInstance {
158+
const instance = SerializableContractInstance.empty().withAddress(withAddress ?? AztecAddress.zero());
159+
return { exists: false, ...instance };
160+
}

0 commit comments

Comments
 (0)