Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(contracts): new challenger #223

Merged
merged 51 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
0280706
wip: challenge proof components poc
merklefruit Sep 11, 2024
c0e47a8
feat: working header proof test
merklefruit Sep 11, 2024
91b2fe3
chore: small changes
merklefruit Sep 11, 2024
2c0239f
feat: working header + account proving. wip: transaction inclusion
merklefruit Sep 11, 2024
cf98dcd
chore: cleanup
merklefruit Sep 11, 2024
54ff8d2
chore: cleanup
merklefruit Sep 12, 2024
f25a714
fix: tx inclusion proof test
merklefruit Sep 12, 2024
8d540b7
chore: wip
merklefruit Sep 15, 2024
d276656
feat: open challenge logic
merklefruit Sep 16, 2024
aa75994
feat: stubbed resolution fns
merklefruit Sep 16, 2024
742372d
wip: rlp envelope decoding stub
merklefruit Sep 16, 2024
6ddef3d
feat: open challenge + commitment test
merklefruit Sep 17, 2024
91d87fb
feat: added tests
merklefruit Sep 17, 2024
3a89d63
feat: rlp decoding legacy + eip155 txs
merklefruit Sep 18, 2024
aa8decb
feat: cycle through all test cases
merklefruit Sep 18, 2024
8b77754
chore: added test
merklefruit Sep 18, 2024
4cea728
feat: added decoding support for 1559 and 4844
merklefruit Sep 18, 2024
3f5a7d4
fix: decode more test cases
merklefruit Sep 18, 2024
41b2113
feat: pass all test vectors
merklefruit Sep 18, 2024
d7bf8ef
chore: added docs
merklefruit Sep 18, 2024
89ee856
fix: forge remappings, minor warnings
merklefruit Sep 18, 2024
d4e287b
feat: update test vectors + decode eip4844 txs
merklefruit Sep 19, 2024
d0a21e9
feat: transfer bonds on challenge resolution
merklefruit Sep 19, 2024
977418d
chore: CEI pattern
merklefruit Sep 19, 2024
022c4aa
feat: first full resolution defense test
merklefruit Sep 20, 2024
86cf4d4
chore: fmt
merklefruit Sep 20, 2024
add1569
chore: fmt
merklefruit Sep 20, 2024
bbcfe26
chore: added docs
merklefruit Sep 23, 2024
59dac06
chore: updated readme, adjusted finalization window
merklefruit Sep 23, 2024
deaea6d
chore: rename target -> commitmentsigner
merklefruit Sep 23, 2024
ee63517
chore: rm relic-sdk dependency
merklefruit Sep 23, 2024
6b07c2c
fix: build
merklefruit Sep 23, 2024
80f84f5
feat: add gas snapshot
merklefruit Sep 24, 2024
82b4744
fix: accurate gas snapshot
merklefruit Sep 24, 2024
ed5c90c
chore(docs): rm broken list items
merklefruit Oct 1, 2024
8db5ed9
feat(contracts/challenger): remove resolved challenges
mempirate Oct 11, 2024
83a4a75
feat: added stacked preconfs in the same slot by the same sender logic
merklefruit Sep 25, 2024
1829971
chore: addressed initial reviews
merklefruit Sep 25, 2024
3b4807e
fix: broken test
merklefruit Sep 25, 2024
16adcce
wip: test stacked transaction proofs
merklefruit Sep 25, 2024
f2179ee
wip: test stacked multiple commitments
merklefruit Sep 26, 2024
94c91e9
fix: stacked commitments test
merklefruit Sep 27, 2024
0b1645c
feat: update snapshot with 5 commitments
merklefruit Sep 27, 2024
05d70b5
chore: add tests, change challenge id formula
merklefruit Sep 27, 2024
e1d1792
chore: update docs
merklefruit Sep 27, 2024
e495312
Merge pull request #289 from chainbound/nico/feat/stacked-challenge
merklefruit Oct 11, 2024
b36c194
chore: lint
merklefruit Oct 11, 2024
0c40d4c
fix: merge conflict
mempirate Oct 14, 2024
4e1a461
fix: rm stale test
mempirate Oct 14, 2024
ff5cb6d
test(contracts): fix challenger tests
mempirate Oct 14, 2024
a5ae01a
test(contracts): fix challenger tests
mempirate Oct 14, 2024
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
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
32 changes: 32 additions & 0 deletions bolt-contracts/.gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
BoltChallengerTest:testCommitmentDigestAndSignature() (gas: 4626)
BoltChallengerTest:testCommitmentSignature() (gas: 6754)
BoltChallengerTest:testOpenAlreadyExistingChallenge() (gas: 16032)
BoltChallengerTest:testOpenChallenge() (gas: 379747)
BoltChallengerTest:testOpenChallengeInvalidSignature() (gas: 22416)
BoltChallengerTest:testOpenChallengeWithInsufficientBond() (gas: 16738)
BoltChallengerTest:testOpenChallengeWithLargebond() (gas: 388679)
BoltChallengerTest:testOpenChallengeWithSlotInTheFuture() (gas: 17029)
BoltChallengerTest:testProveAccountData() (gas: 355542)
BoltChallengerTest:testProveHeaderData() (gas: 45617)
BoltChallengerTest:testProveTransactionInclusion() (gas: 176543)
BoltChallengerTest:testResolveChallengeFullDefense() (gas: 575605)
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/
56 changes: 55 additions & 1 deletion bolt-contracts/README.md
merklefruit marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,61 @@ 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
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:
- the block number of the block containing the included transaction
- the RLP-encoded block header of the block containing the included transaction
- the account merkle proof of the sender of the included transaction
- the transaction merkle proof of the included transaction against the header's transaction root
- the transaction index in the block of the 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
LOST and the `BoltChallenger` will keep track of this information for future reference.

### Slashing of validators

If a challenge is LOST (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 lost challenges from the `BoltChallenger` is a trustless way to determine if a slashing request
is valid according to Bolt Protocol rules.

## Testing

Expand Down
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
Loading