Merge pull request #1469 from nspcc-dev/fix-protocol-limits

Fix protocol limits
This commit is contained in:
Roman Khimov 2020-10-08 13:39:25 +03:00 committed by GitHub
commit 705d04eda6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 99 additions and 22 deletions

View file

@ -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()
} }

View file

@ -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.

View 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))
}

View file

@ -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.

View file

@ -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)
}

View file

@ -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)
} }

View file

@ -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()

View file

@ -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 {

View file

@ -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

View file

@ -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: