Skip to content

Commit bf38c3a

Browse files
Merge branch 'master' into illia-malachyn/6635-tests-for-websocket-controller
2 parents 4b7811a + 61a0b0e commit bf38c3a

File tree

4 files changed

+106
-8
lines changed

4 files changed

+106
-8
lines changed

cmd/util/cmd/verify_execution_result/cmd.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,33 @@ func run(*cobra.Command, []string) {
5353
chainID := flow.ChainID(flagChain)
5454
_ = chainID.Chain()
5555

56+
lg := log.With().
57+
Str("chain", string(chainID)).
58+
Str("datadir", flagDatadir).
59+
Str("chunk_data_pack_dir", flagChunkDataPackDir).
60+
Logger()
61+
5662
if flagFromTo != "" {
5763
from, to, err := parseFromTo(flagFromTo)
5864
if err != nil {
59-
log.Fatal().Err(err).Msg("could not parse from_to")
65+
lg.Fatal().Err(err).Msg("could not parse from_to")
6066
}
6167

62-
log.Info().Msgf("verifying range from %d to %d", from, to)
68+
lg.Info().Msgf("verifying range from %d to %d", from, to)
6369
err = verifier.VerifyRange(from, to, chainID, flagDatadir, flagChunkDataPackDir)
6470
if err != nil {
65-
log.Fatal().Err(err).Msgf("could not verify range from %d to %d", from, to)
71+
lg.Fatal().Err(err).Msgf("could not verify range from %d to %d", from, to)
6672
}
67-
log.Info().Msgf("successfully verified range from %d to %d", from, to)
73+
lg.Info().Msgf("successfully verified range from %d to %d", from, to)
6874

6975
} else {
70-
log.Info().Msgf("verifying last %d sealed blocks", flagLastK)
76+
lg.Info().Msgf("verifying last %d sealed blocks", flagLastK)
7177
err := verifier.VerifyLastKHeight(flagLastK, chainID, flagDatadir, flagChunkDataPackDir)
7278
if err != nil {
73-
log.Fatal().Err(err).Msg("could not verify last k height")
79+
lg.Fatal().Err(err).Msg("could not verify last k height")
7480
}
7581

76-
log.Info().Msgf("successfully verified last %d sealed blocks", flagLastK)
82+
lg.Info().Msgf("successfully verified last %d sealed blocks", flagLastK)
7783
}
7884
}
7985

engine/verification/verifier/verifiers.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
// VerifyLastKHeight verifies the last k sealed blocks by verifying all chunks in the results.
2525
// It assumes the latest sealed block has been executed, and the chunk data packs have not been
2626
// pruned.
27+
// Note, it returns nil if certain block is not executed, in this case warning will be logged
2728
func VerifyLastKHeight(k uint64, chainID flow.ChainID, protocolDataDir string, chunkDataPackDir string) (err error) {
2829
closer, storages, chunkDataPacks, state, verifier, err := initStorages(chainID, protocolDataDir, chunkDataPackDir)
2930
if err != nil {
@@ -73,6 +74,7 @@ func VerifyLastKHeight(k uint64, chainID flow.ChainID, protocolDataDir string, c
7374
}
7475

7576
// VerifyRange verifies all chunks in the results of the blocks in the given range.
77+
// Note, it returns nil if certain block is not executed, in this case warning will be logged
7678
func VerifyRange(
7779
from, to uint64,
7880
chainID flow.ChainID,
@@ -124,7 +126,8 @@ func initStorages(chainID flow.ChainID, dataDir string, chunkDataPackDir string)
124126
return nil, nil, nil, nil, nil, fmt.Errorf("could not init protocol state: %w", err)
125127
}
126128

127-
chunkDataPackDB, err := storagepebble.OpenDefaultPebbleDB(chunkDataPackDir)
129+
// require the chunk data pack data must exist before returning the storage module
130+
chunkDataPackDB, err := storagepebble.MustOpenDefaultPebbleDB(chunkDataPackDir)
128131
if err != nil {
129132
return nil, nil, nil, nil, nil, fmt.Errorf("could not open chunk data pack DB: %w", err)
130133
}
@@ -147,6 +150,8 @@ func initStorages(chainID flow.ChainID, dataDir string, chunkDataPackDir string)
147150
return closer, storages, chunkDataPacks, state, verifier, nil
148151
}
149152

153+
// verifyHeight verifies all chunks in the results of the block at the given height.
154+
// Note: it returns nil if the block is not executed.
150155
func verifyHeight(
151156
height uint64,
152157
headers storage.Headers,
@@ -164,6 +169,11 @@ func verifyHeight(
164169

165170
result, err := results.ByBlockID(blockID)
166171
if err != nil {
172+
if errors.Is(err, storage.ErrNotFound) {
173+
log.Warn().Uint64("height", height).Hex("block_id", blockID[:]).Msg("execution result not found")
174+
return nil
175+
}
176+
167177
return fmt.Errorf("could not get execution result by block ID %s: %w", blockID, err)
168178
}
169179
snapshot := state.AtBlockID(blockID)

storage/pebble/open.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package pebble
33
import (
44
"errors"
55
"fmt"
6+
"os"
7+
"path/filepath"
68

79
"github.com/cockroachdb/pebble"
810
"github.com/hashicorp/go-multierror"
@@ -54,6 +56,8 @@ func OpenRegisterPebbleDB(dir string) (*pebble.DB, error) {
5456

5557
// OpenDefaultPebbleDB opens a pebble database using default options,
5658
// such as cache size and comparer
59+
// If the pebbleDB is not bootstrapped at this folder, it will auto-bootstrap it,
60+
// use MustOpenDefaultPebbleDB if you want to return error instead
5761
func OpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
5862
cache := pebble.NewCache(DefaultPebbleCacheSize)
5963
defer cache.Unref()
@@ -66,6 +70,57 @@ func OpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
6670
return db, nil
6771
}
6872

73+
// MustOpenDefaultPebbleDB returns error if the pebbleDB is not bootstrapped at this folder
74+
// if bootstrapped, then open the pebbleDB
75+
func MustOpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
76+
err := IsPebbleInitialized(dir)
77+
if err != nil {
78+
return nil, fmt.Errorf("pebble db is not initialized: %w", err)
79+
}
80+
81+
return OpenDefaultPebbleDB(dir)
82+
}
83+
84+
// IsPebbleInitialized checks if the given folder contains a valid Pebble DB.
85+
func IsPebbleInitialized(folderPath string) error {
86+
// Check if the folder exists
87+
info, err := os.Stat(folderPath)
88+
if os.IsNotExist(err) {
89+
return fmt.Errorf("directory does not exist: %s", folderPath)
90+
}
91+
if !info.IsDir() {
92+
return fmt.Errorf("not a directory: %s", folderPath)
93+
}
94+
95+
// Look for Pebble-specific files
96+
requiredFiles := []string{"CURRENT", "MANIFEST-*"}
97+
for _, pattern := range requiredFiles {
98+
matches, err := filepath.Glob(filepath.Join(folderPath, pattern))
99+
if err != nil {
100+
return fmt.Errorf("error checking for files: %v", err)
101+
}
102+
if len(matches) == 0 {
103+
return fmt.Errorf("missing required file: %s", pattern)
104+
}
105+
}
106+
107+
// Optionally, validate the CURRENT file references a MANIFEST file
108+
currentPath := filepath.Join(folderPath, "CURRENT")
109+
currentFile, err := os.Open(currentPath)
110+
if err != nil {
111+
return fmt.Errorf("error reading CURRENT file: %v", err)
112+
}
113+
defer currentFile.Close()
114+
115+
// Basic validation by ensuring the CURRENT file is non-empty
116+
stat, err := currentFile.Stat()
117+
if err != nil || stat.Size() == 0 {
118+
return fmt.Errorf("CURRENT file is invalid")
119+
}
120+
121+
return nil
122+
}
123+
69124
// ReadHeightsFromBootstrappedDB reads the first and latest height from a bootstrapped register db
70125
// If the register db is not bootstrapped, it returns storage.ErrNotBootstrapped
71126
// If the register db is corrupted, it returns an error

storage/pebble/open_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package pebble
22

33
import (
44
"errors"
5+
"fmt"
56
"testing"
67

78
"github.com/stretchr/testify/require"
@@ -74,3 +75,29 @@ func TestNewBootstrappedRegistersWithPath(t *testing.T) {
7475
require.NoError(t, db2.Close())
7576
})
7677
}
78+
79+
func TestMustOpenDefaultPebbleDB(t *testing.T) {
80+
t.Parallel()
81+
unittest.RunWithTempDir(t, func(dir string) {
82+
// verify error is returned when the db is not bootstrapped
83+
_, err := MustOpenDefaultPebbleDB(dir)
84+
require.Error(t, err)
85+
require.Contains(t, err.Error(), "not initialized")
86+
87+
// bootstrap the db
88+
db, err := OpenDefaultPebbleDB(dir)
89+
require.NoError(t, err)
90+
require.NoError(t, initHeights(db, uint64(10)))
91+
require.NoError(t, db.Close())
92+
fmt.Println(dir)
93+
94+
// verify no error is returned when the db is bootstrapped
95+
db, err = MustOpenDefaultPebbleDB(dir)
96+
require.NoError(t, err)
97+
98+
h, err := latestStoredHeight(db)
99+
require.NoError(t, err)
100+
require.Equal(t, uint64(10), h)
101+
require.NoError(t, db.Close())
102+
})
103+
}

0 commit comments

Comments
 (0)