downloader_test.go 7.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package downloader

import (
	"encoding/binary"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
)

var knownHash = common.Hash{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

15
func createHashes(start, amount int) (hashes []common.Hash) {
16 17 18 19 20 21 22 23 24 25
	hashes = make([]common.Hash, amount+1)
	hashes[len(hashes)-1] = knownHash

	for i := range hashes[:len(hashes)-1] {
		binary.BigEndian.PutUint64(hashes[i][:8], uint64(i+2))
	}

	return
}

26 27 28 29 30 31 32 33
func createBlock(i int, prevHash, hash common.Hash) *types.Block {
	header := &types.Header{Number: big.NewInt(int64(i))}
	block := types.NewBlockWithHeader(header)
	block.HeaderHash = hash
	block.ParentHeaderHash = knownHash
	return block
}

34 35
func createBlocksFromHashes(hashes []common.Hash) map[common.Hash]*types.Block {
	blocks := make(map[common.Hash]*types.Block)
36

37
	for i, hash := range hashes {
38
		blocks[hash] = createBlock(len(hashes)-i, knownHash, hash)
39 40 41 42 43 44
	}

	return blocks
}

type downloadTester struct {
O
obscuren 已提交
45 46 47 48 49 50 51
	downloader   *Downloader
	hashes       []common.Hash
	blocks       map[common.Hash]*types.Block
	t            *testing.T
	pcount       int
	done         chan bool
	activePeerId string
52 53 54 55
}

func newTester(t *testing.T, hashes []common.Hash, blocks map[common.Hash]*types.Block) *downloadTester {
	tester := &downloadTester{t: t, hashes: hashes, blocks: blocks, done: make(chan bool)}
56
	downloader := New(tester.hasBlock, tester.getBlock)
57 58 59 60 61
	tester.downloader = downloader

	return tester
}

O
obscuren 已提交
62 63
func (dl *downloadTester) sync(peerId string, hash common.Hash) error {
	dl.activePeerId = peerId
64
	return dl.downloader.Synchronise(peerId, hash)
O
obscuren 已提交
65 66
}

67 68 69 70 71 72 73
func (dl *downloadTester) hasBlock(hash common.Hash) bool {
	if knownHash == hash {
		return true
	}
	return false
}

74 75
func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
	return dl.blocks[knownHash]
76 77 78
}

func (dl *downloadTester) getHashes(hash common.Hash) error {
79
	dl.downloader.DeliverHashes(dl.activePeerId, dl.hashes)
80 81 82 83 84 85 86 87 88 89
	return nil
}

func (dl *downloadTester) getBlocks(id string) func([]common.Hash) error {
	return func(hashes []common.Hash) error {
		blocks := make([]*types.Block, len(hashes))
		for i, hash := range hashes {
			blocks[i] = dl.blocks[hash]
		}

90
		go dl.downloader.DeliverBlocks(id, blocks)
91 92 93 94 95 96 97 98

		return nil
	}
}

func (dl *downloadTester) newPeer(id string, td *big.Int, hash common.Hash) {
	dl.pcount++

O
obscuren 已提交
99
	dl.downloader.RegisterPeer(id, hash, dl.getHashes, dl.getBlocks(id))
100 101 102 103 104 105
}

func (dl *downloadTester) badBlocksPeer(id string, td *big.Int, hash common.Hash) {
	dl.pcount++

	// This bad peer never returns any blocks
O
obscuren 已提交
106
	dl.downloader.RegisterPeer(id, hash, dl.getHashes, func([]common.Hash) error {
107 108 109 110 111
		return nil
	})
}

func TestDownload(t *testing.T) {
112
	minDesiredPeerCount = 4
O
obscuren 已提交
113
	blockTtl = 1 * time.Second
114

115 116
	targetBlocks := 1000
	hashes := createHashes(0, targetBlocks)
117 118 119
	blocks := createBlocksFromHashes(hashes)
	tester := newTester(t, hashes, blocks)

120
	tester.newPeer("peer1", big.NewInt(10000), hashes[0])
121 122 123
	tester.newPeer("peer2", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer3", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer4", big.NewInt(0), common.Hash{})
O
obscuren 已提交
124
	tester.activePeerId = "peer1"
125

O
obscuren 已提交
126
	err := tester.sync("peer1", hashes[0])
127 128 129 130
	if err != nil {
		t.Error("download error", err)
	}

131
	inqueue := len(tester.downloader.queue.blockCache)
132 133
	if inqueue != targetBlocks {
		t.Error("expected", targetBlocks, "have", inqueue)
134 135
	}
}
136 137

func TestMissing(t *testing.T) {
138
	targetBlocks := 1000
139 140 141 142 143 144 145 146 147 148
	hashes := createHashes(0, 1000)
	extraHashes := createHashes(1001, 1003)
	blocks := createBlocksFromHashes(append(extraHashes, hashes...))
	tester := newTester(t, hashes, blocks)

	tester.newPeer("peer1", big.NewInt(10000), hashes[len(hashes)-1])

	hashes = append(extraHashes, hashes[:len(hashes)-1]...)
	tester.newPeer("peer2", big.NewInt(0), common.Hash{})

O
obscuren 已提交
149
	err := tester.sync("peer1", hashes[0])
150 151
	if err != nil {
		t.Error("download error", err)
152 153
	}

154
	inqueue := len(tester.downloader.queue.blockCache)
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	if inqueue != targetBlocks {
		t.Error("expected", targetBlocks, "have", inqueue)
	}
}

func TestTaking(t *testing.T) {
	minDesiredPeerCount = 4
	blockTtl = 1 * time.Second

	targetBlocks := 1000
	hashes := createHashes(0, targetBlocks)
	blocks := createBlocksFromHashes(hashes)
	tester := newTester(t, hashes, blocks)

	tester.newPeer("peer1", big.NewInt(10000), hashes[0])
	tester.newPeer("peer2", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer3", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer4", big.NewInt(0), common.Hash{})

O
obscuren 已提交
174
	err := tester.sync("peer1", hashes[0])
175 176 177 178
	if err != nil {
		t.Error("download error", err)
	}

179
	bs1 := tester.downloader.TakeBlocks()
180 181
	if len(bs1) != 1000 {
		t.Error("expected to take 1000, got", len(bs1))
182
	}
183
}
184

185 186 187 188 189 190
func TestInactiveDownloader(t *testing.T) {
	targetBlocks := 1000
	hashes := createHashes(0, targetBlocks)
	blocks := createBlocksFromHashSet(createHashSet(hashes))
	tester := newTester(t, hashes, nil)

191
	err := tester.downloader.DeliverHashes("bad peer 001", hashes)
192 193 194 195
	if err != errNoSyncActive {
		t.Error("expected no sync error, got", err)
	}

196
	err = tester.downloader.DeliverBlocks("bad peer 001", blocks)
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	if err != errNoSyncActive {
		t.Error("expected no sync error, got", err)
	}
}

func TestCancel(t *testing.T) {
	minDesiredPeerCount = 4
	blockTtl = 1 * time.Second

	targetBlocks := 1000
	hashes := createHashes(0, targetBlocks)
	blocks := createBlocksFromHashes(hashes)
	tester := newTester(t, hashes, blocks)

	tester.newPeer("peer1", big.NewInt(10000), hashes[0])

	err := tester.sync("peer1", hashes[0])
	if err != nil {
		t.Error("download error", err)
	}

	if !tester.downloader.Cancel() {
		t.Error("cancel operation unsuccessfull")
	}

	hashSize, blockSize := tester.downloader.queue.Size()
	if hashSize > 0 || blockSize > 0 {
		t.Error("block (", blockSize, ") or hash (", hashSize, ") not 0")
	}
}

228 229 230 231
func TestThrottling(t *testing.T) {
	minDesiredPeerCount = 4
	blockTtl = 1 * time.Second

232
	targetBlocks := 16 * blockCacheLimit
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
	hashes := createHashes(0, targetBlocks)
	blocks := createBlocksFromHashes(hashes)
	tester := newTester(t, hashes, blocks)

	tester.newPeer("peer1", big.NewInt(10000), hashes[0])
	tester.newPeer("peer2", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer3", big.NewInt(0), common.Hash{})
	tester.badBlocksPeer("peer4", big.NewInt(0), common.Hash{})

	// Concurrently download and take the blocks
	errc := make(chan error, 1)
	go func() {
		errc <- tester.sync("peer1", hashes[0])
	}()

	done := make(chan struct{})
	took := []*types.Block{}
	go func() {
		for {
			select {
			case <-done:
				took = append(took, tester.downloader.TakeBlocks()...)
				done <- struct{}{}
				return
			default:
				took = append(took, tester.downloader.TakeBlocks()...)
259
				time.Sleep(time.Millisecond)
260 261 262 263
			}
		}
	}()

264
	// Synchronise the two threads and verify
265 266 267 268 269
	err := <-errc
	done <- struct{}{}
	<-done

	if err != nil {
270
		t.Fatalf("failed to synchronise blocks: %v", err)
271 272 273 274 275
	}
	if len(took) != targetBlocks {
		t.Fatalf("downloaded block mismatch: have %v, want %v", len(took), targetBlocks)
	}
}