Closed bitwiseguy closed 1 month ago
Fault Game Genesis Output Root
for permissioned game only chains can be anything - makes sense to require it to a specific and obviously wrong value like 0xdead...
. For permissionless games this should be verified as being the correct output root for the canonical block at Fault Game Genesis Block
and that the block is finalized. When configuring the chain it should be set to a fairly recent finalized block but is otherwise arbitrary.
Fault Game Absolute Prestate
- should verify that this matches the hash of a op-program release - may want to require it to match a governance approved op-program release for mainnet chains. We verify that the prestate build is reproducible so have a list of versions and their hashes in https://github.com/ethereum-optimism/optimism/blob/a2653a38946e697ef4f1a76b62d9d77acd8a8cad/.circleci/config.yml#L1079-L1106 - would be quite happy to start pulling that list from somewhere better and maybe it could be shared. We do want to include builds that aren't yet governance approved in the list we test though. There's also a script to rebuild all released prestates: https://github.com/ethereum-optimism/optimism/blob/52d0e60c16498ad4efec8798e3fc1b36b13f46a2/op-program/scripts/build-prestates.sh
@mds1 what level of chain should all of these new param checks be run against? The options are:
My thinking would be "standard chain candidates" (and stricter, so standard chains also), but would like to confirm with @ajsutton
Definitely for standard chains since the configurability.md
part of specs is intended to be the definition of standard chains.
So I think it also makes sense to apply to standard chain candidates at least to flag something that's not yet standard. I assume that part of becoming actually standard means checking that no invalid withdrawals were ever allowed. Getting these config params wrong can lead to dispute games resolving incorrectly and invalid withdrawals if no-one steps in. The same can happen by just not running challenger or a malicious permissioned proposer/challenger though so I don't think we need to worry about bad historic configurations since we have to check for potential abuse anyway.
Universal chains seems incredibly broad so not really sure what threshold of checks would/should apply there. They may well have reasons to change a bunch of the params from the fixed value for standard configs, and if they're using permissioned game then the genesis output root and absolute prestate may not be set correctly so those checks probably don't mean much.
So yeah, standard chain candidates and stricter makes sense to me.
@mds1 @ajsutton
It sounds like we need to detect whether a chain is using permissioned vs permissionless fault proofs, and base some expected results on which flavor of fault proofs is used. What is the best way to tell [1] that a chain is using fault proofs and [2] which type of fault proof is used? Are there any smart contracts methods I can query that would give me that information directly? Or should I imply it from the existence of PermissionedDisputeGame
and maybe some other contract addresses in the chain's config?
OptimismPortal.respectedGameType would tell you what's currently in use (0 is permissionless, 1 is permissioned). But it may be better to relax checks for chains that don't have an implementation for the permissionless game at all (DisputeGameFactory.gameImpls(0) is the 0 address).
@mds1 @ajsutton getting closer but have a few more questions:
OptimismPortal.respectedGameType would tell you what's currently in use (0 is permissionless, 1 is permissioned)
Will use that call to determine permissionless vs permissioned. I can then use the return value to pass the arg to this AnchorStateRegistryProxy.anchors(uint32) call.
OptimismPortal.respectedGameType
indicates the chains is using permissionless?may be better to relax checks for chains that don't have an implementation for the permissionless game
Fault Game Genesis Output Root for permissioned game only chains can be anything - makes sense to require it to a specific and obviously wrong value like 0xdead.... For permissionless games this should be verified as being the correct output root for the canonical block at Fault Game Genesis Block and that the block is finalized. When configuring the chain it should be set to a fairly recent finalized block but is otherwise arbitrary.
AnchorStateRegistry.anchors(1)
, since this chain is on permissioned proofs based on the OptimismPortal.respectedGameType
return value. However, instead of getting a root hash of 0xdead000000000000000000000000000000000000000000000000000000000000
as expected based on the notion doc, I got 0xa4988434f3931ecf3169f182985899e9ee9d615c8e905af4c03c79df6d25562a
. Any idea what is causing that discrepancy?Fault Game Genesis Output Root
check: how do I determine if the output root is correct? That output root hash should match a block hash of a l2 block? Where do I find the l2 block number? I see the PermissionedDisputeGame.l2BlockNumber()
function, but is that the right one to call for a permissionless
chain?I added a file here that keeps track of all the op-program
prestate hashes that will allow the Fault Game Absolute Prestate
test to pass. This follows a pattern we have established for tracking standard config values for other validation checks. Would it be acceptable to add a step to the op-program
release flow to update that file with new standard release version+hash?
Should we exclude all checks on the PermissionedDisputeGame contract for chains where the call to OptimismPortal.respectedGameType indicates the chains is using permissionless?
No, chains using permissionless may need to switch back to permissioned if there are issues, so we want to know that it is correctly configured and ready to go.
Can you explain this a bit more? Which validation checks could be relaxed?
Mostly you'd skip all the checks for permisisionless since it doesn't exist. You don't need op-program to be a standard value (though it's recommended still to make upgrading to permissionless later easier). The anchor state for the permissioned game would be allowed to be either a correct finalized output root or something like 0xdead. If permissionless games are deployed, even if they're not active, we could require all games types to have a valid finalized output root and not allow 0xdead.
In the context of the validation checks, is there a distinction between "permissioned game only" chains and "permissioned with option to turn on permissionless"? Or are there only two categories: [1] permissioned and [2] permissionless?
You could boil it down to just two categories but they would be whether the permissionless game type is deployed or not. Which game is currently in use doesn't matter (the guardian can change that), which game types are available is meaningful (ProxyAdminOwner has to change that). As mentioned above, you could make checks on the permissioned game a bit more strict if permissionless is deployed but you don't need to. It sounds like it's probably better to keep it simple and just enforce certain checks on the permissionless game (if present) and the slightly relaxed checks on the permissioned one (eg accept invalid anchor state root).
For op-mainnet I called AnchorStateRegistry.anchors(1), since this chain is on permissioned proofs based on the OptimismPortal.respectedGameType return value. However, instead of getting a root hash of 0xdead000000000000000000000000000000000000000000000000000000000000 as expected based on the notion doc, I got 0xa4988434f3931ecf3169f182985899e9ee9d615c8e905af4c03c79df6d25562a. Any idea what is causing that discrepancy?
I think this was answered in discord but for the record, the AnchorStateRegistry
is updated when games of that type resolve as valid. So for permissioned games we should allow it to start with something like 0xdead but as it updates it will become a valid safe output root which will almost certainly also be finalized unless L1 fails to finalise for at least 3.5 days. If an invalid proposal incorrectly resolves as valid the AnchorStateRegistry
will be updated with that invalid output root and the Guardian will need to step in to fix it (as well as blacklist the game to prevent withdrawals etc), so during incidents you may see the check fail because of an invalid anchor state until it gets fixed.
For permissionless Fault Game Genesis Output Root check: how do I determine if the output root is correct? That output root hash should match a block hash of a l2 block? Where do I find the l2 block number? I see the PermissionedDisputeGame.l2BlockNumber() function, but is that the right one to call for a permissionless chain?
The AnchorStateRegistry
should return both the output root and L2 block number it comes from. It returns a OutputRoot
struct which is the output root hash and the l2 block number. So just AnchorStateRegistry.anchors(<gameType>)
should give you the inputs. Checking the output root is correct depends on having access to the RPC for an op-node instance which can be hard to find.
Both PermissionedDisputeGame
and FaultDisputeGame
expose a l2BlockNumber()
function which is the L2 block number the proposal is for but that may not be the one that's in the AnchorStateRegistry
and it will only be set for actual games, not the implementation contract you get back from DisputeGameFactory.gameImpls
.
In general, I wonder if superchain-registry
is the right place to be trying to check the anchor state. It makes sense to me for it to check the initial anchor state (the Fault Game Genesis Output Root
) specified in the deploy config, but continually monitoring the anchor states as they update feels more like a security response kind of monitoring. The superchain-registry doesn't try to monitor that all withdrawals are valid for example. We do want that monitoring, this just doesn't seem like the right place.
Additional params added here. This section shows the checks that smart-contracts team did manually that need to be added to the Superchain Registry
Details on some of the new params (work with proofs team to fill in the gap):
Fault Game Genesis Output Root
: will be the same for all chains deploying straight to permissioned, but not necessarily for existing chains that upgrade to permissionless fault proofsFault Game Genesis Block
: Zero for all chains that use fault proofs (permissioned or permissionless) since genesis, but unsure what it should be for chains upgrading to fault proofsFault Game Absolute Prestate
: for all new chains we expect this value, but it changes with new op-program releases (I am unsure how frequently those are)Large Preimage Proposal Challenge Period
: Must be the same for all chains, whether new or existingMinimum Large Preimage Proposal Size, Bond Withdrawal Delay, Game Clock Extension, Max Game Clock Duration, Fault Game Split Depth, Fault Game Max Depth
: Must be the same for all chains, whether new or existing