mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 03:41:34 +00:00
Merge pull request #2334 from nspcc-dev/extendable-validators
Extendable validators
This commit is contained in:
commit
1df447cd68
23 changed files with 460 additions and 129 deletions
|
@ -197,6 +197,7 @@ protocol-related settings described in the table below.
|
||||||
|
|
||||||
| Section | Type | Default value | Description | Notes |
|
| Section | Type | Default value | Description | Notes |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
|
| CommitteeHistory | map[uint32]int | none | Number of committee members after given height, for example `{0: 1, 20: 4}` sets up a chain with one committee member since the genesis and then changes the setting to 4 committee members at the height of 20. `StandbyCommittee` committee setting must have the number of keys equal or exceeding the highest value in this option. Blocks numbers where the change happens must be divisble by the old and by the new values simultaneously. If not set, committee size is derived from the `StandbyCommittee` setting and never changes. |
|
||||||
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store latest state. If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. |
|
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store latest state. If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. |
|
||||||
| Magic | `uint32` | `0` | Magic number which uniquely identifies NEO network. |
|
| Magic | `uint32` | `0` | Magic number which uniquely identifies NEO network. |
|
||||||
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
||||||
|
@ -216,6 +217,7 @@ protocol-related settings described in the table below.
|
||||||
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
|
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
|
||||||
| StateRootInHeader | `bool` | `false` | Enables storing state root in block header. | Experimental protocol extension! |
|
| StateRootInHeader | `bool` | `false` | Enables storing state root in block header. | Experimental protocol extension! |
|
||||||
| StateSyncInterval | `int` | `40000` | The number of blocks between state heights available for MPT state data synchronization. | `P2PStateExchangeExtensions` should be enabled to use this setting. |
|
| StateSyncInterval | `int` | `40000` | The number of blocks between state heights available for MPT state data synchronization. | `P2PStateExchangeExtensions` should be enabled to use this setting. |
|
||||||
| ValidatorsCount | `int` | `0` | Number of validators. |
|
| ValidatorsCount | `int` | `0` | Number of validators set for the whole network lifetime, can't be set if `ValidatorsHistory` setting is used. |
|
||||||
|
| ValidatorsHistory | map[uint32]int | none | Number of consensus nodes to use after given height (see `CommitteeHistory` also). Heights where the change occurs must be divisible by the number of committee members at that height. Can't be used with `ValidatorsCount` not equal to zero. |
|
||||||
| VerifyBlocks | `bool` | `false` | Denotes whether to verify received blocks. |
|
| VerifyBlocks | `bool` | `false` | Denotes whether to verify received blocks. |
|
||||||
| VerifyTransactions | `bool` | `false` | Denotes whether to verify transactions in received blocks. |
|
| VerifyTransactions | `bool` | `false` | Denotes whether to verify transactions in received blocks. |
|
||||||
|
|
|
@ -300,16 +300,6 @@ func (chain *FakeChain) GetValidators() ([]*keys.PublicKey, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStandByCommittee implements Blockchainer interface.
|
|
||||||
func (chain *FakeChain) GetStandByCommittee() keys.PublicKeys {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStandByValidators implements Blockchainer interface.
|
|
||||||
func (chain *FakeChain) GetStandByValidators() keys.PublicKeys {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEnrollments implements Blockchainer interface.
|
// GetEnrollments implements Blockchainer interface.
|
||||||
func (chain *FakeChain) GetEnrollments() ([]state.Validator, error) {
|
func (chain *FakeChain) GetEnrollments() ([]state.Validator, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc"
|
"github.com/nspcc-dev/neo-go/pkg/rpc"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
@ -63,10 +62,9 @@ func LoadFile(configPath string) (Config, error) {
|
||||||
return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
|
return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name := range config.ProtocolConfiguration.NativeUpdateHistories {
|
err = config.ProtocolConfiguration.Validate()
|
||||||
if !nativenames.IsValid(name) {
|
if err != nil {
|
||||||
return Config{}, fmt.Errorf("NativeActivations configuration section contains unexpected native contract name: %s", name)
|
return Config{}, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProtocolConfiguration represents the protocol config.
|
// ProtocolConfiguration represents the protocol config.
|
||||||
type (
|
type (
|
||||||
ProtocolConfiguration struct {
|
ProtocolConfiguration struct {
|
||||||
|
// CommitteeHistory stores committee size change history (height: size).
|
||||||
|
CommitteeHistory map[uint32]int `yaml:"CommitteeHistory"`
|
||||||
Magic netmode.Magic `yaml:"Magic"`
|
Magic netmode.Magic `yaml:"Magic"`
|
||||||
MemPoolSize int `yaml:"MemPoolSize"`
|
MemPoolSize int `yaml:"MemPoolSize"`
|
||||||
|
|
||||||
|
@ -53,9 +60,123 @@ type (
|
||||||
// It is valid only if P2PStateExchangeExtensions are enabled.
|
// It is valid only if P2PStateExchangeExtensions are enabled.
|
||||||
StateSyncInterval int `yaml:"StateSyncInterval"`
|
StateSyncInterval int `yaml:"StateSyncInterval"`
|
||||||
ValidatorsCount int `yaml:"ValidatorsCount"`
|
ValidatorsCount int `yaml:"ValidatorsCount"`
|
||||||
|
// Validators stores history of changes to consensus node number (height: number).
|
||||||
|
ValidatorsHistory map[uint32]int `yaml:"ValidatorsHistory"`
|
||||||
// Whether to verify received blocks.
|
// Whether to verify received blocks.
|
||||||
VerifyBlocks bool `yaml:"VerifyBlocks"`
|
VerifyBlocks bool `yaml:"VerifyBlocks"`
|
||||||
// Whether to verify transactions in received blocks.
|
// Whether to verify transactions in received blocks.
|
||||||
VerifyTransactions bool `yaml:"VerifyTransactions"`
|
VerifyTransactions bool `yaml:"VerifyTransactions"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// heightNumber is an auxiliary structure for configuration checks.
|
||||||
|
type heightNumber struct {
|
||||||
|
h uint32
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks ProtocolConfiguration for internal consistency and returns
|
||||||
|
// error if anything inappropriate found. Other methods can rely on protocol
|
||||||
|
// validity after this.
|
||||||
|
func (p *ProtocolConfiguration) Validate() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for name := range p.NativeUpdateHistories {
|
||||||
|
if !nativenames.IsValid(name) {
|
||||||
|
return fmt.Errorf("NativeActivations configuration section contains unexpected native contract name: %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.ValidatorsCount != 0 && len(p.ValidatorsHistory) != 0 {
|
||||||
|
return errors.New("configuration should either have ValidatorsCount or ValidatorsHistory, not both")
|
||||||
|
}
|
||||||
|
if len(p.StandbyCommittee) < p.ValidatorsCount {
|
||||||
|
return errors.New("validators count can't exceed the size of StandbyCommittee")
|
||||||
|
}
|
||||||
|
var arr = make([]heightNumber, 0, len(p.CommitteeHistory))
|
||||||
|
for h, n := range p.CommitteeHistory {
|
||||||
|
if int(n) > len(p.StandbyCommittee) {
|
||||||
|
return fmt.Errorf("too small StandbyCommittee for required number of committee members at %d", h)
|
||||||
|
}
|
||||||
|
arr = append(arr, heightNumber{h, n})
|
||||||
|
}
|
||||||
|
if len(arr) != 0 {
|
||||||
|
err = sortCheckZero(arr, "CommitteeHistory")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, hn := range arr[1:] {
|
||||||
|
if int64(hn.h)%int64(hn.n) != 0 || int64(hn.h)%int64(arr[i].n) != 0 {
|
||||||
|
return fmt.Errorf("invalid CommitteeHistory: bad %d height for %d and %d committee", hn.h, hn.n, arr[i].n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = arr[:0]
|
||||||
|
for h, n := range p.ValidatorsHistory {
|
||||||
|
if int(n) > len(p.StandbyCommittee) {
|
||||||
|
return fmt.Errorf("too small StandbyCommittee for required number of validators at %d", h)
|
||||||
|
}
|
||||||
|
arr = append(arr, heightNumber{h, n})
|
||||||
|
}
|
||||||
|
if len(arr) != 0 {
|
||||||
|
err = sortCheckZero(arr, "ValidatorsHistory")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, hn := range arr {
|
||||||
|
if int64(hn.n) > int64(p.GetCommitteeSize(hn.h)) {
|
||||||
|
return fmt.Errorf("requested number of validators is too big: %d at %d", hn.n, hn.h)
|
||||||
|
}
|
||||||
|
if int64(hn.h)%int64(p.GetCommitteeSize(hn.h)) != 0 {
|
||||||
|
return fmt.Errorf("validators number change is not aligned with committee change at %d", hn.h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortCheckZero sorts heightNumber array and checks for zero height presence.
|
||||||
|
func sortCheckZero(arr []heightNumber, field string) error {
|
||||||
|
sort.Slice(arr, func(i, j int) bool {
|
||||||
|
return arr[i].h < arr[j].h
|
||||||
|
})
|
||||||
|
if arr[0].h != 0 {
|
||||||
|
return fmt.Errorf("invalid %s: no height 0 specified", field)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitteeSize returns the committee size for the given height. It implies
|
||||||
|
// valid configuration file.
|
||||||
|
func (p *ProtocolConfiguration) GetCommitteeSize(height uint32) int {
|
||||||
|
if len(p.CommitteeHistory) == 0 {
|
||||||
|
return len(p.StandbyCommittee)
|
||||||
|
}
|
||||||
|
return getBestFromMap(p.CommitteeHistory, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBestFromMap(dict map[uint32]int, height uint32) int {
|
||||||
|
var res int
|
||||||
|
var bestH = uint32(0)
|
||||||
|
for h, n := range dict {
|
||||||
|
if h >= bestH && h <= height {
|
||||||
|
res = n
|
||||||
|
bestH = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumOfCNs returns the number of validators for the given height.
|
||||||
|
// It implies valid configuration file.
|
||||||
|
func (p *ProtocolConfiguration) GetNumOfCNs(height uint32) int {
|
||||||
|
if len(p.ValidatorsHistory) == 0 {
|
||||||
|
return p.ValidatorsCount
|
||||||
|
}
|
||||||
|
return getBestFromMap(p.ValidatorsHistory, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldUpdateCommitteeAt answers the question of whether the committee
|
||||||
|
// should be updated at the given height.
|
||||||
|
func (p *ProtocolConfiguration) ShouldUpdateCommitteeAt(height uint32) bool {
|
||||||
|
return height%uint32(p.GetCommitteeSize(height)) == 0
|
||||||
|
}
|
||||||
|
|
130
pkg/config/protocol_config_test.go
Normal file
130
pkg/config/protocol_config_test.go
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProtocolConfigurationValidation(t *testing.T) {
|
||||||
|
p := &ProtocolConfiguration{
|
||||||
|
ValidatorsCount: 1,
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
NativeUpdateHistories: map[string][]uint32{
|
||||||
|
"someContract": {0, 10},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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]int{0: 4},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 4, 1000: 5},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 4, 1000: 5},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 4},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 1, 999: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 1},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 1, 1000: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 1, 999: 4},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 1, 100: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 4, 100: 4},
|
||||||
|
}
|
||||||
|
require.Error(t, p.Validate())
|
||||||
|
p = &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 1, 100: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{0: 1, 100: 4},
|
||||||
|
}
|
||||||
|
require.NoError(t, p.Validate())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCommitteeAndCNs(t *testing.T) {
|
||||||
|
p := &ProtocolConfiguration{
|
||||||
|
StandbyCommittee: []string{
|
||||||
|
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||||
|
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||||
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
|
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||||
|
},
|
||||||
|
CommitteeHistory: map[uint32]int{0: 1, 100: 4},
|
||||||
|
ValidatorsHistory: map[uint32]int{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))
|
||||||
|
}
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -48,6 +47,7 @@ const Category = "dBFT"
|
||||||
type Ledger interface {
|
type Ledger interface {
|
||||||
AddBlock(block *coreb.Block) error
|
AddBlock(block *coreb.Block) error
|
||||||
ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction
|
ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction
|
||||||
|
GetConfig() config.ProtocolConfiguration
|
||||||
GetMemPool() *mempool.Pool
|
GetMemPool() *mempool.Pool
|
||||||
GetNextBlockValidators() ([]*keys.PublicKey, error)
|
GetNextBlockValidators() ([]*keys.PublicKey, error)
|
||||||
GetStateModule() blockchainer.StateRoot
|
GetStateModule() blockchainer.StateRoot
|
||||||
|
@ -676,7 +676,8 @@ func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
||||||
|
|
||||||
var validators keys.PublicKeys
|
var validators keys.PublicKeys
|
||||||
var err error
|
var err error
|
||||||
if native.ShouldUpdateCommittee(ctx.BlockIndex, s.Chain) {
|
cfg := s.Chain.GetConfig()
|
||||||
|
if cfg.ShouldUpdateCommitteeAt(ctx.BlockIndex) {
|
||||||
validators, err = s.Chain.GetValidators()
|
validators, err = s.Chain.GetValidators()
|
||||||
} else {
|
} else {
|
||||||
validators, err = s.Chain.GetNextBlockValidators()
|
validators, err = s.Chain.GetNextBlockValidators()
|
||||||
|
@ -684,7 +685,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Fatal(fmt.Sprintf("failed to get validators: %s", err.Error()))
|
s.log.Fatal(fmt.Sprintf("failed to get validators: %s", err.Error()))
|
||||||
}
|
}
|
||||||
script, err := smartcontract.CreateMultiSigRedeemScript(s.dbft.Context.M(), validators)
|
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Fatal(fmt.Sprintf("failed to create multisignature script: %s", err.Error()))
|
s.log.Fatal(fmt.Sprintf("failed to create multisignature script: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,8 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
|
||||||
require.NoError(t, bc.PoolTx(tx))
|
require.NoError(t, bc.PoolTx(tx))
|
||||||
srv.dbft.OnTimeout(timer.HV{Height: srv.dbft.Context.BlockIndex})
|
srv.dbft.OnTimeout(timer.HV{Height: srv.dbft.Context.BlockIndex})
|
||||||
|
|
||||||
for i := srv.dbft.BlockIndex; !native.ShouldUpdateCommittee(i+offset, bc); i++ {
|
cfg := bc.GetConfig()
|
||||||
|
for i := srv.dbft.BlockIndex; !cfg.ShouldUpdateCommitteeAt(i + offset); i++ {
|
||||||
srv.dbft.OnTimeout(timer.HV{Height: srv.dbft.Context.BlockIndex})
|
srv.dbft.OnTimeout(timer.HV{Height: srv.dbft.Context.BlockIndex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,8 +152,6 @@ type Blockchain struct {
|
||||||
// Block's transactions are passed via mempool.
|
// Block's transactions are passed via mempool.
|
||||||
postBlock []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
|
postBlock []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
|
||||||
|
|
||||||
sbCommittee keys.PublicKeys
|
|
||||||
|
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
|
|
||||||
lastBatch *storage.MemBatch
|
lastBatch *storage.MemBatch
|
||||||
|
@ -162,8 +160,11 @@ type Blockchain struct {
|
||||||
|
|
||||||
extensible atomic.Value
|
extensible atomic.Value
|
||||||
|
|
||||||
|
// knownValidatorsCount is the latest known validators count used
|
||||||
|
// for defaultBlockWitness.
|
||||||
|
knownValidatorsCount atomic.Value
|
||||||
// defaultBlockWitness stores transaction.Witness with m out of n multisig,
|
// defaultBlockWitness stores transaction.Witness with m out of n multisig,
|
||||||
// where n = ValidatorsCount.
|
// where n = knownValidatorsCount.
|
||||||
defaultBlockWitness atomic.Value
|
defaultBlockWitness atomic.Value
|
||||||
|
|
||||||
stateRoot *stateroot.Module
|
stateRoot *stateroot.Module
|
||||||
|
@ -244,10 +245,6 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
||||||
zap.Int("StateSyncInterval", cfg.StateSyncInterval))
|
zap.Int("StateSyncInterval", cfg.StateSyncInterval))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
committee, err := committeeFromConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(cfg.NativeUpdateHistories) == 0 {
|
if len(cfg.NativeUpdateHistories) == 0 {
|
||||||
cfg.NativeUpdateHistories = map[string][]uint32{}
|
cfg.NativeUpdateHistories = map[string][]uint32{}
|
||||||
log.Info("NativeActivations are not set, using default values")
|
log.Info("NativeActivations are not set, using default values")
|
||||||
|
@ -259,7 +256,6 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
runToExitCh: make(chan struct{}),
|
runToExitCh: make(chan struct{}),
|
||||||
memPool: mempool.New(cfg.MemPoolSize, 0, false),
|
memPool: mempool.New(cfg.MemPoolSize, 0, false),
|
||||||
sbCommittee: committee,
|
|
||||||
log: log,
|
log: log,
|
||||||
events: make(chan bcEvent),
|
events: make(chan bcEvent),
|
||||||
subCh: make(chan interface{}),
|
subCh: make(chan interface{}),
|
||||||
|
@ -1177,7 +1173,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error {
|
func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error {
|
||||||
updateCommittee := native.ShouldUpdateCommittee(height, bc)
|
updateCommittee := bc.config.ShouldUpdateCommitteeAt(height)
|
||||||
stateVals, sh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.StateValidator, height)
|
stateVals, sh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.StateValidator, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1787,14 +1783,17 @@ func (bc *Blockchain) ApplyPolicyToTxSet(txes []*transaction.Transaction) []*tra
|
||||||
}
|
}
|
||||||
maxBlockSize := bc.config.MaxBlockSize
|
maxBlockSize := bc.config.MaxBlockSize
|
||||||
maxBlockSysFee := bc.config.MaxBlockSystemFee
|
maxBlockSysFee := bc.config.MaxBlockSystemFee
|
||||||
|
oldVC := bc.knownValidatorsCount.Load()
|
||||||
defaultWitness := bc.defaultBlockWitness.Load()
|
defaultWitness := bc.defaultBlockWitness.Load()
|
||||||
if defaultWitness == nil {
|
curVC := bc.config.GetNumOfCNs(bc.BlockHeight() + 1)
|
||||||
m := smartcontract.GetDefaultHonestNodeCount(bc.config.ValidatorsCount)
|
if oldVC == nil || oldVC != curVC {
|
||||||
|
m := smartcontract.GetDefaultHonestNodeCount(curVC)
|
||||||
verification, _ := smartcontract.CreateDefaultMultiSigRedeemScript(bc.contracts.NEO.GetNextBlockValidatorsInternal())
|
verification, _ := smartcontract.CreateDefaultMultiSigRedeemScript(bc.contracts.NEO.GetNextBlockValidatorsInternal())
|
||||||
defaultWitness = transaction.Witness{
|
defaultWitness = transaction.Witness{
|
||||||
InvocationScript: make([]byte, 66*m),
|
InvocationScript: make([]byte, 66*m),
|
||||||
VerificationScript: verification,
|
VerificationScript: verification,
|
||||||
}
|
}
|
||||||
|
bc.knownValidatorsCount.Store(curVC)
|
||||||
bc.defaultBlockWitness.Store(defaultWitness)
|
bc.defaultBlockWitness.Store(defaultWitness)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
@ -2083,16 +2082,6 @@ func (bc *Blockchain) PoolTxWithData(t *transaction.Transaction, data interface{
|
||||||
return bc.verifyAndPoolTx(t, mp, feer, data)
|
return bc.verifyAndPoolTx(t, mp, feer, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStandByValidators returns validators from the configuration.
|
|
||||||
func (bc *Blockchain) GetStandByValidators() keys.PublicKeys {
|
|
||||||
return bc.sbCommittee[:bc.config.ValidatorsCount].Copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStandByCommittee returns standby committee from the configuration.
|
|
||||||
func (bc *Blockchain) GetStandByCommittee() keys.PublicKeys {
|
|
||||||
return bc.sbCommittee.Copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCommittee returns the sorted list of public keys of nodes in committee.
|
// GetCommittee returns the sorted list of public keys of nodes in committee.
|
||||||
func (bc *Blockchain) GetCommittee() (keys.PublicKeys, error) {
|
func (bc *Blockchain) GetCommittee() (keys.PublicKeys, error) {
|
||||||
pubs := bc.contracts.NEO.GetCommitteeMembers()
|
pubs := bc.contracts.NEO.GetCommitteeMembers()
|
||||||
|
|
|
@ -1828,6 +1828,81 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChainWithVolatileNumOfValidators(t *testing.T) {
|
||||||
|
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||||
|
c.ProtocolConfiguration.ValidatorsCount = 0
|
||||||
|
c.ProtocolConfiguration.CommitteeHistory = map[uint32]int{
|
||||||
|
0: 1,
|
||||||
|
4: 4,
|
||||||
|
24: 6,
|
||||||
|
}
|
||||||
|
c.ProtocolConfiguration.ValidatorsHistory = map[uint32]int{
|
||||||
|
0: 1,
|
||||||
|
4: 4,
|
||||||
|
}
|
||||||
|
require.NoError(t, c.ProtocolConfiguration.Validate())
|
||||||
|
})
|
||||||
|
require.Equal(t, uint32(0), bc.BlockHeight())
|
||||||
|
|
||||||
|
priv0 := testchain.PrivateKeyByID(0)
|
||||||
|
|
||||||
|
vals, err := bc.GetValidators()
|
||||||
|
require.NoError(t, err)
|
||||||
|
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(vals)
|
||||||
|
require.NoError(t, err)
|
||||||
|
curWit := transaction.Witness{
|
||||||
|
VerificationScript: script,
|
||||||
|
}
|
||||||
|
for i := 1; i < 26; i++ {
|
||||||
|
comm, err := bc.GetCommittee()
|
||||||
|
require.NoError(t, err)
|
||||||
|
if i < 5 {
|
||||||
|
require.Equal(t, 1, len(comm))
|
||||||
|
} else if i < 25 {
|
||||||
|
require.Equal(t, 4, len(comm))
|
||||||
|
} else {
|
||||||
|
require.Equal(t, 6, len(comm))
|
||||||
|
}
|
||||||
|
// Mimic consensus.
|
||||||
|
if bc.config.ShouldUpdateCommitteeAt(uint32(i)) {
|
||||||
|
vals, err = bc.GetValidators()
|
||||||
|
} else {
|
||||||
|
vals, err = bc.GetNextBlockValidators()
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
if i < 4 {
|
||||||
|
require.Equalf(t, 1, len(vals), "at %d", i)
|
||||||
|
} else {
|
||||||
|
require.Equalf(t, 4, len(vals), "at %d", i)
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(vals)
|
||||||
|
require.NoError(t, err)
|
||||||
|
nextWit := transaction.Witness{
|
||||||
|
VerificationScript: script,
|
||||||
|
}
|
||||||
|
b := &block.Block{
|
||||||
|
Header: block.Header{
|
||||||
|
NextConsensus: nextWit.ScriptHash(),
|
||||||
|
Script: curWit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
curWit = nextWit
|
||||||
|
b.PrevHash = bc.GetHeaderHash(i - 1)
|
||||||
|
b.Timestamp = uint64(time.Now().UTC().Unix())*1000 + uint64(i)
|
||||||
|
b.Index = uint32(i)
|
||||||
|
b.RebuildMerkleRoot()
|
||||||
|
if i < 5 {
|
||||||
|
signa := priv0.SignHashable(uint32(bc.config.Magic), b)
|
||||||
|
b.Script.InvocationScript = append([]byte{byte(opcode.PUSHDATA1), byte(len(signa))}, signa...)
|
||||||
|
} else {
|
||||||
|
b.Script.InvocationScript = testchain.Sign(b)
|
||||||
|
}
|
||||||
|
err = bc.AddBlock(b)
|
||||||
|
require.NoErrorf(t, err, "at %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setSigner(tx *transaction.Transaction, h util.Uint160) {
|
func setSigner(tx *transaction.Transaction, h util.Uint160) {
|
||||||
tx.Signers = []transaction.Signer{{
|
tx.Signers = []transaction.Signer{{
|
||||||
Account: h,
|
Account: h,
|
||||||
|
|
|
@ -56,8 +56,6 @@ type Blockchainer interface {
|
||||||
GetNotaryContractScriptHash() util.Uint160
|
GetNotaryContractScriptHash() util.Uint160
|
||||||
GetNotaryBalance(acc util.Uint160) *big.Int
|
GetNotaryBalance(acc util.Uint160) *big.Int
|
||||||
GetValidators() ([]*keys.PublicKey, error)
|
GetValidators() ([]*keys.PublicKey, error)
|
||||||
GetStandByCommittee() keys.PublicKeys
|
|
||||||
GetStandByValidators() keys.PublicKeys
|
|
||||||
GetStateModule() StateRoot
|
GetStateModule() StateRoot
|
||||||
GetStorageItem(id int32, key []byte) state.StorageItem
|
GetStorageItem(id int32, key []byte) state.StorageItem
|
||||||
GetStorageItems(id int32) ([]state.StorageItemWithKey, error)
|
GetStorageItems(id int32) ([]state.StorageItemWithKey, error)
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
|
@ -42,8 +41,6 @@ type Ledger interface {
|
||||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||||
GetConfig() config.ProtocolConfiguration
|
GetConfig() config.ProtocolConfiguration
|
||||||
GetHeaderHash(int) util.Uint256
|
GetHeaderHash(int) util.Uint256
|
||||||
GetStandByCommittee() keys.PublicKeys
|
|
||||||
GetStandByValidators() keys.PublicKeys
|
|
||||||
GetStoragePrice() int64
|
GetStoragePrice() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -135,7 +136,12 @@ func (g *GAS) BalanceOf(d dao.DAO, acc util.Uint160) *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, error) {
|
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, error) {
|
||||||
s, err := smartcontract.CreateDefaultMultiSigRedeemScript(ic.Chain.GetStandByValidators())
|
cfg := ic.Chain.GetConfig()
|
||||||
|
committee, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint160{}, err
|
||||||
|
}
|
||||||
|
s, err := smartcontract.CreateDefaultMultiSigRedeemScript(committee[:cfg.GetNumOfCNs(0)])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
||||||
|
@ -54,6 +55,10 @@ type NEO struct {
|
||||||
// It is set in state-modifying methods only and read in `PostPersist` thus is not protected
|
// It is set in state-modifying methods only and read in `PostPersist` thus is not protected
|
||||||
// by any mutex.
|
// by any mutex.
|
||||||
gasPerVoteCache map[string]big.Int
|
gasPerVoteCache map[string]big.Int
|
||||||
|
// Configuration and standby keys are set during initialization and then
|
||||||
|
// only read from.
|
||||||
|
cfg config.ProtocolConfiguration
|
||||||
|
standbyKeys keys.PublicKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -190,6 +195,10 @@ func newNEO() *NEO {
|
||||||
|
|
||||||
// Initialize initializes NEO contract.
|
// Initialize initializes NEO contract.
|
||||||
func (n *NEO) Initialize(ic *interop.Context) error {
|
func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
|
err := n.initConfigCache(ic.Chain)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if err := n.nep17TokenNative.Initialize(ic); err != nil {
|
if err := n.nep17TokenNative.Initialize(ic); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -199,9 +208,9 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
return errors.New("already initialized")
|
return errors.New("already initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
committee := ic.Chain.GetStandByCommittee()
|
committee0 := n.standbyKeys[:n.cfg.GetCommitteeSize(ic.Block.Index)]
|
||||||
cvs := toKeysWithVotes(committee)
|
cvs := toKeysWithVotes(committee0)
|
||||||
err := n.updateCache(cvs, ic.Chain)
|
err = n.updateCache(cvs, ic.Chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -244,6 +253,10 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
// Cache initialisation should be done apart from Initialize because Initialize is
|
// Cache initialisation should be done apart from Initialize because Initialize is
|
||||||
// called only when deploying native contracts.
|
// called only when deploying native contracts.
|
||||||
func (n *NEO) InitializeCache(bc interop.Ledger, d dao.DAO) error {
|
func (n *NEO) InitializeCache(bc interop.Ledger, d dao.DAO) error {
|
||||||
|
err := n.initConfigCache(bc)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
var committee = keysWithVotes{}
|
var committee = keysWithVotes{}
|
||||||
si := d.GetStorageItem(n.ID, prefixCommittee)
|
si := d.GetStorageItem(n.ID, prefixCommittee)
|
||||||
if err := committee.DecodeBytes(si); err != nil {
|
if err := committee.DecodeBytes(si); err != nil {
|
||||||
|
@ -263,6 +276,14 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d dao.DAO) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NEO) initConfigCache(bc interop.Ledger) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
n.cfg = bc.GetConfig()
|
||||||
|
n.standbyKeys, err = keys.NewPublicKeysFromStrings(n.cfg.StandbyCommittee)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (n *NEO) updateCache(cvs keysWithVotes, bc interop.Ledger) error {
|
func (n *NEO) updateCache(cvs keysWithVotes, bc interop.Ledger) error {
|
||||||
n.committee.Store(cvs)
|
n.committee.Store(cvs)
|
||||||
|
|
||||||
|
@ -273,7 +294,7 @@ func (n *NEO) updateCache(cvs keysWithVotes, bc interop.Ledger) error {
|
||||||
}
|
}
|
||||||
n.committeeHash.Store(hash.Hash160(script))
|
n.committeeHash.Store(hash.Hash160(script))
|
||||||
|
|
||||||
nextVals := committee[:bc.GetConfig().ValidatorsCount].Copy()
|
nextVals := committee[:n.cfg.GetNumOfCNs(bc.BlockHeight()+1)].Copy()
|
||||||
sort.Sort(nextVals)
|
sort.Sort(nextVals)
|
||||||
n.nextValidators.Store(nextVals)
|
n.nextValidators.Store(nextVals)
|
||||||
return nil
|
return nil
|
||||||
|
@ -298,16 +319,15 @@ func (n *NEO) updateCommittee(ic *interop.Context) error {
|
||||||
return ic.DAO.PutStorageItem(n.ID, prefixCommittee, cvs.Bytes())
|
return ic.DAO.PutStorageItem(n.ID, prefixCommittee, cvs.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldUpdateCommittee returns true if committee is updated at block h.
|
|
||||||
func ShouldUpdateCommittee(h uint32, bc interop.Ledger) bool {
|
|
||||||
cfg := bc.GetConfig()
|
|
||||||
r := len(cfg.StandbyCommittee)
|
|
||||||
return h%uint32(r) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnPersist implements Contract interface.
|
// OnPersist implements Contract interface.
|
||||||
func (n *NEO) OnPersist(ic *interop.Context) error {
|
func (n *NEO) OnPersist(ic *interop.Context) error {
|
||||||
if ShouldUpdateCommittee(ic.Block.Index, ic.Chain) {
|
if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
|
||||||
|
oldKeys := n.nextValidators.Load().(keys.PublicKeys)
|
||||||
|
oldCom := n.committee.Load().(keysWithVotes)
|
||||||
|
if n.cfg.GetNumOfCNs(ic.Block.Index) != len(oldKeys) ||
|
||||||
|
n.cfg.GetCommitteeSize(ic.Block.Index) != len(oldCom) {
|
||||||
|
n.votesChanged.Store(true)
|
||||||
|
}
|
||||||
if err := n.updateCommittee(ic); err != nil {
|
if err := n.updateCommittee(ic); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -319,16 +339,16 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
||||||
func (n *NEO) PostPersist(ic *interop.Context) error {
|
func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||||
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||||
pubs := n.GetCommitteeMembers()
|
pubs := n.GetCommitteeMembers()
|
||||||
committeeSize := len(ic.Chain.GetConfig().StandbyCommittee)
|
committeeSize := n.cfg.GetCommitteeSize(ic.Block.Index)
|
||||||
index := int(ic.Block.Index) % committeeSize
|
index := int(ic.Block.Index) % committeeSize
|
||||||
committeeReward := new(big.Int).Mul(gas, bigCommitteeRewardRatio)
|
committeeReward := new(big.Int).Mul(gas, bigCommitteeRewardRatio)
|
||||||
n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big100), false)
|
n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big100), false)
|
||||||
|
|
||||||
if ShouldUpdateCommittee(ic.Block.Index, ic.Chain) {
|
if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
|
||||||
var voterReward = new(big.Int).Set(bigVoterRewardRatio)
|
var voterReward = new(big.Int).Set(bigVoterRewardRatio)
|
||||||
voterReward.Mul(voterReward, gas)
|
voterReward.Mul(voterReward, gas)
|
||||||
voterReward.Mul(voterReward, big.NewInt(voterRewardFactor*int64(committeeSize)))
|
voterReward.Mul(voterReward, big.NewInt(voterRewardFactor*int64(committeeSize)))
|
||||||
var validatorsCount = ic.Chain.GetConfig().ValidatorsCount
|
var validatorsCount = n.cfg.GetNumOfCNs(ic.Block.Index)
|
||||||
voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
|
voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
|
||||||
voterReward.Div(voterReward, big100)
|
voterReward.Div(voterReward, big100)
|
||||||
|
|
||||||
|
@ -938,14 +958,15 @@ func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stacki
|
||||||
|
|
||||||
// ComputeNextBlockValidators returns an actual list of current validators.
|
// ComputeNextBlockValidators returns an actual list of current validators.
|
||||||
func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d dao.DAO) (keys.PublicKeys, error) {
|
func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d dao.DAO) (keys.PublicKeys, error) {
|
||||||
if vals := n.validators.Load().(keys.PublicKeys); vals != nil {
|
numOfCNs := n.cfg.GetNumOfCNs(bc.BlockHeight() + 1)
|
||||||
|
if vals := n.validators.Load().(keys.PublicKeys); vals != nil && numOfCNs == len(vals) {
|
||||||
return vals.Copy(), nil
|
return vals.Copy(), nil
|
||||||
}
|
}
|
||||||
result, _, err := n.computeCommitteeMembers(bc, d)
|
result, _, err := n.computeCommitteeMembers(bc, d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result = result[:bc.GetConfig().ValidatorsCount]
|
result = result[:numOfCNs]
|
||||||
sort.Sort(result)
|
sort.Sort(result)
|
||||||
n.validators.Store(result)
|
n.validators.Store(result)
|
||||||
return result, nil
|
return result, nil
|
||||||
|
@ -1006,8 +1027,9 @@ func (n *NEO) computeCommitteeMembers(bc interop.Ledger, d dao.DAO) (keys.Public
|
||||||
_, totalSupply := n.getTotalSupply(d)
|
_, totalSupply := n.getTotalSupply(d)
|
||||||
voterTurnout := votersCount.Div(votersCount, totalSupply)
|
voterTurnout := votersCount.Div(votersCount, totalSupply)
|
||||||
|
|
||||||
sbVals := bc.GetStandByCommittee()
|
count := n.cfg.GetCommitteeSize(bc.BlockHeight() + 1)
|
||||||
count := len(sbVals)
|
// Can be sorted and/or returned to outside users, thus needs to be copied.
|
||||||
|
sbVals := keys.PublicKeys(n.standbyKeys[:count]).Copy()
|
||||||
cs, err := n.getCandidates(d, false)
|
cs, err := n.getCandidates(d, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -50,8 +50,9 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
||||||
e := neoCommitteeInvoker.Executor
|
e := neoCommitteeInvoker.Executor
|
||||||
|
|
||||||
committeeSize := len(neoValidatorsInvoker.Chain.GetConfig().StandbyCommittee)
|
cfg := e.Chain.GetConfig()
|
||||||
validatorsCount := neoCommitteeInvoker.Chain.GetConfig().ValidatorsCount
|
committeeSize := cfg.GetCommitteeSize(0)
|
||||||
|
validatorsCount := cfg.GetNumOfCNs(0)
|
||||||
freq := validatorsCount + committeeSize
|
freq := validatorsCount + committeeSize
|
||||||
advanceChain := func(t *testing.T) {
|
advanceChain := func(t *testing.T) {
|
||||||
for i := 0; i < freq; i++ {
|
for i := 0; i < freq; i++ {
|
||||||
|
@ -59,7 +60,9 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standBySorted := e.Chain.GetStandByValidators()
|
standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
|
||||||
|
require.NoError(t, err)
|
||||||
|
standBySorted = standBySorted[:validatorsCount]
|
||||||
sort.Sort(standBySorted)
|
sort.Sort(standBySorted)
|
||||||
pubs, err := e.Chain.GetValidators()
|
pubs, err := e.Chain.GetValidators()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -250,7 +253,8 @@ func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
|
||||||
neoCommitteeInvoker := newNeoCommitteeClient(t, 0)
|
neoCommitteeInvoker := newNeoCommitteeClient(t, 0)
|
||||||
e := neoCommitteeInvoker.Executor
|
e := neoCommitteeInvoker.Executor
|
||||||
|
|
||||||
hs := e.Chain.GetStandByCommittee()
|
hs, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
|
||||||
|
require.NoError(t, err)
|
||||||
committeeSize := len(hs)
|
committeeSize := len(hs)
|
||||||
|
|
||||||
const singleBounty = 50000000
|
const singleBounty = 50000000
|
||||||
|
|
|
@ -392,9 +392,10 @@ func (n *Notary) GetMaxNotValidBeforeDelta(dao dao.DAO) uint32 {
|
||||||
// setMaxNotValidBeforeDelta is Notary contract method and sets the maximum NotValidBefore delta.
|
// setMaxNotValidBeforeDelta is Notary contract method and sets the maximum NotValidBefore delta.
|
||||||
func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||||
value := toUint32(args[0])
|
value := toUint32(args[0])
|
||||||
maxInc := ic.Chain.GetConfig().MaxValidUntilBlockIncrement
|
cfg := ic.Chain.GetConfig()
|
||||||
if value > maxInc/2 || value < uint32(ic.Chain.GetConfig().ValidatorsCount) {
|
maxInc := cfg.MaxValidUntilBlockIncrement
|
||||||
panic(fmt.Errorf("MaxNotValidBeforeDelta cannot be more than %d or less than %d", maxInc/2, ic.Chain.GetConfig().ValidatorsCount))
|
if value > maxInc/2 || value < uint32(cfg.GetNumOfCNs(ic.Chain.BlockHeight())) {
|
||||||
|
panic(fmt.Errorf("MaxNotValidBeforeDelta cannot be more than %d or less than %d", maxInc/2, cfg.GetNumOfCNs(ic.Chain.BlockHeight())))
|
||||||
}
|
}
|
||||||
if !n.NEO.checkCommittee(ic) {
|
if !n.NEO.checkCommittee(ic) {
|
||||||
panic("invalid committee signature")
|
panic("invalid committee signature")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -50,26 +49,11 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
||||||
vs, err := committeeFromConfig(cfg)
|
vs, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return vs[:cfg.ValidatorsCount], nil
|
return vs[:cfg.GetNumOfCNs(0)], nil
|
||||||
}
|
|
||||||
|
|
||||||
func committeeFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
|
||||||
if len(cfg.StandbyCommittee) < cfg.ValidatorsCount {
|
|
||||||
return nil, errors.New("validators count can be less than the size of StandbyCommittee")
|
|
||||||
}
|
|
||||||
validators := make([]*keys.PublicKey, len(cfg.StandbyCommittee))
|
|
||||||
for i := range validators {
|
|
||||||
pubKey, err := keys.NewPublicKeyFromString(cfg.StandbyCommittee[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
validators[i] = pubKey
|
|
||||||
}
|
|
||||||
return validators, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
||||||
|
|
|
@ -32,6 +32,20 @@ type PublicKeys []*PublicKey
|
||||||
var big0 = big.NewInt(0)
|
var big0 = big.NewInt(0)
|
||||||
var big3 = big.NewInt(3)
|
var big3 = big.NewInt(3)
|
||||||
|
|
||||||
|
// NewPublicKeysFromStrings converts an array of string-encoded P256 public keys
|
||||||
|
// into an array of PublicKeys.
|
||||||
|
func NewPublicKeysFromStrings(ss []string) (PublicKeys, error) {
|
||||||
|
arr := make([]*PublicKey, len(ss))
|
||||||
|
for i := range ss {
|
||||||
|
pubKey, err := NewPublicKeyFromString(ss[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arr[i] = pubKey
|
||||||
|
}
|
||||||
|
return PublicKeys(arr), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (keys PublicKeys) Len() int { return len(keys) }
|
func (keys PublicKeys) Len() int { return len(keys) }
|
||||||
func (keys PublicKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] }
|
func (keys PublicKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] }
|
||||||
func (keys PublicKeys) Less(i, j int) bool {
|
func (keys PublicKeys) Less(i, j int) bool {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
|
@ -89,10 +88,8 @@ type (
|
||||||
// id also known as the nonce of the server.
|
// id also known as the nonce of the server.
|
||||||
id uint32
|
id uint32
|
||||||
|
|
||||||
// Network's magic number for correct message decoding.
|
// A copy of the Ledger's config.
|
||||||
network netmode.Magic
|
config config.ProtocolConfiguration
|
||||||
// stateRootInHeader specifies if block header contain state root.
|
|
||||||
stateRootInHeader bool
|
|
||||||
|
|
||||||
transport Transporter
|
transport Transporter
|
||||||
discovery Discoverer
|
discovery Discoverer
|
||||||
|
@ -169,8 +166,7 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
|
||||||
ServerConfig: config,
|
ServerConfig: config,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
id: randomID(),
|
id: randomID(),
|
||||||
network: chain.GetConfig().Magic,
|
config: chain.GetConfig(),
|
||||||
stateRootInHeader: chain.GetConfig().StateRootInHeader,
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
register: make(chan Peer),
|
register: make(chan Peer),
|
||||||
unregister: make(chan peerDrop),
|
unregister: make(chan peerDrop),
|
||||||
|
@ -186,7 +182,7 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
|
||||||
}
|
}
|
||||||
if chain.P2PSigExtensionsEnabled() {
|
if chain.P2PSigExtensionsEnabled() {
|
||||||
s.notaryFeer = NewNotaryFeer(chain)
|
s.notaryFeer = NewNotaryFeer(chain)
|
||||||
s.notaryRequestPool = mempool.New(chain.GetConfig().P2PNotaryRequestPayloadPoolSize, 1, true)
|
s.notaryRequestPool = mempool.New(s.config.P2PNotaryRequestPayloadPoolSize, 1, true)
|
||||||
chain.RegisterPostBlock(func(isRelevant func(*transaction.Transaction, *mempool.Pool, bool) bool, txpool *mempool.Pool, _ *block.Block) {
|
chain.RegisterPostBlock(func(isRelevant func(*transaction.Transaction, *mempool.Pool, bool) bool, txpool *mempool.Pool, _ *block.Block) {
|
||||||
s.notaryRequestPool.RemoveStale(func(t *transaction.Transaction) bool {
|
s.notaryRequestPool.RemoveStale(func(t *transaction.Transaction) bool {
|
||||||
return isRelevant(t, txpool, true)
|
return isRelevant(t, txpool, true)
|
||||||
|
@ -773,10 +769,10 @@ func (s *Server) handleGetDataCmd(p Peer, inv *payload.Inventory) error {
|
||||||
|
|
||||||
// handleGetMPTDataCmd processes the received MPT inventory.
|
// handleGetMPTDataCmd processes the received MPT inventory.
|
||||||
func (s *Server) handleGetMPTDataCmd(p Peer, inv *payload.MPTInventory) error {
|
func (s *Server) handleGetMPTDataCmd(p Peer, inv *payload.MPTInventory) error {
|
||||||
if !s.chain.GetConfig().P2PStateExchangeExtensions {
|
if !s.config.P2PStateExchangeExtensions {
|
||||||
return errors.New("GetMPTDataCMD was received, but P2PStateExchangeExtensions are disabled")
|
return errors.New("GetMPTDataCMD was received, but P2PStateExchangeExtensions are disabled")
|
||||||
}
|
}
|
||||||
if s.chain.GetConfig().KeepOnlyLatestState {
|
if s.config.KeepOnlyLatestState {
|
||||||
// TODO: implement keeping MPT states for P1 and P2 height (#2095, #2152 related)
|
// TODO: implement keeping MPT states for P1 and P2 height (#2095, #2152 related)
|
||||||
return errors.New("GetMPTDataCMD was received, but only latest MPT state is supported")
|
return errors.New("GetMPTDataCMD was received, but only latest MPT state is supported")
|
||||||
}
|
}
|
||||||
|
@ -814,7 +810,7 @@ func (s *Server) handleGetMPTDataCmd(p Peer, inv *payload.MPTInventory) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleMPTDataCmd(p Peer, data *payload.MPTData) error {
|
func (s *Server) handleMPTDataCmd(p Peer, data *payload.MPTData) error {
|
||||||
if !s.chain.GetConfig().P2PStateExchangeExtensions {
|
if !s.config.P2PStateExchangeExtensions {
|
||||||
return errors.New("MPTDataCMD was received, but P2PStateExchangeExtensions are disabled")
|
return errors.New("MPTDataCMD was received, but P2PStateExchangeExtensions are disabled")
|
||||||
}
|
}
|
||||||
return s.stateSync.AddMPTNodes(data.Nodes)
|
return s.stateSync.AddMPTNodes(data.Nodes)
|
||||||
|
@ -1396,10 +1392,11 @@ func (s *Server) broadcastTxHashes(hs []util.Uint256) {
|
||||||
|
|
||||||
// initStaleMemPools initializes mempools for stale tx/payload processing.
|
// initStaleMemPools initializes mempools for stale tx/payload processing.
|
||||||
func (s *Server) initStaleMemPools() {
|
func (s *Server) initStaleMemPools() {
|
||||||
cfg := s.chain.GetConfig()
|
|
||||||
threshold := 5
|
threshold := 5
|
||||||
if cfg.ValidatorsCount*2 > threshold {
|
// Not perfect, can change over time, but should be sufficient.
|
||||||
threshold = cfg.ValidatorsCount * 2
|
numOfCNs := s.config.GetNumOfCNs(s.chain.BlockHeight())
|
||||||
|
if numOfCNs*2 > threshold {
|
||||||
|
threshold = numOfCNs * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mempool.SetResendThreshold(uint32(threshold), s.broadcastTX)
|
s.mempool.SetResendThreshold(uint32(threshold), s.broadcastTX)
|
||||||
|
|
|
@ -813,7 +813,7 @@ func TestHandleMPTData(t *testing.T) {
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
expected := [][]byte{{1, 2, 3}, {2, 3, 4}}
|
expected := [][]byte{{1, 2, 3}, {2, 3, 4}}
|
||||||
s := newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
s := newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
||||||
s.chain.(*fakechain.FakeChain).P2PStateExchangeExtensions = true
|
s.config.P2PStateExchangeExtensions = true
|
||||||
s.stateSync = &fakechain.FakeStateSync{
|
s.stateSync = &fakechain.FakeStateSync{
|
||||||
AddMPTNodesFunc: func(nodes [][]byte) error {
|
AddMPTNodesFunc: func(nodes [][]byte) error {
|
||||||
require.Equal(t, expected, nodes)
|
require.Equal(t, expected, nodes)
|
||||||
|
|
|
@ -167,7 +167,7 @@ func (p *TCPPeer) handleConn() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r := io.NewBinReaderFromIO(p.conn)
|
r := io.NewBinReaderFromIO(p.conn)
|
||||||
for {
|
for {
|
||||||
msg := &Message{StateRootInHeader: p.server.stateRootInHeader}
|
msg := &Message{StateRootInHeader: p.server.config.StateRootInHeader}
|
||||||
err = msg.Decode(r)
|
err = msg.Decode(r)
|
||||||
|
|
||||||
if err == payload.ErrTooManyHeaders {
|
if err == payload.ErrTooManyHeaders {
|
||||||
|
@ -207,7 +207,7 @@ func (p *TCPPeer) handleQueues() {
|
||||||
var p2pSkipCounter uint32
|
var p2pSkipCounter uint32
|
||||||
const p2pSkipDivisor = 4
|
const p2pSkipDivisor = 4
|
||||||
|
|
||||||
var writeTimeout = time.Duration(p.server.chain.GetConfig().SecondsPerBlock) * time.Second
|
var writeTimeout = time.Duration(p.server.config.SecondsPerBlock) * time.Second
|
||||||
for {
|
for {
|
||||||
var msg []byte
|
var msg []byte
|
||||||
|
|
||||||
|
|
|
@ -533,7 +533,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) {
|
||||||
MaxValidUntilBlockIncrement: cfg.MaxValidUntilBlockIncrement,
|
MaxValidUntilBlockIncrement: cfg.MaxValidUntilBlockIncrement,
|
||||||
MaxTransactionsPerBlock: cfg.MaxTransactionsPerBlock,
|
MaxTransactionsPerBlock: cfg.MaxTransactionsPerBlock,
|
||||||
MemoryPoolMaxTransactions: cfg.MemPoolSize,
|
MemoryPoolMaxTransactions: cfg.MemPoolSize,
|
||||||
ValidatorsCount: byte(cfg.ValidatorsCount),
|
ValidatorsCount: byte(cfg.GetNumOfCNs(s.chain.BlockHeight())),
|
||||||
InitialGasDistribution: cfg.InitialGASSupply,
|
InitialGasDistribution: cfg.InitialGASSupply,
|
||||||
StateRootInHeader: cfg.StateRootInHeader,
|
StateRootInHeader: cfg.StateRootInHeader,
|
||||||
},
|
},
|
||||||
|
|
|
@ -699,8 +699,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
{
|
{
|
||||||
params: "[]",
|
params: "[]",
|
||||||
result: func(e *executor) interface{} {
|
result: func(e *executor) interface{} {
|
||||||
// it's a test chain, so committee is a sorted standby committee
|
expected, _ := e.chain.GetCommittee()
|
||||||
expected := e.chain.GetStandByCommittee()
|
|
||||||
sort.Sort(expected)
|
sort.Sort(expected)
|
||||||
return &expected
|
return &expected
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,7 +64,9 @@ func main() {
|
||||||
bc, err := newChain()
|
bc, err := newChain()
|
||||||
handleError("can't initialize blockchain", err)
|
handleError("can't initialize blockchain", err)
|
||||||
|
|
||||||
valScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(bc.GetStandByValidators())
|
nbVals, err := bc.GetNextBlockValidators()
|
||||||
|
handleError("can't get next block validators", err)
|
||||||
|
valScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(nbVals)
|
||||||
handleError("can't create verification script", err)
|
handleError("can't create verification script", err)
|
||||||
lastBlock, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight())))
|
lastBlock, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight())))
|
||||||
handleError("can't fetch last block", err)
|
handleError("can't fetch last block", err)
|
||||||
|
|
Loading…
Reference in a new issue