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
package main
import (
"encoding/hex"
"fmt"
"log/slog"
"os"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
opservice "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
)
const EnvPrefix = "OP_CHAIN_OPS_PROTOCOL_VERSION"
var (
MajorFlag = &cli.Uint64Flag{
Name: "major",
Value: 0,
Usage: "major version component",
EnvVars: opservice.PrefixEnvVar(EnvPrefix, "MAJOR"),
}
MinorFlag = &cli.Uint64Flag{
Name: "minor",
Value: 0,
Usage: "minor version component",
EnvVars: opservice.PrefixEnvVar(EnvPrefix, "MINOR"),
}
PatchFlag = &cli.Uint64Flag{
Name: "patch",
Value: 0,
Usage: "patch version component",
EnvVars: opservice.PrefixEnvVar(EnvPrefix, "PATCH"),
}
PrereleaseFlag = &cli.Uint64Flag{
Name: "prerelease",
Value: 0,
Usage: "prerelease version component",
EnvVars: opservice.PrefixEnvVar(EnvPrefix, "PRERELEASE"),
}
BuildFlag = &cli.StringFlag{
Name: "build",
Value: "0000000000000000",
Usage: "build version component as 8-byte hex string without 0x prefix",
EnvVars: opservice.PrefixEnvVar(EnvPrefix, "BUILD"),
}
)
func main() {
color := isatty.IsTerminal(os.Stderr.Fd())
oplog.SetGlobalLogHandler(log.NewTerminalHandlerWithLevel(os.Stdout, slog.LevelDebug, color))
app := &cli.App{
Name: "protocol-version",
Usage: "Util to interact with protocol-version data",
Flags: []cli.Flag{},
Writer: os.Stdout,
}
app.Commands = []*cli.Command{
{
Name: "encode",
Usage: "Encode a protocol version (type 0) to its onchain bytes32 form.",
Flags: []cli.Flag{
MajorFlag, MinorFlag, PatchFlag, PrereleaseFlag, BuildFlag,
},
Action: encodeProtocolVersion,
},
{
Name: "decode",
Usage: "Decode a protocol version from its onchain bytes32 form (incl. 0x prefix).",
ArgsUsage: "<bytes32>",
Action: decodeProtocolVersion,
},
}
if err := app.Run(os.Args); err != nil {
log.Crit("critical error", "err", err)
}
}
func encodeProtocolVersion(ctx *cli.Context) error {
u32Flag := func(name string) (uint32, error) {
v := ctx.Uint64(name)
if v >= uint64(1<<32) {
return 0, fmt.Errorf("value of flag %q must be valid uint32, %d (0x%x)", name, v, v)
}
return uint32(v), nil
}
major, err := u32Flag(MajorFlag.Name)
if err != nil {
return err
}
minor, err := u32Flag(MinorFlag.Name)
if err != nil {
return err
}
patch, err := u32Flag(PatchFlag.Name)
if err != nil {
return err
}
prerelease, err := u32Flag(PrereleaseFlag.Name)
if err != nil {
return err
}
buildVal := ctx.String(BuildFlag.Name)
if len(buildVal) != 16 {
return fmt.Errorf("build flag value must be 16 characters")
}
var build [8]byte
if _, err := hex.Decode(build[:], []byte(buildVal)); err != nil {
return fmt.Errorf("failed to decode build flag: %q", buildVal)
}
version := params.ProtocolVersionV0{
Build: build,
Major: major,
Minor: minor,
Patch: patch,
PreRelease: prerelease,
}.Encode()
_, err = fmt.Fprintln(ctx.App.Writer, common.Hash(version).String())
return err
}
func decodeProtocolVersion(ctx *cli.Context) error {
if ctx.NArg() != 1 {
return fmt.Errorf("expected 1 argument: protocol version")
}
hexVersion := ctx.Args().Get(0)
var v params.ProtocolVersion
if err := v.UnmarshalText([]byte(hexVersion)); err != nil {
return fmt.Errorf("failed to decode protocol version: %w", err)
}
_, err := fmt.Fprintln(ctx.App.Writer, v.String())
return err
}