From f29e6ddb652baa67c924d418bd5ff045df3f278c Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:14:58 -0700 Subject: [PATCH 1/9] feat: shutdown node at upgrade height --- cmd/geth/main.go | 3 +++ cmd/utils/cmd.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a94a49ea7daf..08e7c1d5b8b8 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -355,6 +355,9 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon // Start up the node itself utils.StartNode(ctx, stack, isConsole) + upgradeBlockHeight := uint64(10) + utils.ShutdownAtUpgradeBlockHeight(ctx, stack, upgradeBlockHeight) + // Unlock any account specifically requested unlockAccounts(ctx, stack) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 4b5716466556..46e4b5325648 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -123,6 +123,35 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { }() } +func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, upgradeBlockHeight uint64) { + sub := n.EventMux().Subscribe(core.ChainHeadEvent{}) + go func() { + defer sub.Unsubscribe() + for { + select { + case <-ctx.Done(): + log.Info("ShutdownAtUpgradeBlockHeight: context cancelled, exiting goroutine") + return + case ev, ok := <-sub.Chan(): + if !ok { + log.Error("ShutdownAtUpgradeBlockHeight: subscription closed, exiting goroutine") + return + } + ch, ok := ev.Data.(core.ChainHeadEvent) + if !ok { + log.Error("ShutdownAtUpgradeBlockHeight: failed to convert ChainHeadEvent, exiting goroutine") + continue + } + if ch.Block.Number().Uint64() >= upgradeBlockHeight { + log.Info("Target upgrade block height reached, initiating shutdown", "block", ch.Block.Number().Uint64()) + n.Close() + return + } + } + } + }() +} + func monitorFreeDiskSpace(sigc chan os.Signal, path string, freeDiskSpaceCritical uint64) { if path == "" { return From 08c0a7669a9db6bc4270abab694617c48fc2cfd1 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:31:32 -0700 Subject: [PATCH 2/9] Update cmd.go --- cmd/utils/cmd.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 46e4b5325648..6e882c6c99da 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -124,6 +124,7 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { } func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, upgradeBlockHeight uint64) { + log.Info("Starting goroutine to shutdown at upgrade block height", "upgradeBlockHeight", upgradeBlockHeight) sub := n.EventMux().Subscribe(core.ChainHeadEvent{}) go func() { defer sub.Unsubscribe() From e7c497b28f7a5d8d7f1e3e21d38ed02a07360820 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:51:28 -0700 Subject: [PATCH 3/9] shutdown after startNode completes --- cmd/geth/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 08e7c1d5b8b8..c6cb9fc39e25 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -342,6 +342,10 @@ func geth(ctx *cli.Context) error { defer stack.Close() startNode(ctx, stack, backend, false) + + upgradeBlockHeight := uint64(10) + utils.ShutdownAtUpgradeBlockHeight(ctx, stack, upgradeBlockHeight) + stack.Wait() return nil } @@ -355,9 +359,6 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon // Start up the node itself utils.StartNode(ctx, stack, isConsole) - upgradeBlockHeight := uint64(10) - utils.ShutdownAtUpgradeBlockHeight(ctx, stack, upgradeBlockHeight) - // Unlock any account specifically requested unlockAccounts(ctx, stack) From 768a50b6c8a27412a505f71215ca743a08668dde Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 4 Jun 2025 18:22:12 -0700 Subject: [PATCH 4/9] use ethClient --- cmd/geth/main.go | 6 +++--- cmd/utils/cmd.go | 22 ++++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index c6cb9fc39e25..3bce579d93d4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -343,9 +343,6 @@ func geth(ctx *cli.Context) error { startNode(ctx, stack, backend, false) - upgradeBlockHeight := uint64(10) - utils.ShutdownAtUpgradeBlockHeight(ctx, stack, upgradeBlockHeight) - stack.Wait() return nil } @@ -370,6 +367,9 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon rpcClient := stack.Attach() ethClient := ethclient.NewClient(rpcClient) + upgradeBlockHeight := uint64(10) + utils.ShutdownAtUpgradeBlockHeight(ctx, stack, ethClient, upgradeBlockHeight) + go func() { // Open any wallets already attached for _, wallet := range stack.AccountManager().Wallets() { diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 6e882c6c99da..b9acef1e4731 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -21,6 +21,7 @@ import ( "bufio" "bytes" "compress/gzip" + "context" "crypto/sha256" "errors" "fmt" @@ -40,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/era" @@ -123,28 +125,28 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { }() } -func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, upgradeBlockHeight uint64) { +func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, ethClient *ethclient.Client, upgradeBlockHeight uint64) { log.Info("Starting goroutine to shutdown at upgrade block height", "upgradeBlockHeight", upgradeBlockHeight) - sub := n.EventMux().Subscribe(core.ChainHeadEvent{}) go func() { + headers := make(chan *types.Header) + sub, err := ethClient.SubscribeNewHead(context.Background(), headers) + if err != nil { + log.Error("ShutdownAtUpgradeBlockHeight: failed to subscribe to new head", "err", err) + return + } defer sub.Unsubscribe() for { select { case <-ctx.Done(): log.Info("ShutdownAtUpgradeBlockHeight: context cancelled, exiting goroutine") return - case ev, ok := <-sub.Chan(): + case header, ok := <-headers: if !ok { log.Error("ShutdownAtUpgradeBlockHeight: subscription closed, exiting goroutine") return } - ch, ok := ev.Data.(core.ChainHeadEvent) - if !ok { - log.Error("ShutdownAtUpgradeBlockHeight: failed to convert ChainHeadEvent, exiting goroutine") - continue - } - if ch.Block.Number().Uint64() >= upgradeBlockHeight { - log.Info("Target upgrade block height reached, initiating shutdown", "block", ch.Block.Number().Uint64()) + if header.Number.Uint64() >= upgradeBlockHeight { + log.Info("Target upgrade block height reached, initiating shutdown", "block", header.Number.Uint64()) n.Close() return } From b2f2783bed463a3c940731903072a569bfb236f5 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 4 Jun 2025 18:26:39 -0700 Subject: [PATCH 5/9] Update main.go --- cmd/geth/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3bce579d93d4..ae529173946b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -342,7 +342,6 @@ func geth(ctx *cli.Context) error { defer stack.Close() startNode(ctx, stack, backend, false) - stack.Wait() return nil } From 6b5a121445ea12d35604c266a640b967dcd1ddac Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:16:07 -0700 Subject: [PATCH 6/9] change to timestamp --- cmd/geth/main.go | 4 ++-- cmd/utils/cmd.go | 13 +++++++++---- cmd/utils/flags.go | 9 +++++++++ node/config.go | 3 +++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ae529173946b..36daf10ae400 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -147,6 +147,7 @@ var ( utils.LogDebugFlag, utils.LogBacktraceAtFlag, utils.ZeroFeeAddressesFlag, + utils.UpgradeTimestampFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ @@ -366,8 +367,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon rpcClient := stack.Attach() ethClient := ethclient.NewClient(rpcClient) - upgradeBlockHeight := uint64(10) - utils.ShutdownAtUpgradeBlockHeight(ctx, stack, ethClient, upgradeBlockHeight) + utils.ShutdownAtUpgradeTimestamp(ctx, stack, ethClient) go func() { // Open any wallets already attached diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index b9acef1e4731..e0d7b0ce59c6 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -125,8 +125,13 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { }() } -func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, ethClient *ethclient.Client, upgradeBlockHeight uint64) { - log.Info("Starting goroutine to shutdown at upgrade block height", "upgradeBlockHeight", upgradeBlockHeight) +func ShutdownAtUpgradeTimestamp(ctx *cli.Context, n *node.Node, ethClient *ethclient.Client) { + upgradeTimestamp := n.Config().UpgradeTimestamp + if upgradeTimestamp == 0 { + log.Info("Upgrade timestamp is not set, skipping shutdown at upgrade timestamp") + return + } + log.Info("Starting goroutine to shutdown at upgrade timestamp", "upgradeTimestamp", upgradeTimestamp) go func() { headers := make(chan *types.Header) sub, err := ethClient.SubscribeNewHead(context.Background(), headers) @@ -145,8 +150,8 @@ func ShutdownAtUpgradeBlockHeight(ctx *cli.Context, n *node.Node, ethClient *eth log.Error("ShutdownAtUpgradeBlockHeight: subscription closed, exiting goroutine") return } - if header.Number.Uint64() >= upgradeBlockHeight { - log.Info("Target upgrade block height reached, initiating shutdown", "block", header.Number.Uint64()) + if header.Time >= upgradeTimestamp { + log.Info("Target upgrade timestamp reached, initiating shutdown", "timestamp", header.Time) n.Close() return } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 6e82143e3565..46a6d712b569 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -566,6 +566,12 @@ var ( Category: flags.MiscCategory, } + UpgradeTimestampFlag = &cli.Uint64Flag{ + Name: "upgrade-timestamp", + Usage: "Timestamp at which the node will shut down for upgrade", + Category: flags.MiscCategory, + } + // RPC settings IPCDisabledFlag = &cli.BoolFlag{ Name: "ipcdisable", @@ -1405,6 +1411,9 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(LogDebugFlag.Name) { log.Warn("log.debug flag is deprecated") } + if ctx.IsSet(UpgradeTimestampFlag.Name) { + cfg.UpgradeTimestamp = ctx.Uint64(UpgradeTimestampFlag.Name) + } } func setSmartCard(ctx *cli.Context, cfg *node.Config) { diff --git a/node/config.go b/node/config.go index 949db887e4e4..e0a59f9da35d 100644 --- a/node/config.go +++ b/node/config.go @@ -211,6 +211,9 @@ type Config struct { EnablePersonal bool `toml:"-"` DBEngine string `toml:",omitempty"` + + // UpgradeTimestamp is approximately the timestamp where the node will shut down for upgrade. + UpgradeTimestamp uint64 `toml:",omitempty"` } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into From e31ad0db64dda963f19946aef5471fe2ee48e035 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:46:36 -0700 Subject: [PATCH 7/9] nits --- cmd/utils/cmd.go | 8 ++++---- cmd/utils/flags.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index e0d7b0ce59c6..5d5d10552b62 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -136,22 +136,22 @@ func ShutdownAtUpgradeTimestamp(ctx *cli.Context, n *node.Node, ethClient *ethcl headers := make(chan *types.Header) sub, err := ethClient.SubscribeNewHead(context.Background(), headers) if err != nil { - log.Error("ShutdownAtUpgradeBlockHeight: failed to subscribe to new head", "err", err) + log.Error("ShutdownAtUpgradeTimestamp: failed to subscribe to new head", "err", err) return } defer sub.Unsubscribe() for { select { case <-ctx.Done(): - log.Info("ShutdownAtUpgradeBlockHeight: context cancelled, exiting goroutine") + log.Info("ShutdownAtUpgradeTimestamp: context cancelled, exiting goroutine") return case header, ok := <-headers: if !ok { - log.Error("ShutdownAtUpgradeBlockHeight: subscription closed, exiting goroutine") + log.Error("ShutdownAtUpgradeTimestamp: subscription closed, exiting goroutine") return } if header.Time >= upgradeTimestamp { - log.Info("Target upgrade timestamp reached, initiating shutdown", "timestamp", header.Time) + log.Info("Target upgrade timestamp reached, initiating shutdown", "header_timestamp", header.Time) n.Close() return } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 46a6d712b569..633741d4e065 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -568,7 +568,7 @@ var ( UpgradeTimestampFlag = &cli.Uint64Flag{ Name: "upgrade-timestamp", - Usage: "Timestamp at which the node will shut down for upgrade", + Usage: "Timestamp (in unix milliseconds) at which the node will shut down for upgrade", Category: flags.MiscCategory, } From 35d2284ba8e7e6dc873de6a164341d550e7058cf Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:48:05 -0700 Subject: [PATCH 8/9] put ms in flag name --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 633741d4e065..b1dd93268c34 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -567,7 +567,7 @@ var ( } UpgradeTimestampFlag = &cli.Uint64Flag{ - Name: "upgrade-timestamp", + Name: "upgrade-timestamp-ms", Usage: "Timestamp (in unix milliseconds) at which the node will shut down for upgrade", Category: flags.MiscCategory, } From 549370c4ff81f6482721da1e247910f029f328e4 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:41:08 -0700 Subject: [PATCH 9/9] Update cmd.go --- cmd/utils/cmd.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 5d5d10552b62..6d222c684739 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -150,8 +150,9 @@ func ShutdownAtUpgradeTimestamp(ctx *cli.Context, n *node.Node, ethClient *ethcl log.Error("ShutdownAtUpgradeTimestamp: subscription closed, exiting goroutine") return } - if header.Time >= upgradeTimestamp { - log.Info("Target upgrade timestamp reached, initiating shutdown", "header_timestamp", header.Time) + shutdownTimestamp := upgradeTimestamp - 200 // Timestamps are in ms, block time is 200ms + if header.Time >= shutdownTimestamp { + log.Info("Final block before upgrade has been sealed, initiating shutdown", "header_timestamp", header.Time) n.Close() return }