github.com/dotlike13/wemix30_go@v1.8.23/swarm/network/stream/intervals_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package stream
    18  
    19  import (
    20  	"context"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/log"
    29  	"github.com/ethereum/go-ethereum/node"
    30  	"github.com/ethereum/go-ethereum/p2p/enode"
    31  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    32  	"github.com/ethereum/go-ethereum/swarm/network/simulation"
    33  	"github.com/ethereum/go-ethereum/swarm/state"
    34  	"github.com/ethereum/go-ethereum/swarm/storage"
    35  	"github.com/ethereum/go-ethereum/swarm/testutil"
    36  )
    37  
    38  func TestIntervalsLive(t *testing.T) {
    39  	testIntervals(t, true, nil, false)
    40  	testIntervals(t, true, nil, true)
    41  }
    42  
    43  func TestIntervalsHistory(t *testing.T) {
    44  	testIntervals(t, false, NewRange(9, 26), false)
    45  	testIntervals(t, false, NewRange(9, 26), true)
    46  }
    47  
    48  func TestIntervalsLiveAndHistory(t *testing.T) {
    49  	testIntervals(t, true, NewRange(9, 26), false)
    50  	testIntervals(t, true, NewRange(9, 26), true)
    51  }
    52  
    53  func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) {
    54  
    55  	nodes := 2
    56  	chunkCount := dataChunkCount
    57  	externalStreamName := "externalStream"
    58  	externalStreamSessionAt := uint64(50)
    59  	externalStreamMaxKeys := uint64(100)
    60  
    61  	sim := simulation.New(map[string]simulation.ServiceFunc{
    62  		"intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) {
    63  			addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket)
    64  			if err != nil {
    65  				return nil, nil, err
    66  			}
    67  
    68  			r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{
    69  				Retrieval: RetrievalDisabled,
    70  				Syncing:   SyncingRegisterOnly,
    71  				SkipCheck: skipCheck,
    72  			}, nil)
    73  			bucket.Store(bucketKeyRegistry, r)
    74  
    75  			r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) {
    76  				return newTestExternalClient(netStore), nil
    77  			})
    78  			r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) {
    79  				return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil
    80  			})
    81  
    82  			cleanup := func() {
    83  				r.Close()
    84  				clean()
    85  			}
    86  
    87  			return r, cleanup, nil
    88  		},
    89  	})
    90  	defer sim.Close()
    91  
    92  	log.Info("Adding nodes to simulation")
    93  	_, err := sim.AddNodesAndConnectChain(nodes)
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
    99  	defer cancel()
   100  
   101  	if _, err := sim.WaitTillHealthy(ctx); err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) {
   106  		nodeIDs := sim.UpNodeIDs()
   107  		storer := nodeIDs[0]
   108  		checker := nodeIDs[1]
   109  
   110  		item, ok := sim.NodeItem(storer, bucketKeyFileStore)
   111  		if !ok {
   112  			return fmt.Errorf("No filestore")
   113  		}
   114  		fileStore := item.(*storage.FileStore)
   115  
   116  		size := chunkCount * chunkSize
   117  
   118  		_, wait, err := fileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false)
   119  		if err != nil {
   120  			return fmt.Errorf("store: %v", err)
   121  		}
   122  		err = wait(ctx)
   123  		if err != nil {
   124  			return fmt.Errorf("wait store: %v", err)
   125  		}
   126  
   127  		item, ok = sim.NodeItem(checker, bucketKeyRegistry)
   128  		if !ok {
   129  			return fmt.Errorf("No registry")
   130  		}
   131  		registry := item.(*Registry)
   132  
   133  		liveErrC := make(chan error)
   134  		historyErrC := make(chan error)
   135  
   136  		err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top)
   137  		if err != nil {
   138  			return err
   139  		}
   140  
   141  		disconnected := watchDisconnections(ctx, sim)
   142  		defer func() {
   143  			if err != nil && disconnected.bool() {
   144  				err = errors.New("disconnect events received")
   145  			}
   146  		}()
   147  
   148  		go func() {
   149  			if !live {
   150  				close(liveErrC)
   151  				return
   152  			}
   153  
   154  			var err error
   155  			defer func() {
   156  				liveErrC <- err
   157  			}()
   158  
   159  			// live stream
   160  			var liveHashesChan chan []byte
   161  			liveHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", true))
   162  			if err != nil {
   163  				log.Error("get hashes", "err", err)
   164  				return
   165  			}
   166  			i := externalStreamSessionAt
   167  
   168  			// we have subscribed, enable notifications
   169  			err = enableNotifications(registry, storer, NewStream(externalStreamName, "", true))
   170  			if err != nil {
   171  				return
   172  			}
   173  
   174  			for {
   175  				select {
   176  				case hash := <-liveHashesChan:
   177  					h := binary.BigEndian.Uint64(hash)
   178  					if h != i {
   179  						err = fmt.Errorf("expected live hash %d, got %d", i, h)
   180  						return
   181  					}
   182  					i++
   183  					if i > externalStreamMaxKeys {
   184  						return
   185  					}
   186  				case <-ctx.Done():
   187  					return
   188  				}
   189  			}
   190  		}()
   191  
   192  		go func() {
   193  			if live && history == nil {
   194  				close(historyErrC)
   195  				return
   196  			}
   197  
   198  			var err error
   199  			defer func() {
   200  				historyErrC <- err
   201  			}()
   202  
   203  			// history stream
   204  			var historyHashesChan chan []byte
   205  			historyHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", false))
   206  			if err != nil {
   207  				log.Error("get hashes", "err", err)
   208  				return
   209  			}
   210  
   211  			var i uint64
   212  			historyTo := externalStreamMaxKeys
   213  			if history != nil {
   214  				i = history.From
   215  				if history.To != 0 {
   216  					historyTo = history.To
   217  				}
   218  			}
   219  
   220  			// we have subscribed, enable notifications
   221  			err = enableNotifications(registry, storer, NewStream(externalStreamName, "", false))
   222  			if err != nil {
   223  				return
   224  			}
   225  
   226  			for {
   227  				select {
   228  				case hash := <-historyHashesChan:
   229  					h := binary.BigEndian.Uint64(hash)
   230  					if h != i {
   231  						err = fmt.Errorf("expected history hash %d, got %d", i, h)
   232  						return
   233  					}
   234  					i++
   235  					if i > historyTo {
   236  						return
   237  					}
   238  				case <-ctx.Done():
   239  					return
   240  				}
   241  			}
   242  		}()
   243  
   244  		if err := <-liveErrC; err != nil {
   245  			return err
   246  		}
   247  		if err := <-historyErrC; err != nil {
   248  			return err
   249  		}
   250  
   251  		return nil
   252  	})
   253  
   254  	if result.Error != nil {
   255  		t.Fatal(result.Error)
   256  	}
   257  }
   258  
   259  func getHashes(ctx context.Context, r *Registry, peerID enode.ID, s Stream) (chan []byte, error) {
   260  	peer := r.getPeer(peerID)
   261  
   262  	client, err := peer.getClient(ctx, s)
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  
   267  	c := client.Client.(*testExternalClient)
   268  
   269  	return c.hashes, nil
   270  }
   271  
   272  func enableNotifications(r *Registry, peerID enode.ID, s Stream) error {
   273  	peer := r.getPeer(peerID)
   274  
   275  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   276  	defer cancel()
   277  
   278  	client, err := peer.getClient(ctx, s)
   279  	if err != nil {
   280  		return err
   281  	}
   282  
   283  	close(client.Client.(*testExternalClient).enableNotificationsC)
   284  
   285  	return nil
   286  }
   287  
   288  type testExternalClient struct {
   289  	hashes               chan []byte
   290  	store                storage.SyncChunkStore
   291  	enableNotificationsC chan struct{}
   292  }
   293  
   294  func newTestExternalClient(store storage.SyncChunkStore) *testExternalClient {
   295  	return &testExternalClient{
   296  		hashes:               make(chan []byte),
   297  		store:                store,
   298  		enableNotificationsC: make(chan struct{}),
   299  	}
   300  }
   301  
   302  func (c *testExternalClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error {
   303  	wait := c.store.FetchFunc(ctx, storage.Address(hash))
   304  	if wait == nil {
   305  		return nil
   306  	}
   307  	select {
   308  	case c.hashes <- hash:
   309  	case <-ctx.Done():
   310  		log.Warn("testExternalClient NeedData context", "err", ctx.Err())
   311  		return func(_ context.Context) error {
   312  			return ctx.Err()
   313  		}
   314  	}
   315  	return wait
   316  }
   317  
   318  func (c *testExternalClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) {
   319  	return nil
   320  }
   321  
   322  func (c *testExternalClient) Close() {}
   323  
   324  type testExternalServer struct {
   325  	t         string
   326  	keyFunc   func(key []byte, index uint64)
   327  	sessionAt uint64
   328  	maxKeys   uint64
   329  }
   330  
   331  func newTestExternalServer(t string, sessionAt, maxKeys uint64, keyFunc func(key []byte, index uint64)) *testExternalServer {
   332  	if keyFunc == nil {
   333  		keyFunc = binary.BigEndian.PutUint64
   334  	}
   335  	return &testExternalServer{
   336  		t:         t,
   337  		keyFunc:   keyFunc,
   338  		sessionAt: sessionAt,
   339  		maxKeys:   maxKeys,
   340  	}
   341  }
   342  
   343  func (s *testExternalServer) SessionIndex() (uint64, error) {
   344  	return s.sessionAt, nil
   345  }
   346  
   347  func (s *testExternalServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) {
   348  	if to > s.maxKeys {
   349  		to = s.maxKeys
   350  	}
   351  	b := make([]byte, HashSize*(to-from+1))
   352  	for i := from; i <= to; i++ {
   353  		s.keyFunc(b[(i-from)*HashSize:(i-from+1)*HashSize], i)
   354  	}
   355  	return b, from, to, nil, nil
   356  }
   357  
   358  func (s *testExternalServer) GetData(context.Context, []byte) ([]byte, error) {
   359  	return make([]byte, 4096), nil
   360  }
   361  
   362  func (s *testExternalServer) Close() {}