Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ir: Use genesis role designations for autodeploy #2652

Merged
merged 2 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU, genesis-based roles are planned to be a standard for the network. How about reverting the meaning of this setting so that it can be skipped in default config? E.g. s/set_roles_in_genesis/skip_genesis_roles.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

propose this in #2643 pls. To me, we aint ready yet to use genesis roles everywhere by default

# 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()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don;t quite like these repeating checks. We have https://github.com/nspcc-dev/neo-go/blob/6c0c2a6a98b0799f1e19dfeac8956169f1aa4a7a/pkg/config/protocol_config.go#L80, and if some check is missing there, then create an issue and we'll add more checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not this issue's point but interesting, moved to #2666

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
Loading