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() }