forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
genesis_validator_add.go
137 lines (115 loc) · 3.1 KB
/
genesis_validator_add.go
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
package main
import (
"context"
"errors"
"flag"
"fmt"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto"
_ "github.com/gnolang/gno/tm2/pkg/crypto/keys"
)
var (
errInvalidPower = errors.New("invalid validator power")
errInvalidName = errors.New("invalid validator name")
errPublicKeyAddressMismatch = errors.New("provided public key and address do not match")
errAddressPresent = errors.New("validator with same address already present in genesis.json")
)
type validatorAddCfg struct {
rootCfg *validatorCfg
pubKey string
name string
power int64
}
// newValidatorAddCmd creates the genesis validator add subcommand
func newValidatorAddCmd(validatorCfg *validatorCfg, io commands.IO) *commands.Command {
cfg := &validatorAddCfg{
rootCfg: validatorCfg,
}
return commands.NewCommand(
commands.Metadata{
Name: "add",
ShortUsage: "validator add [flags]",
ShortHelp: "adds a new validator to the genesis.json",
},
cfg,
func(_ context.Context, _ []string) error {
return execValidatorAdd(cfg, io)
},
)
}
func (c *validatorAddCfg) RegisterFlags(fs *flag.FlagSet) {
fs.StringVar(
&c.pubKey,
"pub-key",
"",
"the bech32 string representation of the validator's public key",
)
fs.StringVar(
&c.name,
"name",
"",
"the name of the validator (must be unique)",
)
fs.Int64Var(
&c.power,
"power",
1,
"the voting power of the validator (must be > 0)",
)
}
func execValidatorAdd(cfg *validatorAddCfg, io commands.IO) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath)
if loadErr != nil {
return fmt.Errorf("unable to load genesis, %w", loadErr)
}
// Check the validator address
address, err := crypto.AddressFromString(cfg.rootCfg.address)
if err != nil {
return fmt.Errorf("invalid validator address, %w", err)
}
// Check the voting power
if cfg.power < 1 {
return errInvalidPower
}
// Check the name
if cfg.name == "" {
return errInvalidName
}
// Check the public key
pubKey, err := crypto.PubKeyFromBech32(cfg.pubKey)
if err != nil {
return fmt.Errorf("invalid validator public key, %w", err)
}
// Check the public key matches the address
if pubKey.Address() != address {
return errPublicKeyAddressMismatch
}
validator := types.GenesisValidator{
Address: address,
PubKey: pubKey,
Power: cfg.power,
Name: cfg.name,
}
// Check if the validator exists
for _, genesisValidator := range genesis.Validators {
// There is no need to check if the public keys match
// since the address is derived from it, and the derivation
// is checked already
if validator.Address == genesisValidator.Address {
return errAddressPresent
}
}
// Add the validator
genesis.Validators = append(genesis.Validators, validator)
// Save the updated genesis
if err := genesis.SaveAs(cfg.rootCfg.genesisPath); err != nil {
return fmt.Errorf("unable to save genesis.json, %w", err)
}
io.Printfln(
"Validator with address %s added to genesis file",
cfg.rootCfg.address,
)
return nil
}