Skip to content

Commit

Permalink
feat: fetch addresses from registry (#12000)
Browse files Browse the repository at this point in the history
Key changes:
- Makes slash factory address optional in L1ContractAddresses interface
- Adds new RegisterNewRollupVersionPayload contract for registering new rollup versions
- Adds new Registry contract with methods for managing rollup versions
- Extracts rollup deployment logic into separate deployRollupAndPeriphery function
- Adds collectAddresses and collectAddressesSafe methods to Registry for fetching contract addresses
- Transfers fee asset ownership to coin issuer during deployment
  • Loading branch information
just-mitch authored Feb 26, 2025
1 parent b0de9e8 commit a90f08e
Show file tree
Hide file tree
Showing 14 changed files with 607 additions and 160 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.27;

import {IPayload} from "@aztec/governance/interfaces/IPayload.sol";
import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol";

/**
* @title RegisterNewRollupVersionPayload
* @author Aztec Labs
* @notice A payload that registers a new rollup version.
*/
contract RegisterNewRollupVersionPayload is IPayload {
IRegistry public immutable REGISTRY;
address public immutable ROLLUP;

constructor(IRegistry _registry, address _rollup) {
REGISTRY = _registry;
ROLLUP = _rollup;
}

function getActions() external view override(IPayload) returns (IPayload.Action[] memory) {
IPayload.Action[] memory res = new IPayload.Action[](1);

res[0] = Action({
target: address(REGISTRY),
data: abi.encodeWithSelector(IRegistry.upgrade.selector, ROLLUP)
});

return res;
}
}
2 changes: 0 additions & 2 deletions spartan/aztec-network/files/config/config-prover-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ coin_issuer_address=$(echo "$output" | grep -oP 'CoinIssuer Address: \K0x[a-fA-F
reward_distributor_address=$(echo "$output" | grep -oP 'RewardDistributor Address: \K0x[a-fA-F0-9]{40}')
governance_proposer_address=$(echo "$output" | grep -oP 'GovernanceProposer Address: \K0x[a-fA-F0-9]{40}')
governance_address=$(echo "$output" | grep -oP 'Governance Address: \K0x[a-fA-F0-9]{40}')
slash_factory_address=$(echo "$output" | grep -oP 'SlashFactory Address: \K0x[a-fA-F0-9]{40}')

# Write the addresses to a file in the shared volume
cat <<EOF >/shared/contracts/contracts.env
Expand All @@ -35,7 +34,6 @@ export COIN_ISSUER_CONTRACT_ADDRESS=$coin_issuer_address
export REWARD_DISTRIBUTOR_CONTRACT_ADDRESS=$reward_distributor_address
export GOVERNANCE_PROPOSER_CONTRACT_ADDRESS=$governance_proposer_address
export GOVERNANCE_CONTRACT_ADDRESS=$governance_address
export SLASH_FACTORY_CONTRACT_ADDRESS=$slash_factory_address
EOF

cat /shared/contracts/contracts.env
1 change: 0 additions & 1 deletion yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ describe('Contract Class', () => {
coinIssuerAddress: EthAddress.random(),
rewardDistributorAddress: EthAddress.random(),
governanceProposerAddress: EthAddress.random(),
slashFactoryAddress: EthAddress.random(),
};

const defaultArtifact: ContractArtifact = {
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ export async function deployL1Contracts(
log(`RewardDistributor Address: ${l1ContractAddresses.rewardDistributorAddress.toString()}`);
log(`GovernanceProposer Address: ${l1ContractAddresses.governanceProposerAddress.toString()}`);
log(`Governance Address: ${l1ContractAddresses.governanceAddress.toString()}`);
log(`SlashFactory Address: ${l1ContractAddresses.slashFactoryAddress.toString()}`);
log(`SlashFactory Address: ${l1ContractAddresses.slashFactoryAddress?.toString()}`);
}
}
4 changes: 2 additions & 2 deletions yarn-project/cli/src/cmds/pxe/get_node_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function getNodeInfo(
rewardDistributor: info.l1ContractAddresses.rewardDistributorAddress.toString(),
governanceProposer: info.l1ContractAddresses.governanceProposerAddress.toString(),
governance: info.l1ContractAddresses.governanceAddress.toString(),
slashFactory: info.l1ContractAddresses.slashFactoryAddress.toString(),
slashFactory: info.l1ContractAddresses.slashFactoryAddress?.toString(),
},
protocolContractAddresses: {
classRegisterer: info.protocolContractAddresses.classRegisterer.toString(),
Expand All @@ -60,7 +60,7 @@ export async function getNodeInfo(
log(` RewardDistributor Address: ${info.l1ContractAddresses.rewardDistributorAddress.toString()}`);
log(` GovernanceProposer Address: ${info.l1ContractAddresses.governanceProposerAddress.toString()}`);
log(` Governance Address: ${info.l1ContractAddresses.governanceAddress.toString()}`);
log(` SlashFactory Address: ${info.l1ContractAddresses.slashFactoryAddress.toString()}`);
log(` SlashFactory Address: ${info.l1ContractAddresses.slashFactoryAddress?.toString()}`);

log(`L2 Contract Addresses:`);
log(` Class Registerer: ${info.protocolContractAddresses.classRegisterer.toString()}`);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('e2e_p2p_slashing', () => {
});

const slashFactory = getContract({
address: getAddress(t.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress.toString()),
address: getAddress(t.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress!.toString()),
abi: SlashFactoryAbi,
client: t.ctx.deployL1ContractsValues.publicClient,
});
Expand Down
1 change: 1 addition & 0 deletions yarn-project/ethereum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@viem/anvil": "^0.0.10",
"get-port": "^7.1.0",
"jest": "^29.5.0",
"lodash.omit": "^4.5.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
},
Expand Down
256 changes: 256 additions & 0 deletions yarn-project/ethereum/src/contracts/registry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
import { Fr } from '@aztec/foundation/fields';
import { type Logger, createLogger } from '@aztec/foundation/log';
import { TestERC20Abi as FeeJuiceAbi, GovernanceAbi } from '@aztec/l1-artifacts';

import type { Anvil } from '@viem/anvil';
import omit from 'lodash.omit';
import { getContract } from 'viem';
import { type PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
import { foundry } from 'viem/chains';

import { DefaultL1ContractsConfig } from '../config.js';
import { createL1Clients, deployL1Contracts, deployRollupAndPeriphery } from '../deploy_l1_contracts.js';
import { EthCheatCodes } from '../eth_cheat_codes.js';
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
import { defaultL1TxUtilsConfig } from '../l1_tx_utils.js';
import { startAnvil } from '../test/start_anvil.js';
import type { L1Clients } from '../types.js';
import { RegistryContract } from './registry.js';

const originalVersionSalt = 42;

describe('Registry', () => {
let anvil: Anvil;
let rpcUrl: string;
let privateKey: PrivateKeyAccount;
let logger: Logger;

let vkTreeRoot: Fr;
let protocolContractTreeRoot: Fr;
let l2FeeJuiceAddress: Fr;
let publicClient: L1Clients['publicClient'];
let walletClient: L1Clients['walletClient'];
let registry: RegistryContract;
let deployedAddresses: L1ContractAddresses;

beforeAll(async () => {
logger = createLogger('ethereum:test:registry');
// this is the 6th address that gets funded by the junk mnemonic
privateKey = privateKeyToAccount('0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba');
vkTreeRoot = Fr.random();
protocolContractTreeRoot = Fr.random();
l2FeeJuiceAddress = Fr.random();

({ anvil, rpcUrl } = await startAnvil());

({ publicClient, walletClient } = createL1Clients(rpcUrl, privateKey));

const deployed = await deployL1Contracts(rpcUrl, privateKey, foundry, logger, {
...DefaultL1ContractsConfig,
salt: originalVersionSalt,
vkTreeRoot,
protocolContractTreeRoot,
l2FeeJuiceAddress,
genesisArchiveRoot: Fr.random(),
genesisBlockHash: Fr.random(),
});
// Since the registry cannot "see" the slash factory, we omit it from the addresses for this test
deployedAddresses = omit(deployed.l1ContractAddresses, 'slashFactoryAddress');
registry = new RegistryContract(publicClient, deployedAddresses.registryAddress);
});

afterAll(async () => {
await anvil.stop();
});

it('gets rollup versions', async () => {
const rollupAddress = deployedAddresses.rollupAddress;
{
const address = await registry.getCanonicalAddress();
expect(address).toEqual(rollupAddress);
}
{
const address = await registry.getRollupAddress('canonical');
expect(address).toEqual(rollupAddress);
}
{
const address = await registry.getRollupAddress(1);
expect(address).toEqual(rollupAddress);
}
});

it('handles non-existent versions', async () => {
const address = await registry.getRollupAddress(2);
expect(address).toBeUndefined();
});

it('collects addresses', async () => {
await expect(
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 'canonical'),
).resolves.toEqual(deployedAddresses);

await expect(
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1),
).resolves.toEqual(deployedAddresses);

// Version 2 does not exist

await expect(RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2)).rejects.toThrow(
'Rollup address is undefined',
);
});

it('adds a version to the registry', async () => {
const addresses = await RegistryContract.collectAddresses(
publicClient,
deployedAddresses.registryAddress,
'canonical',
);
const newVersionSalt = originalVersionSalt + 1;

const { rollup: newRollup, payloadAddress } = await deployRollupAndPeriphery(
rpcUrl,
foundry,
privateKey,
{
...DefaultL1ContractsConfig,
salt: newVersionSalt,
vkTreeRoot,
protocolContractTreeRoot,
l2FeeJuiceAddress,
genesisArchiveRoot: Fr.random(),
genesisBlockHash: Fr.random(),
},
{
feeJuicePortalAddress: addresses.feeJuicePortalAddress,
rewardDistributorAddress: addresses.rewardDistributorAddress,
stakingAssetAddress: addresses.stakingAssetAddress,
registryAddress: deployedAddresses.registryAddress,
},
logger,
defaultL1TxUtilsConfig,
);

const { governance, voteAmount } = await createGovernanceProposal(
payloadAddress.toString(),
addresses,
privateKey,
publicClient,
logger,
);

await executeGovernanceProposal(0n, governance, voteAmount, privateKey, publicClient, walletClient, rpcUrl, logger);

const newAddresses = await newRollup.getRollupAddresses();

const newCanonicalAddresses = await RegistryContract.collectAddresses(
publicClient,
deployedAddresses.registryAddress,
'canonical',
);

expect(newCanonicalAddresses).toEqual({
...deployedAddresses,
...newAddresses,
});

await expect(
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 2),
).resolves.toEqual(newCanonicalAddresses);

await expect(
RegistryContract.collectAddresses(publicClient, deployedAddresses.registryAddress, 1),
).resolves.toEqual(deployedAddresses);
});
});

async function executeGovernanceProposal(
proposalId: bigint,
governance: any,
voteAmount: bigint,
privateKey: PrivateKeyAccount,
publicClient: L1Clients['publicClient'],
walletClient: L1Clients['walletClient'],
rpcUrl: string,
logger: Logger,
) {
const proposal = await governance.read.getProposal([proposalId]);

const waitL1Block = async () => {
await publicClient.waitForTransactionReceipt({
hash: await walletClient.sendTransaction({
to: privateKey.address,
value: 1n,
account: privateKey,
}),
});
};

const cheatCodes = new EthCheatCodes(rpcUrl, logger);

const timeToActive = proposal.creation + proposal.config.votingDelay;
logger.info(`Warping to ${timeToActive + 1n}`);
await cheatCodes.warp(Number(timeToActive + 1n));
logger.info(`Warped to ${timeToActive + 1n}`);
await waitL1Block();

logger.info(`Voting`);
const voteTx = await governance.write.vote([proposalId, voteAmount, true], { account: privateKey });
await publicClient.waitForTransactionReceipt({ hash: voteTx });
logger.info(`Voted`);

const timeToExecutable = timeToActive + proposal.config.votingDuration + proposal.config.executionDelay + 1n;
logger.info(`Warping to ${timeToExecutable}`);
await cheatCodes.warp(Number(timeToExecutable));
logger.info(`Warped to ${timeToExecutable}`);
await waitL1Block();

const executeTx = await governance.write.execute([proposalId], { account: privateKey });
await publicClient.waitForTransactionReceipt({ hash: executeTx });
logger.info(`Executed proposal`);
}

async function createGovernanceProposal(
payloadAddress: `0x${string}`,
addresses: L1ContractAddresses,
privateKey: PrivateKeyAccount,
publicClient: L1Clients['publicClient'],
logger: Logger,
) {
const token = getContract({
address: addresses.feeJuiceAddress.toString(),
abi: FeeJuiceAbi,
client: publicClient,
});

const governance = getContract({
address: addresses.governanceAddress.toString(),
abi: GovernanceAbi,
client: publicClient,
});

const lockAmount = 10000n * 10n ** 18n;
const voteAmount = 10000n * 10n ** 18n;

const mintTx = await token.write.mint([privateKey.address, lockAmount + voteAmount], { account: privateKey });
await publicClient.waitForTransactionReceipt({ hash: mintTx });
logger.info(`Minted tokens`);

const approveTx = await token.write.approve([addresses.governanceAddress.toString(), lockAmount + voteAmount], {
account: privateKey,
});
await publicClient.waitForTransactionReceipt({ hash: approveTx });
logger.info(`Approved tokens`);

const depositTx = await governance.write.deposit([privateKey.address, lockAmount + voteAmount], {
account: privateKey,
});
await publicClient.waitForTransactionReceipt({ hash: depositTx });
logger.info(`Deposited tokens`);

await governance.write.proposeWithLock([payloadAddress, privateKey.address], {
account: privateKey,
});

return { governance, voteAmount };
}
Loading

1 comment on commit a90f08e

@AztecBot
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'P2P Testbench'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.05.

Benchmark suite Current: a90f08e Previous: b0de9e8 Ratio
degree-1-strict - numberReceived 4 ms 3 ms 1.33
degree-1-strict - medianDelay 759 ms 477 ms 1.59
normal-degree-50-nodes - numberReceived 49 ms 44 ms 1.11
normal-degree-50-nodes - minDelay 215 ms 187 ms 1.15

This comment was automatically generated by workflow using github-action-benchmark.

CC: @Maddiaa0

Please sign in to comment.