199 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package eth
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"log"
 | |
| 	"os"
 | |
| 	"sync"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/ethereum/go-ethereum/core/types"
 | |
| 	"github.com/ethereum/go-ethereum/crypto"
 | |
| 	"github.com/ethereum/go-ethereum/ethutil"
 | |
| 	ethlogger "github.com/ethereum/go-ethereum/logger"
 | |
| )
 | |
| 
 | |
| var sys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
 | |
| 
 | |
| type testChainManager struct {
 | |
| 	knownBlock func(hash []byte) bool
 | |
| 	addBlock   func(*types.Block) error
 | |
| 	checkPoW   func(*types.Block) bool
 | |
| }
 | |
| 
 | |
| func (self *testChainManager) KnownBlock(hash []byte) bool {
 | |
| 	if self.knownBlock != nil {
 | |
| 		return self.knownBlock(hash)
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (self *testChainManager) AddBlock(block *types.Block) error {
 | |
| 	if self.addBlock != nil {
 | |
| 		return self.addBlock(block)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *testChainManager) CheckPoW(block *types.Block) bool {
 | |
| 	if self.checkPoW != nil {
 | |
| 		return self.checkPoW(block)
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func knownBlock(hashes ...[]byte) (f func([]byte) bool) {
 | |
| 	f = func(block []byte) bool {
 | |
| 		for _, hash := range hashes {
 | |
| 			if bytes.Compare(block, hash) == 0 {
 | |
| 				return true
 | |
| 			}
 | |
| 		}
 | |
| 		return false
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func addBlock(hashes ...[]byte) (f func(*types.Block) error) {
 | |
| 	f = func(block *types.Block) error {
 | |
| 		for _, hash := range hashes {
 | |
| 			if bytes.Compare(block.Hash(), hash) == 0 {
 | |
| 				return fmt.Errorf("invalid by test")
 | |
| 			}
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func checkPoW(hashes ...[]byte) (f func(*types.Block) bool) {
 | |
| 	f = func(block *types.Block) bool {
 | |
| 		for _, hash := range hashes {
 | |
| 			if bytes.Compare(block.Hash(), hash) == 0 {
 | |
| 				return false
 | |
| 			}
 | |
| 		}
 | |
| 		return true
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func newTestChainManager(knownBlocks [][]byte, invalidBlocks [][]byte, invalidPoW [][]byte) *testChainManager {
 | |
| 	return &testChainManager{
 | |
| 		knownBlock: knownBlock(knownBlocks...),
 | |
| 		addBlock:   addBlock(invalidBlocks...),
 | |
| 		checkPoW:   checkPoW(invalidPoW...),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type intToHash map[int][]byte
 | |
| 
 | |
| type hashToInt map[string]int
 | |
| 
 | |
| type testHashPool struct {
 | |
| 	intToHash
 | |
| 	hashToInt
 | |
| }
 | |
| 
 | |
| func newHash(i int) []byte {
 | |
| 	return crypto.Sha3([]byte(string(i)))
 | |
| }
 | |
| 
 | |
| func newTestBlockPool(knownBlockIndexes []int, invalidBlockIndexes []int, invalidPoWIndexes []int) (hashPool *testHashPool, blockPool *BlockPool) {
 | |
| 	hashPool = &testHashPool{make(intToHash), make(hashToInt)}
 | |
| 	knownBlocks := hashPool.indexesToHashes(knownBlockIndexes)
 | |
| 	invalidBlocks := hashPool.indexesToHashes(invalidBlockIndexes)
 | |
| 	invalidPoW := hashPool.indexesToHashes(invalidPoWIndexes)
 | |
| 	blockPool = NewBlockPool(newTestChainManager(knownBlocks, invalidBlocks, invalidPoW))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (self *testHashPool) indexesToHashes(indexes []int) (hashes [][]byte) {
 | |
| 	for _, i := range indexes {
 | |
| 		hash, found := self.intToHash[i]
 | |
| 		if !found {
 | |
| 			hash = newHash(i)
 | |
| 			self.intToHash[i] = hash
 | |
| 			self.hashToInt[string(hash)] = i
 | |
| 		}
 | |
| 		hashes = append(hashes, hash)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (self *testHashPool) hashesToIndexes(hashes [][]byte) (indexes []int) {
 | |
| 	for _, hash := range hashes {
 | |
| 		i, found := self.hashToInt[string(hash)]
 | |
| 		if !found {
 | |
| 			i = -1
 | |
| 		}
 | |
| 		indexes = append(indexes, i)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| type protocolChecker struct {
 | |
| 	blockHashesRequests []int
 | |
| 	blocksRequests      [][]int
 | |
| 	invalidBlocks       []error
 | |
| 	hashPool            *testHashPool
 | |
| 	lock                sync.Mutex
 | |
| }
 | |
| 
 | |
| // -1 is special: not found (a hash never seen)
 | |
| func (self *protocolChecker) requestBlockHashesCallBack() (requestBlockHashesCallBack func([]byte) error) {
 | |
| 	requestBlockHashesCallBack = func(hash []byte) error {
 | |
| 		indexes := self.hashPool.hashesToIndexes([][]byte{hash})
 | |
| 		self.lock.Lock()
 | |
| 		defer self.lock.Unlock()
 | |
| 		self.blockHashesRequests = append(self.blockHashesRequests, indexes[0])
 | |
| 		return nil
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (self *protocolChecker) requestBlocksCallBack() (requestBlocksCallBack func([][]byte) error) {
 | |
| 	requestBlocksCallBack = func(hashes [][]byte) error {
 | |
| 		indexes := self.hashPool.hashesToIndexes(hashes)
 | |
| 		self.lock.Lock()
 | |
| 		defer self.lock.Unlock()
 | |
| 		self.blocksRequests = append(self.blocksRequests, indexes)
 | |
| 		return nil
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (self *protocolChecker) invalidBlockCallBack() (invalidBlockCallBack func(error)) {
 | |
| 	invalidBlockCallBack = func(err error) {
 | |
| 		self.invalidBlocks = append(self.invalidBlocks, err)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func TestAddPeer(t *testing.T) {
 | |
| 	ethlogger.AddLogSystem(sys)
 | |
| 	knownBlockIndexes := []int{0, 1}
 | |
| 	invalidBlockIndexes := []int{2, 3}
 | |
| 	invalidPoWIndexes := []int{4, 5}
 | |
| 	hashPool, blockPool := newTestBlockPool(knownBlockIndexes, invalidBlockIndexes, invalidPoWIndexes)
 | |
| 	// TODO:
 | |
| 	// hashPool, blockPool, blockChainChecker = newTestBlockPool(knownBlockIndexes, invalidBlockIndexes, invalidPoWIndexes)
 | |
| 	peer0 := &protocolChecker{
 | |
| 		// blockHashesRequests: make([]int),
 | |
| 		// blocksRequests:      make([][]int),
 | |
| 		// invalidBlocks:       make([]error),
 | |
| 		hashPool: hashPool,
 | |
| 	}
 | |
| 	best := blockPool.AddPeer(ethutil.Big1, newHash(100), "0",
 | |
| 		peer0.requestBlockHashesCallBack(),
 | |
| 		peer0.requestBlocksCallBack(),
 | |
| 		peer0.invalidBlockCallBack(),
 | |
| 	)
 | |
| 	if !best {
 | |
| 		t.Errorf("peer not accepted as best")
 | |
| 	}
 | |
| 	blockPool.Stop()
 | |
| 
 | |
| }
 |