mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-23 13:38:35 +00:00
5f745dff72
ProtocolConfiguration section must include stand by committee and the number of validators or committee/validators history. Close #3247 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
382 lines
13 KiB
Go
382 lines
13 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TestProtocolConfigurationValidation(t *testing.T) {
|
|
p := &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
TimePerBlock: time.Microsecond,
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
},
|
|
ValidatorsCount: 3,
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
ValidatorsCount: 4,
|
|
ValidatorsHistory: map[uint32]uint32{0: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 4, 1000: 5},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 4, 1000: 5},
|
|
ValidatorsHistory: map[uint32]uint32{0: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 999: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 1000: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1, 999: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 4, 100: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 0, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 0, 100: 4},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
}
|
|
require.NoError(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
}
|
|
err := p.Validate()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "configuration should include StandbyCommittee")
|
|
p = &ProtocolConfiguration{
|
|
StandbyCommittee: []string{"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2"},
|
|
}
|
|
err = p.Validate()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "configuration should either have one of ValidatorsCount or ValidatorsHistory, not both")
|
|
}
|
|
|
|
func TestProtocolConfigurationValidation_Hardforks(t *testing.T) {
|
|
p := &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Unknown": 123, // Unknown hard-fork.
|
|
},
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Aspidochelone": 2,
|
|
"Basilisk": 1, // Lower height in higher hard-fork.
|
|
},
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.Error(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Aspidochelone": 2,
|
|
"Basilisk": 2, // Same height is OK.
|
|
}, StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.NoError(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Aspidochelone": 2,
|
|
"Basilisk": 3, // Larger height is OK.
|
|
},
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.NoError(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Aspidochelone": 2,
|
|
},
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.NoError(t, p.Validate())
|
|
p = &ProtocolConfiguration{
|
|
Hardforks: map[string]uint32{
|
|
"Basilisk": 2,
|
|
},
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
},
|
|
ValidatorsCount: 1,
|
|
}
|
|
require.NoError(t, p.Validate())
|
|
}
|
|
|
|
func TestGetCommitteeAndCNs(t *testing.T) {
|
|
p := &ProtocolConfiguration{
|
|
StandbyCommittee: []string{
|
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
|
},
|
|
CommitteeHistory: map[uint32]uint32{0: 1, 100: 4},
|
|
ValidatorsHistory: map[uint32]uint32{0: 1, 200: 4},
|
|
}
|
|
require.Equal(t, 1, p.GetCommitteeSize(0))
|
|
require.Equal(t, 1, p.GetCommitteeSize(99))
|
|
require.Equal(t, 4, p.GetCommitteeSize(100))
|
|
require.Equal(t, 4, p.GetCommitteeSize(101))
|
|
require.Equal(t, 4, p.GetCommitteeSize(200))
|
|
require.Equal(t, 4, p.GetCommitteeSize(201))
|
|
require.Equal(t, 1, p.GetNumOfCNs(0))
|
|
require.Equal(t, 1, p.GetNumOfCNs(100))
|
|
require.Equal(t, 1, p.GetNumOfCNs(101))
|
|
require.Equal(t, 1, p.GetNumOfCNs(199))
|
|
require.Equal(t, 4, p.GetNumOfCNs(200))
|
|
require.Equal(t, 4, p.GetNumOfCNs(201))
|
|
}
|
|
|
|
func TestProtocolConfigurationEquals(t *testing.T) {
|
|
p := &ProtocolConfiguration{}
|
|
o := &ProtocolConfiguration{}
|
|
require.True(t, p.Equals(o))
|
|
require.True(t, o.Equals(p))
|
|
require.True(t, p.Equals(p))
|
|
|
|
cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"))
|
|
require.NoError(t, err)
|
|
cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml"))
|
|
require.NoError(t, err)
|
|
require.False(t, cfg1.ProtocolConfiguration.Equals(&cfg2.ProtocolConfiguration))
|
|
|
|
cfg2, err = LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"))
|
|
require.NoError(t, err)
|
|
p = &cfg1.ProtocolConfiguration
|
|
o = &cfg2.ProtocolConfiguration
|
|
require.True(t, p.Equals(o))
|
|
|
|
o.CommitteeHistory = map[uint32]uint32{111: 7}
|
|
p.CommitteeHistory = map[uint32]uint32{111: 7}
|
|
require.True(t, p.Equals(o))
|
|
p.CommitteeHistory[111] = 8
|
|
require.False(t, p.Equals(o))
|
|
|
|
o.CommitteeHistory = nil
|
|
p.CommitteeHistory = nil
|
|
|
|
p.Hardforks = map[string]uint32{"Fork": 42}
|
|
o.Hardforks = map[string]uint32{"Fork": 42}
|
|
require.True(t, p.Equals(o))
|
|
p.Hardforks = map[string]uint32{"Fork2": 42}
|
|
require.False(t, p.Equals(o))
|
|
|
|
p.Hardforks = nil
|
|
o.Hardforks = nil
|
|
|
|
p.SeedList = []string{"url1", "url2"}
|
|
o.SeedList = []string{"url1", "url2"}
|
|
require.True(t, p.Equals(o))
|
|
p.SeedList = []string{"url11", "url22"}
|
|
require.False(t, p.Equals(o))
|
|
|
|
p.SeedList = nil
|
|
o.SeedList = nil
|
|
|
|
p.StandbyCommittee = []string{"key1", "key2"}
|
|
o.StandbyCommittee = []string{"key1", "key2"}
|
|
require.True(t, p.Equals(o))
|
|
p.StandbyCommittee = []string{"key2", "key1"}
|
|
require.False(t, p.Equals(o))
|
|
|
|
p.StandbyCommittee = nil
|
|
o.StandbyCommittee = nil
|
|
|
|
o.ValidatorsHistory = map[uint32]uint32{111: 0}
|
|
p.ValidatorsHistory = map[uint32]uint32{111: 0}
|
|
require.True(t, p.Equals(o))
|
|
p.ValidatorsHistory = map[uint32]uint32{112: 0}
|
|
require.False(t, p.Equals(o))
|
|
}
|
|
|
|
func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
|
pk, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
pub := pk.PublicKey()
|
|
|
|
t.Run("MarshalUnmarshalYAML", func(t *testing.T) {
|
|
g := &Genesis{
|
|
Roles: map[noderoles.Role]keys.PublicKeys{
|
|
noderoles.NeoFSAlphabet: {pub},
|
|
noderoles.P2PNotary: {pub},
|
|
},
|
|
Transaction: &GenesisTransaction{
|
|
Script: []byte{1, 2, 3, 4},
|
|
SystemFee: 123,
|
|
},
|
|
}
|
|
testserdes.MarshalUnmarshalYAML(t, g, new(Genesis))
|
|
})
|
|
|
|
t.Run("unmarshal config", func(t *testing.T) {
|
|
t.Run("good", func(t *testing.T) {
|
|
pubStr := hex.EncodeToString(pub.Bytes())
|
|
script := []byte{1, 2, 3, 4}
|
|
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
|
Genesis:
|
|
Transaction:
|
|
Script: "%s"
|
|
SystemFee: 123
|
|
Roles:
|
|
NeoFSAlphabet:
|
|
- %s
|
|
- %s
|
|
Oracle:
|
|
- %s
|
|
- %s`, base64.StdEncoding.EncodeToString(script), pubStr, pubStr, pubStr, pubStr)
|
|
cfg := new(Config)
|
|
require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg))
|
|
require.Equal(t, 2, len(cfg.ProtocolConfiguration.Genesis.Roles))
|
|
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.NeoFSAlphabet])
|
|
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.Oracle])
|
|
require.Equal(t, &GenesisTransaction{
|
|
Script: script,
|
|
SystemFee: 123,
|
|
}, cfg.ProtocolConfiguration.Genesis.Transaction)
|
|
})
|
|
|
|
t.Run("empty", func(t *testing.T) {
|
|
cfgYml := `ProtocolConfiguration:`
|
|
cfg := new(Config)
|
|
require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg))
|
|
require.Nil(t, cfg.ProtocolConfiguration.Genesis.Transaction)
|
|
require.Empty(t, cfg.ProtocolConfiguration.Genesis.Roles)
|
|
})
|
|
|
|
t.Run("unknown role", func(t *testing.T) {
|
|
pubStr := hex.EncodeToString(pub.Bytes())
|
|
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
|
Genesis:
|
|
Roles:
|
|
BadRole:
|
|
- %s`, pubStr)
|
|
cfg := new(Config)
|
|
err := yaml.Unmarshal([]byte(cfgYml), cfg)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "unknown node role: BadRole")
|
|
})
|
|
|
|
t.Run("last role", func(t *testing.T) {
|
|
pubStr := hex.EncodeToString(pub.Bytes())
|
|
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
|
Genesis:
|
|
Roles:
|
|
last:
|
|
- %s`, pubStr)
|
|
cfg := new(Config)
|
|
err := yaml.Unmarshal([]byte(cfgYml), cfg)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "unknown node role: last")
|
|
})
|
|
})
|
|
}
|