neo-go/pkg/neorpc/result/version.go
Ekaterina Pavlova 9fb6d3266e rpcsrv: add seedlist and standbycommittee to getversion
Port neo-project/neo#3443.

Close #3538

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-08-09 12:53:31 +03:00

175 lines
6.2 KiB
Go

package result
import (
"encoding/json"
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
)
type (
// Version model used for reporting server version
// info.
Version struct {
TCPPort uint16 `json:"tcpport"`
WSPort uint16 `json:"wsport,omitempty"`
Nonce uint32 `json:"nonce"`
UserAgent string `json:"useragent"`
Protocol Protocol `json:"protocol"`
RPC RPC `json:"rpc"`
}
// RPC represents the RPC server configuration.
RPC struct {
MaxIteratorResultItems int `json:"maxiteratorresultitems"`
SessionEnabled bool `json:"sessionenabled"`
}
// Protocol represents network-dependent parameters.
Protocol struct {
AddressVersion byte
Network netmode.Magic
MillisecondsPerBlock int
MaxTraceableBlocks uint32
MaxValidUntilBlockIncrement uint32
MaxTransactionsPerBlock uint16
MemoryPoolMaxTransactions int
ValidatorsCount byte
InitialGasDistribution fixedn.Fixed8
// Hardforks is the map of network hardforks with the enabling height.
Hardforks map[config.Hardfork]uint32
StandbyCommittee keys.PublicKeys
SeedList []string
// Below are NeoGo-specific extensions to the protocol that are
// returned by the server in case they're enabled.
// CommitteeHistory stores height:size map of the committee size.
CommitteeHistory map[uint32]uint32
// P2PSigExtensions is true when Notary subsystem is enabled on the network.
P2PSigExtensions bool
// StateRootInHeader is true if state root is contained in block header.
StateRootInHeader bool
// ValidatorsHistory stores height:size map of the validators count.
ValidatorsHistory map[uint32]uint32
}
// protocolMarshallerAux is an auxiliary struct used for Protocol JSON marshalling.
protocolMarshallerAux struct {
AddressVersion byte `json:"addressversion"`
Network netmode.Magic `json:"network"`
MillisecondsPerBlock int `json:"msperblock"`
MaxTraceableBlocks uint32 `json:"maxtraceableblocks"`
MaxValidUntilBlockIncrement uint32 `json:"maxvaliduntilblockincrement"`
MaxTransactionsPerBlock uint16 `json:"maxtransactionsperblock"`
MemoryPoolMaxTransactions int `json:"memorypoolmaxtransactions"`
ValidatorsCount byte `json:"validatorscount"`
InitialGasDistribution int64 `json:"initialgasdistribution"`
Hardforks []hardforkAux `json:"hardforks"`
StandbyCommittee []string `json:"standbycommittee"`
SeedList []string `json:"seedlist"`
CommitteeHistory map[uint32]uint32 `json:"committeehistory,omitempty"`
P2PSigExtensions bool `json:"p2psigextensions,omitempty"`
StateRootInHeader bool `json:"staterootinheader,omitempty"`
ValidatorsHistory map[uint32]uint32 `json:"validatorshistory,omitempty"`
}
// hardforkAux is an auxiliary struct used for Hardfork JSON marshalling.
hardforkAux struct {
Name string `json:"name"`
Height uint32 `json:"blockheight"`
}
)
// prefixHardfork is a prefix used for hardfork names in C# node.
const prefixHardfork = "HF_"
// MarshalJSON implements the JSON marshaler interface.
func (p Protocol) MarshalJSON() ([]byte, error) {
// Keep hardforks sorted by name in the result.
hfs := make([]hardforkAux, 0, len(p.Hardforks))
for _, hf := range config.Hardforks {
if h, ok := p.Hardforks[hf]; ok {
hfs = append(hfs, hardforkAux{
Name: hf.String(),
Height: h,
})
}
}
standbyCommittee := make([]string, len(p.StandbyCommittee))
for i, key := range p.StandbyCommittee {
standbyCommittee[i] = key.StringCompressed()
}
aux := protocolMarshallerAux{
AddressVersion: p.AddressVersion,
Network: p.Network,
MillisecondsPerBlock: p.MillisecondsPerBlock,
MaxTraceableBlocks: p.MaxTraceableBlocks,
MaxValidUntilBlockIncrement: p.MaxValidUntilBlockIncrement,
MaxTransactionsPerBlock: p.MaxTransactionsPerBlock,
MemoryPoolMaxTransactions: p.MemoryPoolMaxTransactions,
ValidatorsCount: p.ValidatorsCount,
InitialGasDistribution: int64(p.InitialGasDistribution),
Hardforks: hfs,
StandbyCommittee: standbyCommittee,
SeedList: p.SeedList,
CommitteeHistory: p.CommitteeHistory,
P2PSigExtensions: p.P2PSigExtensions,
StateRootInHeader: p.StateRootInHeader,
ValidatorsHistory: p.ValidatorsHistory,
}
return json.Marshal(aux)
}
// UnmarshalJSON implements the JSON unmarshaler interface.
func (p *Protocol) UnmarshalJSON(data []byte) error {
var aux protocolMarshallerAux
err := json.Unmarshal(data, &aux)
if err != nil {
return err
}
standbyCommittee, err := keys.NewPublicKeysFromStrings(aux.StandbyCommittee)
if err != nil {
return err
}
p.AddressVersion = aux.AddressVersion
p.Network = aux.Network
p.MillisecondsPerBlock = aux.MillisecondsPerBlock
p.MaxTraceableBlocks = aux.MaxTraceableBlocks
p.MaxValidUntilBlockIncrement = aux.MaxValidUntilBlockIncrement
p.MaxTransactionsPerBlock = aux.MaxTransactionsPerBlock
p.MemoryPoolMaxTransactions = aux.MemoryPoolMaxTransactions
p.ValidatorsCount = aux.ValidatorsCount
p.CommitteeHistory = aux.CommitteeHistory
p.P2PSigExtensions = aux.P2PSigExtensions
p.StateRootInHeader = aux.StateRootInHeader
p.ValidatorsHistory = aux.ValidatorsHistory
p.InitialGasDistribution = fixedn.Fixed8(aux.InitialGasDistribution)
p.StandbyCommittee = standbyCommittee
p.SeedList = aux.SeedList
// Filter out unknown hardforks.
for i := range aux.Hardforks {
aux.Hardforks[i].Name = strings.TrimPrefix(aux.Hardforks[i].Name, prefixHardfork)
if !config.IsHardforkValid(aux.Hardforks[i].Name) {
return fmt.Errorf("unexpected hardfork: %s", aux.Hardforks[i].Name)
}
}
p.Hardforks = make(map[config.Hardfork]uint32, len(aux.Hardforks))
for _, cfgHf := range config.Hardforks {
for _, auxHf := range aux.Hardforks {
if auxHf.Name == cfgHf.String() {
p.Hardforks[cfgHf] = auxHf.Height
}
}
}
return nil
}