Implement waku/1
Why make the change? This implements waku/1 which is a breaking change as waku/0 diverged from the specs. What has changed? - Added v1 namespace - Changed the testing code to test from the outside rather than stubbing p2p specific messages, so that any version specific code is under `vx` namespaces - Split waku vs waku/x test code - Added a test suite that can be used for different versions Things still to do I kept the tests we have for the versioned aspect of waku, probably we want to add some or change other to provide the optimal test coverage.
This commit is contained in:
parent
8aa42e4148
commit
299b3fc093
|
@ -1,4 +1,3 @@
|
||||||
### waku/1
|
### waku/1
|
||||||
|
|
||||||
This namespace implements `waku` 1.0 as described in https://github.com/vacp2p/specs/blob/master/specs/waku/waku-1.md.
|
This namespace implements `waku` 1.0 as described in https://github.com/vacp2p/specs/blob/master/specs/waku/waku-1.md
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ package v1
|
||||||
|
|
||||||
// Waku protocol parameters
|
// Waku protocol parameters
|
||||||
const (
|
const (
|
||||||
Version = uint64(0) // Peer version number
|
Version = uint64(1) // Peer version number
|
||||||
VersionStr = "0" // The same, as a string
|
VersionStr = "1" // The same, as a string
|
||||||
Name = "waku" // Nickname of the protocol
|
Name = "waku" // Nickname of the protocol
|
||||||
|
|
||||||
// Waku protocol message codes, according to https://github.com/vacp2p/specs/blob/master/specs/waku/waku-0.md
|
// Waku protocol message codes, according to https://github.com/vacp2p/specs/blob/master/specs/waku/waku-0.md
|
||||||
|
|
|
@ -389,7 +389,7 @@ func (p *Peer) handshake() error {
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 1)
|
||||||
opts := StatusOptionsFromHost(p.host)
|
opts := StatusOptionsFromHost(p.host)
|
||||||
go func() {
|
go func() {
|
||||||
errc <- p2p.SendItems(p.rw, statusCode, Version, opts)
|
errc <- p2p.Send(p.rw, statusCode, opts)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Fetch the remote status packet and verify protocol match
|
// Fetch the remote status packet and verify protocol match
|
||||||
|
@ -401,34 +401,21 @@ func (p *Peer) handshake() error {
|
||||||
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 (
|
var peerOptions StatusOptions
|
||||||
peerProtocolVersion uint64
|
|
||||||
peerOptions StatusOptions
|
|
||||||
)
|
|
||||||
s := rlp.NewStream(packet.Payload, uint64(packet.Size))
|
s := rlp.NewStream(packet.Payload, uint64(packet.Size))
|
||||||
if _, err := s.List(); err != nil {
|
|
||||||
return fmt.Errorf("p [%x]: failed to decode status packet: %v", p.ID(), err)
|
|
||||||
}
|
|
||||||
// Validate protocol version.
|
|
||||||
if err := s.Decode(&peerProtocolVersion); err != nil {
|
|
||||||
return fmt.Errorf("p [%x]: failed to decode peer protocol version: %v", p.ID(), err)
|
|
||||||
}
|
|
||||||
if peerProtocolVersion != Version {
|
|
||||||
return fmt.Errorf("p [%x]: protocol version mismatch %d != %d", p.ID(), peerProtocolVersion, Version)
|
|
||||||
}
|
|
||||||
// Decode and validate other status packet options.
|
// Decode and validate other status packet options.
|
||||||
if err := s.Decode(&peerOptions); err != nil {
|
if err := s.Decode(&peerOptions); err != nil {
|
||||||
return fmt.Errorf("p [%x]: failed to decode status options: %v", p.ID(), err)
|
return fmt.Errorf("p [%x]: failed to decode status options: %v", p.ID(), err)
|
||||||
}
|
}
|
||||||
if err := s.ListEnd(); err != nil {
|
|
||||||
return fmt.Errorf("p [%x]: failed to decode status packet: %v", p.ID(), err)
|
|
||||||
}
|
|
||||||
if err := p.setOptions(peerOptions.WithDefaults()); err != nil {
|
if err := p.setOptions(peerOptions.WithDefaults()); err != nil {
|
||||||
return fmt.Errorf("p [%x]: failed to set options: %v", p.ID(), err)
|
return fmt.Errorf("p [%x]: failed to set options: %v", p.ID(), err)
|
||||||
}
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = packet.Discard()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,25 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
mrand "math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
"github.com/status-im/status-go/waku/common"
|
"github.com/status-im/status-go/waku/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var seed int64
|
||||||
|
|
||||||
|
// initSingleTest should be called in the beginning of every
|
||||||
|
// test, which uses RNG, in order to make the tests
|
||||||
|
// reproduciblity independent of their sequence.
|
||||||
|
func initSingleTest() {
|
||||||
|
seed = time.Now().Unix()
|
||||||
|
mrand.Seed(seed)
|
||||||
|
}
|
||||||
|
|
||||||
var sharedTopic = common.TopicType{0xF, 0x1, 0x2, 0}
|
var sharedTopic = common.TopicType{0xF, 0x1, 0x2, 0}
|
||||||
var wrongTopic = common.TopicType{0, 0, 0, 0}
|
var wrongTopic = common.TopicType{0, 0, 0, 0}
|
||||||
|
|
||||||
|
@ -58,3 +72,54 @@ func TestTopicOrBloomMatchFullNode(t *testing.T) {
|
||||||
t.Fatal("envelope should not match")
|
t.Fatal("envelope should not match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPeerBasic(t *testing.T) {
|
||||||
|
initSingleTest()
|
||||||
|
|
||||||
|
params, err := generateMessageParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed generateMessageParams with seed %d.", seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
params.PoW = 0.001
|
||||||
|
msg, err := common.NewSentMessage(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
|
||||||
|
}
|
||||||
|
env, err := msg.Wrap(params, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed Wrap with seed %d.", seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := NewPeer(nil, nil, nil, nil)
|
||||||
|
p.Mark(env)
|
||||||
|
if !p.Marked(env) {
|
||||||
|
t.Fatalf("failed mark with seed %d.", seed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateMessageParams() (*common.MessageParams, error) {
|
||||||
|
// set all the parameters except p.Dst and p.Padding
|
||||||
|
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
mrand.Read(buf) // nolint: gosec
|
||||||
|
sz := mrand.Intn(400)
|
||||||
|
|
||||||
|
var p common.MessageParams
|
||||||
|
p.PoW = 0.01
|
||||||
|
p.WorkTime = 1
|
||||||
|
p.TTL = uint32(mrand.Intn(1024))
|
||||||
|
p.Payload = make([]byte, sz)
|
||||||
|
p.KeySym = make([]byte, common.AESKeyLength)
|
||||||
|
mrand.Read(p.Payload) // nolint: gosec
|
||||||
|
mrand.Read(p.KeySym) // nolint: gosec
|
||||||
|
p.Topic = common.BytesToTopic(buf)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
p.Src, err = crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p, nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// statusOptionKey is a current type used in StatusOptions as a key.
|
// statusOptionKey is a current type used in StatusOptions as a key.
|
||||||
type statusOptionKey string
|
type statusOptionKey uint64
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultMinPoW = math.Float64bits(0.001)
|
defaultMinPoW = math.Float64bits(0.001)
|
||||||
|
@ -84,10 +85,14 @@ func initRLPKeyFields() {
|
||||||
if len(keys) != 2 || keys[0] != "key" {
|
if len(keys) != 2 || keys[0] != "key" {
|
||||||
panic("invalid value of \"rlp\" tag, expected \"key=N\" where N is uint")
|
panic("invalid value of \"rlp\" tag, expected \"key=N\" where N is uint")
|
||||||
}
|
}
|
||||||
|
key, err := strconv.ParseUint(keys[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic("could not parse \"rlp\" key")
|
||||||
|
}
|
||||||
|
|
||||||
// typecast key to be of statusOptionKey type
|
// typecast key to be of statusOptionKey type
|
||||||
keyFieldIdx[statusOptionKey(keys[1])] = i
|
keyFieldIdx[statusOptionKey(key)] = i
|
||||||
idxFieldKey[i] = statusOptionKey(keys[1])
|
idxFieldKey[i] = statusOptionKey(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,12 +189,12 @@ loop:
|
||||||
// Read the rest of the list items and dump peer.
|
// Read the rest of the list items and dump peer.
|
||||||
_, err := s.Raw()
|
_, err := s.Raw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read the value of key %s: %v", key, err)
|
return fmt.Errorf("failed to read the value of key %d: %v", key, err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := s.Decode(v.Elem().Field(idx).Addr().Interface()); err != nil {
|
if err := s.Decode(v.Elem().Field(idx).Addr().Interface()); err != nil {
|
||||||
return fmt.Errorf("failed to decode an option %s: %v", key, err)
|
return fmt.Errorf("failed to decode an option %d: %v", key, err)
|
||||||
}
|
}
|
||||||
if err := s.ListEnd(); err != nil {
|
if err := s.ListEnd(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -38,7 +38,7 @@ func TestEncodeDecodeRLP(t *testing.T) {
|
||||||
|
|
||||||
func TestBackwardCompatibility(t *testing.T) {
|
func TestBackwardCompatibility(t *testing.T) {
|
||||||
alist := []interface{}{
|
alist := []interface{}{
|
||||||
[]interface{}{"0", math.Float64bits(2.05)},
|
[]interface{}{uint64(0), math.Float64bits(2.05)},
|
||||||
}
|
}
|
||||||
data, err := rlp.EncodeToBytes(alist)
|
data, err := rlp.EncodeToBytes(alist)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -53,8 +53,8 @@ func TestBackwardCompatibility(t *testing.T) {
|
||||||
func TestForwardCompatibility(t *testing.T) {
|
func TestForwardCompatibility(t *testing.T) {
|
||||||
pow := math.Float64bits(2.05)
|
pow := math.Float64bits(2.05)
|
||||||
alist := []interface{}{
|
alist := []interface{}{
|
||||||
[]interface{}{"0", pow},
|
[]interface{}{uint64(0), pow},
|
||||||
[]interface{}{"99", uint(10)}, // some future option
|
[]interface{}{uint64(99), uint(10)}, // some future option
|
||||||
}
|
}
|
||||||
data, err := rlp.EncodeToBytes(alist)
|
data, err := rlp.EncodeToBytes(alist)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -67,20 +67,20 @@ func TestForwardCompatibility(t *testing.T) {
|
||||||
|
|
||||||
func TestInitRLPKeyFields(t *testing.T) {
|
func TestInitRLPKeyFields(t *testing.T) {
|
||||||
ifk := map[int]statusOptionKey{
|
ifk := map[int]statusOptionKey{
|
||||||
0: "0",
|
0: 0,
|
||||||
1: "1",
|
1: 1,
|
||||||
2: "2",
|
2: 2,
|
||||||
3: "3",
|
3: 3,
|
||||||
4: "4",
|
4: 4,
|
||||||
5: "5",
|
5: 5,
|
||||||
}
|
}
|
||||||
kfi := map[statusOptionKey]int{
|
kfi := map[statusOptionKey]int{
|
||||||
"0": 0,
|
0: 0,
|
||||||
"1": 1,
|
1: 1,
|
||||||
"2": 2,
|
2: 2,
|
||||||
"3": 3,
|
3: 3,
|
||||||
"4": 4,
|
4: 4,
|
||||||
"5": 5,
|
5: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that the kfi length matches the inited global keyFieldIdx length
|
// Test that the kfi length matches the inited global keyFieldIdx length
|
||||||
|
|
Loading…
Reference in New Issue