github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/config/protocol_config_test.go (about) 1 package config 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "path/filepath" 7 "testing" 8 "time" 9 10 "github.com/nspcc-dev/neo-go/internal/testserdes" 11 "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" 12 "github.com/nspcc-dev/neo-go/pkg/crypto/keys" 13 "github.com/stretchr/testify/require" 14 "gopkg.in/yaml.v3" 15 ) 16 17 func TestProtocolConfigurationValidation(t *testing.T) { 18 p := &ProtocolConfiguration{ 19 StandbyCommittee: []string{ 20 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 21 }, 22 ValidatorsCount: 1, 23 TimePerBlock: time.Microsecond, 24 } 25 require.Error(t, p.Validate()) 26 p = &ProtocolConfiguration{ 27 ValidatorsCount: 1, 28 } 29 require.Error(t, p.Validate()) 30 p = &ProtocolConfiguration{ 31 StandbyCommittee: []string{ 32 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 33 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 34 }, 35 ValidatorsCount: 3, 36 } 37 require.Error(t, p.Validate()) 38 p = &ProtocolConfiguration{ 39 StandbyCommittee: []string{ 40 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 41 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 42 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 43 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 44 }, 45 ValidatorsCount: 4, 46 ValidatorsHistory: map[uint32]uint32{0: 4}, 47 } 48 require.Error(t, p.Validate()) 49 p = &ProtocolConfiguration{ 50 StandbyCommittee: []string{ 51 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 52 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 53 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 54 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 55 }, 56 CommitteeHistory: map[uint32]uint32{0: 4}, 57 ValidatorsHistory: map[uint32]uint32{0: 4, 1000: 5}, 58 } 59 require.Error(t, p.Validate()) 60 p = &ProtocolConfiguration{ 61 StandbyCommittee: []string{ 62 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 63 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 64 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 65 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 66 }, 67 CommitteeHistory: map[uint32]uint32{0: 4, 1000: 5}, 68 ValidatorsHistory: map[uint32]uint32{0: 4}, 69 } 70 require.Error(t, p.Validate()) 71 p = &ProtocolConfiguration{ 72 StandbyCommittee: []string{ 73 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 74 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 75 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 76 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 77 }, 78 CommitteeHistory: map[uint32]uint32{0: 1, 999: 4}, 79 ValidatorsHistory: map[uint32]uint32{0: 1}, 80 } 81 require.Error(t, p.Validate()) 82 p = &ProtocolConfiguration{ 83 StandbyCommittee: []string{ 84 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 85 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 86 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 87 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 88 }, 89 CommitteeHistory: map[uint32]uint32{0: 1, 1000: 4}, 90 ValidatorsHistory: map[uint32]uint32{0: 1, 999: 4}, 91 } 92 require.Error(t, p.Validate()) 93 p = &ProtocolConfiguration{ 94 StandbyCommittee: []string{ 95 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 96 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 97 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 98 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 99 }, 100 CommitteeHistory: map[uint32]uint32{0: 1, 100: 4}, 101 ValidatorsHistory: map[uint32]uint32{0: 4, 100: 4}, 102 } 103 require.Error(t, p.Validate()) 104 p = &ProtocolConfiguration{ 105 StandbyCommittee: []string{ 106 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 107 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 108 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 109 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 110 }, 111 CommitteeHistory: map[uint32]uint32{0: 0, 100: 4}, 112 ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4}, 113 } 114 require.Error(t, p.Validate()) 115 p = &ProtocolConfiguration{ 116 StandbyCommittee: []string{ 117 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 118 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 119 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 120 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 121 }, 122 CommitteeHistory: map[uint32]uint32{0: 1, 100: 4}, 123 ValidatorsHistory: map[uint32]uint32{0: 0, 100: 4}, 124 } 125 require.Error(t, p.Validate()) 126 p = &ProtocolConfiguration{ 127 StandbyCommittee: []string{ 128 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 129 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 130 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 131 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 132 }, 133 CommitteeHistory: map[uint32]uint32{0: 1, 100: 4}, 134 ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4}, 135 } 136 require.NoError(t, p.Validate()) 137 p = &ProtocolConfiguration{ 138 StandbyCommittee: []string{}, 139 CommitteeHistory: map[uint32]uint32{0: 1, 100: 4}, 140 ValidatorsHistory: map[uint32]uint32{0: 1, 100: 4}, 141 } 142 err := p.Validate() 143 require.Error(t, err) 144 require.Contains(t, err.Error(), "configuration should include StandbyCommittee") 145 p = &ProtocolConfiguration{ 146 StandbyCommittee: []string{"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2"}, 147 } 148 err = p.Validate() 149 require.Error(t, err) 150 require.Contains(t, err.Error(), "configuration should either have one of ValidatorsCount or ValidatorsHistory, not both") 151 } 152 153 func TestProtocolConfigurationValidation_Hardforks(t *testing.T) { 154 p := &ProtocolConfiguration{ 155 Hardforks: map[string]uint32{ 156 "Unknown": 123, // Unknown hard-fork. 157 }, 158 } 159 require.Error(t, p.Validate()) 160 p = &ProtocolConfiguration{ 161 Hardforks: map[string]uint32{ 162 "Aspidochelone": 2, 163 "Basilisk": 1, // Lower height in higher hard-fork. 164 }, 165 StandbyCommittee: []string{ 166 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 167 }, 168 ValidatorsCount: 1, 169 } 170 require.Error(t, p.Validate()) 171 p = &ProtocolConfiguration{ 172 Hardforks: map[string]uint32{ 173 "Aspidochelone": 2, 174 "Basilisk": 2, // Same height is OK. 175 }, StandbyCommittee: []string{ 176 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 177 }, 178 ValidatorsCount: 1, 179 } 180 require.NoError(t, p.Validate()) 181 p = &ProtocolConfiguration{ 182 Hardforks: map[string]uint32{ 183 "Aspidochelone": 2, 184 "Basilisk": 3, // Larger height is OK. 185 }, 186 StandbyCommittee: []string{ 187 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 188 }, 189 ValidatorsCount: 1, 190 } 191 require.NoError(t, p.Validate()) 192 p = &ProtocolConfiguration{ 193 Hardforks: map[string]uint32{ 194 "Aspidochelone": 2, 195 }, 196 StandbyCommittee: []string{ 197 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 198 }, 199 ValidatorsCount: 1, 200 } 201 require.NoError(t, p.Validate()) 202 p = &ProtocolConfiguration{ 203 Hardforks: map[string]uint32{ 204 "Basilisk": 2, 205 }, 206 StandbyCommittee: []string{ 207 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 208 }, 209 ValidatorsCount: 1, 210 } 211 require.NoError(t, p.Validate()) 212 } 213 214 func TestGetCommitteeAndCNs(t *testing.T) { 215 p := &ProtocolConfiguration{ 216 StandbyCommittee: []string{ 217 "02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", 218 "02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e", 219 "03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699", 220 "02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62", 221 }, 222 CommitteeHistory: map[uint32]uint32{0: 1, 100: 4}, 223 ValidatorsHistory: map[uint32]uint32{0: 1, 200: 4}, 224 } 225 require.Equal(t, 1, p.GetCommitteeSize(0)) 226 require.Equal(t, 1, p.GetCommitteeSize(99)) 227 require.Equal(t, 4, p.GetCommitteeSize(100)) 228 require.Equal(t, 4, p.GetCommitteeSize(101)) 229 require.Equal(t, 4, p.GetCommitteeSize(200)) 230 require.Equal(t, 4, p.GetCommitteeSize(201)) 231 require.Equal(t, 1, p.GetNumOfCNs(0)) 232 require.Equal(t, 1, p.GetNumOfCNs(100)) 233 require.Equal(t, 1, p.GetNumOfCNs(101)) 234 require.Equal(t, 1, p.GetNumOfCNs(199)) 235 require.Equal(t, 4, p.GetNumOfCNs(200)) 236 require.Equal(t, 4, p.GetNumOfCNs(201)) 237 } 238 239 func TestProtocolConfigurationEquals(t *testing.T) { 240 p := &ProtocolConfiguration{} 241 o := &ProtocolConfiguration{} 242 require.True(t, p.Equals(o)) 243 require.True(t, o.Equals(p)) 244 require.True(t, p.Equals(p)) 245 246 cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml")) 247 require.NoError(t, err) 248 cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml")) 249 require.NoError(t, err) 250 require.False(t, cfg1.ProtocolConfiguration.Equals(&cfg2.ProtocolConfiguration)) 251 252 cfg2, err = LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml")) 253 require.NoError(t, err) 254 p = &cfg1.ProtocolConfiguration 255 o = &cfg2.ProtocolConfiguration 256 require.True(t, p.Equals(o)) 257 258 o.CommitteeHistory = map[uint32]uint32{111: 7} 259 p.CommitteeHistory = map[uint32]uint32{111: 7} 260 require.True(t, p.Equals(o)) 261 p.CommitteeHistory[111] = 8 262 require.False(t, p.Equals(o)) 263 264 o.CommitteeHistory = nil 265 p.CommitteeHistory = nil 266 267 p.Hardforks = map[string]uint32{"Fork": 42} 268 o.Hardforks = map[string]uint32{"Fork": 42} 269 require.True(t, p.Equals(o)) 270 p.Hardforks = map[string]uint32{"Fork2": 42} 271 require.False(t, p.Equals(o)) 272 273 p.Hardforks = nil 274 o.Hardforks = nil 275 276 p.SeedList = []string{"url1", "url2"} 277 o.SeedList = []string{"url1", "url2"} 278 require.True(t, p.Equals(o)) 279 p.SeedList = []string{"url11", "url22"} 280 require.False(t, p.Equals(o)) 281 282 p.SeedList = nil 283 o.SeedList = nil 284 285 p.StandbyCommittee = []string{"key1", "key2"} 286 o.StandbyCommittee = []string{"key1", "key2"} 287 require.True(t, p.Equals(o)) 288 p.StandbyCommittee = []string{"key2", "key1"} 289 require.False(t, p.Equals(o)) 290 291 p.StandbyCommittee = nil 292 o.StandbyCommittee = nil 293 294 o.ValidatorsHistory = map[uint32]uint32{111: 0} 295 p.ValidatorsHistory = map[uint32]uint32{111: 0} 296 require.True(t, p.Equals(o)) 297 p.ValidatorsHistory = map[uint32]uint32{112: 0} 298 require.False(t, p.Equals(o)) 299 } 300 301 func TestGenesisExtensionsMarshalYAML(t *testing.T) { 302 pk, err := keys.NewPrivateKey() 303 require.NoError(t, err) 304 pub := pk.PublicKey() 305 306 t.Run("MarshalUnmarshalYAML", func(t *testing.T) { 307 g := &Genesis{ 308 Roles: map[noderoles.Role]keys.PublicKeys{ 309 noderoles.NeoFSAlphabet: {pub}, 310 noderoles.P2PNotary: {pub}, 311 }, 312 Transaction: &GenesisTransaction{ 313 Script: []byte{1, 2, 3, 4}, 314 SystemFee: 123, 315 }, 316 } 317 testserdes.MarshalUnmarshalYAML(t, g, new(Genesis)) 318 }) 319 320 t.Run("unmarshal config", func(t *testing.T) { 321 t.Run("good", func(t *testing.T) { 322 pubStr := pub.StringCompressed() 323 script := []byte{1, 2, 3, 4} 324 cfgYml := fmt.Sprintf(`ProtocolConfiguration: 325 Genesis: 326 Transaction: 327 Script: "%s" 328 SystemFee: 123 329 Roles: 330 NeoFSAlphabet: 331 - %s 332 - %s 333 Oracle: 334 - %s 335 - %s`, base64.StdEncoding.EncodeToString(script), pubStr, pubStr, pubStr, pubStr) 336 cfg := new(Config) 337 require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg)) 338 require.Equal(t, 2, len(cfg.ProtocolConfiguration.Genesis.Roles)) 339 require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.NeoFSAlphabet]) 340 require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.Oracle]) 341 require.Equal(t, &GenesisTransaction{ 342 Script: script, 343 SystemFee: 123, 344 }, cfg.ProtocolConfiguration.Genesis.Transaction) 345 }) 346 347 t.Run("empty", func(t *testing.T) { 348 cfgYml := `ProtocolConfiguration:` 349 cfg := new(Config) 350 require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg)) 351 require.Nil(t, cfg.ProtocolConfiguration.Genesis.Transaction) 352 require.Empty(t, cfg.ProtocolConfiguration.Genesis.Roles) 353 }) 354 355 t.Run("unknown role", func(t *testing.T) { 356 pubStr := pub.StringCompressed() 357 cfgYml := fmt.Sprintf(`ProtocolConfiguration: 358 Genesis: 359 Roles: 360 BadRole: 361 - %s`, pubStr) 362 cfg := new(Config) 363 err := yaml.Unmarshal([]byte(cfgYml), cfg) 364 require.Error(t, err) 365 require.Contains(t, err.Error(), "unknown node role: BadRole") 366 }) 367 368 t.Run("last role", func(t *testing.T) { 369 pubStr := pub.StringCompressed() 370 cfgYml := fmt.Sprintf(`ProtocolConfiguration: 371 Genesis: 372 Roles: 373 last: 374 - %s`, pubStr) 375 cfg := new(Config) 376 err := yaml.Unmarshal([]byte(cfgYml), cfg) 377 require.Error(t, err) 378 require.Contains(t, err.Error(), "unknown node role: last") 379 }) 380 }) 381 }