Skip to content

Commit

Permalink
Merge pull request #223 from chainbound/nico/feat/new-challenger
Browse files Browse the repository at this point in the history
feat(contracts): new challenger
  • Loading branch information
mempirate authored Oct 14, 2024
2 parents b764a8e + a5ae01a commit 960dfaa
Show file tree
Hide file tree
Showing 61 changed files with 5,348 additions and 17 deletions.
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
[submodule "bolt-contracts/lib/openzeppelin-contracts"]
path = bolt-contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "bolt-contracts/lib/relic-sdk"]
path = bolt-contracts/lib/relic-sdk
url = https://github.com/Relic-Protocol/relic-sdk
[submodule "bolt-contracts/lib/core"]
path = bolt-contracts/lib/core
url = https://github.com/symbioticfi/core
Expand Down
33 changes: 33 additions & 0 deletions bolt-contracts/.gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
BoltChallengerTest:testCommitmentDigestAndSignature() (gas: 4626)
BoltChallengerTest:testCommitmentSignature() (gas: 6754)
BoltChallengerTest:testOpenAlreadyExistingChallenge() (gas: 112649)
BoltChallengerTest:testOpenChallengeInvalidSignature() (gas: 25461)
BoltChallengerTest:testOpenChallengeSingleTx() (gas: 407773)
BoltChallengerTest:testOpenChallengeWithIncorrectBond() (gas: 17130)
BoltChallengerTest:testOpenChallengeWithLargebond() (gas: 17141)
BoltChallengerTest:testOpenChallengeWithSlotInTheFuture() (gas: 17517)
BoltChallengerTest:testProveAccountData() (gas: 355542)
BoltChallengerTest:testProveHeaderData() (gas: 46228)
BoltChallengerTest:testProveTransactionInclusion() (gas: 176543)
BoltChallengerTest:testResolveChallengeFullDefenseSingleTx() (gas: 697131)
BoltChallengerTest:testResolveChallengeFullDefenseStackedTxs() (gas: 1166625)
BoltManagerEigenLayerTest:testGetNonExistentProposerStatus() (gas: 921620)
BoltManagerEigenLayerTest:testGetWhitelistedCollaterals() (gas: 99988)
BoltManagerEigenLayerTest:testNonWhitelistedCollateral() (gas: 103013)
BoltManagerEigenLayerTest:testProposersLookaheadStatus() (gas: 2142632)
BoltManagerEigenLayerTest:test_deregisterEigenLayerOperatorFromAVS() (gas: 898067)
BoltManagerEigenLayerTest:test_getEigenLayerOperatorStake() (gas: 935483)
BoltManagerEigenLayerTest:test_getEigenLayerProposerStatus() (gas: 938074)
BoltManagerTest:testGetNonExistentProposerStatus() (gas: 1197534)
BoltManagerTest:testGetProposerStatus() (gas: 1431371)
BoltManagerTest:testGetWhitelistedCollaterals() (gas: 16818)
BoltManagerTest:testNonWhitelistedCollateral() (gas: 41889)
BoltManagerTest:testProposersLookaheadStatus() (gas: 2421869)
BoltManagerTest:testReadOperatorStake() (gas: 1520048)
BoltValidatorsTest:testUnsafeRegistration() (gas: 145625)
BoltValidatorsTest:testUnsafeRegistrationFailsIfAlreadyRegistered() (gas: 143729)
BoltValidatorsTest:testUnsafeRegistrationInvalidCollateralProvider() (gas: 18821)
BoltValidatorsTest:testUnsafeRegistrationInvalidOperator() (gas: 19050)
BoltValidatorsTest:testUnsafeRegistrationWhenNotAllowed() (gas: 22565)
TransactionDecoderTest:testDecodeAllTestCases() (gas: 0)
TransactionDecoderTest:testDecodeGasUsage() (gas: 53281)
3 changes: 3 additions & 0 deletions bolt-contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ out/
broadcast/

.env

node_modules/
target/
68 changes: 58 additions & 10 deletions bolt-contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ The opt-in process requires the following steps:
> Operator (NO), since the same steps apply to solo stakers.
As a Node Operator you will be an ["Operator"](https://docs.eigenlayer.xyz/eigenlayer/overview/key-terms)
in the Bolt AVS built on top of EigenLayer. This requires
in the Bolt AVS built on top of EigenLayer. This requires
running an Ethereum validator and the Bolt sidecar in order issue
preconfirmations.

Expand Down Expand Up @@ -151,7 +151,63 @@ The steps required are the following:

## Fault Proof Challenge and Slashing: `BoltChallenger`

WIP
The [`BoltChallenger`](./src/contracts/BoltChallenger.sol) contract is the component responsible
for handling fault attribution in the case of a validator failing to meet their commitments.

In short, the challenger contract allows any user to challenge a validator's commitment by opening
a dispute with the following inputs:

1. The signed commitment made by the validator (or a list of commitments on the same slot)
2. An ETH bond to cover the cost of the dispute and disincentivize frivolous challenges

The entrypoint is the `openChallenge` function. Once a challenge is opened, a `ChallengeOpened` event
is emitted, and any arbitrator has a time window to submit a valid response to settle the dispute.

### Dispute resolution

The dispute resolution process is one-shot and requires the arbitrator to submit all necessary evidence
of the validator's correct behaviour within the challenge time window.

The arbitrator is _anyone_ who can submit a valid response to the challenge. It doesn't have to be the
validator themselves. There is however one limitation: the time window for submitting a response must be
respected in the following way:

- Start: the target block must be justified by LMD-GHOST: a minimum of 32 slots must have passed
- End: depending on the EVM block hash oracle:
- . If using the `BLOCKHASH` EVM opcode, the window is limited to 256 blocks (roughly 1 hour)
- . If using the [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) historical oracle, the window is limited to 8192 blocks (roughly 1 day)

The inputs to the resolution process are as follows:

1. The ID of the challenge to respond to: this is emitted in the `ChallengeOpened` event and is unique.
2. The [inclusion proofs](https://github.com/chainbound/bolt/blob/6c0f1b696cfe3de7e7e3830ac28c369c6ddf271e/bolt-contracts/src/interfaces/IBoltChallenger.sol#L39), consisting of the following components:
a. the block number of the block containing the committed transactions (we call it "inclusionBlock")
b. the RLP-encoded block header of the block **before** the one containing the committed transactions (we call it "previousBlock")
b. the RLP-encoded block header of the block containing the included transactions (aka "inclusionBlock")
c. the account merkle proofs of the sender of the committed transactions against the previousBlock's state root
d. the transaction merkle proofs of the included transactions against the inclusionBlock's transaction root
e. the transaction index in the block of each included transaction

If the arbitrator submits a valid response that satisfies the requirements for the challenge, the
challenge is considered `DEFENDED` and the challenger's bond is slashed to cover the cost of the dispute
and to incentivize speedy resolution.

If no arbitrators respond successfully within the challenge time window, the challenge is considered
`BREACHED` and anyone can call the `resolveExpiredChallenge()` method. The `BoltChallenger` will keep
track of this information for future reference.

### Slashing of validators

If a challenge is `BREACHED` (as per the above definition), the validator's stake should be slashed to cover
the cost of a missed commitment. This is done by calling the `slash` function on the correct staking adapter
and reading into the `BoltChallenger` contract to trustlessly determine if the challenge was lost.

In practice, slashing behaviour is abstracted behind any staking adapter – an example is Symbiotic's `VetoSlasher`
which will receive a request to slash a validator's stake and will have a last opportunity to veto
the slashing request before it is executed on-chain.

Subscribing to breached challenge events from the `BoltChallenger` is a trustless way to determine if a slashing
request is valid according to Bolt Protocol rules.

## Testing

Expand Down Expand Up @@ -186,11 +242,3 @@ The following considerations should be taken into account before interacting wit
- Restaking is a complex process that involves trusting external systems and smart contracts.
- Validators should be aware of the potential for slashing if they fail to meet their commitments or engage in malicious behavior.
- Smart contracts are susceptible to bugs and vulnerabilities that could be exploited by attackers.

## Conclusion

The Bolt smart contracts provide a robust and flexible framework for integrating validator registration,
delegation, and restaking mechanism within the Bolt Ecosystem.

By leveraging the power and security of Symbiotic and Eigenlayer solutions, Bolt offers a sophisticated
solution for staking pools that wish to opt-in to multiple conditions with extreme granularity.
1 change: 1 addition & 0 deletions bolt-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ remappings = [
"@relic/=lib/relic-sdk/packages/contracts",
"@symbiotic/=lib/core/src/",
"@eigenlayer/=lib/eigenlayer-contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts",

# Symbiotic remappings contexts
"lib/core/:forge-std/=lib/core/lib/forge-std/src/",
Expand Down
1 change: 0 additions & 1 deletion bolt-contracts/lib/relic-sdk
Submodule relic-sdk deleted from 8d6c88
Loading

0 comments on commit 960dfaa

Please sign in to comment.