98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
|
//
|
|
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package blockchain
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"sync"
|
|
"syscall"
|
|
|
|
coreerr "dappco.re/go/core/log"
|
|
|
|
cli "dappco.re/go/core/cli/pkg/cli"
|
|
store "dappco.re/go/core/store"
|
|
|
|
"dappco.re/go/core/blockchain/chain"
|
|
"dappco.re/go/core/blockchain/tui"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
const chainExplorerFrameTitle = "Chain Explorer"
|
|
|
|
// newChainExplorerCommand builds the interactive `chain explorer` command.
|
|
//
|
|
// Example:
|
|
//
|
|
// core-chain chain explorer --data-dir ~/.lethean/chain
|
|
//
|
|
// Use it alongside `AddChainCommands` to expose the TUI node view.
|
|
func newChainExplorerCommand(dataDir, seed *string, testnet *bool) *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: chainExplorerCommandName,
|
|
Short: chainExplorerCommandShort,
|
|
Long: chainExplorerCommandLong,
|
|
Example: chainExplorerExample,
|
|
Args: cobra.NoArgs,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
resolvedDataDir, err := resolveChainCommandDataDir(*dataDir, *testnet, cmd.Flags().Changed("data-dir"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return runChainExplorer(resolvedDataDir, *seed, *testnet)
|
|
},
|
|
}
|
|
}
|
|
|
|
func runChainExplorer(dataDir, seed string, testnet bool) error {
|
|
resolvedDataDir, err := resolveChainDataDir(dataDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := validateChainRuntimeInputs(resolvedDataDir, seed); err != nil {
|
|
return err
|
|
}
|
|
if err := ensureChainDataDirExists(resolvedDataDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
dbPath := filepath.Join(resolvedDataDir, "chain.db")
|
|
chainStore, err := store.New(dbPath)
|
|
if err != nil {
|
|
return coreerr.E("runChainExplorer", "open store", err)
|
|
}
|
|
defer chainStore.Close()
|
|
|
|
blockchain := chain.New(chainStore)
|
|
chainConfig, hardForks, resolvedSeed := chainConfigForSeed(testnet, seed)
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer cancel()
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
runChainSyncLoop(ctx, blockchain, &chainConfig, hardForks, resolvedSeed)
|
|
}()
|
|
|
|
node := tui.NewNode(blockchain)
|
|
status := tui.NewStatusModel(node)
|
|
explorer := tui.NewExplorerModel(blockchain)
|
|
hints := tui.NewKeyHintsModel()
|
|
|
|
explorerFrame := cli.NewFrame(chainExplorerFrameTitle)
|
|
explorerFrame.Header(status)
|
|
explorerFrame.Content(explorer)
|
|
explorerFrame.Footer(hints)
|
|
explorerFrame.Run()
|
|
|
|
cancel() // Signal the sync loop to stop.
|
|
wg.Wait() // Wait for it before closing store.
|
|
return nil
|
|
}
|