refactor(blockchain): spell out command sync names
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
243749a6d8
commit
a2df164822
4 changed files with 69 additions and 55 deletions
|
|
@ -16,6 +16,8 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const defaultChainSeed = "seeds.lthn.io:36942"
|
||||
|
||||
// AddChainCommands registers the `chain` command group on a Cobra root.
|
||||
//
|
||||
// Example:
|
||||
|
|
@ -37,8 +39,8 @@ func AddChainCommands(root *cobra.Command) {
|
|||
Long: "Manage the Lethean blockchain — sync, explore, and mine.",
|
||||
}
|
||||
|
||||
chainCmd.PersistentFlags().StringVar(&dataDir, "data-dir", defaultChainDataDir(), "blockchain data directory")
|
||||
chainCmd.PersistentFlags().StringVar(&seed, "seed", "seeds.lthn.io:36942", "seed peer address (host:port)")
|
||||
chainCmd.PersistentFlags().StringVar(&dataDir, "data-dir", defaultChainDataDirPath(), "blockchain data directory")
|
||||
chainCmd.PersistentFlags().StringVar(&seed, "seed", defaultChainSeed, "seed peer address (host:port)")
|
||||
chainCmd.PersistentFlags().BoolVar(&testnet, "testnet", false, "use testnet")
|
||||
|
||||
chainCmd.AddCommand(
|
||||
|
|
@ -49,17 +51,17 @@ func AddChainCommands(root *cobra.Command) {
|
|||
root.AddCommand(chainCmd)
|
||||
}
|
||||
|
||||
func resolveChainConfig(testnet bool, seed *string) (config.ChainConfig, []config.HardFork) {
|
||||
func chainConfigForSeed(testnet bool, seed string) (config.ChainConfig, []config.HardFork, string) {
|
||||
if testnet {
|
||||
if *seed == "seeds.lthn.io:36942" {
|
||||
*seed = "localhost:46942"
|
||||
if seed == defaultChainSeed {
|
||||
seed = "localhost:46942"
|
||||
}
|
||||
return config.Testnet, config.TestnetForks
|
||||
return config.Testnet, config.TestnetForks, seed
|
||||
}
|
||||
return config.Mainnet, config.MainnetForks
|
||||
return config.Mainnet, config.MainnetForks, seed
|
||||
}
|
||||
|
||||
func defaultChainDataDir() string {
|
||||
func defaultChainDataDirPath() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return ".lethean"
|
||||
|
|
@ -67,9 +69,9 @@ func defaultChainDataDir() string {
|
|||
return filepath.Join(home, ".lethean", "chain")
|
||||
}
|
||||
|
||||
func ensureChainDataDir(dataDir string) error {
|
||||
func ensureChainDataDirExists(dataDir string) error {
|
||||
if err := coreio.Local.EnsureDir(dataDir); err != nil {
|
||||
return coreerr.E("ensureChainDataDir", "create data dir", err)
|
||||
return coreerr.E("ensureChainDataDirExists", "create data dir", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ import (
|
|||
)
|
||||
|
||||
// newChainExplorerCommand builds the interactive `chain explorer` command.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// 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{
|
||||
|
|
@ -36,19 +41,19 @@ func newChainExplorerCommand(dataDir, seed *string, testnet *bool) *cobra.Comman
|
|||
}
|
||||
|
||||
func runChainExplorer(dataDir, seed string, testnet bool) error {
|
||||
if err := ensureChainDataDir(dataDir); err != nil {
|
||||
if err := ensureChainDataDirExists(dataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(dataDir, "chain.db")
|
||||
s, err := store.New(dbPath)
|
||||
chainStore, err := store.New(dbPath)
|
||||
if err != nil {
|
||||
return coreerr.E("runChainExplorer", "open store", err)
|
||||
}
|
||||
defer s.Close()
|
||||
defer chainStore.Close()
|
||||
|
||||
c := chain.New(s)
|
||||
cfg, forks := resolveChainConfig(testnet, &seed)
|
||||
blockchain := chain.New(chainStore)
|
||||
chainConfig, hardForks, resolvedSeed := chainConfigForSeed(testnet, seed)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
|
@ -57,12 +62,12 @@ func runChainExplorer(dataDir, seed string, testnet bool) error {
|
|||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
runChainSyncLoop(ctx, c, &cfg, forks, seed)
|
||||
runChainSyncLoop(ctx, blockchain, &chainConfig, hardForks, resolvedSeed)
|
||||
}()
|
||||
|
||||
node := tui.NewNode(c)
|
||||
node := tui.NewNode(blockchain)
|
||||
status := tui.NewStatusModel(node)
|
||||
explorer := tui.NewExplorerModel(c)
|
||||
explorer := tui.NewExplorerModel(blockchain)
|
||||
hints := tui.NewKeyHintsModel()
|
||||
|
||||
frame := cli.NewFrame("HCF")
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ import (
|
|||
)
|
||||
|
||||
// newChainSyncCommand builds the `chain sync` command family.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// chain sync
|
||||
// chain sync --daemon
|
||||
// chain sync --stop
|
||||
//
|
||||
// It keeps the foreground and daemon modes behind a predictable command path.
|
||||
func newChainSyncCommand(dataDir, seed *string, testnet *bool) *cobra.Command {
|
||||
var (
|
||||
|
|
@ -53,37 +60,37 @@ func newChainSyncCommand(dataDir, seed *string, testnet *bool) *cobra.Command {
|
|||
}
|
||||
|
||||
func runChainSyncForeground(dataDir, seed string, testnet bool) error {
|
||||
if err := ensureChainDataDir(dataDir); err != nil {
|
||||
if err := ensureChainDataDirExists(dataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(dataDir, "chain.db")
|
||||
s, err := store.New(dbPath)
|
||||
chainStore, err := store.New(dbPath)
|
||||
if err != nil {
|
||||
return coreerr.E("runChainSyncForeground", "open store", err)
|
||||
}
|
||||
defer s.Close()
|
||||
defer chainStore.Close()
|
||||
|
||||
c := chain.New(s)
|
||||
cfg, forks := resolveChainConfig(testnet, &seed)
|
||||
blockchain := chain.New(chainStore)
|
||||
chainConfig, hardForks, resolvedSeed := chainConfigForSeed(testnet, seed)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
|
||||
log.Println("Starting headless P2P sync...")
|
||||
runChainSyncLoop(ctx, c, &cfg, forks, seed)
|
||||
runChainSyncLoop(ctx, blockchain, &chainConfig, hardForks, resolvedSeed)
|
||||
log.Println("Sync stopped.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func runChainSyncDaemon(dataDir, seed string, testnet bool) error {
|
||||
if err := ensureChainDataDir(dataDir); err != nil {
|
||||
if err := ensureChainDataDirExists(dataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pidFile := filepath.Join(dataDir, "sync.pid")
|
||||
|
||||
d := process.NewDaemon(process.DaemonOptions{
|
||||
daemon := process.NewDaemon(process.DaemonOptions{
|
||||
PIDFile: pidFile,
|
||||
Registry: process.DefaultRegistry(),
|
||||
RegistryEntry: process.DaemonEntry{
|
||||
|
|
@ -92,35 +99,35 @@ func runChainSyncDaemon(dataDir, seed string, testnet bool) error {
|
|||
},
|
||||
})
|
||||
|
||||
if err := d.Start(); err != nil {
|
||||
if err := daemon.Start(); err != nil {
|
||||
return coreerr.E("runChainSyncDaemon", "daemon start", err)
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(dataDir, "chain.db")
|
||||
s, err := store.New(dbPath)
|
||||
chainStore, err := store.New(dbPath)
|
||||
if err != nil {
|
||||
_ = d.Stop()
|
||||
_ = daemon.Stop()
|
||||
return coreerr.E("runChainSyncDaemon", "open store", err)
|
||||
}
|
||||
defer s.Close()
|
||||
defer chainStore.Close()
|
||||
|
||||
c := chain.New(s)
|
||||
cfg, forks := resolveChainConfig(testnet, &seed)
|
||||
blockchain := chain.New(chainStore)
|
||||
chainConfig, hardForks, resolvedSeed := chainConfigForSeed(testnet, seed)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
|
||||
d.SetReady(true)
|
||||
daemon.SetReady(true)
|
||||
log.Println("Sync daemon started.")
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
runChainSyncLoop(ctx, c, &cfg, forks, seed)
|
||||
runChainSyncLoop(ctx, blockchain, &chainConfig, hardForks, resolvedSeed)
|
||||
}()
|
||||
|
||||
err = d.Run(ctx)
|
||||
err = daemon.Run(ctx)
|
||||
wg.Wait() // Wait for the sync loop to finish before closing the store.
|
||||
return err
|
||||
}
|
||||
|
|
@ -132,12 +139,12 @@ func stopChainSyncDaemon(dataDir string) error {
|
|||
return coreerr.E("stopChainSyncDaemon", "no running sync daemon found", nil)
|
||||
}
|
||||
|
||||
proc, err := os.FindProcess(pid)
|
||||
processHandle, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
return coreerr.E("stopChainSyncDaemon", fmt.Sprintf("find process %d", pid), err)
|
||||
}
|
||||
|
||||
if err := proc.Signal(syscall.SIGTERM); err != nil {
|
||||
if err := processHandle.Signal(syscall.SIGTERM); err != nil {
|
||||
return coreerr.E("stopChainSyncDaemon", fmt.Sprintf("signal process %d", pid), err)
|
||||
}
|
||||
|
||||
|
|
|
|||
36
sync_loop.go
36
sync_loop.go
|
|
@ -22,10 +22,10 @@ import (
|
|||
levin "dappco.re/go/core/p2p/node/levin"
|
||||
)
|
||||
|
||||
func runChainSyncLoop(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, forks []config.HardFork, seed string) {
|
||||
func runChainSyncLoop(ctx context.Context, blockchain *chain.Chain, chainConfig *config.ChainConfig, hardForks []config.HardFork, seed string) {
|
||||
opts := chain.SyncOptions{
|
||||
VerifySignatures: false,
|
||||
Forks: forks,
|
||||
Forks: hardForks,
|
||||
}
|
||||
|
||||
for {
|
||||
|
|
@ -35,7 +35,7 @@ func runChainSyncLoop(ctx context.Context, c *chain.Chain, cfg *config.ChainConf
|
|||
default:
|
||||
}
|
||||
|
||||
if err := runChainSyncOnce(ctx, c, cfg, opts, seed); err != nil {
|
||||
if err := runChainSyncOnce(ctx, blockchain, chainConfig, opts, seed); err != nil {
|
||||
log.Printf("sync: %v (retrying in 10s)", err)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
|
@ -53,24 +53,24 @@ func runChainSyncLoop(ctx context.Context, c *chain.Chain, cfg *config.ChainConf
|
|||
}
|
||||
}
|
||||
|
||||
func runChainSyncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, opts chain.SyncOptions, seed string) error {
|
||||
func runChainSyncOnce(ctx context.Context, blockchain *chain.Chain, chainConfig *config.ChainConfig, opts chain.SyncOptions, seed string) error {
|
||||
conn, err := net.DialTimeout("tcp", seed, 10*time.Second)
|
||||
if err != nil {
|
||||
return coreerr.E("runChainSyncOnce", fmt.Sprintf("dial %s", seed), err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
lc := levin.NewConnection(conn)
|
||||
levinConn := levin.NewConnection(conn)
|
||||
|
||||
var peerIDBuf [8]byte
|
||||
rand.Read(peerIDBuf[:])
|
||||
peerID := binary.LittleEndian.Uint64(peerIDBuf[:])
|
||||
var peerIDBytes [8]byte
|
||||
rand.Read(peerIDBytes[:])
|
||||
peerID := binary.LittleEndian.Uint64(peerIDBytes[:])
|
||||
|
||||
localHeight, _ := c.Height()
|
||||
localHeight, _ := blockchain.Height()
|
||||
|
||||
req := p2p.HandshakeRequest{
|
||||
handshakeReq := p2p.HandshakeRequest{
|
||||
NodeData: p2p.NodeData{
|
||||
NetworkID: cfg.NetworkID,
|
||||
NetworkID: chainConfig.NetworkID,
|
||||
PeerID: peerID,
|
||||
LocalTime: time.Now().Unix(),
|
||||
MyPort: 0,
|
||||
|
|
@ -81,15 +81,15 @@ func runChainSyncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConf
|
|||
NonPruningMode: true,
|
||||
},
|
||||
}
|
||||
payload, err := p2p.EncodeHandshakeRequest(&req)
|
||||
payload, err := p2p.EncodeHandshakeRequest(&handshakeReq)
|
||||
if err != nil {
|
||||
return coreerr.E("runChainSyncOnce", "encode handshake", err)
|
||||
}
|
||||
if err := lc.WritePacket(p2p.CommandHandshake, payload, true); err != nil {
|
||||
if err := levinConn.WritePacket(p2p.CommandHandshake, payload, true); err != nil {
|
||||
return coreerr.E("runChainSyncOnce", "write handshake", err)
|
||||
}
|
||||
|
||||
hdr, data, err := lc.ReadPacket()
|
||||
hdr, data, err := levinConn.ReadPacket()
|
||||
if err != nil {
|
||||
return coreerr.E("runChainSyncOnce", "read handshake", err)
|
||||
}
|
||||
|
|
@ -97,8 +97,8 @@ func runChainSyncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConf
|
|||
return coreerr.E("runChainSyncOnce", fmt.Sprintf("unexpected command %d", hdr.Command), nil)
|
||||
}
|
||||
|
||||
var resp p2p.HandshakeResponse
|
||||
if err := resp.Decode(data); err != nil {
|
||||
var handshakeResp p2p.HandshakeResponse
|
||||
if err := handshakeResp.Decode(data); err != nil {
|
||||
return coreerr.E("runChainSyncOnce", "decode handshake", err)
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ func runChainSyncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConf
|
|||
ClientVersion: config.ClientVersion,
|
||||
NonPruningMode: true,
|
||||
}
|
||||
p2pConn := chain.NewLevinP2PConn(lc, resp.PayloadData.CurrentHeight, localSync)
|
||||
p2pConn := chain.NewLevinP2PConn(levinConn, handshakeResp.PayloadData.CurrentHeight, localSync)
|
||||
|
||||
return c.P2PSync(ctx, p2pConn, opts)
|
||||
return blockchain.P2PSync(ctx, p2pConn, opts)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue