Skip to content

Commit

Permalink
test: add reward payout check
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Oct 21, 2024
1 parent a6f1667 commit 20607ee
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 10 deletions.
8 changes: 7 additions & 1 deletion l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,18 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
if (blockNumber <= assumeProvenThroughBlockNumber) {
fakeBlockNumberAsProven(blockNumber);

if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) {
bool isFeeCanonical = address(this) == FEE_JUICE_PORTAL.canonicalRollup();
bool isSysstiaCanonical = address(this) == SYSSTIA.canonicalRollup();

if (isFeeCanonical && header.globalVariables.coinbase != address(0) && header.totalFees > 0) {
// @note This will currently fail if there are insufficient funds in the bridge
// which WILL happen for the old version after an upgrade where the bridge follow.
// Consider allowing a failure. See #7938.
FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees);
}
if (isSysstiaCanonical && header.globalVariables.coinbase != address(0)) {
SYSSTIA.claim(header.globalVariables.coinbase);
}

emit L2ProofVerified(blockNumber, "CHEAT");
}
Expand Down
16 changes: 12 additions & 4 deletions yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type CompleteAddress,
type DebugLogger,
type DeployL1Contracts,
EthAddress,
ExtendedNote,
type Fq,
Fr,
Expand Down Expand Up @@ -88,14 +89,20 @@ export class FullProverTest {
private context!: SubsystemsContext;
private proverNode!: ProverNode;
private simulatedProverNode!: ProverNode;
private l1Contracts!: DeployL1Contracts;

constructor(testName: string, private minNumberOfTxsPerBlock: number, private realProofs = true) {
public l1Contracts!: DeployL1Contracts;
public proverAddress!: EthAddress;

constructor(
testName: string,
private minNumberOfTxsPerBlock: number,
coinbase: EthAddress,
private realProofs = true,
) {
this.logger = createDebugLogger(`aztec:full_prover_test:${testName}`);
this.snapshotManager = createSnapshotManager(
`full_prover_integration/${testName}`,
dataPath,
{ startProverNode: true },
{ startProverNode: true, fundSysstia: true, coinbase },
{ assumeProvenThrough: undefined },
);
}
Expand Down Expand Up @@ -261,6 +268,7 @@ export class FullProverTest {
// The simulated prover node (now shutdown) used private key index 2
const proverNodePrivateKey = getPrivateKeyFromIndex(2);
const proverNodeSenderAddress = privateKeyToAddress(new Buffer32(proverNodePrivateKey!).to0xString());
this.proverAddress = EthAddress.fromString(proverNodeSenderAddress);

this.logger.verbose(`Funding prover node at ${proverNodeSenderAddress}`);
await this.mintL1ERC20(proverNodeSenderAddress, 100_000_000n);
Expand Down
51 changes: 49 additions & 2 deletions yarn-project/end-to-end/src/e2e_prover/full.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { type AztecAddress, retryUntil } from '@aztec/aztec.js';
import { type AztecAddress, EthAddress, retryUntil } from '@aztec/aztec.js';
import { RollupAbi, SysstiaAbi, TestERC20Abi } from '@aztec/l1-artifacts';

import '@jest/globals';
import { type Chain, type GetContractReturnType, type HttpTransport, type PublicClient, getContract } from 'viem';

import { FullProverTest } from './e2e_prover_test.js';

Expand All @@ -11,12 +13,17 @@ process.env.AVM_PROVING_STRICT = '1';

describe('full_prover', () => {
const realProofs = !['true', '1'].includes(process.env.FAKE_PROOFS ?? '');
const t = new FullProverTest('full_prover', 1, realProofs);
const COINBASE_ADDRESS = EthAddress.random();
const t = new FullProverTest('full_prover', 1, COINBASE_ADDRESS, realProofs);

let { provenAssets, accounts, tokenSim, logger, cheatCodes } = t;
let sender: AztecAddress;
let recipient: AztecAddress;

let rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>;
let feeJuice: GetContractReturnType<typeof TestERC20Abi, PublicClient<HttpTransport, Chain>>;
let sysstia: GetContractReturnType<typeof SysstiaAbi, PublicClient<HttpTransport, Chain>>;

beforeAll(async () => {
await t.applyBaseSnapshots();
await t.applyMintSnapshot();
Expand All @@ -25,6 +32,24 @@ describe('full_prover', () => {

({ provenAssets, accounts, tokenSim, logger, cheatCodes } = t);
[sender, recipient] = accounts.map(a => a.address);

rollup = getContract({
abi: RollupAbi,
address: t.l1Contracts.l1ContractAddresses.rollupAddress.toString(),
client: t.l1Contracts.publicClient,
});

feeJuice = getContract({
abi: TestERC20Abi,
address: t.l1Contracts.l1ContractAddresses.feeJuiceAddress.toString(),
client: t.l1Contracts.publicClient,
});

sysstia = getContract({
abi: SysstiaAbi,
address: t.l1Contracts.l1ContractAddresses.sysstiaAddress.toString(),
client: t.l1Contracts.publicClient,
});
});

afterAll(async () => {
Expand Down Expand Up @@ -86,6 +111,9 @@ describe('full_prover', () => {
logger.info(`Advancing from epoch ${epoch} to next epoch`);
await cheatCodes.rollup.advanceToNextEpoch();

const balanceBeforeCoinbase = await feeJuice.read.balanceOf([COINBASE_ADDRESS.toString()]);
const balanceBeforeProver = await feeJuice.read.balanceOf([t.proverAddress.toString()]);

// Wait until the prover node submits a quote
logger.info(`Waiting for prover node to submit quote for epoch ${epoch}`);
await retryUntil(() => t.aztecNode.getEpochProofQuotes(epoch).then(qs => qs.length > 0), 'quote', 60, 1);
Expand All @@ -108,6 +136,25 @@ describe('full_prover', () => {
// And wait for the first pair of txs to be proven
logger.info(`Awaiting proof for the previous epoch`);
await Promise.all(txs.map(tx => tx.wait({ timeout: 300, interval: 10, proven: true, provenTimeout: 1500 })));

const provenBn = await rollup.read.getProvenBlockNumber();
const balanceAfterCoinbase = await feeJuice.read.balanceOf([COINBASE_ADDRESS.toString()]);
const balanceAfterProver = await feeJuice.read.balanceOf([t.proverAddress.toString()]);
const blockReward = (await sysstia.read.BLOCK_REWARD()) as bigint;
const fees = (
await Promise.all([t.aztecNode.getBlock(Number(provenBn - 1n)), t.aztecNode.getBlock(Number(provenBn))])
).map(b => b!.header.totalFees.toBigInt());

const rewards = fees.map(fee => fee + blockReward);
const toProver = rewards
.map(reward => (reward * claim!.basisPointFee) / 10_000n)
.reduce((acc, fee) => acc + fee, 0n);
const toCoinbase = rewards.reduce((acc, reward) => acc + reward, 0n) - toProver;

expect(provenBn + 1n).toBe(await rollup.read.getPendingBlockNumber());
expect(balanceAfterCoinbase).toBe(balanceBeforeCoinbase + toCoinbase);
expect(balanceAfterProver).toBe(balanceBeforeProver + toProver);
expect(claim!.bondProvider).toEqual(t.proverAddress);
},
TIMEOUT,
);
Expand Down
27 changes: 25 additions & 2 deletions yarn-project/end-to-end/src/fixtures/snapshot_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
type Wallet,
} from '@aztec/aztec.js';
import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment';
import { type DeployL1ContractsArgs, createL1Clients } from '@aztec/ethereum';
import { type DeployL1ContractsArgs, createL1Clients, l1Artifacts } from '@aztec/ethereum';
import { asyncMap } from '@aztec/foundation/async-map';
import { type Logger, createDebugLogger } from '@aztec/foundation/log';
import { resolver, reviver } from '@aztec/foundation/serialize';
Expand All @@ -31,7 +31,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import { copySync, removeSync } from 'fs-extra/esm';
import getPort from 'get-port';
import { join } from 'path';
import { type Hex } from 'viem';
import { type Hex, getContract } from 'viem';
import { mnemonicToAccount } from 'viem/accounts';

import { MNEMONIC } from './fixtures.js';
Expand Down Expand Up @@ -336,6 +336,29 @@ async function setupFromFresh(
aztecNodeConfig.l1Contracts = deployL1ContractsValues.l1ContractAddresses;
aztecNodeConfig.l1PublishRetryIntervalMS = 100;

if (opts.fundSysstia) {
// Mints block rewards for 10000 blocks to the sysstia contract

const sysstia = getContract({
address: deployL1ContractsValues.l1ContractAddresses.sysstiaAddress.toString(),
abi: l1Artifacts.sysstia.contractAbi,
client: deployL1ContractsValues.publicClient,
});

const blockReward = await sysstia.read.BLOCK_REWARD([]);
const mintAmount = 10_000n * (blockReward as bigint);

const feeJuice = getContract({
address: deployL1ContractsValues.l1ContractAddresses.feeJuiceAddress.toString(),
abi: l1Artifacts.feeJuice.contractAbi,
client: deployL1ContractsValues.walletClient,
});

const sysstiaMintTxHash = await feeJuice.write.mint([sysstia.address, mintAmount], {} as any);
await deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash: sysstiaMintTxHash });
logger.info(`Funding sysstia in ${sysstiaMintTxHash}`);
}

const watcher = new AnvilTestWatcher(
new EthCheatCodes(aztecNodeConfig.l1RpcUrl),
deployL1ContractsValues.l1ContractAddresses.rollupAddress,
Expand Down
28 changes: 27 additions & 1 deletion yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { deployInstance, registerContractClass } from '@aztec/aztec.js/deploymen
import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint';
import { type BBNativePrivateKernelProver } from '@aztec/bb-prover';
import { type EthAddress, GasSettings, getContractClassFromArtifact } from '@aztec/circuits.js';
import { NULL_KEY, isAnvilTestChain } from '@aztec/ethereum';
import { NULL_KEY, isAnvilTestChain, l1Artifacts } from '@aztec/ethereum';
import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
Expand All @@ -50,6 +50,7 @@ import {
type PrivateKeyAccount,
createPublicClient,
createWalletClient,
getContract,
http,
} from 'viem';
import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
Expand Down Expand Up @@ -247,6 +248,8 @@ export type SetupOptions = {
assumeProvenThrough?: number;
/** Whether to start a prover node */
startProverNode?: boolean;
/** Whether to fund the sysstia */
fundSysstia?: boolean;
} & Partial<AztecNodeConfig>;

/** Context for an end-to-end test as returned by the `setup` function */
Expand Down Expand Up @@ -360,6 +363,29 @@ export async function setup(

config.l1Contracts = deployL1ContractsValues.l1ContractAddresses;

if (opts.fundSysstia) {
// Mints block rewards for 10000 blocks to the sysstia contract

const sysstia = getContract({
address: deployL1ContractsValues.l1ContractAddresses.sysstiaAddress.toString(),
abi: l1Artifacts.sysstia.contractAbi,
client: deployL1ContractsValues.publicClient,
});

const blockReward = await sysstia.read.BLOCK_REWARD([]);
const mintAmount = 10_000n * (blockReward as bigint);

const feeJuice = getContract({
address: deployL1ContractsValues.l1ContractAddresses.feeJuiceAddress.toString(),
abi: l1Artifacts.feeJuice.contractAbi,
client: deployL1ContractsValues.walletClient,
});

const sysstiaMintTxHash = await feeJuice.write.mint([sysstia.address, mintAmount], {} as any);
await deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash: sysstiaMintTxHash });
logger.info(`Funding sysstia in ${sysstiaMintTxHash}`);
}

if (opts.l2StartTime) {
// This should only be used in synching test or when you need to have a stable
// timestamp for the first l2 block.
Expand Down

0 comments on commit 20607ee

Please sign in to comment.