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

Fix reorg on init flags #2538

Merged
merged 5 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions arbnode/transaction_streamer.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ func (s *TransactionStreamer) reorg(batch ethdb.Batch, count arbutil.MessageInde
if count == 0 {
return errors.New("cannot reorg out init message")
}

// If not started, use a background context.
// This can happening when reorging on startup using the init flag.
ctx := context.Background()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should no longer be necessary, since now reorg happends after Start

if s.Started() {
ctx = s.GetContext()
}

lastDelayedSeqNum, err := s.getPrevPrevDelayedRead(count)
if err != nil {
return err
Expand Down Expand Up @@ -324,7 +332,7 @@ func (s *TransactionStreamer) reorg(batch ethdb.Batch, count arbutil.MessageInde
continue
}
msgBlockNum := new(big.Int).SetUint64(oldMessage.Message.Header.BlockNumber)
delayedInBlock, err := s.delayedBridge.LookupMessagesInRange(s.GetContext(), msgBlockNum, msgBlockNum, nil)
delayedInBlock, err := s.delayedBridge.LookupMessagesInRange(ctx, msgBlockNum, msgBlockNum, nil)
if err != nil {
log.Error("reorg-resequence: failed to serialize old delayed message from database", "err", err)
continue
Expand Down Expand Up @@ -368,7 +376,7 @@ func (s *TransactionStreamer) reorg(batch ethdb.Batch, count arbutil.MessageInde
s.broadcastMessages(messagesWithComputedBlockHash, count)

if s.validator != nil {
err = s.validator.Reorg(s.GetContext(), count)
err = s.validator.Reorg(ctx, count)
if err != nil {
return err
}
Expand Down
16 changes: 13 additions & 3 deletions cmd/conf/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ type InitConfig struct {
PruneBloomSize uint64 `koanf:"prune-bloom-size"`
PruneThreads int `koanf:"prune-threads"`
PruneTrieCleanCache int `koanf:"prune-trie-clean-cache"`
ResetToMessage int64 `koanf:"reset-to-message"`
RecreateMissingStateFrom uint64 `koanf:"recreate-missing-state-from"`
RebuildLocalWasm bool `koanf:"rebuild-local-wasm"`
ReorgToBatch int64 `koanf:"reorg-to-batch"`
ReorgToMessageBatch int64 `koanf:"reorg-to-message-batch"`
ReorgToBlockBatch int64 `koanf:"reorg-to-block-batch"`
}

var InitConfigDefault = InitConfig{
Expand All @@ -54,9 +56,11 @@ var InitConfigDefault = InitConfig{
PruneBloomSize: 2048,
PruneThreads: runtime.NumCPU(),
PruneTrieCleanCache: gethexec.DefaultCachingConfig.TrieCleanCache,
ResetToMessage: -1,
RecreateMissingStateFrom: 0, // 0 = disabled
RebuildLocalWasm: true,
ReorgToBatch: -1,
ReorgToMessageBatch: -1,
ReorgToBlockBatch: -1,
}

func InitConfigAddOptions(prefix string, f *pflag.FlagSet) {
Expand All @@ -78,9 +82,11 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) {
f.Uint64(prefix+".prune-bloom-size", InitConfigDefault.PruneBloomSize, "the amount of memory in megabytes to use for the pruning bloom filter (higher values prune better)")
f.Int(prefix+".prune-threads", InitConfigDefault.PruneThreads, "the number of threads to use when pruning")
f.Int(prefix+".prune-trie-clean-cache", InitConfigDefault.PruneTrieCleanCache, "amount of memory in megabytes to cache unchanged state trie nodes with when traversing state database during pruning")
f.Int64(prefix+".reset-to-message", InitConfigDefault.ResetToMessage, "forces a reset to an old message height. Also set max-reorg-resequence-depth=0 to force re-reading messages")
f.Uint64(prefix+".recreate-missing-state-from", InitConfigDefault.RecreateMissingStateFrom, "block number to start recreating missing states from (0 = disabled)")
f.Bool(prefix+".rebuild-local-wasm", InitConfigDefault.RebuildLocalWasm, "rebuild local wasm database on boot if needed (otherwise-will be done lazily)")
f.Int64(prefix+".reorg-to-batch", InitConfigDefault.ReorgToBatch, "rolls back the blockchain to a specified batch number")
f.Int64(prefix+".reorg-to-message-batch", InitConfigDefault.ReorgToMessageBatch, "rolls back the blockchain to the first batch at or before a given message index")
f.Int64(prefix+".reorg-to-block-batch", InitConfigDefault.ReorgToBlockBatch, "rolls back the blockchain to the first batch at or before a given block number")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add to Validate() a test that at most one of those is >= 0

}

func (c *InitConfig) Validate() error {
Expand All @@ -99,6 +105,10 @@ func (c *InitConfig) Validate() error {
return nil
}

func (c *InitConfig) IsReorgRequested() bool {
return c.ReorgToBatch >= 0 || c.ReorgToBlockBatch >= 0 || c.ReorgToMessageBatch >= 0
}

var (
acceptedSnapshotKinds = []string{"archive", "pruned", "genesis"}
acceptedSnapshotKindsStr = "(accepted values: \"" + strings.Join(acceptedSnapshotKinds, "\" | \"") + "\")"
Expand Down
54 changes: 39 additions & 15 deletions cmd/nitro/nitro.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ func mainImpl() int {
}
}

if nodeConfig.Init.ThenQuit && nodeConfig.Init.ResetToMessage < 0 {
if nodeConfig.Init.ThenQuit && !nodeConfig.Init.IsReorgRequested() {
return 0
}

Expand Down Expand Up @@ -669,29 +669,53 @@ func mainImpl() int {
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt, syscall.SIGTERM)

exitCode := 0

if err == nil && nodeConfig.Init.ResetToMessage > 0 {
err = currentNode.TxStreamer.ReorgTo(arbutil.MessageIndex(nodeConfig.Init.ResetToMessage))
if err != nil {
fatalErrChan <- fmt.Errorf("error reseting message: %w", err)
exitCode = 1
if err == nil && nodeConfig.Init.IsReorgRequested() {
var batchCount uint64
if nodeConfig.Init.ReorgToBatch >= 0 {
batchCount = uint64(nodeConfig.Init.ReorgToBatch) + 1
} else {
var messageIndex arbutil.MessageIndex
if nodeConfig.Init.ReorgToMessageBatch >= 0 {
messageIndex = arbutil.MessageIndex(nodeConfig.Init.ReorgToMessageBatch)
} else {
messageIndex, err = currentNode.Execution.BlockNumberToMessageIndex(uint64(nodeConfig.Init.ReorgToBlockBatch))
}
// Reorg out the batch containing the next message
var missing bool
batchCount, missing, err = currentNode.InboxTracker.FindInboxBatchContainingMessage(messageIndex + 1)
if err == nil && missing {
err = fmt.Errorf("cannot reorg to unknown message index %v", messageIndex)
}
}
if nodeConfig.Init.ThenQuit {
return exitCode
if err == nil {
err = currentNode.InboxTracker.ReorgBatchesTo(batchCount)
}
if err != nil {
fatalErrChan <- fmt.Errorf("error reorging per init config: %w", err)
} else if nodeConfig.Init.ThenQuit {
return 0
}
}

err = nil
select {
case err := <-fatalErrChan:
case err = <-fatalErrChan:
case <-sigint:
// If there was both a sigint and a fatal error, we want to log the fatal error
select {
case err = <-fatalErrChan:
default:
log.Info("shutting down because of sigint")
}
}

if err != nil {
log.Error("shutting down due to fatal error", "err", err)
defer log.Error("shut down due to fatal error", "err", err)
exitCode = 1
case <-sigint:
log.Info("shutting down because of sigint")
return 1
}

return exitCode
return 0
}

type NodeConfig struct {
Expand Down
18 changes: 3 additions & 15 deletions execution/gethexec/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,6 @@ import (
flag "github.com/spf13/pflag"
)

type DangerousConfig struct {
ReorgToBlock int64 `koanf:"reorg-to-block"`
}

var DefaultDangerousConfig = DangerousConfig{
ReorgToBlock: -1,
}

func DangerousConfigAddOptions(prefix string, f *flag.FlagSet) {
f.Int64(prefix+".reorg-to-block", DefaultDangerousConfig.ReorgToBlock, "DANGEROUS! forces a reorg to an old block height. To be used for testing only. -1 to disable")
}

type Config struct {
ParentChainReader headerreader.Config `koanf:"parent-chain-reader" reload:"hot"`
Sequencer SequencerConfig `koanf:"sequencer" reload:"hot"`
Expand All @@ -49,7 +37,6 @@ type Config struct {
Caching CachingConfig `koanf:"caching"`
RPC arbitrum.Config `koanf:"rpc"`
TxLookupLimit uint64 `koanf:"tx-lookup-limit"`
Dangerous DangerousConfig `koanf:"dangerous"`
EnablePrefetchBlock bool `koanf:"enable-prefetch-block"`
SyncMonitor SyncMonitorConfig `koanf:"sync-monitor"`

Expand Down Expand Up @@ -89,7 +76,6 @@ func ConfigAddOptions(prefix string, f *flag.FlagSet) {
CachingConfigAddOptions(prefix+".caching", f)
SyncMonitorConfigAddOptions(prefix+".sync-monitor", f)
f.Uint64(prefix+".tx-lookup-limit", ConfigDefault.TxLookupLimit, "retain the ability to lookup transactions by hash for the past N blocks (0 = all blocks)")
DangerousConfigAddOptions(prefix+".dangerous", f)
f.Bool(prefix+".enable-prefetch-block", ConfigDefault.EnablePrefetchBlock, "enable prefetching of blocks")
}

Expand All @@ -103,7 +89,6 @@ var ConfigDefault = Config{
TxPreChecker: DefaultTxPreCheckerConfig,
TxLookupLimit: 126_230_400, // 1 year at 4 blocks per second
Caching: DefaultCachingConfig,
Dangerous: DefaultDangerousConfig,
Forwarder: DefaultNodeForwarderConfig,
EnablePrefetchBlock: true,
}
Expand Down Expand Up @@ -348,6 +333,9 @@ func (n *ExecutionNode) ResultAtPos(pos arbutil.MessageIndex) (*execution.Messag
func (n *ExecutionNode) ArbOSVersionForMessageNumber(messageNum arbutil.MessageIndex) (uint64, error) {
return n.ExecEngine.ArbOSVersionForMessageNumber(messageNum)
}
func (n *ExecutionNode) BlockNumberToMessageIndex(blockNum uint64) (arbutil.MessageIndex, error) {
return n.ExecEngine.BlockNumberToMessageIndex(blockNum)
}

func (n *ExecutionNode) RecordBlockCreation(
ctx context.Context,
Expand Down
1 change: 1 addition & 0 deletions execution/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type FullExecutionClient interface {
Maintenance() error

ArbOSVersionForMessageNumber(messageNum arbutil.MessageIndex) (uint64, error)
BlockNumberToMessageIndex(blockNum uint64) (arbutil.MessageIndex, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that reorg is a good enough reason to add it to the API.
reorg-to-*batch will always be an advanced functionality, that should only be used by those who know what they are doing. I don't mind making it a little harder.

We should make genesis-block-number be easy to find. It's in chain-config which sounds reasonable.. maybe we should print chain config on init so it'll be even easier to find?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most 3rd party providers only really know block numbers. Is there a significant downside to adding this interface? It seems generally useful to me

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this a bit more, we have access to the chain config directly here, so I switched to using that instead and removed this interface

}

// not implemented in execution, used as input
Expand Down
Loading