-
Notifications
You must be signed in to change notification settings - Fork 261
Expand file tree
/
Copy pathrollback.go
More file actions
170 lines (141 loc) · 5.07 KB
/
rollback.go
File metadata and controls
170 lines (141 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package cmd
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"github.com/ethereum/go-ethereum/common"
ds "github.com/ipfs/go-datastore"
"github.com/spf13/cobra"
goheaderstore "github.com/celestiaorg/go-header/store"
"github.com/evstack/ev-node/execution/evm"
rollcmd "github.com/evstack/ev-node/pkg/cmd"
"github.com/evstack/ev-node/pkg/store"
"github.com/evstack/ev-node/types"
)
// NewRollbackCmd creates a command to rollback ev-node state by one height.
func NewRollbackCmd() *cobra.Command {
var (
height uint64
syncNode bool
)
cmd := &cobra.Command{
Use: "rollback",
Short: "rollback ev-node state by one height. Pass --height to specify another height to rollback to.",
RunE: func(cmd *cobra.Command, args []string) error {
nodeConfig, err := rollcmd.ParseConfig(cmd)
if err != nil {
return err
}
goCtx := cmd.Context()
if goCtx == nil {
goCtx = context.Background()
}
// evolve db
rawEvolveDB, err := store.NewDefaultKVStore(nodeConfig.RootDir, nodeConfig.DBPath, evmDbName)
if err != nil {
return err
}
defer func() {
if closeErr := rawEvolveDB.Close(); closeErr != nil {
cmd.Printf("Warning: failed to close evolve database: %v\n", closeErr)
}
}()
// prefixed evolve db
evolveDB := store.NewEvNodeKVStore(rawEvolveDB)
evolveStore := store.New(evolveDB)
if height == 0 {
currentHeight, err := evolveStore.Height(goCtx)
if err != nil {
return err
}
height = currentHeight - 1
}
// rollback ev-node main state
if err := evolveStore.Rollback(goCtx, height, !syncNode); err != nil {
return fmt.Errorf("failed to rollback ev-node state: %w", err)
}
// rollback execution layer via EngineClient
engineClient, err := createRollbackEngineClient(cmd, rawEvolveDB)
if err != nil {
cmd.Printf("Warning: failed to create engine client, skipping EL rollback: %v\n", err)
} else {
if err := engineClient.Rollback(goCtx, height); err != nil {
return fmt.Errorf("failed to rollback execution layer: %w", err)
}
cmd.Printf("Rolled back execution layer to height %d\n", height)
}
// rollback ev-node goheader state
headerStore, err := goheaderstore.NewStore[*types.P2PSignedHeader](
evolveDB,
goheaderstore.WithStorePrefix("headerSync"),
goheaderstore.WithMetrics(),
)
if err != nil {
return err
}
dataStore, err := goheaderstore.NewStore[*types.P2PData](
evolveDB,
goheaderstore.WithStorePrefix("dataSync"),
goheaderstore.WithMetrics(),
)
if err != nil {
return err
}
if err := headerStore.Start(goCtx); err != nil {
return fmt.Errorf("failed to start header store: %w", err)
}
defer headerStore.Stop(goCtx)
if err := dataStore.Start(goCtx); err != nil {
return fmt.Errorf("failed to start data store: %w", err)
}
defer dataStore.Stop(goCtx)
var errs error
if err := headerStore.DeleteRange(goCtx, height+1, headerStore.Height()); err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to rollback header sync service state: %w", err))
}
if err := dataStore.DeleteRange(goCtx, height+1, dataStore.Height()); err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to rollback data sync service state: %w", err))
}
cmd.Printf("Rolled back ev-node state to height %d\n", height)
if syncNode {
fmt.Println("Restart the node with the `--evnode.clear_cache` flag")
}
return errs
},
}
cmd.Flags().Uint64Var(&height, "height", 0, "rollback to a specific height")
cmd.Flags().BoolVar(&syncNode, "sync-node", false, "sync node (no aggregator)")
// EVM flags for execution layer rollback
cmd.Flags().String(evm.FlagEvmEthURL, "http://localhost:8545", "URL of the Ethereum JSON-RPC endpoint")
cmd.Flags().String(evm.FlagEvmEngineURL, "http://localhost:8551", "URL of the Engine API endpoint")
cmd.Flags().String(evm.FlagEvmJWTSecretFile, "", "Path to file containing the JWT secret for authentication")
return cmd
}
func createRollbackEngineClient(cmd *cobra.Command, db ds.Batching) (*evm.EngineClient, error) {
ethURL, err := cmd.Flags().GetString(evm.FlagEvmEthURL)
if err != nil {
return nil, fmt.Errorf("failed to get '%s' flag: %w", evm.FlagEvmEthURL, err)
}
engineURL, err := cmd.Flags().GetString(evm.FlagEvmEngineURL)
if err != nil {
return nil, fmt.Errorf("failed to get '%s' flag: %w", evm.FlagEvmEngineURL, err)
}
jwtSecretFile, err := cmd.Flags().GetString(evm.FlagEvmJWTSecretFile)
if err != nil {
return nil, fmt.Errorf("failed to get '%s' flag: %w", evm.FlagEvmJWTSecretFile, err)
}
if jwtSecretFile == "" {
return nil, fmt.Errorf("JWT secret file must be provided via --evm.jwt-secret-file for EL rollback")
}
secretBytes, err := os.ReadFile(jwtSecretFile)
if err != nil {
return nil, fmt.Errorf("failed to read JWT secret from file '%s': %w", jwtSecretFile, err)
}
jwtSecret := string(bytes.TrimSpace(secretBytes))
if jwtSecret == "" {
return nil, fmt.Errorf("JWT secret file '%s' is empty", jwtSecretFile)
}
return evm.NewEngineExecutionClient(ethURL, engineURL, jwtSecret, common.Hash{}, common.Address{}, db, false)
}