Implement new waku/0 handshake (#1848)

This commit is contained in:
Adam Babik 2020-02-11 17:59:21 +01:00 committed by GitHub
parent da4f30ffd2
commit 1b515a5a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 350 additions and 137 deletions

View File

@ -261,7 +261,8 @@ test-unit: UNIT_TEST_PACKAGES = $(shell go list ./... | \
grep -v /lib | \ grep -v /lib | \
grep -v /transactions/fake ) grep -v /transactions/fake )
test-unit: ##@tests Run unit and integration tests test-unit: ##@tests Run unit and integration tests
go test -v -failfast $(UNIT_TEST_PACKAGES) $(gotest_extraflags) && cd ./protocol && $(MAKE) test go test -v -failfast $(UNIT_TEST_PACKAGES) $(gotest_extraflags)
cd ./waku && go test -v -failfast ./... $(gotest_extraflags)
test-unit-race: gotest_extraflags=-race test-unit-race: gotest_extraflags=-race
test-unit-race: test-unit ##@tests Run unit and integration tests with -race flag test-unit-race: test-unit ##@tests Run unit and integration tests with -race flag

View File

@ -1,52 +0,0 @@
GO111MODULE = on
ENABLE_METRICS ?= true
BUILD_FLAGS ?= $(shell echo "-ldflags '\
-X github.com/status-im/status-go/protocol/vendor/github.com/ethereum/go-ethereum/metrics.EnabledStr=$(ENABLE_METRICS)'")
test:
go test ./...
.PHONY: test
test-race:
go test -race ./...
.PHONY: test-race
lint:
golangci-lint run -v
.PHONY: lint
install-linter:
# install linter
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.21.0
.PHONY: install-linter
install-dev:
# a tool to vendor non-go files
go get github.com/goware/modvendor@latest
go get github.com/golang/mock/gomock@latest
go install github.com/golang/mock/mockgen
go get github.com/kevinburke/go-bindata/go-bindata@v3.13.0
go get github.com/golang/protobuf/protoc-gen-go@v1.3.1
.PHONY: install-dev
generate:
go generate ./...
.PHONY: generate
new-migration:
@if [ -z "$$DIR" ]; then \
echo 'missing DIR var'; \
exit 1; \
fi
@if [ -z "$$NAME" ]; then \
echo 'missing NAME var'; \
exit 1; \
fi
mkdir -p $(DIR)
touch $(DIR)/`date +"%s"`_$(NAME).down.sql ./$(DIR)/`date +"%s"`_$(NAME).up.sql
.PHONY: create-migration

View File

@ -2,7 +2,7 @@ module github.com/status-im/status-go/waku
go 1.13 go 1.13
replace github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.6 replace github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.7
require ( require (
github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 // indirect github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 // indirect

View File

@ -27,6 +27,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/btcsuite/btcd v0.20.0-beta h1:DnZGUjFbRkpytojHWwy6nfUSA7vFrzWXDLpFNzt74ZA= github.com/btcsuite/btcd v0.20.0-beta h1:DnZGUjFbRkpytojHWwy6nfUSA7vFrzWXDLpFNzt74ZA=
github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
@ -191,6 +192,9 @@ github.com/status-im/go-ethereum v1.9.5-status.5 h1:d2RJC6ltNZJM2mrAW6kDWYdzewF8
github.com/status-im/go-ethereum v1.9.5-status.5/go.mod h1:g2+E89NWtyA+55p6XEl5Sdt7Mtez3V0T3+Y7mJNb+tI= github.com/status-im/go-ethereum v1.9.5-status.5/go.mod h1:g2+E89NWtyA+55p6XEl5Sdt7Mtez3V0T3+Y7mJNb+tI=
github.com/status-im/go-ethereum v1.9.5-status.6 h1:ytuTO1yBIAuTVRtRQoc2mrdyngtP+XOQ9IHIibbz7/I= github.com/status-im/go-ethereum v1.9.5-status.6 h1:ytuTO1yBIAuTVRtRQoc2mrdyngtP+XOQ9IHIibbz7/I=
github.com/status-im/go-ethereum v1.9.5-status.6/go.mod h1:08JvQWE+IOnAFSe4UD4ACLNe2fDd9XmWMCq5Yzy9mk0= github.com/status-im/go-ethereum v1.9.5-status.6/go.mod h1:08JvQWE+IOnAFSe4UD4ACLNe2fDd9XmWMCq5Yzy9mk0=
github.com/status-im/go-ethereum v1.9.5-status.7 h1:DKH1GiF52LwaZaw6YDBliFEgm/JDsbIT+hn7ph6X94Q=
github.com/status-im/go-ethereum v1.9.5-status.7/go.mod h1:YyH5DKB6+z+Vaya7eIm67pnuPZ1oiUMbbsZW41ktN0g=
github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -226,6 +230,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=

125
waku/handshake.go Normal file
View File

@ -0,0 +1,125 @@
package waku
import (
"errors"
"fmt"
"io"
"math"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/rlp"
)
// statusOptions defines additional information shared between peers
// during the handshake.
// There might be more options provided then fields in statusOptions
// and they should be ignored during deserialization to stay forward compatible.
// In the case of RLP, options should be serialized to an array of tuples
// where the first item is a field name and the second is a RLP-serialized value.
type statusOptions struct {
PoWRequirement uint64 `rlp:"key=0"` // RLP does not support float64 natively
BloomFilter []byte `rlp:"key=1"`
LightNodeEnabled bool `rlp:"key=2"`
ConfirmationsEnabled bool `rlp:"key=3"`
RateLimits RateLimits `rlp:"key=4"`
TopicInterest []TopicType `rlp:"key=5"`
}
var idxFieldKey = make(map[int]string)
var keyFieldIdx = func() map[string]int {
result := make(map[string]int)
opts := statusOptions{}
v := reflect.ValueOf(opts)
for i := 0; i < v.NumField(); i++ {
// skip unexported fields
if !v.Field(i).CanInterface() {
continue
}
rlpTag := v.Type().Field(i).Tag.Get("rlp")
// skip fields without rlp field tag
if rlpTag == "" {
continue
}
key := strings.Split(rlpTag, "=")[1]
result[key] = i
idxFieldKey[i] = key
}
return result
}()
func (o statusOptions) PoWRequirementF() float64 {
return math.Float64frombits(o.PoWRequirement)
}
func (o *statusOptions) SetPoWRequirementFromF(val float64) {
o.PoWRequirement = math.Float64bits(val)
}
func (o statusOptions) EncodeRLP(w io.Writer) error {
v := reflect.ValueOf(o)
optionsList := make([]interface{}, 0, v.NumField())
for i := 0; i < v.NumField(); i++ {
value := v.Field(i).Interface()
key, ok := idxFieldKey[i]
if !ok {
continue
}
optionsList = append(optionsList, []interface{}{key, value})
}
return rlp.Encode(w, optionsList)
}
func (o *statusOptions) DecodeRLP(s *rlp.Stream) error {
_, err := s.List()
if err != nil {
return fmt.Errorf("expected an outer list: %w", err)
}
v := reflect.ValueOf(o)
loop:
for {
_, err := s.List()
switch err {
case nil:
// continue to decode a key
case rlp.EOL:
break loop
default:
return fmt.Errorf("expected an inner list: %w", err)
}
var key string
if err := s.Decode(&key); err != nil {
return fmt.Errorf("invalid key: %w", err)
}
// Skip processing if a key does not exist.
// It might happen when there is a new peer
// which supports a new option with
// a higher index.
idx, ok := keyFieldIdx[key]
if !ok {
// Read the rest of the list items and dump them.
_, err := s.Raw()
if err != nil {
return fmt.Errorf("failed to read the value of key %s: %w", key, err)
}
continue
}
if err := s.Decode(v.Elem().Field(idx).Addr().Interface()); err != nil {
return fmt.Errorf("failed to decode an option %s: %w", key, err)
}
if err := s.ListEnd(); err != nil {
return err
}
}
return s.ListEnd()
}
func (o statusOptions) Validate() error {
if len(o.TopicInterest) > 1000 {
return errors.New("topic interest is limited by 1000 items")
}
return nil
}

59
waku/handshake_test.go Normal file
View File

@ -0,0 +1,59 @@
package waku
import (
"math"
"testing"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/rlp"
)
func TestEncodeDecodeRLP(t *testing.T) {
opts := statusOptions{
PoWRequirement: math.Float64bits(6.02),
BloomFilter: TopicToBloom(TopicType{0xaa, 0xbb, 0xcc, 0xdd}),
LightNodeEnabled: true,
ConfirmationsEnabled: true,
RateLimits: RateLimits{
IPLimits: 10,
PeerIDLimits: 5,
TopicLimits: 1,
},
TopicInterest: []TopicType{{0x01}, {0x02}, {0x03}, {0x04}},
}
data, err := rlp.EncodeToBytes(opts)
require.NoError(t, err)
var optsDecoded statusOptions
err = rlp.DecodeBytes(data, &optsDecoded)
require.NoError(t, err)
require.EqualValues(t, opts, optsDecoded)
}
func TestBackwardCompatibility(t *testing.T) {
alist := []interface{}{
[]interface{}{"0", math.Float64bits(2.05)},
}
data, err := rlp.EncodeToBytes(alist)
require.NoError(t, err)
var optsDecoded statusOptions
err = rlp.DecodeBytes(data, &optsDecoded)
require.NoError(t, err)
require.EqualValues(t, statusOptions{PoWRequirement: math.Float64bits(2.05)}, optsDecoded)
}
func TestForwardCompatibility(t *testing.T) {
alist := []interface{}{
[]interface{}{"0", math.Float64bits(2.05)},
[]interface{}{"99", uint(10)}, // some future option
}
data, err := rlp.EncodeToBytes(alist)
require.NoError(t, err)
var optsDecoded statusOptions
err = rlp.DecodeBytes(data, &optsDecoded)
require.NoError(t, err)
require.EqualValues(t, statusOptions{PoWRequirement: math.Float64bits(2.05)}, optsDecoded)
}

View File

@ -96,13 +96,15 @@ func (p *Peer) handshake() error {
isLightNode := p.host.LightClientMode() isLightNode := p.host.LightClientMode()
isRestrictedLightNodeConnection := p.host.LightClientModeConnectionRestricted() isRestrictedLightNodeConnection := p.host.LightClientModeConnectionRestricted()
go func() { go func() {
pow := p.host.MinPow() opts := statusOptions{
powConverted := math.Float64bits(pow) BloomFilter: p.host.BloomFilter(),
bloom := p.host.BloomFilter() LightNodeEnabled: isLightNode,
confirmationsEnabled := p.host.ConfirmationsEnabled() ConfirmationsEnabled: p.host.ConfirmationsEnabled(),
rateLimits := p.host.RateLimits() RateLimits: p.host.RateLimits(),
TopicInterest: nil,
errc <- p2p.SendItems(p.ws, statusCode, ProtocolVersion, powConverted, bloom, isLightNode, confirmationsEnabled, rateLimits) }
opts.SetPoWRequirementFromF(p.host.MinPow())
errc <- p2p.SendItems(p.ws, statusCode, ProtocolVersion, opts)
}() }()
// Fetch the remote status packet and verify protocol match // Fetch the remote status packet and verify protocol match
@ -113,56 +115,51 @@ func (p *Peer) handshake() error {
if packet.Code != statusCode { if packet.Code != statusCode {
return fmt.Errorf("p [%x] sent packet %x before status packet", p.ID(), packet.Code) return fmt.Errorf("p [%x] sent packet %x before status packet", p.ID(), packet.Code)
} }
var (
peerProtocolVersion uint64
peerOptions statusOptions
)
s := rlp.NewStream(packet.Payload, uint64(packet.Size)) s := rlp.NewStream(packet.Payload, uint64(packet.Size))
_, err = s.List() if _, err := s.List(); err != nil {
if err != nil { return fmt.Errorf("p [%x]: failed to decode status packet: %w", p.ID(), err)
return fmt.Errorf("p [%x] sent bad status message: %v", p.ID(), err)
} }
peerVersion, err := s.Uint() // Validate protocol version.
if err != nil { if err := s.Decode(&peerProtocolVersion); err != nil {
return fmt.Errorf("p [%x] sent bad status message (unable to decode version): %v", p.ID(), err) return fmt.Errorf("p [%x]: failed to decode peer protocol version: %w", p.ID(), err)
} }
if peerVersion != ProtocolVersion { if peerProtocolVersion != ProtocolVersion {
return fmt.Errorf("p [%x]: protocol version mismatch %d != %d", p.ID(), peerVersion, ProtocolVersion) return fmt.Errorf("p [%x]: protocol version mismatch %d != %d", p.ID(), peerProtocolVersion, ProtocolVersion)
} }
// Decode and validate other status packet options.
// only version is mandatory, subsequent parameters are optional if err := s.Decode(&peerOptions); err != nil {
powRaw, err := s.Uint() return fmt.Errorf("p [%x]: failed to decode status options: %w", p.ID(), err)
if err == nil {
pow := math.Float64frombits(powRaw)
if math.IsInf(pow, 0) || math.IsNaN(pow) || pow < 0.0 {
return fmt.Errorf("p [%x] sent bad status message: invalid pow", p.ID())
}
p.powRequirement = pow
var bloom []byte
err = s.Decode(&bloom)
if err == nil {
sz := len(bloom)
if sz != BloomFilterSize && sz != 0 {
return fmt.Errorf("p [%x] sent bad status message: wrong bloom filter size %d", p.ID(), sz)
}
p.setBloomFilter(bloom)
}
} }
if err := s.ListEnd(); err != nil {
isRemotePeerLightNode, _ := s.Bool() return fmt.Errorf("p [%x]: failed to decode status packet: %w", p.ID(), err)
if isRemotePeerLightNode && isLightNode && isRestrictedLightNodeConnection { }
if err := peerOptions.Validate(); err != nil {
return fmt.Errorf("p [%x]: sent invalid options: %w", p.ID(), err)
}
// Validate and save peer's PoW.
pow := peerOptions.PoWRequirementF()
if math.IsInf(pow, 0) || math.IsNaN(pow) || pow < 0.0 {
return fmt.Errorf("p [%x]: sent bad status message: invalid pow", p.ID())
}
p.powRequirement = pow
// Validate and save peer's bloom filters.
bloom := peerOptions.BloomFilter
bloomSize := len(bloom)
if bloomSize != 0 && bloomSize != BloomFilterSize {
return fmt.Errorf("p [%x] sent bad status message: wrong bloom filter size %d", p.ID(), bloomSize)
}
p.setBloomFilter(bloom)
// Validate and save other peer's options.
if peerOptions.LightNodeEnabled && isLightNode && isRestrictedLightNodeConnection {
return fmt.Errorf("p [%x] is useless: two light client communication restricted", p.ID()) return fmt.Errorf("p [%x] is useless: two light client communication restricted", p.ID())
} }
confirmationsEnabled, err := s.Bool() p.confirmationsEnabled = peerOptions.ConfirmationsEnabled
if err != nil || !confirmationsEnabled { p.setRateLimits(peerOptions.RateLimits)
p.logger.Info("confirmations are disabled for peer", zap.Binary("peer", p.ID()))
} else {
p.confirmationsEnabled = confirmationsEnabled
}
var rateLimits RateLimits
if err := s.Decode(&rateLimits); err != nil {
p.logger.Info("rate limiting is disabled for peer", zap.Binary("peer", p.ID()))
} else {
p.setRateLimits(rateLimits)
}
if err := <-errc; err != nil { if err := <-errc; err != nil {
return fmt.Errorf("p [%x] failed to send status packet: %v", p.ID(), err) return fmt.Errorf("p [%x] failed to send status packet: %v", p.ID(), err)

View File

@ -514,7 +514,10 @@ func TestPeerHandshakeWithTwoFullNode(t *testing.T) {
p1 := newPeer( p1 := newPeer(
&w1, &w1,
p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}),
&rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), false}}, &rwStub{[]interface{}{
ProtocolVersion,
statusOptions{PoWRequirement: 123},
}},
nil, nil,
) )
err := p1.handshake() err := p1.handshake()
@ -529,7 +532,10 @@ func TestHandshakeWithOldVersionWithoutLightModeFlag(t *testing.T) {
p1 := newPeer( p1 := newPeer(
&w1, &w1,
p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}),
&rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize)}}, &rwStub{[]interface{}{
ProtocolVersion,
statusOptions{PoWRequirement: 123},
}},
nil, nil,
) )
err := p1.handshake() err := p1.handshake()
@ -546,7 +552,10 @@ func TestTwoLightPeerHandshakeRestrictionOff(t *testing.T) {
p1 := newPeer( p1 := newPeer(
&w1, &w1,
p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}),
&rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), true}}, &rwStub{[]interface{}{
ProtocolVersion,
statusOptions{PoWRequirement: 123, LightNodeEnabled: true},
}},
nil, nil,
) )
err := p1.handshake() err := p1.handshake()

View File

@ -28,6 +28,8 @@ import (
"testing" "testing"
"time" "time"
"go.uber.org/zap"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
@ -913,6 +915,7 @@ func TestSendP2PDirect(t *testing.T) {
rwStub := &rwP2PMessagesStub{} rwStub := &rwP2PMessagesStub{}
peerW := newPeer(w, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), rwStub, nil) peerW := newPeer(w, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), rwStub, nil)
w.peers[peerW] = struct{}{}
params, err := generateMessageParams() params, err := generateMessageParams()
if err != nil { if err != nil {
@ -929,7 +932,7 @@ func TestSendP2PDirect(t *testing.T) {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err) t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
} }
err = w.SendP2PDirect(peerW, env, env, env) err = w.SendP2PDirect(peerW.ID(), env, env, env)
if err != nil { if err != nil {
t.Fatalf("failed to send envelope with seed %d: %s.", seed, err) t.Fatalf("failed to send envelope with seed %d: %s.", seed, err)
} }
@ -1053,7 +1056,14 @@ func testConfirmationsHandshake(t *testing.T, expectConfirmations bool) {
p2p.ExpectMsg( p2p.ExpectMsg(
rw1, rw1,
statusCode, statusCode,
[]interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, expectConfirmations, RateLimits{}}, []interface{}{
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
LightNodeEnabled: false,
ConfirmationsEnabled: expectConfirmations,
},
},
), ),
) )
} }
@ -1067,12 +1077,14 @@ func TestHandshakeWithConfirmationsDisabled(t *testing.T) {
} }
func TestConfirmationReceived(t *testing.T) { func TestConfirmationReceived(t *testing.T) {
logger, err := zap.NewDevelopment()
require.NoError(t, err)
conf := &Config{ conf := &Config{
MinimumAcceptedPoW: 0, MinimumAcceptedPoW: 0,
MaxMessageSize: 10 << 20, MaxMessageSize: 10 << 20,
EnableConfirmations: true, EnableConfirmations: true,
} }
w := New(conf, nil) w := New(conf, logger)
p := p2p.NewPeer(enode.ID{1}, "1", []p2p.Cap{{"waku", 0}}) p := p2p.NewPeer(enode.ID{1}, "1", []p2p.Cap{{"waku", 0}})
rw1, rw2 := p2p.MsgPipe() rw1, rw2 := p2p.MsgPipe()
errorc := make(chan error, 1) errorc := make(chan error, 1)
@ -1080,15 +1092,27 @@ func TestConfirmationReceived(t *testing.T) {
err := w.HandlePeer(p, rw2) err := w.HandlePeer(p, rw2)
errorc <- err errorc <- err
}() }()
time.AfterFunc(5*time.Second, func() { go func() {
rw1.Close() select {
}) case err := <-errorc:
t.Log(err)
case <-time.After(time.Second * 5):
rw1.Close()
}
}()
require.NoError( require.NoError(
t, t,
p2p.ExpectMsg( p2p.ExpectMsg(
rw1, rw1,
statusCode, statusCode,
[]interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, true, RateLimits{}}, []interface{}{
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
ConfirmationsEnabled: true,
},
},
), ),
) )
require.NoError( require.NoError(
@ -1097,10 +1121,12 @@ func TestConfirmationReceived(t *testing.T) {
rw1, rw1,
statusCode, statusCode,
ProtocolVersion, ProtocolVersion,
math.Float64bits(w.MinPow()), statusOptions{
w.BloomFilter(), PoWRequirement: math.Float64bits(w.MinPow()),
true, BloomFilter: w.BloomFilter(),
true, ConfirmationsEnabled: true,
LightNodeEnabled: true,
},
), ),
) )
@ -1142,7 +1168,14 @@ func TestMessagesResponseWithError(t *testing.T) {
p2p.ExpectMsg( p2p.ExpectMsg(
rw1, rw1,
statusCode, statusCode,
[]interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, true, RateLimits{}}, []interface{}{
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
ConfirmationsEnabled: true,
},
},
), ),
) )
require.NoError( require.NoError(
@ -1151,10 +1184,12 @@ func TestMessagesResponseWithError(t *testing.T) {
rw1, rw1,
statusCode, statusCode,
ProtocolVersion, ProtocolVersion,
math.Float64bits(w.MinPow()), w.BloomFilter(), statusOptions{
true, PoWRequirement: math.Float64bits(w.MinPow()),
true, BloomFilter: w.BloomFilter(),
RateLimits{}, ConfirmationsEnabled: true,
LightNodeEnabled: true,
},
), ),
) )
@ -1204,9 +1239,29 @@ func testConfirmationEvents(t *testing.T, envelope Envelope, envelopeErrors []En
time.AfterFunc(5*time.Second, func() { time.AfterFunc(5*time.Second, func() {
rw1.Close() rw1.Close()
}) })
require.NoError(t, p2p.ExpectMsg(rw1, statusCode, []interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, true, RateLimits{}})) require.NoError(t, p2p.ExpectMsg(
require.NoError(t, p2p.SendItems(rw1, statusCode, ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), true, true)) rw1,
statusCode,
[]interface{}{
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
ConfirmationsEnabled: true,
},
},
))
require.NoError(t, p2p.SendItems(
rw1,
statusCode,
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
ConfirmationsEnabled: true,
LightNodeEnabled: true,
},
))
require.NoError(t, w.Send(&envelope)) require.NoError(t, w.Send(&envelope))
require.NoError(t, p2p.ExpectMsg(rw1, messagesCode, []*Envelope{&envelope})) require.NoError(t, p2p.ExpectMsg(rw1, messagesCode, []*Envelope{&envelope}))
@ -1286,7 +1341,13 @@ func TestEventsWithoutConfirmation(t *testing.T) {
p2p.ExpectMsg( p2p.ExpectMsg(
rw1, rw1,
statusCode, statusCode,
[]interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, false, RateLimits{}}, []interface{}{
ProtocolVersion,
statusOptions{
PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
},
},
), ),
) )
require.NoError( require.NoError(
@ -1295,11 +1356,11 @@ func TestEventsWithoutConfirmation(t *testing.T) {
rw1, rw1,
statusCode, statusCode,
ProtocolVersion, ProtocolVersion,
math.Float64bits(w.MinPow()), statusOptions{
w.BloomFilter(), PoWRequirement: math.Float64bits(w.MinPow()),
true, BloomFilter: w.BloomFilter(),
false, LightNodeEnabled: true,
RateLimits{}, },
), ),
) )
@ -1464,10 +1525,17 @@ func TestRateLimiterIntegration(t *testing.T) {
p2p.ExpectMsg( p2p.ExpectMsg(
rw1, rw1,
statusCode, statusCode,
[]interface{}{ProtocolVersion, math.Float64bits(w.MinPow()), w.BloomFilter(), false, false, RateLimits{ []interface{}{
IPLimits: 10, ProtocolVersion,
PeerIDLimits: 5, statusOptions{
}}, PoWRequirement: math.Float64bits(w.MinPow()),
BloomFilter: w.BloomFilter(),
RateLimits: RateLimits{
IPLimits: 10,
PeerIDLimits: 5,
},
},
},
), ),
) )
select { select {

View File

@ -911,6 +911,7 @@ func TestSendP2PDirect(t *testing.T) {
rwStub := &rwP2PMessagesStub{} rwStub := &rwP2PMessagesStub{}
peerW := newPeer(w, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), rwStub) peerW := newPeer(w, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), rwStub)
w.peers[peerW] = struct{}{}
params, err := generateMessageParams() params, err := generateMessageParams()
if err != nil { if err != nil {
@ -928,7 +929,7 @@ func TestSendP2PDirect(t *testing.T) {
} }
// verify sending a single envelope // verify sending a single envelope
err = w.SendP2PDirect(peerW, env) err = w.SendP2PDirect(peerW.ID(), env)
if err != nil { if err != nil {
t.Fatalf("failed to send envelope with seed %d: %s.", seed, err) t.Fatalf("failed to send envelope with seed %d: %s.", seed, err)
} }