-
Notifications
You must be signed in to change notification settings - Fork 449
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
Support the Arbitrum BoLD Challenge Protocol in Nitro #2362
base: master
Are you sure you want to change the base?
Conversation
… into sepolia-tooling-merge
… into sepolia-tooling-merge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
found some pending comments. Not done reviewing
It is no longer required (or even efficient) for the state provider to be populating all the missing leafs in a virtual tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initial
staker/bold_state_provider.go
Outdated
// Produces the L2 execution state to assert to after the previous assertion state. | ||
// Returns either the state at the batch count maxInboxCount or the state maxNumberOfBlocks after previousBlockHash, | ||
// whichever is an earlier state. If previousBlockHash is zero, this function simply returns the state at maxInboxCount. | ||
// TODO: Check the block validator has validated the execution state we are proposing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eljobe WDYT?
staker/bold_state_provider.go
Outdated
} | ||
return nil, err | ||
} | ||
if previousGlobalState != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eljobe let's talk and understand what's going on here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, I think @tsahee has brought up some very good points and we should rework this code to be clearer and to mix fewer of the concerns which should be separate between the Nitro Validator and the BoLD machinery.
staker/bold_state_provider.go
Outdated
// Produces the L2 execution state to assert to after the previous assertion state. | ||
// Returns either the state at the batch count maxInboxCount or the state maxNumberOfBlocks after previousBlockHash, | ||
// whichever is an earlier state. If previousBlockHash is zero, this function simply returns the state at maxInboxCount. | ||
// TODO: Check the block validator has validated the execution state we are proposing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the general sentiment that this method is doing too much. The clearest evidence of this, in my mind, is how much of the code/logic is the same (or nearly the same) as in the mock implementation. I think we have the responsibilities of the nitro node and the bold node out of whack.
For one, I don't think that the state provider should logically be responsible for calculating the history commitment. The history package should be a concern of just the BoLD machinery.
I think the ideal interface here would be more closer to, "Hey Nitro, I need N blocks' end hashes starting at block X." That's pretty much the contract of StatesInBatchRange. The problem that I think this additional method is trying to solve is essentially the problem of "What if the validator simply hasn't executed and validated enough blocks to return all those hashes?" The other thing is that tracking the state of the inbox does feel like it's solidly the responsibility of the Nitro validator. BoLD cares about Assertions, and the Nitro validator cares about L2 Blocks, Inbox Messages, and Machine states within a block.
I think we are closer to the sort of API we want/need with the CollectMachineHashes method. But, even that one is requiring the nitro side to understand concepts which I really think belong clearly in the BoLD machinery's domain. Namely, it talks about BlockChallengeHeight. I don't think that a thing that is supposed to just really efficiently go get a set of machineState hashes in a block with given step sizes should need to know that those step sizes will be different depending on the BlockChallengeHeight. It's also doing too much.
staker/bold_state_provider.go
Outdated
} | ||
return nil, err | ||
} | ||
if previousGlobalState != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previousGlobalState will, in production, never be nil. But, in test cases, nil is passed with maxInboxCount == 0 to bootstrap the genesisBlock. See here: https://github.com/OffchainLabs/bold/blob/9d0448fa760a8925a0ebc3dfb92762705e02c46b/testing/setup/rollup_stack.go#L135
Actually, I guess for brand new arbitrum chains that want to use bold, there would also need to be a similar call during the bootstrapping of the chain. But, we should more clearly document that calling pattern, or make a separate explicit function for that use-case. It's a little unnerving to think that we have to allow silly combinations like maxInboxCount = 30, previousGlobalState = nil.
This also adjusts all the imports to use the lowercase offchainlabs.
Background
This PR includes the Arbitrum BoLD challenge protocol as part of a Nitro node, enabled optionally. The goal is to have Nitro
master
capable of supporting BoLD challenges on Arbitrum Sepolia once the upgrade occurs and on the existing BoLD testnet.BoLD, standing for Bounded Liquidity Delay, is a protocol for resolving disputes over execution of the Arbitrum inbox. The BoLD protocol allows for permissionless validation of Arbitrum One and Nova. It also ensures an upper-bound on withdrawal delays from L2 to L1.
To learn more about the basics of BoLD, see the gentle introduction here, or the research paper here. A presentation explaining what the BoLD software does and how it works can be found here
BoLD Software Responsibilities
BoLD is a modular component of Nitro nodes that can do the following tasks:
All of these responsibilities are performed by the BoLD challenge manager service, which is currently included as a git submodule of Nitro, with its git repository OffchainLabs/bold, with long term plans to port it fully intro Nitro.
Supporting BoLD in Nitro
In order for Nitro to support this BoLD module, Nitro has to provide a dependency to the bold challenge manager that defines the following methods:
We implement these methods in
staker/bold_state_provider.go
and also add a new RPC method to the validation node calledGetMachineHashesWithStepSize
that can execute an Arbitrator machine at a start program counter and collect machine hashes in increments ofstep_size
as required by BoLD.We also implement a new
challengecache
package which can cache hashes retrieved from the validation node in a filesystem hierarchy for fast access by the Nitro node during BoLD challenges. This cache is required for efficient computation of challenge moves, and is a new addition. It stores hashes as bytes in files nested by challenge level hierarchy.Switching from Old Protocol to BoLD at Runtime
To change from the old staker to the BoLD staker at runtime, we provide a new service called
MultiProtocolStaker
, which holds a reference to the old, L1 staker, and the new BoLD staker and can swap to BoLD once it is supported. The way it works is it checks if the rollup contract supports a certain method calledExtraChallengeBlocks
. If the method is unsupported, the Nitro validator should be switching to BoLD.Changelog Summary
Git / Deps
Arbitrator
Nitro Node
StakeToken
address field to the L2 chain info JSONMultiProtocolStaker
instead of aStaker
which is aware of BoLD and can switch protocolschallengecache
package to cache hashes obtained from validation node computation to be used when making moves in BoLDValidation Node API
GetMachineHashesWithStepSize
method that can execute Arbitrator machines at specific program counters, step through them in custom step sizes, and collect machine hashes along the wayMulti Protocol Staker Definition
Testing
TestChallengeProtocolBOLD
which runs a complete challenge, with an L1 node two different L2 nodes disagreeing about the execution of a certain batch posted to the Arbitrum inbox. It uses the BoLD dispute protocol to fully resolve the challengeTestChallengeProtocolBOLD_StateProvider
which tests the invariants of thebold_state_provider.go
implementation needed by the BoLD challenge managerMissing Features