2023-09-27 11:05:46 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/monza/internal/chain"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
func stutter(c *cli.Context) (err error) {
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
|
|
|
|
|
|
// parse blockchain info
|
|
|
|
cacheDir := c.String(cacheFlagKey)
|
|
|
|
if len(cacheDir) == 0 {
|
|
|
|
cacheDir, err = defaultConfigDir()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-19 14:20:45 +00:00
|
|
|
blockchain, err := chain.Open(ctx, cacheDir, c.String(endpointFlagKey), false)
|
2023-09-27 11:05:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("cannot initialize remote blockchain client: %w", err)
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
blockchain.Close()
|
|
|
|
cancel()
|
|
|
|
}()
|
|
|
|
|
|
|
|
// parse block indices
|
|
|
|
from, to, err := parseInterval(c.String(fromFlagKey), c.String(toFlagKey), blockchain.Client)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
threshold := c.Duration(stutterThresholdFlagKey)
|
|
|
|
|
|
|
|
// need at least two blocks
|
|
|
|
if to-from < 2 {
|
|
|
|
return errors.New("range must contain at least two blocks")
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetch blocks
|
|
|
|
err = cacheBlocks(ctx, ¶ms{
|
|
|
|
from: from,
|
|
|
|
to: to,
|
|
|
|
blockchain: blockchain,
|
|
|
|
workers: int(c.Uint64(workersFlagKey)),
|
|
|
|
disableBar: c.Bool(disableProgressBarFlagKey),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// process blocks one by one
|
|
|
|
var (
|
|
|
|
prev, curr *block.Block
|
|
|
|
prevTS, currTS time.Time
|
|
|
|
lastStutterBlock uint32
|
|
|
|
)
|
|
|
|
|
|
|
|
for i := from; i < to; i++ {
|
|
|
|
b, err := blockchain.Block(i)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("cannot fetch block %d: %w", i, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
prev, prevTS = curr, currTS
|
|
|
|
curr = b
|
|
|
|
currTS = time.Unix(int64(b.Timestamp/1e3), 0)
|
|
|
|
if prev == nil { // first block case
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
blockDelta := currTS.Sub(prevTS)
|
|
|
|
if blockDelta <= threshold {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
skippedBlocks := prev.Index - lastStutterBlock
|
|
|
|
if lastStutterBlock > 0 && skippedBlocks > 1 {
|
|
|
|
fmt.Printf("-- skipped %d blocks --\n", skippedBlocks-1)
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintBlock(prev, "")
|
|
|
|
PrintBlock(curr, fmt.Sprintf("<- stutter for %s", blockDelta))
|
|
|
|
lastStutterBlock = curr.Index
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|