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