Skip to content

Commit

Permalink
feat(contracts): integrate challenger
Browse files Browse the repository at this point in the history
  • Loading branch information
mempirate committed Oct 14, 2024
1 parent db0946a commit 147467c
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 29 deletions.
17 changes: 15 additions & 2 deletions bolt-contracts/script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,23 @@ contract DeployBolt is Script {

uint48 epochDuration = 1 days;
uint48 slashingWindow = 7 days;
uint48 maxChallengeDuration = 7 days;
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;

bytes memory initParameters =
abi.encodeCall(BoltParameters.initialize, (admin, epochDuration, slashingWindow, allowUnsafeRegistration));
bytes memory initParameters = abi.encodeCall(
BoltParameters.initialize,
(
admin,
epochDuration,
slashingWindow,
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
)
);
address parametersProxy = Upgrades.deployUUPSProxy("BoltParameters.sol", initParameters);
console.log("BoltParameters proxy deployed at", parametersProxy);

Expand Down
51 changes: 32 additions & 19 deletions bolt-contracts/src/contracts/BoltChallenger.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
Expand All @@ -12,8 +15,9 @@ import {RLPWriter} from "../lib/rlp/RLPWriter.sol";
import {BeaconChainUtils} from "../lib/BeaconChainUtils.sol";
import {TransactionDecoder} from "../lib/TransactionDecoder.sol";
import {IBoltChallenger} from "../interfaces/IBoltChallenger.sol";
import {IBoltParameters} from "../interfaces/IBoltParameters.sol";

contract BoltChallenger is IBoltChallenger {
contract BoltChallenger is IBoltChallenger, OwnableUpgradeable, UUPSUpgradeable {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;
using TransactionDecoder for bytes;
Expand All @@ -22,26 +26,29 @@ contract BoltChallenger is IBoltChallenger {

// ========= STORAGE =========

/// @notice Bolt Parameters contract.
IBoltParameters public parameters;

/// @notice The set of existing unique challenge IDs.
EnumerableSet.Bytes32Set internal challengeIDs;

/// @notice The mapping of challenge IDs to their respective challenges.
mapping(bytes32 => Challenge) internal challenges;

// ========= CONSTANTS =========

/// @notice The challenge bond required to open a challenge.
uint256 public constant CHALLENGE_BOND = 1 ether;
// ========= INITIALIZER =========

/// @notice The maximum duration of a challenge to be considered valid.
uint256 public constant MAX_CHALLENGE_DURATION = 7 days;
/// @notice Initializer
/// @param _owner Address of the owner of the contract
/// @param _parameters Address of the Bolt Parameters contract
function initialize(address _owner, address _parameters) public initializer {
__Ownable_init(_owner);

/// @notice The maximum number of blocks to look back for block hashes in the EVM.
uint256 public constant BLOCKHASH_EVM_LOOKBACK = 256;

// ========= CONSTRUCTOR =========
parameters = IBoltParameters(_parameters);
}

constructor() {}
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}

// ========= VIEW FUNCTIONS =========

Expand Down Expand Up @@ -109,7 +116,7 @@ contract BoltChallenger is IBoltChallenger {
}

// Check that the attached bond amount is correct
if (msg.value != CHALLENGE_BOND) {
if (msg.value != parameters.CHALLENGE_BOND()) {
revert IncorrectChallengeBond();
}

Expand Down Expand Up @@ -194,14 +201,20 @@ contract BoltChallenger is IBoltChallenger {

// The visibility of the BLOCKHASH opcode is limited to the 256 most recent blocks.
// For simplicity we restrict this to 256 slots even though 256 blocks would be more accurate.
if (challenges[challengeID].targetSlot < BeaconChainUtils._getCurrentSlot() - BLOCKHASH_EVM_LOOKBACK) {
if (
challenges[challengeID].targetSlot
< BeaconChainUtils._getCurrentSlot() - parameters.BLOCKHASH_EVM_LOOKBACK()
) {
revert BlockIsTooOld();
}

// Check that the previous block is within the EVM lookback window for block hashes.
// Clearly, if the previous block is available, the inclusion one will be too.
uint256 previousBlockNumber = proof.inclusionBlockNumber - 1;
if (previousBlockNumber > block.number || previousBlockNumber < block.number - BLOCKHASH_EVM_LOOKBACK) {
if (
previousBlockNumber > block.number
|| previousBlockNumber < block.number - parameters.BLOCKHASH_EVM_LOOKBACK()
) {
revert InvalidBlockNumber();
}

Expand Down Expand Up @@ -229,7 +242,7 @@ contract BoltChallenger is IBoltChallenger {
revert ChallengeAlreadyResolved();
}

if (challenge.openedAt + MAX_CHALLENGE_DURATION >= Time.timestamp()) {
if (challenge.openedAt + parameters.MAX_CHALLENGE_DURATION() >= Time.timestamp()) {
revert ChallengeNotExpired();
}

Expand All @@ -254,7 +267,7 @@ contract BoltChallenger is IBoltChallenger {
revert ChallengeAlreadyResolved();
}

if (challenge.openedAt + MAX_CHALLENGE_DURATION < Time.timestamp()) {
if (challenge.openedAt + parameters.MAX_CHALLENGE_DURATION() < Time.timestamp()) {
// If the challenge has expired without being resolved, it is considered breached.
// This should be handled by calling the `resolveExpiredChallenge()` function instead.
revert ChallengeExpired();
Expand Down Expand Up @@ -468,7 +481,7 @@ contract BoltChallenger is IBoltChallenger {
function _transferFullBond(
address recipient
) internal {
(bool success,) = payable(recipient).call{value: CHALLENGE_BOND}("");
(bool success,) = payable(recipient).call{value: parameters.CHALLENGE_BOND()}("");
if (!success) {
revert BondTransferFailed();
}
Expand All @@ -479,7 +492,7 @@ contract BoltChallenger is IBoltChallenger {
function _transferHalfBond(
address recipient
) internal {
(bool success,) = payable(recipient).call{value: CHALLENGE_BOND / 2}("");
(bool success,) = payable(recipient).call{value: parameters.CHALLENGE_BOND() / 2}("");
if (!success) {
revert BondTransferFailed();
}
Expand Down
24 changes: 21 additions & 3 deletions bolt-contracts/src/contracts/BoltParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";

contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
// =========== STORAGE =========== //

// --> Storage layout marker: 0 bits

/// @notice Duration of an epoch in seconds.
Expand All @@ -19,6 +21,16 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
bool public ALLOW_UNSAFE_REGISTRATION;
// --> Storage layout marker: 48 + 48 + 8 = 104 bits

/// @notice The maximum duration of a challenge before it is automatically considered valid.
uint48 public MAX_CHALLENGE_DURATION;

/// @notice The challenge bond required to open a challenge.
uint256 public CHALLENGE_BOND;

/// @notice The maximum number of blocks to look back for block hashes in the EVM.
uint256 public BLOCKHASH_EVM_LOOKBACK;
// --> Storage layout marker: 3 words

/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
Expand All @@ -27,23 +39,29 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
*
* Total storage slots: 50
*/
uint256[49] private __gap;
uint256[47] private __gap;

// ============== PROXY METHODS ============== //
// ============== INITIALIZER ============== //

/// @notice The initializer for the BoltManager contract.
/// @param _epochDuration The epoch duration.
function initialize(
address _owner,
uint48 _epochDuration,
uint48 _slashingWindow,
bool _allowUnsafeRegistration
uint48 _maxChallengeDuration,
bool _allowUnsafeRegistration,
uint256 _challengeBond,
uint256 _blockhashEvmLookback
) public initializer {
__Ownable_init(_owner);

EPOCH_DURATION = _epochDuration;
SLASHING_WINDOW = _slashingWindow;
ALLOW_UNSAFE_REGISTRATION = _allowUnsafeRegistration;
MAX_CHALLENGE_DURATION = _maxChallengeDuration;
CHALLENGE_BOND = _challengeBond;
BLOCKHASH_EVM_LOOKBACK = _blockhashEvmLookback;
}

function _authorizeUpgrade(
Expand Down
5 changes: 3 additions & 2 deletions bolt-contracts/src/contracts/BoltValidators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, OwnableUpgrade
/// @param validator Validator struct
event ValidatorRegistered(bytes32 indexed pubkeyHash, Validator validator);

// ========= CONSTRUCTOR =========
// ========= INITIALIZER =========

/// @notice Constructor
/// @notice Initializer
/// @param _owner Address of the owner of the contract
/// @param _parameters Address of the Bolt Parameters contract
function initialize(address _owner, address _parameters) public initializer {
__Ownable_init(_owner);

Expand Down
3 changes: 3 additions & 0 deletions bolt-contracts/src/interfaces/IBoltParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ interface IBoltParameters {
function EPOCH_DURATION() external view returns (uint48);
function SLASHING_WINDOW() external view returns (uint48);
function ALLOW_UNSAFE_REGISTRATION() external view returns (bool);
function MAX_CHALLENGE_DURATION() external view returns (uint48);
function CHALLENGE_BOND() external view returns (uint256);
function BLOCKHASH_EVM_LOOKBACK() external view returns (uint256);
}
21 changes: 21 additions & 0 deletions bolt-contracts/test/BoltChallenger.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Test, console} from "forge-std/Test.sol";

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import {BoltParameters} from "../src/contracts/BoltParameters.sol";
import {BoltChallenger} from "../src/contracts/BoltChallenger.sol";
import {IBoltChallenger} from "../src/interfaces/IBoltChallenger.sol";
import {RLPReader} from "../src/lib/rlp/RLPReader.sol";
Expand Down Expand Up @@ -41,6 +42,7 @@ contract BoltChallengerTest is Test {

BoltChallengerExt boltChallenger;

address admin = makeAddr("admin");
address challenger = makeAddr("challenger");
address resolver = makeAddr("resolver");

Expand All @@ -51,7 +53,26 @@ contract BoltChallengerTest is Test {
vm.pauseGasMetering();
(target, targetPK) = makeAddrAndKey("target");

uint48 epochDuration = 1 days;
uint48 slashingWindow = 7 days;
uint48 maxChallengeDuration = 7 days;
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;

BoltParameters parameters = new BoltParameters();
parameters.initialize(
admin,
epochDuration,
slashingWindow,
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
);

boltChallenger = new BoltChallengerExt();
boltChallenger.initialize(admin, address(parameters));

vm.deal(challenger, 100 ether);
vm.deal(resolver, 100 ether);
Expand Down
13 changes: 12 additions & 1 deletion bolt-contracts/test/BoltManager.EigenLayer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,21 @@ contract BoltManagerEigenLayerTest is Test {

uint48 epochDuration = 1 days;
uint48 slashingWindow = 7 days;
uint48 maxChallengeDuration = 7 days;
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;

BoltParameters parameters = new BoltParameters();
parameters.initialize(admin, epochDuration, slashingWindow, allowUnsafeRegistration);
parameters.initialize(
admin,
epochDuration,
slashingWindow,
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
);

// Deploy Bolt contracts
validators = new BoltValidators();
Expand Down
13 changes: 12 additions & 1 deletion bolt-contracts/test/BoltManager.Symbiotic.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,21 @@ contract BoltManagerSymbioticTest is Test {

uint48 epochDuration = 1 days;
uint48 slashingWindow = 7 days;
uint48 maxChallengeDuration = 7 days;
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;

BoltParameters parameters = new BoltParameters();
parameters.initialize(admin, epochDuration, slashingWindow, allowUnsafeRegistration);
parameters.initialize(
admin,
epochDuration,
slashingWindow,
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
);

validators = new BoltValidators();
validators.initialize(admin, address(parameters));
Expand Down
13 changes: 12 additions & 1 deletion bolt-contracts/test/BoltValidators.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,22 @@ contract BoltValidatorsTest is Test {
function setUp() public {
uint48 epochDuration = 1 days;
uint48 slashingWindow = 7 days;
uint48 maxChallengeDuration = 7 days;
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;

parameters = new BoltParameters();

parameters.initialize(admin, epochDuration, slashingWindow, allowUnsafeRegistration);
parameters.initialize(
admin,
epochDuration,
slashingWindow,
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
);
validators = new BoltValidators();
validators.initialize(admin, address(parameters));
}
Expand Down

0 comments on commit 147467c

Please sign in to comment.