-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5acf995
commit 7d0c94d
Showing
2 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package find_trie_root | ||
|
||
import ( | ||
"encoding/hex" | ||
"fmt" | ||
"math" | ||
|
||
prometheusWAL "github.com/onflow/wal/wal" | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/rs/zerolog" | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/onflow/flow-go/ledger" | ||
"github.com/onflow/flow-go/ledger/common/hash" | ||
"github.com/onflow/flow-go/ledger/complete/wal" | ||
) | ||
|
||
var ( | ||
flagExecutionStateDir string | ||
flagRootHash string | ||
flagFrom int | ||
flagTo int | ||
) | ||
|
||
var Cmd = &cobra.Command{ | ||
Use: "find-trie-root", | ||
Short: "find trie root", | ||
Run: run, | ||
} | ||
|
||
func init() { | ||
Cmd.Flags().StringVarP(&flagExecutionStateDir, "execution-state-dir", "e", "/var/flow/data/execution", "directory to the execution state") | ||
_ = Cmd.MarkFlagRequired("execution-state-dir") | ||
|
||
Cmd.Flags().StringVar(&flagRootHash, "root-hash", "", | ||
"ledger root hash (hex-encoded, 64 characters)") | ||
_ = Cmd.MarkFlagRequired("root-hash") | ||
|
||
Cmd.Flags().IntVar(&flagFrom, "from", 0, "from segment") | ||
Cmd.Flags().IntVar(&flagTo, "to", math.MaxInt32, "to segment") | ||
} | ||
|
||
func run(*cobra.Command, []string) { | ||
rootHash, err := parseInput(flagRootHash) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("cannot parse input") | ||
} | ||
|
||
segment, offset, err := searchRootHashInSegments(rootHash, flagExecutionStateDir, flagFrom, flagTo) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("cannot find root hash in segments") | ||
} | ||
log.Info().Msgf("found root hash in segment %d at offset %d", segment, offset) | ||
} | ||
|
||
func parseInput(rootHashStr string) (ledger.RootHash, error) { | ||
rootHashBytes, err := hex.DecodeString(rootHashStr) | ||
if err != nil { | ||
return ledger.RootHash(hash.DummyHash), fmt.Errorf("cannot decode root hash: %w", err) | ||
} | ||
rootHash, err := ledger.ToRootHash(rootHashBytes) | ||
if err != nil { | ||
return ledger.RootHash(hash.DummyHash), fmt.Errorf("invalid root hash: %w", err) | ||
} | ||
return rootHash, nil | ||
} | ||
|
||
func searchRootHashInSegments( | ||
expectedHash ledger.RootHash, | ||
dir string, | ||
wantFrom, wantTo int, | ||
) (int, int64, error) { | ||
log := zerolog.Logger{} | ||
w, err := prometheusWAL.NewSize(log, prometheus.DefaultRegisterer, dir, wal.SegmentSize, false) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("cannot create WAL: %w", err) | ||
} | ||
|
||
from, to, err := prometheusWAL.Segments(dir) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("cannot get segments: %w", err) | ||
} | ||
|
||
if wantFrom > to { | ||
return 0, 0, fmt.Errorf("from segment %d is greater than the last segment %d", wantFrom, to) | ||
} | ||
|
||
if wantTo < from { | ||
return 0, 0, fmt.Errorf("to segment %d is less than the first segment %d", wantTo, from) | ||
} | ||
|
||
if wantFrom > from { | ||
from = wantFrom | ||
} | ||
|
||
if wantTo < to { | ||
to = wantTo | ||
} | ||
|
||
log.Info(). | ||
Str("dir", dir). | ||
Int("from", from). | ||
Int("to", to). | ||
Int("want-from", wantFrom). | ||
Int("want-to", wantTo). | ||
Msgf("searching for trie root hash %x in segments [%d,%d]", expectedHash, wantFrom, wantTo) | ||
|
||
sr, err := prometheusWAL.NewSegmentsRangeReader(log, prometheusWAL.SegmentRange{ | ||
Dir: w.Dir(), | ||
First: from, | ||
Last: to, | ||
}) | ||
|
||
if err != nil { | ||
return 0, 0, fmt.Errorf("cannot create WAL segments reader: %w", err) | ||
} | ||
|
||
defer sr.Close() | ||
|
||
reader := prometheusWAL.NewReader(sr) | ||
|
||
for reader.Next() { | ||
record := reader.Record() | ||
operation, rootHash, _, err := wal.Decode(record) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("cannot decode LedgerWAL record: %w", err) | ||
} | ||
switch operation { | ||
case wal.WALUpdate: | ||
if rootHash == expectedHash { | ||
log.Info().Msgf("found expected trie root hash %x", rootHash) | ||
return reader.Segment(), reader.Offset(), nil | ||
} | ||
default: | ||
} | ||
|
||
err = reader.Err() | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("cannot read LedgerWAL: %w", err) | ||
} | ||
} | ||
|
||
return 0, 0, fmt.Errorf("finish reading all segment files from %d to %d, but not found", from, to) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters