Chained CCIP-Reads are already supported!
Correct, but in a trustless gateway setup, a rogue gateway can provide a variety of status codes that will terminate the CCIP-Read session.
Shuffling the endpoints lets you dodge the rogue gateway via retry.
However, the callback function should be able to signal that the response was unacceptable and that further endpoints should be tried.
An additional OffchainLookup
revert during the callback would be insufficient as the protocol doesn’t reveal the state of the endpoint iterator.
Instead of OffchainNext
, it could just be an overload of OffchainLookup
, where the endpoint array contains some signal value, like ["$next"]
. This would be backwards-compatible as it would just appear like an error to unaware clients.
For open gateways that provide arbitrary storage proofs following some standard, a different solution would be the ability to identify these types of interchangeable endpoints and substitute them with client-side choices.
Edit: If a data URL was a valid CCIP endpoint (maybe it is?), then the contract could do it’s own iteration and randomization by providing pairs for each actual endpoint: [url_i, "data:text/json,{"data":...}]
. If url_i
fails, the data URL will succeed, and the next URL can be tried: [url_i+1, "data..."]
. If url_i
succeeds but is a faux response, the callback can just revert again with [url_i+1, "data:..."]
.
Ah, I see what you mean. Yes, some way for the contract to canonically indicate that the response was unacceptable would be ideal here.
Instead of recursive CCIP-read we can also use multiple gateways as multisig…
0 > start with reverting OffchainLookup with random list of gateways,
eg. we’ve 3 gateways.
1st gateway will read records data from DB/L2 then call another gateway for signature.
- if 1st gateway fails, ccip-read will auto fallback to next gateway in lookup array
2nd gateway will read from their DB/L2 endpoints and reply 1st gateway with signed data.
- if 2nd gateway fails 1st gateway can request 3rd gateway
1st gateway can pack their data + signature with 2nd gateway’s signature in {data:…} so resolver contract can check if same data is signed by 2/3 of unique gateways.
we’re testing around basic multisig gateways for .sol+ENS integration, we’ve dev works paused for now as we need proper ccip-write specs for 2-way read-write.
** still WIP, not tested codes
I created a version of this that works pretty well: resolveworks/OffchainNext.sol
It’s a contract base which has a helper function offchainLookup()
that invokes revert OffchainLookup
with some additional logic:
- It “randomizes” using the current
block.number
and tries pairs[uri_i, data:...]
. - If the response is 200, it calls the original callback, and if that reverts with an error that satisfies
_shouldTryNext() -> bool
, it will try the next endpoint until all endpoints are tried, thenrevert OffchainEOL
. - By default,
_shouldTryNext()
returnstrue
forrevert OffchainNext()
.
It has a blocksmith test, where I give it 5 endpoints:
- a random website
- server that signs
- server that throws
- server that returns the wrong answer
- server that returns the right answer
I call the example CCIP-Read function in a loop and it succeeds 100% of the time, with a randomized order.
adraffy/CCIPRewriter.sol is a resolver that modifies how name
is resolved when input as [name].[basename]
. This is very similar to the XOR where [name].[basename]
resolves name
via ENSIP-10 and then calls the non-ENSIP-10 equivalents instead (ie. an exclusively on-chain version of the name.)
For CCIPRewriter, [name].{base32(endpoint)}.[basename]
resolves name
via ENSIP-10 and then wraps OffchainLookup()
and rewrite urls = [endpoint]
. An on-chain name or a name that doesn’t revert is unaffected.
Two obvious use-cases: debugging (rewrite to localhost) and privacy (rewrite to local gateway.)
Example:
eth.coinbase.debug.eth
- This is using endpoint:
https://raffy.xyz/tog/multi/s2
- This is using endpoint:
eth.coinbase.debug.eth.{https://raffy.xyz/tog/fixed/s2}.rewrite.eth
base32("nb2hi4dthixs64tbmzthsltypf5c65dpm4xwm2lymvsc64zs") = "https://raffy.xyz/tog/fixed/s2"
- Should be the same as:
fixed.debug.eth
- I made a quick tool to create rewritten names
I had this behavior available in my resolver (using debugger → custom ccip rewrite) and found it very useful but this technique makes it use-able anywhere ENSIP-10 is supported.
Edit: since gas was 6 gwei, I deployed a version to mainnet at ccipr.eth
For interested parties it is worth following the governance discussion on the protocol upgrade associated with this update on OP mainnet.
Whilst it is certainly coming, given the complexity of the DisputeGame smart contracts it is not cut and dry that the upgrades will occur on the originally proposed time lines.
Update: The Fjord Network Upgrade is expected to go to a vote on or around June 13. After the veto period ends near June 26, the proposers will ask the Security Council to sign transactions to update the DisputeGameFactory
to use the new FaultDisputeGame
and PermissionedDisputeGame
implementations.
This transaction must be executed before the actual Fjord activation to avoid a broken Fault Proofs system post-activation.
If all goes to plan, the upgrade will occur Wednesday, July 10 2024 at 16:00:01 UTC. Source: Optimism Governance Forum.