Skip to content

Commit 2ee8859

Browse files
authored
p2p: snappy encoding for devp2p (version bump to 5) (#15106)
* p2p: snappy encoding for devp2p (version bump to 5) * p2p: remove lazy decompression, enforce 16MB limit
1 parent 2b4a5f2 commit 2ee8859

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

p2p/peer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ import (
3232
)
3333

3434
const (
35-
baseProtocolVersion = 4
35+
baseProtocolVersion = 5
3636
baseProtocolLength = uint64(16)
3737
baseProtocolMaxMsgSize = 2 * 1024
3838

39+
snappyProtocolVersion = 5
40+
3941
pingInterval = 15 * time.Second
4042
)
4143

p2p/rlpx.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"fmt"
3030
"hash"
3131
"io"
32+
"io/ioutil"
3233
mrand "math/rand"
3334
"net"
3435
"sync"
@@ -40,6 +41,7 @@ import (
4041
"github.com/ethereum/go-ethereum/crypto/sha3"
4142
"github.com/ethereum/go-ethereum/p2p/discover"
4243
"github.com/ethereum/go-ethereum/rlp"
44+
"github.com/golang/snappy"
4345
)
4446

4547
const (
@@ -68,6 +70,10 @@ const (
6870
discWriteTimeout = 1 * time.Second
6971
)
7072

73+
// errPlainMessageTooLarge is returned if a decompressed message length exceeds
74+
// the allowed 24 bits (i.e. length >= 16MB).
75+
var errPlainMessageTooLarge = errors.New("message length >= 16MB")
76+
7177
// rlpx is the transport protocol used by actual (non-test) connections.
7278
// It wraps the frame encoder with locks and read/write deadlines.
7379
type rlpx struct {
@@ -127,6 +133,9 @@ func (t *rlpx) doProtoHandshake(our *protoHandshake) (their *protoHandshake, err
127133
if err := <-werr; err != nil {
128134
return nil, fmt.Errorf("write error: %v", err)
129135
}
136+
// If the protocol version supports Snappy encoding, upgrade immediately
137+
t.rw.snappy = their.Version >= snappyProtocolVersion
138+
130139
return their, nil
131140
}
132141

@@ -556,6 +565,8 @@ type rlpxFrameRW struct {
556565
macCipher cipher.Block
557566
egressMAC hash.Hash
558567
ingressMAC hash.Hash
568+
569+
snappy bool
559570
}
560571

561572
func newRLPXFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW {
@@ -583,6 +594,17 @@ func newRLPXFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW {
583594
func (rw *rlpxFrameRW) WriteMsg(msg Msg) error {
584595
ptype, _ := rlp.EncodeToBytes(msg.Code)
585596

597+
// if snappy is enabled, compress message now
598+
if rw.snappy {
599+
if msg.Size > maxUint24 {
600+
return errPlainMessageTooLarge
601+
}
602+
payload, _ := ioutil.ReadAll(msg.Payload)
603+
payload = snappy.Encode(nil, payload)
604+
605+
msg.Payload = bytes.NewReader(payload)
606+
msg.Size = uint32(len(payload))
607+
}
586608
// write header
587609
headbuf := make([]byte, 32)
588610
fsize := uint32(len(ptype)) + msg.Size
@@ -668,6 +690,26 @@ func (rw *rlpxFrameRW) ReadMsg() (msg Msg, err error) {
668690
}
669691
msg.Size = uint32(content.Len())
670692
msg.Payload = content
693+
694+
// if snappy is enabled, verify and decompress message
695+
if rw.snappy {
696+
payload, err := ioutil.ReadAll(msg.Payload)
697+
if err != nil {
698+
return msg, err
699+
}
700+
size, err := snappy.DecodedLen(payload)
701+
if err != nil {
702+
return msg, err
703+
}
704+
if size > int(maxUint24) {
705+
return msg, errPlainMessageTooLarge
706+
}
707+
payload, err = snappy.Decode(nil, payload)
708+
if err != nil {
709+
return msg, err
710+
}
711+
msg.Size, msg.Payload = uint32(size), bytes.NewReader(payload)
712+
}
671713
return msg, nil
672714
}
673715

0 commit comments

Comments
 (0)