Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
c561c38f
Commit
c561c38f
authored
Apr 05, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove implementation details
Updates toc Address Mark's comments
parent
b31146ac
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
57 additions
and
44 deletions
+57
-44
dispute-game-interface.md
specs/dispute-game-interface.md
+22
-13
dispute-game.md
specs/dispute-game.md
+35
-31
No files found.
specs/dispute-game-interface.md
View file @
c561c38f
...
...
@@ -65,17 +65,20 @@ type Claim is bytes32;
The dispute game factory is responsible for creating new
`DisputeGame`
contracts
given a
`GameType`
and a root
`Claim`
. Challenger agents will listen to the
`DisputeGameCreated`
events that are emitted by the factory in order to keep up
`DisputeGameCreated`
events that are emitted by the factory as well as other events
that pertain to detecting fault (i.e.
`OutputProposed(bytes32,uint256,uint256,uint256)`
) in order to keep up
with on-going disputes in the protocol.
For the factory, a
[
Huff
](
https://huff.sh
)
implementation of
[
`clones-with-immutable-args`
](
https://github.com/wighawag/clones-with-immutable-args/tree/master
)
by @wighawag is used to create Clones. Each
`GameType`
has a corresponding implementation within the factory,
and when a new game is created, the factory creates a clone of the
`GameType`
's
pre-deployed implementation contract.
A
[
`clones-with-immutable-args`
](
https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args
)
factory
(originally by @wighawag, but forked by @Saw-mon-and-Natalie) is used to create Clones. Each
`GameType`
has
a corresponding implementation within the factory, and when a new game is created, the factory creates a
clone of the
`GameType`
's pre-deployed implementation contract.
When the
`DisputeGameFactory`
creates a new
`DisputeGame`
contract, it calls
`initialize()`
on the clone to set up the game.
The
`rootClaim`
of created dispute games can either be a claim that the creator agrees or disagrees with.
This is an implementation detail that is left up to the
`IDisputeGame`
to handle within its
`resolve`
function.
When the
`DisputeGameFactory`
creates a new
`DisputeGame`
contract, it calls
`initialize()`
on the clone to
set up the game.
```
solidity
/// @title IDisputeGameFactory
...
...
@@ -87,18 +90,19 @@ interface IDisputeGameFactory {
/// @param rootClaim The root claim of the dispute game
event DisputeGameCreated(address indexed disputeProxy, GameType indexed gameType, Claim indexed rootClaim);
/// @notice `games`
is a mapping that maps the hash of `gameType ++ rootClaim ++ extraData` to the deployed
/// `DisputeGame` clone.
/// @notice `games`
queries an internal a mapping that maps the hash of `gameType ++ rootClaim ++ extraData`
///
to the deployed
`DisputeGame` clone.
/// @dev `++` equates to concatenation.
/// @param gameType The type of the DisputeGame - used to decide the proxy implementation
/// @param rootClaim The root claim of the DisputeGame.
/// @param extraData Any extra data that should be provided to the created dispute game.
/// @return _proxy The clone of the `DisputeGame` created with the given parameters.
address(0)
if nonexistent.
/// @return _proxy The clone of the `DisputeGame` created with the given parameters.
Returns `address(0)`
if nonexistent.
function games(GameType gameType, Claim rootClaim, bytes calldata extraData) external view returns (IDisputeGame _proxy);
/// @notice `gameImpls` is a mapping that maps `GameType`s to their respective `IDisputeGame` implementations.
/// @param gameType The type of the dispute game.
/// @return _impl The address of the implementation of the game type. Will be cloned on creation.
/// @return _impl The address of the implementation of the game type. Will be cloned on creation of a new dispute game
/// with the given `gameType`.
function gameImpls(GameType gameType) public view returns (IDisputeGame _impl);
/// @notice The owner of the contract.
...
...
@@ -114,6 +118,7 @@ interface IDisputeGameFactory {
function create(GameType gameType, Claim rootClaim, bytes calldata extraData) external returns (IDisputeGame proxy);
/// @notice Sets the implementation contract for a specific `GameType`
/// @dev May only be called by the `owner`.
/// @param gameType The type of the DisputeGame
/// @param impl The implementation contract for the given `GameType`
function setImplementation(GameType gameType, IDisputeGame impl) external;
...
...
@@ -200,6 +205,9 @@ interface IDisputeGame_OutputAttestation is IDisputeGame {
/// @custom:invariant The `signatureThreshold` may never be greater than the length of the `signerSet`.
function signatureThreshold() public view returns (uint16 _signatureThreshold);
/// @notice Returns the L2 Block Number that the `rootClaim` commits to. Exists within the `extraData`.
function l2BlockNumber() public view returns (uint256 _l2BlockNumber);
/// @notice Challenge the `rootClaim`.
/// @dev - If the `ecrecover`ed address that created the signature is not a part of the
/// signer set returned by `signerSet`, this function should revert.
...
...
@@ -209,7 +217,8 @@ interface IDisputeGame_OutputAttestation is IDisputeGame {
/// the function should call the `resolve` function to resolve the game as `CHALLENGER_WINS`.
/// - When the game resolves, the bond attached to the root claim should be distributed among
/// the signers who participated in challenging the invalid claim.
/// @param signature A signed message of the `rootClaim` from the attestor's EOA.
/// @param signature An EIP-712 signature committing to the `rootClaim` and `l2BlockNumber` (within the `extraData`)
/// from a key that exists within the `signerSet`.
function challenge(bytes calldata signature) external;
}
```
specs/dispute-game.md
View file @
c561c38f
...
...
@@ -8,37 +8,47 @@
-
[
Smart Contract Implementation
](
#smart-contract-implementation
)
-
[
Attestation Structure
](
#attestation-structure
)
-
[
Why EIP-712
](
#why-eip-712
)
-
[
Offchain Actor
](
#offchain-actor
)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Attestation Dispute Game
The attestation based dispute game is meant to be a dispute game based on social consensus that
can progressively decentralize over time with larger participant sets. When submitting an output
proposal is permissionless, a social quorum can be used to revert "invalid" output proposals.
A set of attestors is maintained and
[
EIP-712
](
https://eips.ethereum.org/EIPS/eip-712
)
signatures
over canonical output roots can be used as attestations.
The output attestation based dispute game shifts the current permissioned output proposal process
to a permissionless, social-consensus based architecture that can progressively decentralize over
time by increasing the size of the signer set. In this "game," output proposals can be submitted
permissionlessly. To prevent "invalid output proposals," a social quorum can revert an output proposal
when an invalid one is discovered. The set of signers is maintained in the
`SystemConfig`
contract,
and these signers will issue
[
EIP-712
](
https://eips.ethereum.org/EIPS/eip-712
)
signatures
over canonical output roots and the
`l2BlockNumber`
s they commit to as attestations. To learn more,
see the
[
DisputeGame Interface Spec
](
./dispute-game-interface.md
)
.
In the above language, an "invalid output proposal" is defined as an output proposal that represents
a non-canonical state of the L2 chain.
### Smart Contract Implementation
The
`AttestationDisputeGame`
should implement the dispute game interface and also be able to call
out to the disputable interface. It is expected that a contract that implements the disputable
interface will have permissions such that the
`AttestationDisputeGame`
has rights to alter its state.
The
`AttestationDisputeGame`
should implement the
`IDisputeGame`
interface and also be able to call
out to the
`L2OutputOracle`
. It is expected that the
`L2OutputOracle`
will grant permissions to
`AttestationDisputeGame`
contracts to call its
`deleteL2Outputs`
function at the
*specific*
`l2BlockNumber`
that is embedded in the
`AttestationDisputeGame`
's
`extraData`
.
The
`AttestationDisputeGame`
should be configured with a quorum ratio at deploy time. It should also
maintain a set of attestor accounts. The ability to add and remove attestor accounts should be
enabled by a single immutable account. It should be impossible to remove accounts such that quorum
maintain a set of attestor accounts, which is fetched by the
`SystemConfig`
contract and snapshotted
at deploy time. This snapshot is necessary to have a fixed upper bound on resolution cost, which in
turn gives a fix cost for the necessary bond attached to output proposals.
The ability to add and remove attestor accounts should be enabled by a single immutable
account that controls the
`SystemConfig`
. It should be impossible to remove accounts such that quorum
is not able to be reached. It is ok to allow accounts to be added or removed in the middle of an
open challenge.
open challenge
, as it will not affect the
`signerSet`
that exists within open challenges
.
A challenge is
opened when an EIP-712 based attestation is presented to the contract and the signer
is in the set of attestors
. Multiple challenges should be able to run in parallel.
A challenge is
created when an alternative output root for a given
`l2BlockNumber`
is presented to the
`DisputeGameFactory`
contract
. Multiple challenges should be able to run in parallel.
For simplicity, the
`AttestationDisputeGame`
does not need to track what output proposals are
committed to as part of the attestations
, it only needs to check that the attested value is
different than the proposed value. If this is not checked, then it will be possible to remov
e
output
s that are in agreement with the attestations and create a griefing vector.
committed to as part of the attestations
. It only needs to check that the attested output root
is different than the proposed output root. If this is not checked, then it will be possibl
e
to remove output proposal
s that are in agreement with the attestations and create a griefing vector.
#### Attestation Structure
...
...
@@ -49,6 +59,14 @@ defined as the following:
TYPE_HASH = keccak256("Dispute(bytes32 outputRoot,uint256 l2BlockNumber)");
```
The components for the
`typeHash`
are as follows:
-
`outputRoot`
- The
**correct**
output root that commits to the given
`l2BlockNumber`
. This should be a
positive attestation where the
`rootClaim`
of the
`AttestationDisputeGame`
is the
**correct**
output root
for the given
`l2BlockNumber`
.
-
`l2BlockNumber`
- The L2 block number that the
`outputRoot`
commits to. The
`outputRoot`
should commit
to the entirety of the L2 state from genesis up to and including this
`l2BlockNumber`
.
### Why EIP-712
It is important to use EIP-712 to decouple the originator of the transaction and the attestor. This
...
...
@@ -57,17 +75,3 @@ for ensuring that all output proposals submitted to the network will not allow f
from the bridge.
It is important to have replay protection to ensure that attestations cannot be used more than once.
### Offchain Actor
The offchain actor should be able to custody an attestation key as well as a transaction signing key.
The offchain actor is expected to watch for each output proposal that is submitted to the
`L2OutputOracle`
and then check the value against the value returned from a trusted RPC endpoint.
If the trusted value does not match what was submitted to the chain, the actor is expected to submit
an EIP-712 signature to the
`AttestationDisputeGame`
contract. After a quorum of signatures are sent
to the contract, the
`AttestationDisputeGame`
will call the
`L2OutputOracle`
and remove the
malicious output proposal.
Longer term, the actor should be capible of calling out to an "Attestation API", so that it will no
longer be responsible for custodying the attestation key itself and instead can rely on public
infrastructure to get attestations.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment