Skip to content

Commit

Permalink
feat: Prover node stakes to escrow contract
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Oct 3, 2024
1 parent 1c3cb63 commit ac8a0bc
Show file tree
Hide file tree
Showing 36 changed files with 579 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Create a basic ERC20 contract that can mint tokens to anyone. We will use this t

Create a file `TestERC20.sol` in the same folder and add:

#include_code contract /l1-contracts/test/TestERC20.sol solidity
#include_code contract /l1-contracts/src/mock/TestERC20.sol solidity

Replace the openzeppelin import with this:

Expand Down Expand Up @@ -81,7 +81,7 @@ Here we want to send a message to mint tokens privately on Aztec! Some key diffe
- The content hash uses a different function name - `mint_private`. This is done to make it easy to separate concerns. If the contentHash between the public and private message was the same, then an attacker could consume a private message publicly!
- Since we want to mint tokens privately, we shouldn’t specify a `to` Aztec address (remember that Ethereum is completely public). Instead, we will use a secret hash - `secretHashForRedeemingMintedNotes`. Only he who knows the preimage to the secret hash can actually mint the notes. This is similar to the mechanism we use for message consumption on L2
- Like with the public flow, we move the user’s funds to the portal
- We now send the message to the inbox with the `recipient` (the sister contract on L2 along with the version of aztec the message is intended for) and the `secretHashForL2MessageConsumption` (such that on L2, the consumption of the message can be private).
- We now send the message to the inbox with the `recipient` (the sister contract on L2 along with the version of aztec the message is intended for) and the `secretHashForL2MessageConsumption` (such that on L2, the consumption of the message can be private).

Note that because L1 is public, everyone can inspect and figure out the contentHash and the recipient contract address.

Expand Down
10 changes: 7 additions & 3 deletions l1-contracts/src/core/ProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract ProofCommitmentEscrow is IProofCommitmentEscrow {
Timestamp executableAt;
}

address public immutable ROLLUP;
address public ROLLUP;
uint256 public constant WITHDRAW_DELAY =
Constants.ETHEREUM_SLOT_DURATION * Constants.AZTEC_EPOCH_DURATION * 3;
mapping(address => uint256) public deposits;
Expand All @@ -30,9 +30,13 @@ contract ProofCommitmentEscrow is IProofCommitmentEscrow {
_;
}

constructor(IERC20 _token, address _owner) {
constructor(IERC20 _token) {
token = _token;
ROLLUP = _owner;
}

function initialize(address _rollup) external {
require(ROLLUP == address(0));
ROLLUP = _rollup;
}

/**
Expand Down
9 changes: 8 additions & 1 deletion l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,14 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {

constructor(
IFeeJuicePortal _fpcJuicePortal,
IProofCommitmentEscrow _proofCommitmentEscrow, // We should create a new instance instead of accepting one, once we remove the Mock version
bytes32 _vkTreeRoot,
address _ares,
address[] memory _validators
) Leonidas(_ares) {
epochProofVerifier = new MockVerifier();
FEE_JUICE_PORTAL = _fpcJuicePortal;
PROOF_COMMITMENT_ESCROW = new MockProofCommitmentEscrow();
PROOF_COMMITMENT_ESCROW = _proofCommitmentEscrow;
INBOX = IInbox(address(new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT)));
OUTBOX = IOutbox(address(new Outbox(address(this))));
vkTreeRoot = _vkTreeRoot;
Expand Down Expand Up @@ -628,6 +629,12 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
)
);

uint256 availableFundsInEscrow = PROOF_COMMITMENT_ESCROW.deposits(_quote.quote.prover);
require(
_quote.quote.bondAmount <= availableFundsInEscrow,
Errors.Rollup__InsufficientFundsInEscrow(_quote.quote.bondAmount, availableFundsInEscrow)
);

require(
_quote.quote.validUntilSlot >= currentSlot,
Errors.Rollup__QuoteExpired(currentSlot, _quote.quote.validUntilSlot)
Expand Down
3 changes: 3 additions & 0 deletions l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity >=0.8.27;

import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";

interface IProofCommitmentEscrow {
event Deposit(address indexed depositor, uint256 amount);
Expand All @@ -17,4 +18,6 @@ interface IProofCommitmentEscrow {
function stakeBond(address _prover, uint256 _amount) external;
function unstakeBond(address _prover, uint256 _amount) external;
function minBalanceAtTime(Timestamp _timestamp, address _prover) external view returns (uint256);
function deposits(address) external view returns (uint256);
function token() external view returns (IERC20);
}
1 change: 1 addition & 0 deletions l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ library Errors {

// Rollup
error Rollup__InsufficientBondAmount(uint256 minimum, uint256 provided); // 0xa165f276
error Rollup__InsufficientFundsInEscrow(uint256 required, uint256 available); // 0xa165f276
error Rollup__InvalidArchive(bytes32 expected, bytes32 actual); // 0xb682a40e
error Rollup__InvalidBlockHash(bytes32 expected, bytes32 actual);
error Rollup__InvalidBlockNumber(uint256 expected, uint256 actual); // 0xe5edf847
Expand Down
16 changes: 13 additions & 3 deletions l1-contracts/src/mock/MockProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ pragma solidity >=0.8.27;

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";

contract MockProofCommitmentEscrow is IProofCommitmentEscrow {
mapping(address => uint256) public deposits;

IERC20 public immutable token;

constructor() {
token = new TestERC20();
}

function deposit(uint256 _amount) external override {
// do nothing
deposits[msg.sender] += _amount;
}

function startWithdraw(uint256 _amount) external override {
Expand All @@ -26,7 +36,7 @@ contract MockProofCommitmentEscrow is IProofCommitmentEscrow {
// do nothing
}

function minBalanceAtTime(Timestamp, address) external pure override returns (uint256) {
return 0;
function minBalanceAtTime(Timestamp, address _who) external view override returns (uint256) {
return deposits[_who];
}
}
File renamed without changes.
17 changes: 14 additions & 3 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import {Outbox} from "@aztec/core/messagebridge/Outbox.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Rollup} from "@aztec/core/Rollup.sol";
import {IRollup} from "@aztec/core/interfaces/IRollup.sol";
import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol";
import {Leonidas} from "@aztec/core/Leonidas.sol";
import {NaiveMerkle} from "./merkle/Naive.sol";
import {MerkleTestUtil} from "./merkle/TestUtil.sol";
import {TestERC20} from "./TestERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
import {MockProofCommitmentEscrow} from "@aztec/mock/MockProofCommitmentEscrow.sol";

import {TxsDecoderHelper} from "./decoders/helpers/TxsDecoderHelper.sol";
import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol";
Expand All @@ -44,6 +46,7 @@ contract RollupTest is DecoderBase {
TxsDecoderHelper internal txsHelper;
TestERC20 internal testERC20;
FeeJuicePortal internal feeJuicePortal;
IProofCommitmentEscrow internal proofCommitmentEscrow;

SignatureLib.Signature[] internal signatures;

Expand All @@ -70,7 +73,9 @@ contract RollupTest is DecoderBase {
feeJuicePortal.initialize(
address(registry), address(testERC20), bytes32(Constants.FEE_JUICE_ADDRESS)
);
rollup = new Rollup(feeJuicePortal, bytes32(0), address(this), new address[](0));
proofCommitmentEscrow = new MockProofCommitmentEscrow();
rollup =
new Rollup(feeJuicePortal, proofCommitmentEscrow, bytes32(0), address(this), new address[](0));
inbox = Inbox(address(rollup.INBOX()));
outbox = Outbox(address(rollup.OUTBOX()));

Expand All @@ -81,14 +86,20 @@ contract RollupTest is DecoderBase {

uint256 privateKey = 0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234;
address signer = vm.addr(privateKey);
uint256 bond = rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST();
quote = EpochProofQuoteLib.EpochProofQuote({
epochToProve: Epoch.wrap(0),
validUntilSlot: Slot.wrap(1),
bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(),
bondAmount: bond,
prover: signer,
basisPointFee: 0
});
signedQuote = _quoteToSignedQuote(quote);

testERC20.mint(signer, bond * 10);
vm.prank(signer);
proofCommitmentEscrow.deposit(bond * 10);

_;
}

Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/test/TestERC20.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.8.18;

import "forge-std/Test.sol";
import {TestERC20} from "./TestERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";

contract TestERC20Test is Test {
TestERC20 testERC20;
Expand Down
11 changes: 9 additions & 2 deletions l1-contracts/test/portals/TokenPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import {Hash} from "@aztec/core/libraries/crypto/Hash.sol";
import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";
import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol";
import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";

// Portal tokens
import {TokenPortal} from "./TokenPortal.sol";
import {TestERC20} from "../TestERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";

import {NaiveMerkle} from "../merkle/Naive.sol";

Expand Down Expand Up @@ -60,7 +61,13 @@ contract TokenPortalTest is Test {
function setUp() public {
registry = new Registry(address(this));
testERC20 = new TestERC20();
rollup = new Rollup(IFeeJuicePortal(address(0)), bytes32(0), address(this), new address[](0));
rollup = new Rollup(
IFeeJuicePortal(address(0)),
IProofCommitmentEscrow(address(0)),
bytes32(0),
address(this),
new address[](0)
);
inbox = rollup.INBOX();
outbox = rollup.OUTBOX();

Expand Down
9 changes: 8 additions & 1 deletion l1-contracts/test/portals/UniswapPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";
import {NaiveMerkle} from "../merkle/Naive.sol";
import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol";
import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";

// Portals
import {TokenPortal} from "./TokenPortal.sol";
Expand Down Expand Up @@ -52,7 +53,13 @@ contract UniswapPortalTest is Test {
vm.selectFork(forkId);

registry = new Registry(address(this));
rollup = new Rollup(IFeeJuicePortal(address(0)), bytes32(0), address(this), new address[](0));
rollup = new Rollup(
IFeeJuicePortal(address(0)),
IProofCommitmentEscrow(address(0)),
bytes32(0),
address(this),
new address[](0)
);
registry.upgrade(address(rollup));

daiTokenPortal = new TokenPortal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {ProofCommitmentEscrow} from "@aztec/core/ProofCommitmentEscrow.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";

import {TestERC20} from "../TestERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";

// solhint-disable comprehensive-interface

Expand All @@ -32,7 +32,8 @@ contract TestProofCommitmentEscrow is Test {

function setUp() public {
TOKEN = new TestERC20();
ESCROW = new ProofCommitmentEscrow(TOKEN, address(this));
ESCROW = new ProofCommitmentEscrow(TOKEN);
ESCROW.initialize(address(this));
}

function testDeposit() public setupWithApproval(address(42), 100) {
Expand Down
11 changes: 9 additions & 2 deletions l1-contracts/test/sparta/Sparta.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import {Rollup} from "@aztec/core/Rollup.sol";
import {Leonidas} from "@aztec/core/Leonidas.sol";
import {NaiveMerkle} from "../merkle/Naive.sol";
import {MerkleTestUtil} from "../merkle/TestUtil.sol";
import {TestERC20} from "../TestERC20.sol";
import {TestERC20} from "@aztec/mock/TestERC20.sol";
import {TxsDecoderHelper} from "../decoders/helpers/TxsDecoderHelper.sol";
import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol";
import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol";

import {Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/TimeMath.sol";
Expand Down Expand Up @@ -74,7 +75,13 @@ contract SpartaTest is DecoderBase {
}

testERC20 = new TestERC20();
rollup = new Rollup(IFeeJuicePortal(address(0)), bytes32(0), address(this), initialValidators);
rollup = new Rollup(
IFeeJuicePortal(address(0)),
IProofCommitmentEscrow(address(0)),
bytes32(0),
address(this),
initialValidators
);
inbox = Inbox(address(rollup.INBOX()));
outbox = Outbox(address(rollup.OUTBOX()));

Expand Down
6 changes: 6 additions & 0 deletions yarn-project/aztec/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
FeeJuicePortalBytecode,
InboxAbi,
InboxBytecode,
MockProofCommitmentEscrowAbi,
MockProofCommitmentEscrowBytecode,
OutboxAbi,
OutboxBytecode,
RegistryAbi,
Expand Down Expand Up @@ -115,6 +117,10 @@ export async function deployContractsToL1(
contractAbi: FeeJuicePortalAbi,
contractBytecode: FeeJuicePortalBytecode,
},
proofCommitmentEscrow: {
contractAbi: MockProofCommitmentEscrowAbi,
contractBytecode: MockProofCommitmentEscrowBytecode,
},
};

const chain = aztecNodeConfig.l1RpcUrl
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/cli/src/utils/aztec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export async function deployAztecContracts(
RegistryBytecode,
RollupAbi,
RollupBytecode,

MockProofCommitmentEscrowAbi,
MockProofCommitmentEscrowBytecode,
FeeJuicePortalAbi,
FeeJuicePortalBytecode,
TestERC20Abi,
Expand Down Expand Up @@ -107,6 +108,10 @@ export async function deployAztecContracts(
contractAbi: FeeJuicePortalAbi,
contractBytecode: FeeJuicePortalBytecode,
},
proofCommitmentEscrow: {
contractAbi: MockProofCommitmentEscrowAbi,
contractBytecode: MockProofCommitmentEscrowBytecode,
},
};
const { getVKTreeRoot } = await import('@aztec/noir-protocol-circuits-types');

Expand Down
22 changes: 19 additions & 3 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 @@ -24,7 +24,8 @@ import {
type UltraKeccakHonkProtocolArtifact,
} from '@aztec/bb-prover';
import { compileContract } from '@aztec/ethereum';
import { RollupAbi } from '@aztec/l1-artifacts';
import { Buffer32 } from '@aztec/foundation/buffer';
import { RollupAbi, TestERC20Abi } from '@aztec/l1-artifacts';
import { TokenContract } from '@aztec/noir-contracts.js';
import { type ProverNode, type ProverNodeConfig, createProverNode } from '@aztec/prover-node';
import { type PXEService } from '@aztec/pxe';
Expand All @@ -33,7 +34,8 @@ import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
// TODO(#7373): Deploy honk solidity verifier
// @ts-expect-error solc-js doesn't publish its types https://github.com/ethereum/solc-js/issues/689
import solc from 'solc';
import { getContract } from 'viem';
import { type Hex, getContract } from 'viem';
import { privateKeyToAddress } from 'viem/accounts';

import { waitRegisteredAccountSynced } from '../benchmarks/utils.js';
import { getACVMConfig } from '../fixtures/get_acvm_config.js';
Expand Down Expand Up @@ -94,7 +96,7 @@ export class FullProverTest {
`full_prover_integration/${testName}`,
dataPath,
{},
{ assumeProvenThrough: undefined },
{ assumeProvenThrough: undefined, useRealProofCommitmentEscrow: true },
);
}

Expand Down Expand Up @@ -258,6 +260,10 @@ 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.logger.verbose(`Funding prover node at ${proverNodeSenderAddress}`);
await this.mintL1ERC20(proverNodeSenderAddress, 100_000_000n);

this.logger.verbose('Starting prover node');
const proverConfig: ProverNodeConfig = {
Expand All @@ -272,6 +278,8 @@ export class FullProverTest {
proverNodePollingIntervalMs: 100,
quoteProviderBasisPointFee: 100,
quoteProviderBondAmount: 1000n,
proverMinimumStakeAmount: 3000n,
proverTargetStakeAmount: 6000n,
};
this.proverNode = await createProverNode(proverConfig, {
aztecNodeTxProvider: this.aztecNode,
Expand All @@ -283,6 +291,14 @@ export class FullProverTest {
return this;
}

private async mintL1ERC20(recipient: Hex, amount: bigint) {
const erc20Address = this.context.deployL1ContractsValues.l1ContractAddresses.feeJuiceAddress;
const client = this.context.deployL1ContractsValues.walletClient;
const erc20 = getContract({ abi: TestERC20Abi, address: erc20Address.toString(), client });
const hash = await erc20.write.mint([recipient, amount]);
await this.context.deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash });
}

snapshot = <T>(
name: string,
apply: (context: SubsystemsContext) => Promise<T>,
Expand Down
Loading

0 comments on commit ac8a0bc

Please sign in to comment.