mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-27 05:42:56 +00:00
Merge pull request #1469 from nspcc-dev/fix-protocol-limits
Fix protocol limits
This commit is contained in:
commit
705d04eda6
10 changed files with 99 additions and 22 deletions
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -14,6 +15,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// MaxScriptLength is the limit for transaction's script length.
|
||||||
|
MaxScriptLength = math.MaxUint16
|
||||||
// MaxTransactionSize is the upper limit size in bytes that a transaction can reach. It is
|
// MaxTransactionSize is the upper limit size in bytes that a transaction can reach. It is
|
||||||
// set to be 102400.
|
// set to be 102400.
|
||||||
MaxTransactionSize = 102400
|
MaxTransactionSize = 102400
|
||||||
|
@ -140,7 +143,7 @@ func (t *Transaction) decodeHashableFields(br *io.BinReader) {
|
||||||
t.ValidUntilBlock = br.ReadU32LE()
|
t.ValidUntilBlock = br.ReadU32LE()
|
||||||
br.ReadArray(&t.Signers, MaxAttributes)
|
br.ReadArray(&t.Signers, MaxAttributes)
|
||||||
br.ReadArray(&t.Attributes, MaxAttributes-len(t.Signers))
|
br.ReadArray(&t.Attributes, MaxAttributes-len(t.Signers))
|
||||||
t.Script = br.ReadVarBytes()
|
t.Script = br.ReadVarBytes(MaxScriptLength)
|
||||||
if br.Err == nil {
|
if br.Err == nil {
|
||||||
br.Err = t.isValid()
|
br.Err = t.isValid()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,16 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MaxInvocationScript is the maximum length of allowed invocation
|
||||||
|
// script. It should fit 11/21 multisignature for the committee.
|
||||||
|
MaxInvocationScript = 1024
|
||||||
|
|
||||||
|
// MaxVerificationScript is the maximum allowed length of verification
|
||||||
|
// script. It should be appropriate for 11/21 multisignature committee.
|
||||||
|
MaxVerificationScript = 1024
|
||||||
|
)
|
||||||
|
|
||||||
// Witness contains 2 scripts.
|
// Witness contains 2 scripts.
|
||||||
type Witness struct {
|
type Witness struct {
|
||||||
InvocationScript []byte `json:"invocation"`
|
InvocationScript []byte `json:"invocation"`
|
||||||
|
@ -14,8 +24,8 @@ type Witness struct {
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// DecodeBinary implements Serializable interface.
|
||||||
func (w *Witness) DecodeBinary(br *io.BinReader) {
|
func (w *Witness) DecodeBinary(br *io.BinReader) {
|
||||||
w.InvocationScript = br.ReadVarBytes()
|
w.InvocationScript = br.ReadVarBytes(MaxInvocationScript)
|
||||||
w.VerificationScript = br.ReadVarBytes()
|
w.VerificationScript = br.ReadVarBytes(MaxVerificationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
|
|
38
pkg/core/transaction/witness_test.go
Normal file
38
pkg/core/transaction/witness_test.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package transaction
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWitnessSerDes(t *testing.T) {
|
||||||
|
var good1 = &Witness{
|
||||||
|
InvocationScript: make([]byte, 64),
|
||||||
|
VerificationScript: make([]byte, 32),
|
||||||
|
}
|
||||||
|
var good2 = &Witness{
|
||||||
|
InvocationScript: make([]byte, MaxInvocationScript),
|
||||||
|
VerificationScript: make([]byte, MaxVerificationScript),
|
||||||
|
}
|
||||||
|
var bad1 = &Witness{
|
||||||
|
InvocationScript: make([]byte, MaxInvocationScript+1),
|
||||||
|
VerificationScript: make([]byte, 32),
|
||||||
|
}
|
||||||
|
var bad2 = &Witness{
|
||||||
|
InvocationScript: make([]byte, 128),
|
||||||
|
VerificationScript: make([]byte, MaxVerificationScript+1),
|
||||||
|
}
|
||||||
|
var exp = new(Witness)
|
||||||
|
testserdes.MarshalUnmarshalJSON(t, good1, exp)
|
||||||
|
testserdes.MarshalUnmarshalJSON(t, good2, exp)
|
||||||
|
testserdes.EncodeDecodeBinary(t, good1, exp)
|
||||||
|
testserdes.EncodeDecodeBinary(t, good2, exp)
|
||||||
|
bin1, err := testserdes.EncodeBinary(bad1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
bin2, err := testserdes.EncodeBinary(bad2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Error(t, testserdes.DecodeBinary(bin1, exp))
|
||||||
|
require.Error(t, testserdes.DecodeBinary(bin2, exp))
|
||||||
|
}
|
|
@ -10,6 +10,10 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MaxAddrsCount is the maximum number of addresses that could be packed into
|
||||||
|
// one payload.
|
||||||
|
const MaxAddrsCount = 200
|
||||||
|
|
||||||
// AddressAndTime payload.
|
// AddressAndTime payload.
|
||||||
type AddressAndTime struct {
|
type AddressAndTime struct {
|
||||||
Timestamp uint32
|
Timestamp uint32
|
||||||
|
@ -75,7 +79,10 @@ func NewAddressList(n int) *AddressList {
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// DecodeBinary implements Serializable interface.
|
||||||
func (p *AddressList) DecodeBinary(br *io.BinReader) {
|
func (p *AddressList) DecodeBinary(br *io.BinReader) {
|
||||||
br.ReadArray(&p.Addrs)
|
br.ReadArray(&p.Addrs, MaxAddrsCount)
|
||||||
|
if len(p.Addrs) == 0 {
|
||||||
|
br.Err = errors.New("no addresses listed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeDecodeAddress(t *testing.T) {
|
func TestEncodeDecodeAddress(t *testing.T) {
|
||||||
|
@ -36,18 +37,38 @@ func TestEncodeDecodeAddress(t *testing.T) {
|
||||||
testserdes.EncodeDecodeBinary(t, addr, new(AddressAndTime))
|
testserdes.EncodeDecodeBinary(t, addr, new(AddressAndTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeDecodeAddressList(t *testing.T) {
|
func fillAddressList(al *AddressList) {
|
||||||
var lenList uint8 = 4
|
for i := 0; i < len(al.Addrs); i++ {
|
||||||
addrList := NewAddressList(int(lenList))
|
e, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:20%d", i))
|
||||||
for i := 0; i < int(lenList); i++ {
|
al.Addrs[i] = NewAddressAndTime(e, time.Now(), capability.Capabilities{
|
||||||
e, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:200%d", i))
|
|
||||||
addrList.Addrs[i] = NewAddressAndTime(e, time.Now(), capability.Capabilities{
|
|
||||||
{
|
{
|
||||||
Type: capability.TCPServer,
|
Type: capability.TCPServer,
|
||||||
Data: &capability.Server{Port: 123},
|
Data: &capability.Server{Port: 123},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeAddressList(t *testing.T) {
|
||||||
|
var lenList uint8 = 4
|
||||||
|
addrList := NewAddressList(int(lenList))
|
||||||
|
fillAddressList(addrList)
|
||||||
testserdes.EncodeDecodeBinary(t, addrList, new(AddressList))
|
testserdes.EncodeDecodeBinary(t, addrList, new(AddressList))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeBadAddressList(t *testing.T) {
|
||||||
|
var newAL = new(AddressList)
|
||||||
|
addrList := NewAddressList(MaxAddrsCount + 1)
|
||||||
|
fillAddressList(addrList)
|
||||||
|
|
||||||
|
bin, err := testserdes.EncodeBinary(addrList)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = testserdes.DecodeBinary(bin, newAL)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
addrList = NewAddressList(0)
|
||||||
|
bin, err = testserdes.EncodeBinary(addrList)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = testserdes.DecodeBinary(bin, newAL)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MaxUserAgentLength is the limit for user agent field.
|
||||||
|
const MaxUserAgentLength = 1024
|
||||||
|
|
||||||
// Version payload.
|
// Version payload.
|
||||||
type Version struct {
|
type Version struct {
|
||||||
// NetMode of the node
|
// NetMode of the node
|
||||||
|
@ -42,7 +45,7 @@ func (p *Version) DecodeBinary(br *io.BinReader) {
|
||||||
p.Version = br.ReadU32LE()
|
p.Version = br.ReadU32LE()
|
||||||
p.Timestamp = br.ReadU32LE()
|
p.Timestamp = br.ReadU32LE()
|
||||||
p.Nonce = br.ReadU32LE()
|
p.Nonce = br.ReadU32LE()
|
||||||
p.UserAgent = br.ReadVarBytes()
|
p.UserAgent = br.ReadVarBytes(MaxUserAgentLength)
|
||||||
p.Capabilities.DecodeBinary(br)
|
p.Capabilities.DecodeBinary(br)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ const (
|
||||||
defaultAttemptConnPeers = 20
|
defaultAttemptConnPeers = 20
|
||||||
defaultMaxPeers = 100
|
defaultMaxPeers = 100
|
||||||
maxBlockBatch = 200
|
maxBlockBatch = 200
|
||||||
maxAddrsToSend = 200
|
|
||||||
minPoolCount = 30
|
minPoolCount = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -690,8 +689,8 @@ func (s *Server) handleAddrCmd(p Peer, addrs *payload.AddressList) error {
|
||||||
// handleGetAddrCmd sends to the peer some good addresses that we know of.
|
// handleGetAddrCmd sends to the peer some good addresses that we know of.
|
||||||
func (s *Server) handleGetAddrCmd(p Peer) error {
|
func (s *Server) handleGetAddrCmd(p Peer) error {
|
||||||
addrs := s.discovery.GoodPeers()
|
addrs := s.discovery.GoodPeers()
|
||||||
if len(addrs) > maxAddrsToSend {
|
if len(addrs) > payload.MaxAddrsCount {
|
||||||
addrs = addrs[:maxAddrsToSend]
|
addrs = addrs[:payload.MaxAddrsCount]
|
||||||
}
|
}
|
||||||
alist := payload.NewAddressList(len(addrs))
|
alist := payload.NewAddressList(len(addrs))
|
||||||
ts := time.Now()
|
ts := time.Now()
|
||||||
|
|
|
@ -184,7 +184,7 @@ func (m *Manifest) EncodeBinary(w *io.BinWriter) {
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable.
|
// DecodeBinary implements io.Serializable.
|
||||||
func (m *Manifest) DecodeBinary(r *io.BinReader) {
|
func (m *Manifest) DecodeBinary(r *io.BinReader) {
|
||||||
data := r.ReadVarBytes()
|
data := r.ReadVarBytes(MaxManifestSize)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
return
|
return
|
||||||
} else if err := json.Unmarshal(data, m); err != nil {
|
} else if err := json.Unmarshal(data, m); err != nil {
|
||||||
|
|
|
@ -203,11 +203,7 @@ func (n *File) DecodeBinary(r *io.BinReader) {
|
||||||
r.Err = errors.New("CRC verification fail")
|
r.Err = errors.New("CRC verification fail")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.Script = r.ReadVarBytes()
|
n.Script = r.ReadVarBytes(MaxScriptLength)
|
||||||
if len(n.Script) > MaxScriptLength {
|
|
||||||
r.Err = errors.New("invalid script length")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !hash.Hash160(n.Script).Equals(n.Header.ScriptHash) {
|
if !hash.Hash160(n.Script).Equals(n.Header.ScriptHash) {
|
||||||
r.Err = errors.New("script hashes mismatch")
|
r.Err = errors.New("script hashes mismatch")
|
||||||
return
|
return
|
||||||
|
|
|
@ -98,13 +98,13 @@ func DecodeBinaryStackItem(r *io.BinReader) Item {
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
case ByteArrayT, BufferT:
|
case ByteArrayT, BufferT:
|
||||||
data := r.ReadVarBytes()
|
data := r.ReadVarBytes(MaxSize)
|
||||||
return NewByteArray(data)
|
return NewByteArray(data)
|
||||||
case BooleanT:
|
case BooleanT:
|
||||||
var b = r.ReadBool()
|
var b = r.ReadBool()
|
||||||
return NewBool(b)
|
return NewBool(b)
|
||||||
case IntegerT:
|
case IntegerT:
|
||||||
data := r.ReadVarBytes()
|
data := r.ReadVarBytes(bigint.MaxBytesLen)
|
||||||
num := bigint.FromBytes(data)
|
num := bigint.FromBytes(data)
|
||||||
return NewBigInteger(num)
|
return NewBigInteger(num)
|
||||||
case ArrayT, StructT:
|
case ArrayT, StructT:
|
||||||
|
|
Loading…
Reference in a new issue