Skip to content
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

[NIT-2484] snap-sync consensus 0.2: start reading parent chain from the right block #2296

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
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 @@ -563,7 +565,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)
amsanghi marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -739,6 +759,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
amsanghi marked this conversation as resolved.
Show resolved Hide resolved
// 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
38 changes: 38 additions & 0 deletions staker/rollup_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,44 @@ func (r *RollupWatcher) LookupNode(ctx context.Context, number uint64) (*NodeInf
}, nil
}

func (r *RollupWatcher) LookupNodeByBlockNumber(ctx context.Context, blockNumber uint64) (*NodeInfo, error) {
amsanghi marked this conversation as resolved.
Show resolved Hide resolved
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 {
amsanghi marked this conversation as resolved.
Show resolved Hide resolved
return nil, fmt.Errorf("couldn't find node at the request blockNumber %v", blockNumber)
}
if len(logs) > 1 {
amsanghi marked this conversation as resolved.
Show resolved Hide resolved
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
Loading