|
|
@@ -17,286 +17,131 @@
|
|
|
package les
|
|
|
|
|
|
import (
|
|
|
+ "crypto/rand"
|
|
|
"math/big"
|
|
|
- "net"
|
|
|
+ "reflect"
|
|
|
+ "sort"
|
|
|
"testing"
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
- "github.com/ethereum/go-ethereum/common/mclock"
|
|
|
- "github.com/ethereum/go-ethereum/core/rawdb"
|
|
|
- "github.com/ethereum/go-ethereum/crypto"
|
|
|
- "github.com/ethereum/go-ethereum/eth"
|
|
|
- "github.com/ethereum/go-ethereum/les/flowcontrol"
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
|
- "github.com/ethereum/go-ethereum/rlp"
|
|
|
)
|
|
|
|
|
|
-const protocolVersion = lpv2
|
|
|
-
|
|
|
-var (
|
|
|
- hash = common.HexToHash("deadbeef")
|
|
|
- genesis = common.HexToHash("cafebabe")
|
|
|
- headNum = uint64(1234)
|
|
|
- td = big.NewInt(123)
|
|
|
-)
|
|
|
-
|
|
|
-func newNodeID(t *testing.T) *enode.Node {
|
|
|
- key, err := crypto.GenerateKey()
|
|
|
- if err != nil {
|
|
|
- t.Fatal("generate key err:", err)
|
|
|
- }
|
|
|
- return enode.NewV4(&key.PublicKey, net.IP{}, 35000, 35000)
|
|
|
-}
|
|
|
-
|
|
|
-// ulc connects to trusted peer and send announceType=announceTypeSigned
|
|
|
-func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
-
|
|
|
- // peer to connect(on ulc side)
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- trusted: true,
|
|
|
- rw: &rwStub{
|
|
|
- WriteHook: func(recvList keyValueList) {
|
|
|
- recv, _ := recvList.decode()
|
|
|
- var reqType uint64
|
|
|
- err := recv.get("announceType", &reqType)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if reqType != announceTypeSigned {
|
|
|
- t.Fatal("Expected announceTypeSigned")
|
|
|
- }
|
|
|
- },
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("serveHeaders", nil)
|
|
|
- l = l.add("serveChainSince", uint64(0))
|
|
|
- l = l.add("serveStateSince", uint64(0))
|
|
|
- l = l.add("txRelay", nil)
|
|
|
- l = l.add("flowControl/BL", uint64(0))
|
|
|
- l = l.add("flowControl/MRR", uint64(0))
|
|
|
- l = l.add("flowControl/MRC", testCostList(0))
|
|
|
- return l
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- }
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, nil)
|
|
|
- if err != nil {
|
|
|
- t.Fatalf("Handshake error: %s", err)
|
|
|
- }
|
|
|
- if p.announceType != announceTypeSigned {
|
|
|
- t.Fatal("Incorrect announceType")
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- rw: &rwStub{
|
|
|
- WriteHook: func(recvList keyValueList) {
|
|
|
- // checking that ulc sends to peer allowedRequests=noRequests and announceType != announceTypeSigned
|
|
|
- recv, _ := recvList.decode()
|
|
|
- var reqType uint64
|
|
|
- err := recv.get("announceType", &reqType)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if reqType == announceTypeSigned {
|
|
|
- t.Fatal("Expected not announceTypeSigned")
|
|
|
- }
|
|
|
- },
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("serveHeaders", nil)
|
|
|
- l = l.add("serveChainSince", uint64(0))
|
|
|
- l = l.add("serveStateSince", uint64(0))
|
|
|
- l = l.add("txRelay", nil)
|
|
|
- l = l.add("flowControl/BL", uint64(0))
|
|
|
- l = l.add("flowControl/MRR", uint64(0))
|
|
|
- l = l.add("flowControl/MRC", testCostList(0))
|
|
|
- return l
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- }
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, nil)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if p.announceType == announceTypeSigned {
|
|
|
- t.Fatal("Incorrect announceType")
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func TestPeerHandshakeDefaultAllRequests(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
-
|
|
|
- s := generateLesServer()
|
|
|
-
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- rw: &rwStub{
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("announceType", uint64(announceTypeSigned))
|
|
|
- l = l.add("allowedRequests", uint64(0))
|
|
|
- return l
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- }
|
|
|
-
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, s)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
- if p.onlyAnnounce {
|
|
|
- t.Fatal("Incorrect announceType")
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
-
|
|
|
- s := generateLesServer()
|
|
|
- s.config.UltraLightOnlyAnnounce = true
|
|
|
-
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- rw: &rwStub{
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("announceType", uint64(announceTypeSigned))
|
|
|
- return l
|
|
|
- },
|
|
|
- WriteHook: func(l keyValueList) {
|
|
|
- for _, v := range l {
|
|
|
- if v.Key == "serveHeaders" ||
|
|
|
- v.Key == "serveChainSince" ||
|
|
|
- v.Key == "serveStateSince" ||
|
|
|
- v.Key == "txRelay" {
|
|
|
- t.Fatalf("%v exists", v.Key)
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- }
|
|
|
-
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, s)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-}
|
|
|
-func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
-
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- rw: &rwStub{
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("flowControl/BL", uint64(0))
|
|
|
- l = l.add("flowControl/MRR", uint64(0))
|
|
|
- l = l.add("flowControl/MRC", RequestCostList{})
|
|
|
-
|
|
|
- l = l.add("announceType", uint64(announceTypeSigned))
|
|
|
-
|
|
|
- return l
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- trusted: true,
|
|
|
- }
|
|
|
-
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, nil)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
- if !p.onlyAnnounce {
|
|
|
- t.Fatal("onlyAnnounce must be true")
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func TestPeerHandshakeClientReturnErrorOnUselessPeer(t *testing.T) {
|
|
|
- id := newNodeID(t).ID()
|
|
|
-
|
|
|
- p := peer{
|
|
|
- Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
|
|
|
- version: protocolVersion,
|
|
|
- rw: &rwStub{
|
|
|
- ReadHook: func(l keyValueList) keyValueList {
|
|
|
- l = l.add("flowControl/BL", uint64(0))
|
|
|
- l = l.add("flowControl/MRR", uint64(0))
|
|
|
- l = l.add("flowControl/MRC", RequestCostList{})
|
|
|
- l = l.add("announceType", uint64(announceTypeSigned))
|
|
|
- return l
|
|
|
- },
|
|
|
- },
|
|
|
- network: NetworkId,
|
|
|
- }
|
|
|
-
|
|
|
- err := p.Handshake(td, hash, headNum, genesis, nil)
|
|
|
- if err == nil {
|
|
|
- t.FailNow()
|
|
|
- }
|
|
|
+type testServerPeerSub struct {
|
|
|
+ regCh chan *serverPeer
|
|
|
+ unregCh chan *serverPeer
|
|
|
}
|
|
|
|
|
|
-func generateLesServer() *LesServer {
|
|
|
- s := &LesServer{
|
|
|
- lesCommons: lesCommons{
|
|
|
- config: ð.Config{UltraLightOnlyAnnounce: true},
|
|
|
- },
|
|
|
- defParams: flowcontrol.ServerParams{
|
|
|
- BufLimit: uint64(300000000),
|
|
|
- MinRecharge: uint64(50000),
|
|
|
- },
|
|
|
- fcManager: flowcontrol.NewClientManager(nil, &mclock.System{}),
|
|
|
+func newTestServerPeerSub() *testServerPeerSub {
|
|
|
+ return &testServerPeerSub{
|
|
|
+ regCh: make(chan *serverPeer, 1),
|
|
|
+ unregCh: make(chan *serverPeer, 1),
|
|
|
}
|
|
|
- s.costTracker, _ = newCostTracker(rawdb.NewMemoryDatabase(), s.config)
|
|
|
- return s
|
|
|
}
|
|
|
|
|
|
-type rwStub struct {
|
|
|
- ReadHook func(l keyValueList) keyValueList
|
|
|
- WriteHook func(l keyValueList)
|
|
|
+func (t *testServerPeerSub) registerPeer(p *serverPeer) { t.regCh <- p }
|
|
|
+func (t *testServerPeerSub) unregisterPeer(p *serverPeer) { t.unregCh <- p }
|
|
|
+
|
|
|
+func TestPeerSubscription(t *testing.T) {
|
|
|
+ peers := newServerPeerSet()
|
|
|
+ defer peers.close()
|
|
|
+
|
|
|
+ checkIds := func(expect []string) {
|
|
|
+ given := peers.ids()
|
|
|
+ if len(given) == 0 && len(expect) == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ sort.Strings(given)
|
|
|
+ sort.Strings(expect)
|
|
|
+ if !reflect.DeepEqual(given, expect) {
|
|
|
+ t.Fatalf("all peer ids mismatch, want %v, given %v", expect, given)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ checkPeers := func(peerCh chan *serverPeer) {
|
|
|
+ select {
|
|
|
+ case <-peerCh:
|
|
|
+ case <-time.NewTimer(100 * time.Millisecond).C:
|
|
|
+ t.Fatalf("timeout, no event received")
|
|
|
+ }
|
|
|
+ select {
|
|
|
+ case <-peerCh:
|
|
|
+ t.Fatalf("unexpected event received")
|
|
|
+ case <-time.NewTimer(10 * time.Millisecond).C:
|
|
|
+ }
|
|
|
+ }
|
|
|
+ checkIds([]string{})
|
|
|
+
|
|
|
+ sub := newTestServerPeerSub()
|
|
|
+ peers.subscribe(sub)
|
|
|
+
|
|
|
+ // Generate a random id and create the peer
|
|
|
+ var id enode.ID
|
|
|
+ rand.Read(id[:])
|
|
|
+ peer := newServerPeer(2, NetworkId, false, p2p.NewPeer(id, "name", nil), nil)
|
|
|
+ peers.register(peer)
|
|
|
+
|
|
|
+ checkIds([]string{peer.id})
|
|
|
+ checkPeers(sub.regCh)
|
|
|
+
|
|
|
+ peers.unregister(peer.id)
|
|
|
+ checkIds([]string{})
|
|
|
+ checkPeers(sub.unregCh)
|
|
|
}
|
|
|
|
|
|
-func (s *rwStub) ReadMsg() (p2p.Msg, error) {
|
|
|
- payload := keyValueList{}
|
|
|
- payload = payload.add("protocolVersion", uint64(protocolVersion))
|
|
|
- payload = payload.add("networkId", uint64(NetworkId))
|
|
|
- payload = payload.add("headTd", td)
|
|
|
- payload = payload.add("headHash", hash)
|
|
|
- payload = payload.add("headNum", headNum)
|
|
|
- payload = payload.add("genesisHash", genesis)
|
|
|
-
|
|
|
- if s.ReadHook != nil {
|
|
|
- payload = s.ReadHook(payload)
|
|
|
- }
|
|
|
- size, p, err := rlp.EncodeToReader(payload)
|
|
|
- if err != nil {
|
|
|
- return p2p.Msg{}, err
|
|
|
- }
|
|
|
- return p2p.Msg{
|
|
|
- Size: uint32(size),
|
|
|
- Payload: p,
|
|
|
- }, nil
|
|
|
-}
|
|
|
-
|
|
|
-func (s *rwStub) WriteMsg(m p2p.Msg) error {
|
|
|
- recvList := keyValueList{}
|
|
|
- if err := m.Decode(&recvList); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- if s.WriteHook != nil {
|
|
|
- s.WriteHook(recvList)
|
|
|
+func TestHandshake(t *testing.T) {
|
|
|
+ // Create a message pipe to communicate through
|
|
|
+ app, net := p2p.MsgPipe()
|
|
|
+
|
|
|
+ // Generate a random id and create the peer
|
|
|
+ var id enode.ID
|
|
|
+ rand.Read(id[:])
|
|
|
+
|
|
|
+ peer1 := newClientPeer(2, NetworkId, p2p.NewPeer(id, "name", nil), net)
|
|
|
+ peer2 := newServerPeer(2, NetworkId, true, p2p.NewPeer(id, "name", nil), app)
|
|
|
+
|
|
|
+ var (
|
|
|
+ errCh1 = make(chan error, 1)
|
|
|
+ errCh2 = make(chan error, 1)
|
|
|
+
|
|
|
+ td = big.NewInt(100)
|
|
|
+ head = common.HexToHash("deadbeef")
|
|
|
+ headNum = uint64(10)
|
|
|
+ genesis = common.HexToHash("cafebabe")
|
|
|
+ )
|
|
|
+ go func() {
|
|
|
+ errCh1 <- peer1.handshake(td, head, headNum, genesis, func(list *keyValueList) {
|
|
|
+ var announceType uint64 = announceTypeSigned
|
|
|
+ *list = (*list).add("announceType", announceType)
|
|
|
+ }, nil)
|
|
|
+ }()
|
|
|
+ go func() {
|
|
|
+ errCh2 <- peer2.handshake(td, head, headNum, genesis, nil, func(recv keyValueMap) error {
|
|
|
+ var reqType uint64
|
|
|
+ err := recv.get("announceType", &reqType)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if reqType != announceTypeSigned {
|
|
|
+ t.Fatal("Expected announceTypeSigned")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ }()
|
|
|
+
|
|
|
+ for i := 0; i < 2; i++ {
|
|
|
+ select {
|
|
|
+ case err := <-errCh1:
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("handshake failed, %v", err)
|
|
|
+ }
|
|
|
+ case err := <-errCh2:
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("handshake failed, %v", err)
|
|
|
+ }
|
|
|
+ case <-time.NewTimer(100 * time.Millisecond).C:
|
|
|
+ t.Fatalf("timeout")
|
|
|
+ }
|
|
|
}
|
|
|
- return nil
|
|
|
}
|