Skip to content

Commit 48dfe94

Browse files
committed
Add syncl1 command
1 parent 5e62e34 commit 48dfe94

File tree

3 files changed

+129
-7
lines changed

3 files changed

+129
-7
lines changed

cmd/juno/juno.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ import (
99
"syscall"
1010
"time"
1111

12+
"github.com/NethermindEth/juno/db/pebble"
13+
"github.com/NethermindEth/juno/l1data"
1214
"github.com/NethermindEth/juno/node"
15+
"github.com/NethermindEth/juno/syncl1"
1316
"github.com/NethermindEth/juno/utils"
17+
"github.com/ethereum/go-ethereum/ethclient"
1418
"github.com/mitchellh/mapstructure"
1519
"github.com/spf13/cobra"
1620
"github.com/spf13/viper"
21+
"tailscale.com/logtail/backoff"
1722
)
1823

1924
const greeting = `
@@ -126,6 +131,43 @@ func main() {
126131
n.Run(cmd.Context())
127132
return nil
128133
})
134+
endBlock := new(uint64)
135+
cmd.AddCommand(newSyncL1Cmd(endBlock, func(cmd *cobra.Command, _ []string) error {
136+
if config.Network != utils.MAINNET {
137+
return fmt.Errorf("syncing from L1 is only supported on mainnet right now")
138+
}
139+
140+
log, err := utils.NewZapLogger(config.LogLevel, config.Colour)
141+
if err != nil {
142+
return fmt.Errorf("create logger: %v", err)
143+
}
144+
database, err := pebble.New(config.DatabasePath, log)
145+
if err != nil {
146+
return fmt.Errorf("open DB: %v", err)
147+
}
148+
ethClient, err := ethclient.Dial(config.EthNode)
149+
if err != nil {
150+
return fmt.Errorf("dial %s: %v", config.EthNode, err)
151+
}
152+
l1Data, err := l1data.New(ethClient)
153+
if err != nil {
154+
return fmt.Errorf("create l1 client: %v", err)
155+
}
156+
l1Data.WithBackoff(backoff.NewBackoff("syncl1", func(format string, a ...any) {
157+
log.Warnw(fmt.Sprintf(format, a...))
158+
}, time.Minute))
159+
fetcher := l1data.NewStateDiffFetcher(l1Data)
160+
s, err := syncl1.New(database, l1Data, fetcher, syncl1.MainnetConfig, *endBlock, log)
161+
if err != nil {
162+
return fmt.Errorf("new l1 synchronizer: %v", err)
163+
}
164+
165+
if err := s.Run(cmd.Context()); err != nil {
166+
return fmt.Errorf("sync l1: %v", err)
167+
}
168+
169+
return nil
170+
}))
129171

130172
if err := cmd.ExecuteContext(ctx); err != nil {
131173
os.Exit(1)
@@ -150,9 +192,9 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
150192
var cfgFile string
151193
var cwdErr error
152194

153-
// PreRunE populates the configuration struct from the Cobra flags and Viper configuration.
195+
// PersistentPreRunE populates the configuration struct from the Cobra flags and Viper configuration.
154196
// This is called in step 3 of the process described above.
155-
junoCmd.PreRunE = func(cmd *cobra.Command, _ []string) error {
197+
junoCmd.PersistentPreRunE = func(cmd *cobra.Command, _ []string) error {
156198
// If we couldn't find the current working directory and the database path is empty,
157199
// return the error.
158200
if cwdErr != nil && config.DatabasePath == "" {
@@ -193,20 +235,20 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
193235
defaultNetwork := utils.MAINNET
194236

195237
junoCmd.Flags().StringVar(&cfgFile, configF, defaultConfig, configFlagUsage)
196-
junoCmd.Flags().Var(&defaultLogLevel, logLevelF, logLevelFlagUsage)
238+
junoCmd.PersistentFlags().Var(&defaultLogLevel, logLevelF, logLevelFlagUsage)
197239
junoCmd.Flags().Bool(httpF, defaultHTTP, httpUsage)
198240
junoCmd.Flags().String(httpHostF, defaulHost, httpHostUsage)
199241
junoCmd.Flags().Uint16(httpPortF, defaultHTTPPort, httpPortUsage)
200242
junoCmd.Flags().Bool(wsF, defaultWS, wsUsage)
201243
junoCmd.Flags().String(wsHostF, defaulHost, wsHostUsage)
202244
junoCmd.Flags().Uint16(wsPortF, defaultWSPort, wsPortUsage)
203-
junoCmd.Flags().String(dbPathF, defaultDBPath, dbPathUsage)
204-
junoCmd.Flags().Var(&defaultNetwork, networkF, networkUsage)
205-
junoCmd.Flags().String(ethNodeF, defaultEthNode, ethNodeUsage)
245+
junoCmd.PersistentFlags().String(dbPathF, defaultDBPath, dbPathUsage)
246+
junoCmd.PersistentFlags().Var(&defaultNetwork, networkF, networkUsage)
247+
junoCmd.PersistentFlags().String(ethNodeF, defaultEthNode, ethNodeUsage)
206248
junoCmd.Flags().Bool(pprofF, defaultPprof, pprofUsage)
207249
junoCmd.Flags().String(pprofHostF, defaulHost, pprofHostUsage)
208250
junoCmd.Flags().Uint16(pprofPortF, defaultPprofPort, pprofPortUsage)
209-
junoCmd.Flags().Bool(colourF, defaultColour, colourUsage)
251+
junoCmd.PersistentFlags().Bool(colourF, defaultColour, colourUsage)
210252
junoCmd.Flags().Duration(pendingPollIntervalF, defaultPendingPollInterval, pendingPollIntervalUsage)
211253
junoCmd.Flags().Bool(p2pF, defaultP2p, p2pUsage)
212254
junoCmd.Flags().String(p2pAddrF, defaultP2pAddr, p2PAddrUsage)

cmd/juno/syncl1.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func newSyncL1Cmd(endBlock *uint64, run func(*cobra.Command, []string) error) *cobra.Command {
11+
cmd := &cobra.Command{
12+
Use: "syncl1 <end-block-number> [flags]",
13+
Short: "sync the state from L1 using Juno's database format.",
14+
Args: cobra.ExactArgs(1),
15+
PreRunE: func(_ *cobra.Command, args []string) error {
16+
var err error
17+
*endBlock, err = strconv.ParseUint(args[0], 10, 64)
18+
if err != nil {
19+
return fmt.Errorf("parse end block number: %v", err)
20+
}
21+
return nil
22+
},
23+
RunE: run,
24+
}
25+
return cmd
26+
}

cmd/juno/syncl1_pkg_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestNewSyncL1Cmd(t *testing.T) {
11+
tests := map[string]struct {
12+
args []string
13+
want int // if negative, expect error
14+
}{
15+
"no args": {
16+
args: []string{},
17+
want: -1,
18+
},
19+
"single empty arg": {
20+
args: []string{""},
21+
want: -1,
22+
},
23+
"single negative arg": {
24+
args: []string{"-1"},
25+
want: -1,
26+
},
27+
"two args": {
28+
args: []string{"1", "1"},
29+
want: -1,
30+
},
31+
"zero": {
32+
args: []string{"0"},
33+
want: 0,
34+
},
35+
"large number": {
36+
args: []string{"1232882"},
37+
want: 1232882,
38+
},
39+
}
40+
41+
for description, test := range tests {
42+
t.Run(description, func(t *testing.T) {
43+
var endBlock uint64
44+
cmd := newSyncL1Cmd(&endBlock, func(_ *cobra.Command, _ []string) error { return nil })
45+
cmd.SetArgs(test.args)
46+
err := cmd.Execute()
47+
if test.want < 0 {
48+
require.Error(t, err)
49+
return
50+
}
51+
require.Equal(t, uint64(test.want), endBlock)
52+
})
53+
}
54+
}

0 commit comments

Comments
 (0)