Skip to content

Commit

Permalink
refactor: Remove legacy deployer (#4777)
Browse files Browse the repository at this point in the history
Removes the legacy deployer. Account contracts are now "deployed" by
directly calling the constructor. This means that account contracts are
by default privately deployed and cannot execute public function calls.

Note that this will break once we require fee payment for every action.
In order to allow an account contract to pay for its own deployment,
we'll have to supply a FeePayload along with it, so the constructor can
act as another entrypoint. Note that we cannot just have the entrypoint
call the constructor because the entrypoint validates the call via an
authwit, and this validation requires the contract to have been
initialized.

Pending: publicly deploy the account when needed (eg public authwit
check).

Builds on #4775
  • Loading branch information
spalladino authored Feb 27, 2024
1 parent b4cfc89 commit 20dc67b
Show file tree
Hide file tree
Showing 15 changed files with 98 additions and 245 deletions.
6 changes: 5 additions & 1 deletion yarn-project/accounts/src/testing/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ export async function deployInitialTestAccounts(pxe: PXE) {
const deployMethods = await Promise.all(
accounts.map(async x => {
const deployMethod = await x.account.getDeployMethod();
await deployMethod.create({ contractAddressSalt: x.account.salt });
await deployMethod.create({
contractAddressSalt: x.account.salt,
skipClassRegistration: true,
skipPublicDeployment: true,
});
await deployMethod.simulate({});
return deployMethod;
}),
Expand Down
8 changes: 7 additions & 1 deletion yarn-project/accounts/src/testing/create_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ export async function createAccounts(pxe: PXE, numberOfAccounts = 1): Promise<Ac
// Unfortunately the function below is not stateless and we call it here because it takes a long time to run and
// the results get stored within the account object. By calling it here we increase the probability of all the
// accounts being deployed in the same block because it makes the deploy() method basically instant.
await account.getDeployMethod().then(d => d.simulate({ contractAddressSalt: account.salt }));
await account.getDeployMethod().then(d =>
d.simulate({
contractAddressSalt: account.salt,
skipClassRegistration: true,
skipPublicDeployment: true,
}),
);
accounts.push(account);
}

Expand Down
25 changes: 17 additions & 8 deletions yarn-project/aztec.js/src/account_manager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { ContractInstanceWithAddress } from '@aztec/types/contracts';
import { AccountContract } from '../account/contract.js';
import { Salt } from '../account/index.js';
import { AccountInterface } from '../account/interface.js';
import { DefaultWaitOpts, WaitOpts } from '../contract/index.js';
import { LegacyContractDeployer } from '../deployment/legacy/legacy_contract_deployer.js';
import { LegacyDeployMethod } from '../deployment/legacy/legacy_deploy_method.js';
import { DeployMethod } from '../contract/deploy_method.js';
import { DefaultWaitOpts, WaitOpts } from '../contract/sent_tx.js';
import { ContractDeployer } from '../deployment/contract_deployer.js';
import { waitForAccountSynch } from '../utils/account.js';
import { generatePublicKey } from '../utils/index.js';
import { AccountWalletWithPrivateKey } from '../wallet/index.js';
import { AccountWalletWithPrivateKey, SignerlessWallet } from '../wallet/index.js';
import { DeployAccountSentTx } from './deploy_account_sent_tx.js';

/**
Expand All @@ -27,7 +27,7 @@ export class AccountManager {
private instance?: ContractInstanceWithAddress;
private encryptionPublicKey?: PublicKey;
// TODO(@spalladino): Update to the new deploy method and kill the legacy one.
private deployMethod?: LegacyDeployMethod;
private deployMethod?: DeployMethod;

constructor(
private pxe: PXE,
Expand Down Expand Up @@ -132,9 +132,13 @@ export class AccountManager {
}
await this.#register();
const encryptionPublicKey = this.getEncryptionPublicKey();
const deployer = new LegacyContractDeployer(
// We use a signerless wallet so we hit the account contract directly and it deploys itself.
// If we used getWallet, the deployment would get routed via the account contract entrypoint
// instead of directly hitting the initializer.
const deployWallet = new SignerlessWallet(this.pxe);
const deployer = new ContractDeployer(
this.accountContract.getContractArtifact(),
this.pxe,
deployWallet,
encryptionPublicKey,
);
const args = this.accountContract.getDeploymentArgs();
Expand All @@ -145,6 +149,7 @@ export class AccountManager {

/**
* Deploys the account contract that backs this account.
* Does not register the associated class nor publicly deploy the instance.
* Uses the salt provided in the constructor or a randomly generated one.
* Note that if the Account is constructed with an explicit complete address
* it is assumed that the account contract has already been deployed and this method will throw.
Expand All @@ -154,7 +159,11 @@ export class AccountManager {
public async deploy(): Promise<DeployAccountSentTx> {
const deployMethod = await this.getDeployMethod();
const wallet = await this.getWallet();
const sentTx = deployMethod.send({ contractAddressSalt: this.salt });
const sentTx = deployMethod.send({
contractAddressSalt: this.salt,
skipClassRegistration: true,
skipPublicDeployment: true,
});
return new DeployAccountSentTx(wallet, sentTx.getTxHash());
}

Expand Down
22 changes: 12 additions & 10 deletions yarn-project/aztec.js/src/contract/deploy_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
import { ContractArtifact, FunctionArtifact } from '@aztec/foundation/abi';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { ContractInstanceWithAddress } from '@aztec/types/contracts';

import { Wallet } from '../account/index.js';
import { deployInstance } from '../deployment/deploy_instance.js';
import { registerContractClass } from '../deployment/register_class.js';
import { createDebugLogger } from '../index.js';
import { BaseContractInteraction, SendMethodOptions } from './base_contract_interaction.js';
import { type Contract } from './contract.js';
import { ContractBase } from './contract_base.js';
Expand Down Expand Up @@ -94,6 +94,17 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
* it returns a promise for an array instead of a function call directly.
*/
public async request(options: DeployOptions = {}): Promise<FunctionCall[]> {
const { address } = this.getInstance(options);
const constructorCall = new ContractFunctionInteraction(this.wallet, address, this.constructorArtifact, this.args);
return [...(await this.getDeploymentFunctionCalls(options)), constructorCall.request()];
}

/**
* Returns calls for registration of the class and deployment of the instance, depending on the provided options.
* @param options - Deployment options.
* @returns A function call array with potentially requests to the class registerer and instance deployer.
*/
protected async getDeploymentFunctionCalls(options: DeployOptions = {}): Promise<FunctionCall[]> {
const calls: FunctionCall[] = [];

// Set contract instance object so it's available for populating the DeploySendTx object
Expand Down Expand Up @@ -127,11 +138,6 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
calls.push(deployInstance(this.wallet, instance, { universalDeploy: options.universalDeploy }).request());
}

// Call the constructor.
calls.push(
new ContractFunctionInteraction(this.wallet, instance.address, this.constructorArtifact, this.args).request(),
);

return calls;
}

Expand All @@ -145,10 +151,6 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
*/
public send(options: DeployOptions = {}): DeploySentTx<TContract> {
const txHashPromise = super.send(options).getTxHash();
// Note the bang on this.instance is brittle: it depends on super.send setting the contract instance
// before any `await` operation, otherwise it'll be undefined by the time we get here. Tests should
// catch it easily though, but if you start seeing instance.address being undefined in DeploySentTx,
// this is probably the culprit.
return new DeploySentTx(this.pxe, txHashPromise, this.postDeployCtor, this.getInstance(options));
}

Expand Down

This file was deleted.

151 changes: 0 additions & 151 deletions yarn-project/aztec.js/src/deployment/legacy/legacy_deploy_method.ts

This file was deleted.

1 change: 0 additions & 1 deletion yarn-project/aztec.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export {
} from './contract/index.js';

export { ContractDeployer } from './deployment/index.js';
export { LegacyContractDeployer } from './deployment/legacy/legacy_contract_deployer.js';

export {
generatePublicKey,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/wallet/signerless_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BaseWallet } from './base_wallet.js';
export class SignerlessWallet extends BaseWallet {
async createTxExecutionRequest(executions: FunctionCall[]): Promise<TxExecutionRequest> {
if (executions.length !== 1) {
throw new Error(`Unexpected number of executions. Expected 1 but received ${executions.length}).`);
throw new Error(`Unexpected number of executions. Expected 1 but received ${executions.length}.`);
}
const [execution] = executions;
const packedArguments = PackedArguments.fromArgs(execution.args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { SlowTreeContract, TokenBlacklistContract, TokenContract } from '@aztec/
import { jest } from '@jest/globals';

import { BITSIZE_TOO_BIG_ERROR, U128_OVERFLOW_ERROR, U128_UNDERFLOW_ERROR } from './fixtures/fixtures.js';
import { setup } from './fixtures/utils.js';
import { publicDeployAccounts, setup } from './fixtures/utils.js';
import { TokenSimulator } from './simulators/token_simulator.js';

const TIMEOUT = 90_000;
Expand Down Expand Up @@ -109,6 +109,7 @@ describe('e2e_blacklist_token_contract', () => {

beforeAll(async () => {
({ teardown, logger, wallets, accounts, cheatCodes } = await setup(4));
await publicDeployAccounts(wallets[0], accounts.slice(0, 3));

slowTree = await SlowTreeContract.deploy(wallets[0]).send().deployed();

Expand Down
3 changes: 2 additions & 1 deletion yarn-project/end-to-end/src/e2e_lending_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { LendingContract, PriceFeedContract, TokenContract } from '@aztec/noir-c

import { jest } from '@jest/globals';

import { setup } from './fixtures/utils.js';
import { publicDeployAccounts, setup } from './fixtures/utils.js';
import { LendingAccount, LendingSimulator, TokenSimulator } from './simulators/index.js';

describe('e2e_lending_contract', () => {
Expand Down Expand Up @@ -72,6 +72,7 @@ describe('e2e_lending_contract', () => {
beforeAll(async () => {
({ teardown, logger, cheatCodes: cc, wallet, accounts } = await setup(1));
({ lendingContract, priceFeedContract, collateralAsset, stableCoin } = await deployContracts());
await publicDeployAccounts(wallet, accounts);

lendingAccount = new LendingAccount(accounts[0].address, new Fr(42));

Expand Down
Loading

0 comments on commit 20dc67b

Please sign in to comment.