main.go 6.56 KB
Newer Older
1 2 3 4 5 6
package main

import (
	"context"
	"fmt"
	"log"
7
	"math/big"
8 9 10 11
	"os"
	"time"

	"github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/fetch"
12
	"github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/reassemble"
13
	"github.com/ethereum-optimism/optimism/op-node/rollup"
14
	"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
15 16
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
17
	"github.com/urfave/cli/v2"
18 19 20 21 22 23
)

func main() {
	app := cli.NewApp()
	app.Name = "batch-decoder"
	app.Usage = "Optimism Batch Decoding Utility"
24
	app.Commands = []*cli.Command{
25 26 27 28
		{
			Name:  "fetch",
			Usage: "Fetches batches in the specified range",
			Flags: []cli.Flag{
29
				&cli.IntFlag{
30 31 32 33
					Name:     "start",
					Required: true,
					Usage:    "First block (inclusive) to fetch",
				},
34
				&cli.IntFlag{
35 36 37 38
					Name:     "end",
					Required: true,
					Usage:    "Last block (exclusive) to fetch",
				},
39
				&cli.StringFlag{
40 41 42 43
					Name:     "inbox",
					Required: true,
					Usage:    "Batch Inbox Address",
				},
44
				&cli.StringFlag{
45 46 47 48
					Name:     "sender",
					Required: true,
					Usage:    "Batch Sender Address",
				},
49
				&cli.StringFlag{
50 51 52 53
					Name:  "out",
					Value: "/tmp/batch_decoder/transactions_cache",
					Usage: "Cache directory for the found transactions",
				},
54
				&cli.StringFlag{
55 56 57
					Name:     "l1",
					Required: true,
					Usage:    "L1 RPC URL",
58
					EnvVars:  []string{"L1_RPC"},
59
				},
60 61 62 63 64
				&cli.IntFlag{
					Name:  "concurrent-requests",
					Value: 10,
					Usage: "Concurrency level when fetching L1",
				},
65 66 67 68 69 70
			},
			Action: func(cliCtx *cli.Context) error {
				client, err := ethclient.Dial(cliCtx.String("l1"))
				if err != nil {
					log.Fatal(err)
				}
71
				ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
72 73 74 75 76 77 78 79 80 81
				defer cancel()
				chainID, err := client.ChainID(ctx)
				if err != nil {
					log.Fatal(err)
				}
				config := fetch.Config{
					Start:   uint64(cliCtx.Int("start")),
					End:     uint64(cliCtx.Int("end")),
					ChainID: chainID,
					BatchSenders: map[common.Address]struct{}{
82
						common.HexToAddress(cliCtx.String("sender")): {},
83
					},
84 85 86
					BatchInbox:         common.HexToAddress(cliCtx.String("inbox")),
					OutDirectory:       cliCtx.String("out"),
					ConcurrentRequests: uint64(cliCtx.Int("concurrent-requests")),
87 88 89 90 91 92 93 94
				}
				totalValid, totalInvalid := fetch.Batches(client, config)
				fmt.Printf("Fetched batches in range [%v,%v). Found %v valid & %v invalid batches\n", config.Start, config.End, totalValid, totalInvalid)
				fmt.Printf("Fetch Config: Chain ID: %v. Inbox Address: %v. Valid Senders: %v.\n", config.ChainID, config.BatchInbox, config.BatchSenders)
				fmt.Printf("Wrote transactions with batches to %v\n", config.OutDirectory)
				return nil
			},
		},
95 96
		{
			Name:  "reassemble",
97
			Usage: "Reassembles channels from fetched batch transactions and decode batches",
98
			Flags: []cli.Flag{
99
				&cli.StringFlag{
100 101 102 103
					Name:  "in",
					Value: "/tmp/batch_decoder/transactions_cache",
					Usage: "Cache directory for the found transactions",
				},
104
				&cli.StringFlag{
105 106 107 108
					Name:  "out",
					Value: "/tmp/batch_decoder/channel_cache",
					Usage: "Cache directory for the found channels",
				},
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
				&cli.Uint64Flag{
					Name:  "l2-chain-id",
					Value: 10,
					Usage: "L2 chain id for span batch derivation. Default value from op-mainnet.",
				},
				&cli.Uint64Flag{
					Name:  "l2-genesis-timestamp",
					Value: 1686068903,
					Usage: "L2 genesis time for span batch derivation. Default value from op-mainnet. " +
						"Superchain-registry prioritized when given value is inconsistent.",
				},
				&cli.Uint64Flag{
					Name:  "l2-block-time",
					Value: 2,
					Usage: "L2 block time for span batch derivation. Default value from op-mainnet. " +
						"Superchain-registry prioritized when given value is inconsistent.",
				},
				&cli.StringFlag{
					Name:  "inbox",
					Value: "0xFF00000000000000000000000000000000000010",
					Usage: "Batch Inbox Address. Default value from op-mainnet. " +
						"Superchain-registry prioritized when given value is inconsistent.",
				},
132 133
			},
			Action: func(cliCtx *cli.Context) error {
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
				var (
					L2GenesisTime     uint64         = cliCtx.Uint64("l2-genesis-timestamp")
					L2BlockTime       uint64         = cliCtx.Uint64("l2-block-time")
					BatchInboxAddress common.Address = common.HexToAddress(cliCtx.String("inbox"))
				)
				L2ChainID := new(big.Int).SetUint64(cliCtx.Uint64("l2-chain-id"))
				rollupCfg, err := rollup.LoadOPStackRollupConfig(L2ChainID.Uint64())
				if err == nil {
					// prioritize superchain config
					if L2GenesisTime != rollupCfg.Genesis.L2Time {
						L2GenesisTime = rollupCfg.Genesis.L2Time
						fmt.Printf("L2GenesisTime overridden: %v\n", L2GenesisTime)
					}
					if L2BlockTime != rollupCfg.BlockTime {
						L2BlockTime = rollupCfg.BlockTime
						fmt.Printf("L2BlockTime overridden: %v\n", L2BlockTime)
					}
					if BatchInboxAddress != rollupCfg.BatchInboxAddress {
						BatchInboxAddress = rollupCfg.BatchInboxAddress
						fmt.Printf("BatchInboxAddress overridden: %v\n", BatchInboxAddress)
					}
				}
156
				config := reassemble.Config{
157 158 159 160 161 162
					BatchInbox:    BatchInboxAddress,
					InDirectory:   cliCtx.String("in"),
					OutDirectory:  cliCtx.String("out"),
					L2ChainID:     L2ChainID,
					L2GenesisTime: L2GenesisTime,
					L2BlockTime:   L2BlockTime,
163 164 165 166 167
				}
				reassemble.Channels(config)
				return nil
			},
		},
168 169 170 171
		{
			Name:  "force-close",
			Usage: "Create the tx data which will force close a channel",
			Flags: []cli.Flag{
172
				&cli.StringFlag{
173 174 175 176
					Name:     "id",
					Required: true,
					Usage:    "ID of the channel to close",
				},
177
				&cli.StringFlag{
178 179 180 181
					Name:  "inbox",
					Value: "0x0000000000000000000000000000000000000000",
					Usage: "(Optional) Batch Inbox Address",
				},
182
				&cli.StringFlag{
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
					Name:  "in",
					Value: "/tmp/batch_decoder/transactions_cache",
					Usage: "Cache directory for the found transactions",
				},
			},
			Action: func(cliCtx *cli.Context) error {
				var id derive.ChannelID
				if err := (&id).UnmarshalText([]byte(cliCtx.String("id"))); err != nil {
					log.Fatal(err)
				}
				frames := reassemble.LoadFrames(cliCtx.String("in"), common.HexToAddress(cliCtx.String("inbox")))
				var filteredFrames []derive.Frame
				for _, frame := range frames {
					if frame.Frame.ID == id {
						filteredFrames = append(filteredFrames, frame.Frame)
					}
				}
				data, err := derive.ForceCloseTxData(filteredFrames)
				if err != nil {
					log.Fatal(err)
				}
				fmt.Printf("%x\n", data)
				return nil
			},
		},
208 209 210 211 212 213
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}