Skip to content

Commit

Permalink
ir: Use genesis role designations for autodeploy (#2652)
Browse files Browse the repository at this point in the history
  • Loading branch information
roman-khimov authored Dec 7, 2023
2 parents 752d8a7 + 482e1f7 commit c0d0159
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Changelog for NeoFS Node
- Support of verified domains for the storage nodes (#2280)
- `neofs-lens storage status` CLI command (#2550)
- Human-readable output of objects' creation timestamp to `neofs-cli container list-objects` (#2653)
- Ability to preset P2PNotary and NeoFSAlphabet roles to validators at the FS chain's genesis (#2643)

### Fixed
- `neofs-cli netmap netinfo` documentation (#2555)
Expand Down
19 changes: 15 additions & 4 deletions config/example/ir.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ morph:
- 0283120f4c8c1fc1d792af5063d2def9da5fddc90bc1384de7fcfdda33c3860170
consensus: # Local consensus launch mode activated only when 'endpoint.client' is unset.
magic: 15405 # Network magic. Must be unsigned integer in range [1:4294967295]
committee: # Initial committee
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2 # Hex-encoded public key
committee: # Hex-encoded public keys of the initial committee
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
storage: # Blockchain storage
type: boltdb # One of following storage types:
# boltdb (local BoltDB)
Expand All @@ -41,8 +44,13 @@ morph:
- node3:20333
hardforks: # Optional hard-forks
name: 1730000 # Maps name to chain height. Heights must not be greater than 4294967295
validators_history: # Optional number of consensus nodes to use after given height
10: 7 # Maps chain height to number of consensus nodes. Values must not be greater than 2147483647
validators_history: # Optional number of consensus nodes to use after given height.
# Maps chain height to number of consensus nodes. Heights must be multiples of the 'committee' size.
# Values must be positive up to 'committee' size.
# If specified, value for 0 (genesis) height must be set.
0: 4
4: 1
12: 4
rpc: # Optional RPC settings
listen: # Optional list of network addresses to listen Neo RPC on. By default, protocol is not served
# TCP addresses in 'host:port' format
Expand Down Expand Up @@ -75,6 +83,9 @@ morph:
ping: # Optional settings of pinging mechanism
interval: 30s # Optional time period between pings. Defaults to 30s. Must not be negative
timeout: 90s # Optional time period to wait for pong. Defaults to 1m. Must not be negative
set_roles_in_genesis: true # Optional flag for designating P2PNotary and NeoFSAlphabet roles to all
# genesis block validators. The validators depend on 'committee' and, if set, 'validators_history'.
# Must be 'true' or 'false'.

fschain_autodeploy: true # Optional flag to run auto-deployment procedure of the FS chain. By default,
# the chain is expected to be deployed/updated in the background (e.g. via NeoFS ADM tool).
Expand Down
15 changes: 14 additions & 1 deletion pkg/innerring/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,24 @@ func parseBlockchainConfig(v *viper.Viper, _logger *zap.Logger) (c blockchain.Co
const validatorsHistoryKey = rootSection + ".validators_history"
if v.IsSet(validatorsHistoryKey) {
c.ValidatorsHistory = make(map[uint32]uint32)
committeeSize := uint64(c.Committee.Len())
err = parseConfigMap(v, validatorsHistoryKey, "validators history", func(name string, val any) error {
height, err := strconv.ParseUint(name, 10, 32)
if err != nil {
return fmt.Errorf("parse unsigned integer: %w", err)
}

if height%committeeSize != 0 {
return fmt.Errorf("height %d is not a multiple of the %q size", height, committeeKey)
}

num, err := cast.ToUint32E(val)
if err != nil {
return err
} else if num > math.MaxInt32 {
} else if num <= 0 {
return fmt.Errorf("value %d is out of allowable range", num)
} else if num > uint32(c.Committee.Len()) {
return fmt.Errorf("value exceeds %q size: %d > %d", committeeKey, num, c.Committee.Len())
}
c.ValidatorsHistory[uint32(height)] = num
return nil
Expand Down Expand Up @@ -210,6 +218,11 @@ func parseBlockchainConfig(v *viper.Viper, _logger *zap.Logger) (c blockchain.Co
}
}

c.SetRolesInGenesis, err = parseConfigBool(v, rootSection+".set_roles_in_genesis", "flag to set roles for the committee in the genesis block")
if err != nil && !errors.Is(err, errMissingConfig) {
return c, err
}

c.Logger = _logger

return c, nil
Expand Down
29 changes: 22 additions & 7 deletions pkg/innerring/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ morph:
committee:
- 02cddc58c3f7d27b5c9967dd90fbd4269798cbbb9cd7b137d886aca209cb734fb6
- 03f87b0a0416e4028bccf7258db3b411412ce1c7426b2c857f54e59d0d23782570
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
storage:
type: boltdb
path: chain.db
Expand All @@ -38,8 +40,9 @@ const validBlockchainConfigOptions = `
hardforks:
name: 1730000
validators_history:
2: 3
10: 7
0: 4
4: 1
12: 4
rpc:
listen:
- localhost:30000
Expand All @@ -64,6 +67,7 @@ const validBlockchainConfigOptions = `
ping:
interval: 44s
timeout: 55s
set_roles_in_genesis: true
`

func _newConfigFromYAML(tb testing.TB, yaml1, yaml2 string) *viper.Viper {
Expand Down Expand Up @@ -124,6 +128,8 @@ func TestParseBlockchainConfig(t *testing.T) {
validCommittee, err := keys.NewPublicKeysFromStrings([]string{
"02cddc58c3f7d27b5c9967dd90fbd4269798cbbb9cd7b137d886aca209cb734fb6",
"03f87b0a0416e4028bccf7258db3b411412ce1c7426b2c857f54e59d0d23782570",
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
})
require.NoError(t, err)

Expand Down Expand Up @@ -190,9 +196,11 @@ func TestParseBlockchainConfig(t *testing.T) {
},
Storage: blockchain.BoltDB("chain.db"),
ValidatorsHistory: map[uint32]uint32{
2: 3,
10: 7,
0: 4,
4: 1,
12: 4,
},
SetRolesInGenesis: true,
}, c)
})

Expand Down Expand Up @@ -246,10 +254,12 @@ func TestParseBlockchainConfig(t *testing.T) {
{kvF("hardforks", map[string]any{"name": -1})},
{kvF("hardforks", map[string]any{"name": math.MaxUint32 + 1})},
{kvF("validators_history", map[string]any{"not a number": 1})},
{kvF("validators_history", map[string]any{"1": "not a number"})},
{kvF("validators_history", map[string]any{"0": "not a number"})},
{kvF("validators_history", map[string]any{"-1": 1})},
{kvF("validators_history", map[string]any{"1": -1})},
{kvF("validators_history", map[string]any{"1": math.MaxInt32 + 1})},
{kvF("validators_history", map[string]any{"0": -1})},
{kvF("validators_history", map[string]any{"0": math.MaxUint32 + 1})},
{kvF("validators_history", map[string]any{"0": len(validCommittee) + 1})},
{kvF("validators_history", map[string]any{"0": 1, "3": 1})}, // height is not a multiple
{kvF("rpc.listen", []string{"not a TCP address"})},
{kvF("rpc.listen", []string{"127.0.0.1"})}, // missing port
{kvF("rpc.tls.enabled", true), kvF("rpc.tls.cert_file", "")}, // enabled but no cert file is provided
Expand All @@ -272,6 +282,11 @@ func TestParseBlockchainConfig(t *testing.T) {
{kvF("p2p.peers.max", math.MaxInt32+1)},
{kvF("p2p.peers.attempts", -1)},
{kvF("p2p.peers.attempts", math.MaxInt32+1)},
{kvF("set_roles_in_genesis", "not a boolean")},
{kvF("set_roles_in_genesis", 1)},
{kvF("set_roles_in_genesis", "True")},
{kvF("set_roles_in_genesis", "False")},
{kvF("set_roles_in_genesis", "not a boolean")},
} {
var reportMsg []string

Expand Down
44 changes: 39 additions & 5 deletions pkg/innerring/internal/blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/consensus"
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
Expand Down Expand Up @@ -235,9 +236,17 @@ type Config struct {

// Maps chain height to number of consensus nodes.
//
// Optional: by default Committee size is used. Each value must not be greater
// than math.MaxInt32.
// Optional: by default Committee size is used. Each value must be positive and
// must not exceed Committee length. Value for zero key (genesis height) is
// required.
ValidatorsHistory map[uint32]uint32

// Whether to designate [noderoles.P2PNotary] and [noderoles.NeoFSAlphabet]
// roles to the Committee (keep an eye on ValidatorsHistory) for genesis block
// in the RoleManagement contract.
//
// Optional: by default, roles are unset.
SetRolesInGenesis bool
}

// New returns new Blockchain configured by the specified Config. New panics if
Expand Down Expand Up @@ -274,9 +283,24 @@ func New(cfg Config) (res *Blockchain, err error) {
panic("negative proto tick interval")
}

for height, num := range cfg.ValidatorsHistory {
if num > math.MaxInt32 {
panic(fmt.Sprintf("number of validators at height %d is out of allowable range %d", height, num))
if cfg.ValidatorsHistory != nil {
_, ok := cfg.ValidatorsHistory[0]
if !ok {
panic("missing 0 (genesis) height in validators history")
}

committeeSize := uint32(cfg.Committee.Len())

for height, num := range cfg.ValidatorsHistory {
if height%committeeSize != 0 {
panic(fmt.Sprintf("validators history's height is not a multiple of the committee size: %d%%%d != 0", height, committeeSize))
}
if num == 0 {
panic(fmt.Sprintf("zero number of validators at height %d", height))
}
if num > committeeSize {
panic(fmt.Sprintf("number of validators at height %d exceeds committee: %d > %d", height, num, committeeSize))
}
}
}

Expand Down Expand Up @@ -334,6 +358,16 @@ func New(cfg Config) (res *Blockchain, err error) {
cfgBaseProto.ValidatorsCount = uint32(len(standByCommittee))
}

if cfg.SetRolesInGenesis {
// note that ValidatorsHistory or ValidatorsCount field must be set above
genesisValidatorsCount := cfgBaseProto.GetNumOfCNs(0)
cfgBaseProto.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{
// Notary service is always enabled, see below
noderoles.P2PNotary: cfg.Committee[:genesisValidatorsCount],
noderoles.NeoFSAlphabet: cfg.Committee[:genesisValidatorsCount],
}
}

cfgBaseApp := &cfgBase.ApplicationConfiguration
cfgBaseApp.Relay = true
cfgBaseApp.Consensus.Enabled = true
Expand Down

0 comments on commit c0d0159

Please sign in to comment.