Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {RollupBuilder} from "./builder/RollupBuilder.sol";
import {Ownable} from "@oz/access/Ownable.sol";
import {AttestationLib, CommitteeAttestations} from "@aztec/core/libraries/rollup/AttestationLib.sol";
import {AttestationLibHelper} from "@test/helper_libraries/AttestationLibHelper.sol";
import {Bps, BpsLib} from "@aztec/core/libraries/rollup/RewardLib.sol";
// solhint-disable comprehensive-interface

/**
Expand Down Expand Up @@ -419,7 +420,8 @@ contract RollupTest is RollupBase {
);
proverFees *= 10; // the price conversion

uint256 expectedProverRewards = rollup.getBlockReward() / 2 * 2 + proverFees;
uint256 sequencerBlockReward = BpsLib.mul(rollup.getBlockReward(), rollup.getRewardConfig().sequencerBps);
uint256 expectedProverRewards = (rollup.getBlockReward() - sequencerBlockReward) * 2 + proverFees;

assertEq(rollup.getCollectiveProverRewardsForEpoch(Epoch.wrap(0)), expectedProverRewards, "invalid prover rewards");
}
Expand Down Expand Up @@ -524,9 +526,10 @@ contract RollupTest is RollupBase {
assertEq(provingCosts, FeeAssetValue.unwrap(interim.provingCostPerManaInFeeAsset), "invalid proving costs");
}

uint256 expectedProverReward =
rollup.getBlockReward() / 2 + FeeAssetValue.unwrap(interim.provingCostPerManaInFeeAsset) * interim.manaUsed;
uint256 expectedSequencerReward = rollup.getBlockReward() / 2 + interim.feeAmount
uint256 sequencerBlockReward = BpsLib.mul(rollup.getBlockReward(), rollup.getRewardConfig().sequencerBps);
uint256 expectedProverReward = rollup.getBlockReward() - sequencerBlockReward
+ FeeAssetValue.unwrap(interim.provingCostPerManaInFeeAsset) * interim.manaUsed;
uint256 expectedSequencerReward = sequencerBlockReward + interim.feeAmount
- FeeAssetValue.unwrap(interim.provingCostPerManaInFeeAsset) * interim.manaUsed;

assertEq(rollup.getSequencerRewards(header.coinbase), expectedSequencerReward, "invalid sequencer rewards");
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/test/benchmark/happy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
* @param _size - The number of validators
* @return Encoded vote data
*/
function createTallyVoteData(uint256 _size) internal returns (bytes memory) {
function createTallyVoteData(uint256 _size) internal view returns (bytes memory) {
require(_size % 4 == 0, "Vote data must have multiple of 4 validators");

bytes32 seed = keccak256(abi.encode(_size, block.timestamp));
Expand Down
9 changes: 9 additions & 0 deletions l1-contracts/test/builder/RollupBuilder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {CoinIssuer} from "@aztec/governance/CoinIssuer.sol";
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {GSEWithSkip} from "@test/GSEWithSkip.sol";
import {TestGov} from "@test/governance/helpers/TestGov.sol";
import {Bps} from "@aztec/core/libraries/rollup/RewardLib.sol";
import {SafeCast} from "@oz/utils/math/SafeCast.sol";

// Stack the layers to avoid the stack too deep 🧌
struct ConfigFlags {
Expand Down Expand Up @@ -62,6 +64,7 @@ struct Config {
*/
contract RollupBuilder is Test {
using stdStorage for StdStorage;
using SafeCast for uint256;

Config public config;

Expand Down Expand Up @@ -160,6 +163,12 @@ contract RollupBuilder is Test {
return this;
}

function setSequencerBps(uint256 _sequencerBps) public returns (RollupBuilder) {
require(_sequencerBps <= 10_000, "Sequencer BPS must be less than or equal to 10000");
config.rollupConfigInput.rewardConfig.sequencerBps = Bps.wrap(_sequencerBps.toUint32());
return this;
}

function setManaTarget(uint256 _manaTarget) public returns (RollupBuilder) {
config.rollupConfigInput.manaTarget = _manaTarget;
return this;
Expand Down
4 changes: 2 additions & 2 deletions l1-contracts/test/fees/FeeRollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import {FeeModelTestPoints, TestPoint, FeeHeaderModel, ManaBaseFeeComponentsMode

import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
import {ProposedHeader} from "@aztec/core/libraries/rollup/ProposedHeaderLib.sol";

import {MinimalFeeModel} from "./MinimalFeeModel.sol";
import {RollupBuilder} from "../builder/RollupBuilder.sol";
import {AttestationLibHelper} from "@test/helper_libraries/AttestationLibHelper.sol";
Expand Down Expand Up @@ -103,7 +102,8 @@ contract FeeRollupTest is FeeModelTestPoints, DecoderBase {

RollupBuilder builder = new RollupBuilder(address(this)).setProvingCostPerMana(provingCost).setManaTarget(
MANA_TARGET
).setSlotDuration(SLOT_DURATION).setEpochDuration(EPOCH_DURATION).setMintFeeAmount(1e30).setTargetCommitteeSize(0);
).setSlotDuration(SLOT_DURATION).setEpochDuration(EPOCH_DURATION).setMintFeeAmount(1e30).setTargetCommitteeSize(0)
.setSequencerBps(5000);
builder.deploy();

rollup = builder.getConfig().rollup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract NoVoteAndExitTest is GovernanceBase {
function test_CannotVoteAndExit(address _voter, uint256 _totalPower, uint256 _votesCast, uint256 _yeas) external {
bytes32 _proposalName = "empty";

vm.assume(_voter != address(0));
vm.assume(_voter != address(0) && _voter != address(governance));
proposal = proposals[_proposalName];
proposalId = proposalIds[_proposalName];

Expand Down
10 changes: 6 additions & 4 deletions l1-contracts/test/governance/scenario/AddRollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,21 @@ contract AddRollupTest is TestBase {
assertEq(originalPayload, address(payload));
assertEq(gsePayload.getURI(), payload.getURI());

uint256 emperorPower = 10_000e18 + rollup.getActivationThreshold() * VALIDATOR_COUNT;

vm.prank(token.owner());
token.mint(EMPEROR, 10_000 ether);
token.mint(EMPEROR, emperorPower);

vm.startPrank(EMPEROR);
token.approve(address(governance), 10_000 ether);
governance.deposit(EMPEROR, 10_000 ether);
token.approve(address(governance), emperorPower);
governance.deposit(EMPEROR, emperorPower);
vm.stopPrank();

vm.warp(Timestamp.unwrap(upw.pendingThrough(proposal)) + 1);
assertTrue(governance.getProposalState(0) == ProposalState.Active);

vm.prank(EMPEROR);
governance.vote(0, 10_000 ether, true);
governance.vote(0, emperorPower, true);

vm.warp(Timestamp.unwrap(upw.activeThrough(proposal)) + 1);
assertTrue(governance.getProposalState(0) == ProposalState.Queued);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,21 @@ contract UpgradeGovernanceProposerTest is TestBase {
assertEq(originalPayload, address(payload));
assertEq(gsePayload.getURI(), payload.getURI());

uint256 emperorPower = 10_000e18 + rollup.getActivationThreshold() * VALIDATOR_COUNT;

vm.prank(token.owner());
token.mint(EMPEROR, 10_000 ether);
token.mint(EMPEROR, emperorPower);

vm.startPrank(EMPEROR);
token.approve(address(governance), 10_000 ether);
governance.deposit(EMPEROR, 10_000 ether);
token.approve(address(governance), emperorPower);
governance.deposit(EMPEROR, emperorPower);
vm.stopPrank();

vm.warp(Timestamp.unwrap(upw.pendingThrough(proposal)) + 1);
assertTrue(governance.getProposalState(0) == ProposalState.Active);

vm.prank(EMPEROR);
governance.vote(0, 10_000 ether, true);
governance.vote(0, emperorPower, true);

vm.warp(Timestamp.unwrap(upw.activeThrough(proposal)) + 1);
assertTrue(governance.getProposalState(0) == ProposalState.Queued);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ contract SlashingTest is TestBase {

IPayload payload = slashFactory.createSlashPayload(offenders, amounts, offenses);

for (uint256 i = 0; i < 10; i++) {
uint256 quorum = slashingProposer.QUORUM_SIZE();

for (uint256 i = 0; i < quorum; i++) {
address proposer = rollup.getCurrentProposer();
vm.prank(proposer);
slashingProposer.signal(payload);
Expand Down Expand Up @@ -225,6 +227,11 @@ contract SlashingTest is TestBase {
// We slash a small amount and see that they are all still validating, but less stake
uint96 slashAmount1 = 10e18;
(uint256 firstSlashingRound,) = _createPayloadAndSignalForSlashing(attesters, slashAmount1, howManyToSlash);

uint256 firstExecutableSlot =
(firstSlashingRound + slashingProposer.EXECUTION_DELAY_IN_ROUNDS() + 1) * slashingProposer.ROUND_SIZE();
timeCheater.cheat__jumpToSlot(firstExecutableSlot);

slashingProposer.submitRoundWinner(firstSlashingRound);

for (uint256 i = 0; i < howManyToSlash; i++) {
Expand All @@ -237,8 +244,14 @@ contract SlashingTest is TestBase {
// Now we do it all again, but this time enough to kick them out of the system!
// Why we doing it in two steps explicitly here? To make sure that it is clear
// that it works like this.
uint96 slashAmount2 = 40e18 + 1;
uint96 slashAmount2 =
uint96(rollup.getActivationThreshold()) - uint96(rollup.getEjectionThreshold()) - slashAmount1 + 1;
(uint256 secondSlashingRound,) = _createPayloadAndSignalForSlashing(attesters, slashAmount2, howManyToSlash);

uint256 secondExecutableSlot =
(secondSlashingRound + slashingProposer.EXECUTION_DELAY_IN_ROUNDS() + 1) * slashingProposer.ROUND_SIZE();
timeCheater.cheat__jumpToSlot(secondExecutableSlot);

slashingProposer.submitRoundWinner(secondSlashingRound);

for (uint256 i = 0; i < howManyToSlash; i++) {
Expand Down
61 changes: 56 additions & 5 deletions l1-contracts/test/governance/scenario/slashing/TallySlashing.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {BN254Lib, G1Point, G2Point} from "@aztec/shared/libraries/BN254Lib.sol";
import {SignatureLib, Signature} from "@aztec/shared/libraries/SignatureLib.sol";
import {SlashRound} from "@aztec/core/libraries/SlashRoundLib.sol";
import {SlasherFlavor} from "@aztec/core/interfaces/ISlasher.sol";
import {Ownable} from "@oz/access/Ownable.sol";

// solhint-disable comprehensive-interface
// solhint-disable func-name-mixedcase
Expand Down Expand Up @@ -197,6 +198,7 @@ contract SlashingTest is TestBase {
assertEq(rollup.getActiveAttesterCount(), validatorCount, "Invalid attester count");
}

/// forge-config: default.fuzz.runs = 8
function test_CannotSlashBeforeDelay(uint256 _lifetimeInRounds, uint256 _executionDelayInRounds, uint256 _jumpToSlot)
public
{
Expand Down Expand Up @@ -225,6 +227,7 @@ contract SlashingTest is TestBase {
slashingProposer.executeRound(firstSlashingRound, committees);
}

/// forge-config: default.fuzz.runs = 8
function test_CanSlashAfterDelay(uint256 _lifetimeInRounds, uint256 _executionDelayInRounds, uint256 _jumpToSlot)
public
{
Expand Down Expand Up @@ -267,6 +270,7 @@ contract SlashingTest is TestBase {
}
}

/// forge-config: default.fuzz.runs = 8
function test_CannotSlashIfVetoed(uint256 _lifetimeInRounds, uint256 _executionDelayInRounds, uint256 _jumpToSlot)
public
{
Expand Down Expand Up @@ -309,9 +313,6 @@ contract SlashingTest is TestBase {

function test_SlashingDisableTimestamp() public {
_setupCommitteeForSlashing();
address[] memory attesters = rollup.getEpochCommittee(Epoch.wrap(INITIAL_EPOCH));
uint96 slashAmount = uint96(slashingProposer.SLASH_AMOUNT_SMALL());
SlashRound firstSlashingRound = _createSlashingVotes(slashAmount, attesters.length);

// Initially slashing should be enabled
assertEq(slasher.isSlashingEnabled(), true, "Slashing should be enabled initially");
Expand Down Expand Up @@ -387,7 +388,7 @@ contract SlashingTest is TestBase {
uint256 howManyToSlash = HOW_MANY_SLASHED;

// We slash a small amount and see that they are all still validating, but less stake
uint96 slashAmount1 = 10e18;
uint96 slashAmount1 = uint96(slashingProposer.SLASH_AMOUNT_SMALL());
SlashRound firstSlashingRound = _createSlashingVotes(slashAmount1, howManyToSlash);

// Grab the attesters and their initial stakes
Expand Down Expand Up @@ -445,7 +446,57 @@ contract SlashingTest is TestBase {
uint256 howManyToSlash = HOW_MANY_SLASHED;

// We slash a small amount and see that they are all still validating, but less stake
uint96 slashAmount1 = 60e18;
uint96 slashAmount1 = uint96(slashingProposer.SLASH_AMOUNT_LARGE());
SlashRound firstSlashingRound = _createSlashingVotes(slashAmount1, howManyToSlash);

// Grab the attesters and their initial stakes
address[][] memory committees = new address[][](slashingProposer.ROUND_SIZE_IN_EPOCHS());
address[] memory attesters = new address[](slashingProposer.ROUND_SIZE_IN_EPOCHS() * COMMITTEE_SIZE);
uint256[] memory stakes = new uint256[](attesters.length);
for (uint256 i = 0; i < slashingProposer.ROUND_SIZE_IN_EPOCHS(); i++) {
Epoch epochSlashed = slashingProposer.getSlashTargetEpoch(firstSlashingRound, i);
address[] memory committee = rollup.getEpochCommittee(epochSlashed);
committees[i] = committee;
for (uint256 j = 0; j < committee.length; j++) {
address attester = committee[j];
attesters[i * COMMITTEE_SIZE + j] = attester;
AttesterView memory attesterView = rollup.getAttesterView(attester);
stakes[i * COMMITTEE_SIZE + j] = attesterView.effectiveBalance;
assertTrue(attesterView.status == Status.VALIDATING, "Invalid status");
}
}

// Wait for execution delay and execute - need to be in the next round for execution
uint256 roundsToWait = slashingProposer.EXECUTION_DELAY_IN_ROUNDS() + 1;
timeCheater.cheat__jumpForwardSlots(roundsToWait * slashingProposer.ROUND_SIZE());

// Execute the slash
slashingProposer.executeRound(firstSlashingRound, committees);

// Check balances
for (uint256 i = 0; i < howManyToSlash; i++) {
AttesterView memory attesterView = rollup.getAttesterView(attesters[i]);
assertEq(attesterView.effectiveBalance, stakes[i] - slashAmount1);
assertEq(attesterView.exit.amount, 0, "Invalid stake");
assertTrue(attesterView.status == Status.VALIDATING, "Invalid status");
}

// Verify that slashing was successful and validators are still active
assertEq(rollup.getActiveAttesterCount(), VALIDATOR_COUNT, "All validators should remain active after small slash");
}

function test_SlashingLargeAmount_smallLocalEjectionThreshold() public {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one is essentially the previous test. The diff in them is just whether we altered the local ejection threshold.

_setupCommitteeForSlashing();

uint256 howManyToSlash = HOW_MANY_SLASHED;

// We slash a large amount AND alter the local ejection threshold, to see that this should kick us out.
uint96 slashAmount1 = uint96(slashingProposer.SLASH_AMOUNT_LARGE());
uint256 localEjectionThreshold = rollup.getActivationThreshold() - slashAmount1 + 1;

vm.prank(Ownable(address(rollup)).owner());
rollup.setLocalEjectionThreshold(localEjectionThreshold);

SlashRound firstSlashingRound = _createSlashingVotes(slashAmount1, howManyToSlash);

// Grab the attesters and their initial stakes
Expand Down
24 changes: 12 additions & 12 deletions l1-contracts/test/harnesses/TestConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ library TestConstants {
uint256 internal constant AZTEC_TARGET_COMMITTEE_SIZE = 48;
uint256 internal constant AZTEC_LAG_IN_EPOCHS = 2;
uint256 internal constant AZTEC_PROOF_SUBMISSION_EPOCHS = 1;
uint256 internal constant AZTEC_SLASHING_QUORUM = 6;
uint256 internal constant AZTEC_SLASHING_ROUND_SIZE = 10;
uint256 internal constant AZTEC_SLASHING_LIFETIME_IN_ROUNDS = 5;
uint256 internal constant AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS = 0;
uint256 internal constant AZTEC_SLASHING_QUORUM = 65;
uint256 internal constant AZTEC_SLASHING_ROUND_SIZE = 4 * AZTEC_EPOCH_DURATION;
uint256 internal constant AZTEC_SLASHING_LIFETIME_IN_ROUNDS = 40;
uint256 internal constant AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS = 28;
uint256 internal constant AZTEC_SLASHING_OFFSET_IN_ROUNDS = 2;
address internal constant AZTEC_SLASHING_VETOER = address(0);
uint256 internal constant AZTEC_SLASHING_DISABLE_DURATION = 5 days;
uint256 internal constant AZTEC_SLASH_AMOUNT_SMALL = 20e18;
uint256 internal constant AZTEC_SLASH_AMOUNT_MEDIUM = 40e18;
uint256 internal constant AZTEC_SLASH_AMOUNT_LARGE = 60e18;
uint256 internal constant AZTEC_SLASH_AMOUNT_SMALL = 2000e18;
uint256 internal constant AZTEC_SLASH_AMOUNT_MEDIUM = 10_000e18;
uint256 internal constant AZTEC_SLASH_AMOUNT_LARGE = 30_000e18;
uint256 internal constant AZTEC_MANA_TARGET = 100_000_000;
uint256 internal constant AZTEC_ENTRY_QUEUE_FLUSH_SIZE_MIN = 4;
uint256 internal constant AZTEC_ENTRY_QUEUE_FLUSH_SIZE_QUOTIENT = 2;
Expand All @@ -40,8 +40,8 @@ library TestConstants {
EthValue internal constant AZTEC_PROVING_COST_PER_MANA = EthValue.wrap(100);
uint256 internal constant AZTEC_COIN_ISSUER_RATE = uint256(25_000_000_000e18) / uint256(60 * 60 * 24 * 365);

uint256 internal constant ACTIVATION_THRESHOLD = 100e18;
uint256 internal constant EJECTION_THRESHOLD = 50e18;
uint256 internal constant ACTIVATION_THRESHOLD = 200_000e18;
uint256 internal constant EJECTION_THRESHOLD = 100_000e18;

// Genesis state
bytes32 internal constant GENESIS_ARCHIVE_ROOT = bytes32(Constants.GENESIS_ARCHIVE_ROOT);
Expand Down Expand Up @@ -70,15 +70,15 @@ library TestConstants {
}

function getRewardBoostConfig() internal pure returns (RewardBoostConfig memory) {
return RewardBoostConfig({increment: 200_000, maxScore: 5_000_000, a: 5000, k: 1_000_000, minimum: 100_000});
return RewardBoostConfig({increment: 1.25e5, maxScore: 150e5, a: 0.01e5, k: 10e5, minimum: 1e5});
}

function getRewardConfig() internal pure returns (RewardConfig memory) {
return RewardConfig({
rewardDistributor: IRewardDistributor(address(0)),
sequencerBps: Bps.wrap(5000),
sequencerBps: Bps.wrap(8000),
booster: IBoosterCore(address(0)), // Will cause a deployment
blockReward: 50e18
blockReward: 500e18
});
}

Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/test/portals/TokenPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ contract TokenPortal {

outbox.consume(message, _l2BlockNumber, _leafIndex, _path);

underlying.transfer(_recipient, _amount);
underlying.safeTransfer(_recipient, _amount);
}
// docs:end:token_portal_withdraw
}
6 changes: 4 additions & 2 deletions l1-contracts/test/staking/15050.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ contract Test15050 is StakingBase {

assertEq(caller.getCurrentRound(), 0);

while (caller.getCurrentRound() == 0) {
uint256 waitUntilRound = caller.EXECUTION_DELAY_IN_ROUNDS() + 1;

while (caller.getCurrentRound() < waitUntilRound) {
vm.warp(block.timestamp + 12);
}

assertEq(caller.getCurrentRound(), 1);
assertEq(caller.getCurrentRound(), waitUntilRound);

RoundAccounting memory r = caller.getRoundData(address(staking), 0);
assertFalse(r.executed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ contract ValidatorSelectionTest is ValidatorSelectionTestBase {
uint96[] memory amounts = new uint96[](attesters.length);

// We say, these things are bad, call the baba yaga to take care of them!
uint96 slashAmount = 90e18;
uint96 slashAmount = 1 + uint96(rollup.getActivationThreshold()) - uint96(rollup.getEjectionThreshold());
for (uint256 i = 0; i < attesters.length; i++) {
AttesterView memory attesterView = rollup.getAttesterView(attesters[i]);
stakes[i] = attesterView.effectiveBalance;
Expand Down
Loading