Skip to content

Commit

Permalink
feat(contracts): integrate BeaconChainUtils in params + challenger,…
Browse files Browse the repository at this point in the history
… remove `ValidatorProver`
  • Loading branch information
Jonas Bostoen committed Oct 15, 2024
1 parent d676783 commit f12505c
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 144 deletions.
8 changes: 7 additions & 1 deletion bolt-contracts/script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ contract DeployBolt is Script {
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;
uint256 justificationDelay = 32;
uint256 eth2GenesisTimestamp = 1_606_824_023;
uint256 slotTime = 12;

bytes memory initParameters = abi.encodeCall(
BoltParameters.initialize,
Expand All @@ -45,7 +48,10 @@ contract DeployBolt is Script {
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
blockhashEvmLookback,
justificationDelay,
eth2GenesisTimestamp,
slotTime
)
);
address parametersProxy = Upgrades.deployUUPSProxy("BoltParameters.sol", initParameters);
Expand Down
70 changes: 64 additions & 6 deletions bolt-contracts/src/contracts/BoltChallenger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {SecureMerkleTrie} from "../lib/trie/SecureMerkleTrie.sol";
import {MerkleTrie} from "../lib/trie/MerkleTrie.sol";
import {RLPReader} from "../lib/rlp/RLPReader.sol";
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";
Expand Down Expand Up @@ -146,7 +145,7 @@ contract BoltChallenger is IBoltChallenger, OwnableUpgradeable, UUPSUpgradeable
}

uint256 targetSlot = commitments[0].slot;
if (targetSlot > BeaconChainUtils._getCurrentSlot() - BeaconChainUtils.JUSTIFICATION_DELAY_SLOTS) {
if (targetSlot > _getCurrentSlot() - parameters.JUSTIFICATION_DELAY()) {
// We cannot open challenges for slots that are not finalized by Ethereum consensus yet.
// This is admittedly a bit strict, since 32-slot deep reorgs are very unlikely.
revert BlockIsNotFinalized();
Expand Down Expand Up @@ -218,10 +217,7 @@ contract BoltChallenger is IBoltChallenger, OwnableUpgradeable, UUPSUpgradeable

// 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() - parameters.BLOCKHASH_EVM_LOOKBACK()
) {
if (challenges[challengeID].targetSlot < _getCurrentSlot() - parameters.BLOCKHASH_EVM_LOOKBACK()) {
revert BlockIsTooOld();
}

Expand Down Expand Up @@ -514,4 +510,66 @@ contract BoltChallenger is IBoltChallenger, OwnableUpgradeable, UUPSUpgradeable
revert BondTransferFailed();
}
}

/// @notice Get the slot number from a given timestamp
/// @param _timestamp The timestamp
/// @return The slot number
function _getSlotFromTimestamp(
uint256 _timestamp
) internal view returns (uint256) {
return (_timestamp - parameters.ETH2_GENESIS_TIMESTAMP()) / parameters.SLOT_TIME();
}

/// @notice Get the timestamp from a given slot
/// @param _slot The slot number
/// @return The timestamp
function _getTimestampFromSlot(
uint256 _slot
) internal view returns (uint256) {
return parameters.ETH2_GENESIS_TIMESTAMP() + _slot * parameters.SLOT_TIME();
}

/// @notice Get the beacon block root for a given slot
/// @param _slot The slot number
/// @return The beacon block root
function _getBeaconBlockRootAtSlot(
uint256 _slot
) internal view returns (bytes32) {
uint256 slotTimestamp = parameters.ETH2_GENESIS_TIMESTAMP() + _slot * parameters.SLOT_TIME();
return _getBeaconBlockRootAtTimestamp(slotTimestamp);
}

function _getBeaconBlockRootAtTimestamp(
uint256 _timestamp
) internal view returns (bytes32) {
(bool success, bytes memory data) = parameters.BEACON_ROOTS_CONTRACT().staticcall(abi.encode(_timestamp));

if (!success || data.length == 0) {
revert BeaconRootNotFound();
}

return abi.decode(data, (bytes32));
}

/// @notice Get the latest beacon block root
/// @return The beacon block root
function _getLatestBeaconBlockRoot() internal view returns (bytes32) {
uint256 latestSlot = _getSlotFromTimestamp(block.timestamp);
return _getBeaconBlockRootAtSlot(latestSlot);
}

/// @notice Get the current slot
/// @return The current slot
function _getCurrentSlot() internal view returns (uint256) {
return _getSlotFromTimestamp(block.timestamp);
}

/// @notice Check if a timestamp is within the EIP-4788 window
/// @param _timestamp The timestamp
/// @return True if the timestamp is within the EIP-4788 window, false otherwise
function _isWithinEIP4788Window(
uint256 _timestamp
) internal view returns (bool) {
return _getSlotFromTimestamp(_timestamp) <= _getCurrentSlot() + parameters.EIP4788_WINDOW();
}
}
32 changes: 29 additions & 3 deletions bolt-contracts/src/contracts/BoltParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeab
/// with the use of storage gaps.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
// =========== CONSTANTS ========= //
/// @dev See EIP-4788 for more info
address internal constant BEACON_ROOTS_CONTRACT = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;

/// @notice The EIP-4788 time window in slots
uint256 internal constant EIP4788_WINDOW = 8191;
// =========== STORAGE =========== //

// --> Storage layout marker: 0 bits
Expand All @@ -34,7 +40,16 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {

/// @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

/// @notice The number of slots to wait before considering a block justified by LMD-GHOST.
uint256 public JUSTIFICATION_DELAY;

/// @notice The timestamp of the eth2 genesis block.
uint256 public ETH2_GENESIS_TIMESTAMP;

/// @notice The duration of a slot in seconds.
uint256 public SLOT_TIME;
// --> Storage layout marker: 6 words

/**
* @dev This empty reserved space is put in place to allow future versions to add new
Expand All @@ -44,7 +59,10 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
*
* Total storage slots: 50
*/
uint256[47] private __gap;
uint256[44] private __gap;

/// @notice Error emitted when a beacon block root is not found
error BeaconRootNotFound();

// ============== INITIALIZER ============== //

Expand All @@ -57,7 +75,10 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
uint48 _maxChallengeDuration,
bool _allowUnsafeRegistration,
uint256 _challengeBond,
uint256 _blockhashEvmLookback
uint256 _blockhashEvmLookback,
uint256 _justificationDelay,
uint256 _eth2GenesisTimestamp,
uint256 _slotTime
) public initializer {
__Ownable_init(_owner);

Expand All @@ -67,6 +88,9 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
MAX_CHALLENGE_DURATION = _maxChallengeDuration;
CHALLENGE_BOND = _challengeBond;
BLOCKHASH_EVM_LOOKBACK = _blockhashEvmLookback;
JUSTIFICATION_DELAY = _justificationDelay;
ETH2_GENESIS_TIMESTAMP = _eth2GenesisTimestamp;
SLOT_TIME = _slotTime;
}

function _authorizeUpgrade(
Expand All @@ -82,4 +106,6 @@ contract BoltParameters is OwnableUpgradeable, UUPSUpgradeable {
) public onlyOwner {
ALLOW_UNSAFE_REGISTRATION = allowUnsafeRegistration;
}

// ============== VIEW METHODS =============== //
}
1 change: 1 addition & 0 deletions bolt-contracts/src/interfaces/IBoltChallenger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ interface IBoltChallenger {
error UnexpectedMixedSigners();
error UnexpectedNonceOrder();
error InvalidProofsLength();
error BeaconRootNotFound();

event ChallengeOpened(bytes32 indexed challengeId, address indexed challenger, address indexed commitmentSigner);
event ChallengeDefended(bytes32 indexed challengeId);
Expand Down
5 changes: 5 additions & 0 deletions bolt-contracts/src/interfaces/IBoltParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ interface IBoltParameters {
function MAX_CHALLENGE_DURATION() external view returns (uint48);
function CHALLENGE_BOND() external view returns (uint256);
function BLOCKHASH_EVM_LOOKBACK() external view returns (uint256);
function JUSTIFICATION_DELAY() external view returns (uint256);
function EIP4788_WINDOW() external view returns (uint256);
function SLOT_TIME() external view returns (uint256);
function ETH2_GENESIS_TIMESTAMP() external view returns (uint256);
function BEACON_ROOTS_CONTRACT() external view returns (address);
}
85 changes: 0 additions & 85 deletions bolt-contracts/src/lib/BeaconChainUtils.sol

This file was deleted.

42 changes: 0 additions & 42 deletions bolt-contracts/src/lib/ssz/ValidatorProver.sol

This file was deleted.

17 changes: 13 additions & 4 deletions bolt-contracts/test/BoltChallenger.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {RLPWriter} from "../src/lib/rlp/RLPWriter.sol";
import {BytesUtils} from "../src/lib/BytesUtils.sol";
import {MerkleTrie} from "../src/lib/trie/MerkleTrie.sol";
import {SecureMerkleTrie} from "../src/lib/trie/SecureMerkleTrie.sol";
import {BeaconChainUtils} from "../src/lib/BeaconChainUtils.sol";
import {TransactionDecoder} from "../src/lib/TransactionDecoder.sol";

// re-export the internal resolver function for testing
Expand All @@ -26,6 +25,10 @@ contract BoltChallengerExt is BoltChallenger {
_resolve(_challengeID, _trustedBlockHash, _proof);
}

function _getCurrentSlotExt() external view returns (uint256) {
return _getCurrentSlot();
}

function _decodeBlockHeaderRLPExt(
bytes calldata _blockHeaderRLP
) external pure returns (IBoltChallenger.BlockHeaderData memory) {
Expand Down Expand Up @@ -59,6 +62,9 @@ contract BoltChallengerTest is Test {
bool allowUnsafeRegistration = true;
uint256 challengeBond = 1 ether;
uint256 blockhashEvmLookback = 256;
uint256 justificationDelay = 32;
uint256 eth2GenesisTimestamp = 1_606_824_023;
uint256 slotTime = 12;

BoltParameters parameters = new BoltParameters();
parameters.initialize(
Expand All @@ -68,7 +74,10 @@ contract BoltChallengerTest is Test {
maxChallengeDuration,
allowUnsafeRegistration,
challengeBond,
blockhashEvmLookback
blockhashEvmLookback,
justificationDelay,
eth2GenesisTimestamp,
slotTime
);

boltChallenger = new BoltChallengerExt();
Expand Down Expand Up @@ -294,7 +303,7 @@ contract BoltChallengerTest is Test {
IBoltChallenger.SignedCommitment[] memory commitments = new IBoltChallenger.SignedCommitment[](1);
commitments[0] = _parseTestCommitment();

commitments[0].slot = uint64(BeaconChainUtils._getCurrentSlot()) + 10;
commitments[0].slot = uint64(boltChallenger._getCurrentSlotExt()) + 10;

// Open a challenge with a slot in the future
vm.resumeGasMetering();
Expand Down Expand Up @@ -532,7 +541,7 @@ contract BoltChallengerTest is Test {
commitment.signedTx = vm.parseJsonBytes(vm.readFile(path), ".raw");

// pick a recent slot, 100 slots behind the current slot
commitment.slot = uint64(BeaconChainUtils._getCurrentSlot() - 100);
commitment.slot = uint64(boltChallenger._getCurrentSlotExt() - 100);

// sign the new commitment with the target's private key
bytes32 commitmentID = _computeCommitmentID(commitment.signedTx, commitment.slot);
Expand Down
Loading

0 comments on commit f12505c

Please sign in to comment.