Skip to content

Commit 90bebdd

Browse files
authored
fix: ensure that contracts can be called after deployment in same block (#12390)
1 parent 9267a90 commit 90bebdd

File tree

17 files changed

+283
-107
lines changed

17 files changed

+283
-107
lines changed

yarn-project/end-to-end/src/e2e_deploy_contract/deploy_method.test.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,28 @@ describe('e2e_deploy_contract deploy method', () => {
140140
await new BatchCall(wallet, [...deploy.calls, init]).send().wait();
141141
}, 300_000);
142142

143-
it.skip('publicly deploys and calls a public function in a tx in the same block', async () => {
144-
// TODO(@spalladino): Requires being able to read a nullifier on the same block it was emitted.
145-
});
143+
it.skip('publicly deploys a contract in one tx and calls a public function on it later in the same block', async () => {
144+
await t.aztecNode.setConfig({ minTxsPerBlock: 2 });
145+
146+
const owner = wallet.getAddress();
147+
logger.debug('Initializing deploy method');
148+
const deployMethod = StatefulTestContract.deploy(wallet, owner, owner, 42);
149+
logger.debug('Creating request/calls to register and deploy contract');
150+
const deploy = await deployMethod.request();
151+
const deployTx = new BatchCall(wallet, deploy.calls);
152+
logger.debug('Getting an instance of the not-yet-deployed contract to batch calls to');
153+
const contract = await StatefulTestContract.at((await deployMethod.getInstance()).address, wallet);
154+
155+
logger.debug('Creating public call to run in same block as deployment');
156+
const publicCall = contract.methods.increment_public_value(owner, 84);
157+
158+
logger.debug('Deploying a contract and calling a public function in the same block');
159+
const [deployTxReceipt, publicCallTxReceipt] = await Promise.all([
160+
deployTx.send({ skipPublicSimulation: true }).wait({ timeout: 600 }),
161+
publicCall.send({ skipPublicSimulation: true }).wait({ timeout: 600 }),
162+
]);
163+
expect(deployTxReceipt.blockNumber).toEqual(publicCallTxReceipt.blockNumber);
164+
}, 300_000);
146165

147166
describe('regressions', () => {
148167
it('fails properly when trying to deploy a contract with a failing constructor with a pxe client with retries', async () => {

yarn-project/simulator/src/public/avm/fixtures/simple_contract_data_source.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import type { Fr } from '@aztec/foundation/fields';
22
import { createLogger } from '@aztec/foundation/log';
33
import { type ContractArtifact, FunctionSelector } from '@aztec/stdlib/abi';
44
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5-
import {
6-
type ContractClassPublic,
7-
type ContractDataSource,
8-
type ContractInstanceWithAddress,
9-
type PublicFunction,
10-
computePublicBytecodeCommitment,
5+
import type {
6+
ContractClassPublic,
7+
ContractDataSource,
8+
ContractInstanceWithAddress,
9+
PublicFunction,
1110
} from '@aztec/stdlib/contract';
1211

1312
import { PUBLIC_DISPATCH_FN_NAME } from './index.js';
@@ -63,9 +62,8 @@ export class SimpleContractDataSource implements ContractDataSource {
6362
return Promise.resolve(this.contractClasses.get(id.toString()));
6463
}
6564

66-
async getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
67-
const contractClass = await this.getContractClass(id);
68-
return Promise.resolve(computePublicBytecodeCommitment(contractClass!.packedBytecode));
65+
getBytecodeCommitment(_id: Fr): Promise<Fr | undefined> {
66+
return Promise.resolve(undefined);
6967
}
7068

7169
getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {

yarn-project/simulator/src/public/avm/journal/journal.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,15 @@ export class AvmPersistableStateManager {
193193
`Value mismatch when performing public data write (got value: ${value}, value in tree: ${newLeafPreimage.value})`,
194194
);
195195
} else {
196-
this.log.debug(`insertion witness data length: ${result.insertionWitnessData.length}`);
197196
// The new leaf preimage should have the new value and slot
198197
newLeafPreimage.slot = leafSlot;
199198
newLeafPreimage.value = value;
200199
// TODO: is this necessary?! Why doesn't sequentialInsert return the newLeafPreimage via
201200
// result.insertionWitnessData[0].leafPreimage?
202201

203-
this.log.debug(
204-
`newLeafPreimage.slot: ${newLeafPreimage.slot}, newLeafPreimage.value: ${newLeafPreimage.value}`,
202+
this.log.trace(
203+
`newLeafPreimage.slot: ${newLeafPreimage.slot}, newLeafPreimage.value: ${newLeafPreimage.value}, insertionIndex: ${result.insertionWitnessData[0].index}`,
205204
);
206-
this.log.debug(`insertion index: ${result.insertionWitnessData[0].index}`);
207205
insertionPath = result.insertionWitnessData[0].siblingPath.toFields();
208206
}
209207

yarn-project/simulator/src/public/fixtures/public_tx_simulation_tester.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { BaseAvmSimulationTester } from '../avm/fixtures/base_avm_simulation_tes
1212
import { getContractFunctionArtifact, getFunctionSelector } from '../avm/fixtures/index.js';
1313
import { SimpleContractDataSource } from '../avm/fixtures/simple_contract_data_source.js';
1414
import { WorldStateDB } from '../public_db_sources.js';
15-
import { type PublicTxResult, PublicTxSimulator } from '../public_tx_simulator.js';
15+
import { type PublicTxResult, PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
1616
import { createTxForPublicCalls } from './index.js';
1717

1818
const TIMESTAMP = new Fr(99833);

yarn-project/simulator/src/public/fixtures/utils.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
1717
import { siloNullifier } from '@aztec/stdlib/hash';
1818
import {
1919
PartialPrivateTailPublicInputsForPublic,
20+
PartialPrivateTailPublicInputsForRollup,
2021
PrivateKernelTailCircuitPublicInputs,
2122
RollupValidationRequests,
2223
ScopedLogHash,
@@ -90,6 +91,28 @@ export async function createTxForPublicCalls(
9091
return tx;
9192
}
9293

94+
export function createTxForPrivateOnly(feePayer = AztecAddress.zero(), gasUsedByPrivate: Gas = new Gas(10, 10)): Tx {
95+
// use max limits
96+
const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
97+
98+
const forRollup = PartialPrivateTailPublicInputsForRollup.empty();
99+
100+
const maxFeesPerGas = feePayer.isZero() ? GasFees.empty() : new GasFees(10, 10);
101+
const gasSettings = new GasSettings(gasLimits, Gas.empty(), maxFeesPerGas, GasFees.empty());
102+
const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings);
103+
const constantData = new TxConstantData(BlockHeader.empty(), txContext, Fr.zero(), Fr.zero());
104+
105+
const txData = new PrivateKernelTailCircuitPublicInputs(
106+
constantData,
107+
RollupValidationRequests.empty(),
108+
/*gasUsed=*/ gasUsedByPrivate,
109+
feePayer,
110+
/*forPublic=*/ undefined,
111+
forRollup,
112+
);
113+
return Tx.newWithTxData(txData);
114+
}
115+
93116
export async function addNewContractClassToTx(
94117
tx: Tx,
95118
contractClass: ContractClassPublic,
@@ -116,13 +139,14 @@ export async function addNewContractClassToTx(
116139
new Fr(REGISTERER_CONTRACT_ADDRESS),
117140
]);
118141

142+
const accumulatedData = tx.data.forPublic ? tx.data.forPublic!.revertibleAccumulatedData : tx.data.forRollup!.end;
119143
if (!skipNullifierInsertion) {
120-
const nextNullifierIndex = countAccumulatedItems(tx.data.forPublic!.revertibleAccumulatedData.nullifiers);
121-
tx.data.forPublic!.revertibleAccumulatedData.nullifiers[nextNullifierIndex] = contractClass.id;
144+
const nextNullifierIndex = countAccumulatedItems(accumulatedData.nullifiers);
145+
accumulatedData.nullifiers[nextNullifierIndex] = contractClass.id;
122146
}
123147

124-
const nextLogIndex = countAccumulatedItems(tx.data.forPublic!.revertibleAccumulatedData.contractClassLogsHashes);
125-
tx.data.forPublic!.revertibleAccumulatedData.contractClassLogsHashes[nextLogIndex] = contractClassLogHash;
148+
const nextLogIndex = countAccumulatedItems(accumulatedData.contractClassLogsHashes);
149+
accumulatedData.contractClassLogsHashes[nextLogIndex] = contractClassLogHash;
126150

127151
tx.contractClassLogs.push(contractClassLog);
128152
}
@@ -164,11 +188,12 @@ export async function addNewContractInstanceToTx(
164188
contractInstance.address.toField(),
165189
);
166190

191+
const accumulatedData = tx.data.forPublic ? tx.data.forPublic!.revertibleAccumulatedData : tx.data.forRollup!.end;
167192
if (!skipNullifierInsertion) {
168-
const nextNullifierIndex = countAccumulatedItems(tx.data.forPublic!.revertibleAccumulatedData.nullifiers);
169-
tx.data.forPublic!.revertibleAccumulatedData.nullifiers[nextNullifierIndex] = contractAddressNullifier;
193+
const nextNullifierIndex = countAccumulatedItems(accumulatedData.nullifiers);
194+
accumulatedData.nullifiers[nextNullifierIndex] = contractAddressNullifier;
170195
}
171196

172-
const nextLogIndex = countAccumulatedItems(tx.data.forPublic!.revertibleAccumulatedData.privateLogs);
173-
tx.data.forPublic!.revertibleAccumulatedData.privateLogs[nextLogIndex] = contractInstanceLog;
197+
const nextLogIndex = countAccumulatedItems(accumulatedData.privateLogs);
198+
accumulatedData.privateLogs[nextLogIndex] = contractInstanceLog;
174199
}

yarn-project/simulator/src/public/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export * from '../common/db_interfaces.js';
2-
export * from './public_tx_simulator.js';
2+
export * from './public_tx_simulator/public_tx_simulator.js';
33
export { type EnqueuedPublicCallExecutionResult, type PublicFunctionCallResult } from './execution.js';
44
export * from './public_db_sources.js';
5-
export { PublicProcessor, PublicProcessorFactory } from './public_processor.js';
5+
export { PublicProcessor, PublicProcessorFactory } from './public_processor/public_processor.js';
66
export { SideEffectTrace } from './side_effect_trace.js';
77
export { getExecutionRequestsByPhase } from './utils.js';
88
export { PublicTxSimulationTester } from './fixtures/index.js';

yarn-project/simulator/src/public/public_db_sources.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,23 +189,22 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
189189
// Try and retrieve from cache
190190
const key = contractClassId.toString();
191191
const result = this.bytecodeCommitmentCache.get(key);
192-
193192
if (result !== undefined) {
194193
return result;
195194
}
196-
197195
// Now try from the store
198196
const fromStore = await this.dataSource.getBytecodeCommitment(contractClassId);
199197
if (fromStore !== undefined) {
200198
this.bytecodeCommitmentCache.set(key, fromStore);
201199
return fromStore;
202200
}
203201

204-
// Not in either the store or the caches, build it here and cache
202+
// Not in either the store or the cache, build it here and cache
205203
const contractClass = await this.getContractClass(contractClassId);
206204
if (contractClass === undefined) {
207205
return undefined;
208206
}
207+
209208
const value = await computePublicBytecodeCommitment(contractClass.packedBytecode);
210209
this.bytecodeCommitmentCache.set(key, value);
211210
return value;

0 commit comments

Comments
 (0)