Skip to content

Commit

Permalink
snap-sync consensus 0.2: start reading parent chain from the right block
Browse files Browse the repository at this point in the history
  • Loading branch information
amsanghi committed May 13, 2024
1 parent b22cf8f commit 70c0808
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 12 deletions.
81 changes: 70 additions & 11 deletions arbnode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,21 @@ type Node struct {
}

type SnapSyncConfig struct {
Enabled bool
PrevBatchMessageCount uint64
PrevDelayedRead uint64
BatchCount uint64
DelayedCount uint64
Enabled bool
PrevBatchMessageCount uint64
PrevDelayedRead uint64
BatchCount uint64
DelayedCount uint64
ParentChainAssertionBlock uint64
}

var DefaultSnapSyncConfig = SnapSyncConfig{
Enabled: false,
PrevBatchMessageCount: 0,
BatchCount: 0,
DelayedCount: 0,
PrevDelayedRead: 0,
Enabled: false,
PrevBatchMessageCount: 0,
PrevDelayedRead: 0,
BatchCount: 0,
DelayedCount: 0,
ParentChainAssertionBlock: 0,
}

type ConfigFetcher interface {
Expand Down Expand Up @@ -564,7 +566,25 @@ func createNodeImpl(
if err != nil {
return nil, err
}
inboxReader, err := NewInboxReader(inboxTracker, l1client, l1Reader, new(big.Int).SetUint64(deployInfo.DeployedAt), delayedBridge, sequencerInbox, func() *InboxReaderConfig { return &configFetcher.Get().InboxReader })
firstMessageBlock := new(big.Int).SetUint64(deployInfo.DeployedAt)
if config.SnapSyncTest.Enabled {
firstMessageToRead := config.SnapSyncTest.DelayedCount
if firstMessageToRead > config.SnapSyncTest.BatchCount {
firstMessageToRead = config.SnapSyncTest.BatchCount
}
if firstMessageToRead > 0 {
firstMessageToRead--
}
// Find the first block containing the first message to read
// Subtract 1 to get the block before the first message to read,
// this is done to fetch previous batch metadata needed for snap sync.
block, err := FindBlockContainingBatch(ctx, deployInfo.Rollup, l1client, config.SnapSyncTest.ParentChainAssertionBlock, firstMessageToRead-1)
if err != nil {
return nil, err
}
firstMessageBlock.SetUint64(block)
}
inboxReader, err := NewInboxReader(inboxTracker, l1client, l1Reader, firstMessageBlock, delayedBridge, sequencerInbox, func() *InboxReaderConfig { return &configFetcher.Get().InboxReader })
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -740,6 +760,45 @@ func createNodeImpl(
}, nil
}

func FindBlockContainingBatch(ctx context.Context, rollupAddress common.Address, l1Client arbutil.L1Interface, parentChainAssertionBlock uint64, batch uint64) (uint64, error) {
callOpts := bind.CallOpts{Context: ctx}
rollup, err := staker.NewRollupWatcher(rollupAddress, l1Client, callOpts)
if err != nil {
return 0, err
}
high := parentChainAssertionBlock
low := high / 2
// Exponentially reduce high and low by a factor of 2 until lowNode.InboxMaxCount < batch
// This will give us a range (low to high) of blocks that contain the batch
for low > 0 {
lowNode, err := rollup.LookupNodeByBlockNumber(ctx, low)
if err != nil {
return 0, err
}
if lowNode.InboxMaxCount.Uint64() > batch {
high = low
low = low / 2
} else {
break
}
}
// Then binary search between low and high to find the block containing the batch
for low < high {
mid := low + (high-low)/2

midNode, err := rollup.LookupNodeByBlockNumber(ctx, mid)
if err != nil {
return 0, err
}
if midNode.InboxMaxCount.Uint64() < batch {
low = mid + 1
} else {
high = mid
}
}
return low, nil
}

func (n *Node) OnConfigReload(_ *Config, _ *Config) error {
// TODO
return nil
Expand Down
39 changes: 38 additions & 1 deletion staker/rollup_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ func NewRollupWatcher(address common.Address, client arbutil.L1Interface, callOp
if err != nil {
return nil, err
}

return &RollupWatcher{
address: address,
client: client,
Expand Down Expand Up @@ -165,6 +164,44 @@ func (r *RollupWatcher) LookupNode(ctx context.Context, number uint64) (*NodeInf
}, nil
}

func (r *RollupWatcher) LookupNodeByBlockNumber(ctx context.Context, blockNumber uint64) (*NodeInfo, error) {
var query = ethereum.FilterQuery{
FromBlock: big.NewInt(int64(blockNumber)),
ToBlock: big.NewInt(int64(blockNumber)),
Addresses: []common.Address{r.address},
Topics: [][]common.Hash{{nodeCreatedID}},
}
logs, err := r.client.FilterLogs(ctx, query)
if err != nil {
return nil, err
}
if len(logs) == 0 {
return nil, fmt.Errorf("couldn't find node at the request blockNumber %v", blockNumber)
}
if len(logs) > 1 {
return nil, fmt.Errorf("found multiple instances of node at the requested blockNumber %v", blockNumber)
}
ethLog := logs[0]
parsedLog, err := r.ParseNodeCreated(ethLog)
if err != nil {
return nil, err
}
l1BlockProposed, err := arbutil.CorrespondingL1BlockNumber(ctx, r.client, ethLog.BlockNumber)
if err != nil {
return nil, err
}
return &NodeInfo{
NodeNum: parsedLog.NodeNum,
L1BlockProposed: l1BlockProposed,
ParentChainBlockProposed: ethLog.BlockNumber,
Assertion: NewAssertionFromSolidity(parsedLog.Assertion),
InboxMaxCount: parsedLog.InboxMaxCount,
AfterInboxBatchAcc: parsedLog.AfterInboxBatchAcc,
NodeHash: parsedLog.NodeHash,
WasmModuleRoot: parsedLog.WasmModuleRoot,
}, nil
}

func (r *RollupWatcher) LookupNodeChildren(ctx context.Context, nodeNum uint64, nodeHash common.Hash) ([]*NodeInfo, error) {
node, err := r.RollupUserLogic.GetNode(r.getCallOpts(ctx), nodeNum)
if err != nil {
Expand Down

0 comments on commit 70c0808

Please sign in to comment.