peer suspension to disallow reconnect after disconnect on fatal error for set period (PeerSuspensionInterval)
This commit is contained in:
parent
01ff0b3176
commit
50661f0e68
@ -33,7 +33,8 @@ var (
|
|||||||
// timeout interval: max time allowed for peer without sending a block
|
// timeout interval: max time allowed for peer without sending a block
|
||||||
blocksTimeout = 60 * time.Second
|
blocksTimeout = 60 * time.Second
|
||||||
//
|
//
|
||||||
idleBestPeerTimeout = 120 * time.Second
|
idleBestPeerTimeout = 120 * time.Second
|
||||||
|
peerSuspensionInterval = 300 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// config embedded in components, by default fall back to constants
|
// config embedded in components, by default fall back to constants
|
||||||
@ -48,6 +49,7 @@ type Config struct {
|
|||||||
BlockHashesTimeout time.Duration
|
BlockHashesTimeout time.Duration
|
||||||
BlocksTimeout time.Duration
|
BlocksTimeout time.Duration
|
||||||
IdleBestPeerTimeout time.Duration
|
IdleBestPeerTimeout time.Duration
|
||||||
|
PeerSuspensionInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockpool errors
|
// blockpool errors
|
||||||
@ -96,6 +98,9 @@ func (self *Config) init() {
|
|||||||
if self.IdleBestPeerTimeout == 0 {
|
if self.IdleBestPeerTimeout == 0 {
|
||||||
self.IdleBestPeerTimeout = idleBestPeerTimeout
|
self.IdleBestPeerTimeout = idleBestPeerTimeout
|
||||||
}
|
}
|
||||||
|
if self.PeerSuspensionInterval == 0 {
|
||||||
|
self.PeerSuspensionInterval = peerSuspensionInterval
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// node is the basic unit of the internal model of block chain/tree in the blockpool
|
// node is the basic unit of the internal model of block chain/tree in the blockpool
|
||||||
@ -188,9 +193,10 @@ func (self *BlockPool) Start() {
|
|||||||
Errors: errorToString,
|
Errors: errorToString,
|
||||||
Level: severity,
|
Level: severity,
|
||||||
},
|
},
|
||||||
peers: make(map[string]*peer),
|
peers: make(map[string]*peer),
|
||||||
status: self.status,
|
blacklist: make(map[string]time.Time),
|
||||||
bp: self,
|
status: self.status,
|
||||||
|
bp: self,
|
||||||
}
|
}
|
||||||
timer := time.NewTicker(3 * time.Second)
|
timer := time.NewTicker(3 * time.Second)
|
||||||
go func() {
|
go func() {
|
||||||
@ -267,7 +273,8 @@ func (self *BlockPool) AddPeer(
|
|||||||
requestBlocks func([]common.Hash) error,
|
requestBlocks func([]common.Hash) error,
|
||||||
peerError func(*errs.Error),
|
peerError func(*errs.Error),
|
||||||
|
|
||||||
) (best bool) {
|
) (best bool, suspended bool) {
|
||||||
|
|
||||||
return self.peers.addPeer(td, currentBlockHash, peerId, requestBlockHashes, requestBlocks, peerError)
|
return self.peers.addPeer(td, currentBlockHash, peerId, requestBlockHashes, requestBlocks, peerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/blockpool/test"
|
"github.com/ethereum/go-ethereum/blockpool/test"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPeerWithKnownBlock(t *testing.T) {
|
func TestPeerWithKnownBlock(t *testing.T) {
|
||||||
@ -69,8 +69,8 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) {
|
|||||||
hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3})
|
hashes := blockPoolTester.hashPool.IndexesToHashes([]int{2, 3})
|
||||||
peer1.waitBlocksRequests(3)
|
peer1.waitBlocksRequests(3)
|
||||||
blockPool.AddBlock(&types.Block{
|
blockPool.AddBlock(&types.Block{
|
||||||
HeaderHash: common.Bytes(hashes[1]),
|
HeaderHash: common.Hash(hashes[1]),
|
||||||
ParentHeaderHash: common.Bytes(hashes[0]),
|
ParentHeaderHash: common.Hash(hashes[0]),
|
||||||
Td: common.Big3,
|
Td: common.Big3,
|
||||||
}, "peer1")
|
}, "peer1")
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/blockpool/test"
|
"github.com/ethereum/go-ethereum/blockpool/test"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/errs"
|
"github.com/ethereum/go-ethereum/errs"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,10 +63,10 @@ func (self *blockPoolTester) Errorf(format string, params ...interface{}) {
|
|||||||
|
|
||||||
// blockPoolTester implements the 3 callbacks needed by the blockPool:
|
// blockPoolTester implements the 3 callbacks needed by the blockPool:
|
||||||
// hasBlock, insetChain, verifyPoW
|
// hasBlock, insetChain, verifyPoW
|
||||||
func (self *blockPoolTester) hasBlock(block []byte) (ok bool) {
|
func (self *blockPoolTester) hasBlock(block common.Hash) (ok bool) {
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
defer self.lock.RUnlock()
|
defer self.lock.RUnlock()
|
||||||
indexes := self.hashPool.HashesToIndexes([][]byte{block})
|
indexes := self.hashPool.HashesToIndexes([]common.Hash{block})
|
||||||
i := indexes[0]
|
i := indexes[0]
|
||||||
_, ok = self.blockChain[i]
|
_, ok = self.blockChain[i]
|
||||||
fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok)
|
fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok)
|
||||||
@ -80,13 +80,13 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error {
|
|||||||
var children, refChildren []int
|
var children, refChildren []int
|
||||||
var ok bool
|
var ok bool
|
||||||
for _, block := range blocks {
|
for _, block := range blocks {
|
||||||
child = self.hashPool.HashesToIndexes([][]byte{block.Hash()})[0]
|
child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0]
|
||||||
_, ok = self.blockChain[child]
|
_, ok = self.blockChain[child]
|
||||||
if ok {
|
if ok {
|
||||||
fmt.Printf("block %v already in blockchain\n", child)
|
fmt.Printf("block %v already in blockchain\n", child)
|
||||||
continue // already in chain
|
continue // already in chain
|
||||||
}
|
}
|
||||||
parent = self.hashPool.HashesToIndexes([][]byte{block.ParentHeaderHash})[0]
|
parent = self.hashPool.HashesToIndexes([]common.Hash{block.ParentHeaderHash})[0]
|
||||||
children, ok = self.blockChain[parent]
|
children, ok = self.blockChain[parent]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("parent %v not in blockchain ", parent)
|
return fmt.Errorf("parent %v not in blockchain ", parent)
|
||||||
@ -274,9 +274,10 @@ func (self *blockPoolTester) initRefBlockChain(n int) {
|
|||||||
|
|
||||||
// peerTester functions that mimic protocol calls to the blockpool
|
// peerTester functions that mimic protocol calls to the blockpool
|
||||||
// registers the peer with the blockPool
|
// registers the peer with the blockPool
|
||||||
func (self *peerTester) AddPeer() bool {
|
func (self *peerTester) AddPeer() (best bool) {
|
||||||
hash := self.hashPool.IndexesToHashes([]int{self.currentBlock})[0]
|
hash := self.hashPool.IndexesToHashes([]int{self.currentBlock})[0]
|
||||||
return self.blockPool.AddPeer(big.NewInt(int64(self.td)), hash, self.id, self.requestBlockHashes, self.requestBlocks, self.peerError)
|
best, _ = self.blockPool.AddPeer(big.NewInt(int64(self.td)), hash, self.id, self.requestBlockHashes, self.requestBlocks, self.peerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// peer sends blockhashes if and when gets a request
|
// peer sends blockhashes if and when gets a request
|
||||||
@ -291,7 +292,7 @@ func (self *peerTester) sendBlockHashes(indexes ...int) {
|
|||||||
fmt.Printf("adding block hashes %v\n", indexes)
|
fmt.Printf("adding block hashes %v\n", indexes)
|
||||||
hashes := self.hashPool.IndexesToHashes(indexes)
|
hashes := self.hashPool.IndexesToHashes(indexes)
|
||||||
i := 1
|
i := 1
|
||||||
next := func() (hash []byte, ok bool) {
|
next := func() (hash common.Hash, ok bool) {
|
||||||
if i < len(hashes) {
|
if i < len(hashes) {
|
||||||
hash = hashes[i]
|
hash = hashes[i]
|
||||||
ok = true
|
ok = true
|
||||||
@ -315,15 +316,15 @@ func (self *peerTester) sendBlocks(indexes ...int) {
|
|||||||
hashes := self.hashPool.IndexesToHashes(indexes)
|
hashes := self.hashPool.IndexesToHashes(indexes)
|
||||||
for i := 1; i < len(hashes); i++ {
|
for i := 1; i < len(hashes); i++ {
|
||||||
fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4])
|
fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4])
|
||||||
self.blockPool.AddBlock(&types.Block{HeaderHash: common.Bytes(hashes[i]), ParentHeaderHash: common.Bytes(hashes[i-1])}, self.id)
|
self.blockPool.AddBlock(&types.Block{HeaderHash: hashes[i], ParentHeaderHash: hashes[i-1]}, self.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// peer callbacks
|
// peer callbacks
|
||||||
// -1 is special: not found (a hash never seen)
|
// -1 is special: not found (a hash never seen)
|
||||||
// records block hashes requests by the blockPool
|
// records block hashes requests by the blockPool
|
||||||
func (self *peerTester) requestBlockHashes(hash []byte) error {
|
func (self *peerTester) requestBlockHashes(hash common.Hash) error {
|
||||||
indexes := self.hashPool.HashesToIndexes([][]byte{hash})
|
indexes := self.hashPool.HashesToIndexes([]common.Hash{hash})
|
||||||
fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4])
|
fmt.Printf("[%s] block hash request %v %x\n", self.id, indexes[0], hash[:4])
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
@ -332,7 +333,7 @@ func (self *peerTester) requestBlockHashes(hash []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// records block requests by the blockPool
|
// records block requests by the blockPool
|
||||||
func (self *peerTester) requestBlocks(hashes [][]byte) error {
|
func (self *peerTester) requestBlocks(hashes []common.Hash) error {
|
||||||
indexes := self.hashPool.HashesToIndexes(hashes)
|
indexes := self.hashPool.HashesToIndexes(hashes)
|
||||||
fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4])
|
fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4])
|
||||||
self.bt.reqlock.Lock()
|
self.bt.reqlock.Lock()
|
||||||
@ -347,4 +348,9 @@ func (self *peerTester) requestBlocks(hashes [][]byte) error {
|
|||||||
// records the error codes of all the peerErrors found the blockPool
|
// records the error codes of all the peerErrors found the blockPool
|
||||||
func (self *peerTester) peerError(err *errs.Error) {
|
func (self *peerTester) peerError(err *errs.Error) {
|
||||||
self.peerErrors = append(self.peerErrors, err.Code)
|
self.peerErrors = append(self.peerErrors, err.Code)
|
||||||
|
fmt.Printf("Error %v on peer %v\n", err, self.id)
|
||||||
|
if err.Fatal() {
|
||||||
|
fmt.Printf("Error %v is fatal, removing peer %v\n", err, self.id)
|
||||||
|
self.blockPool.RemovePeer(self.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,13 @@ func TestBlockPoolConfig(t *testing.T) {
|
|||||||
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, blockHashesTimeout, t)
|
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, blockHashesTimeout, t)
|
||||||
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
|
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
|
||||||
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, idleBestPeerTimeout, t)
|
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, idleBestPeerTimeout, t)
|
||||||
|
test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, peerSuspensionInterval, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBlockPoolOverrideConfig(t *testing.T) {
|
func TestBlockPoolOverrideConfig(t *testing.T) {
|
||||||
test.LogInit()
|
test.LogInit()
|
||||||
blockPool := &BlockPool{Config: &Config{}}
|
blockPool := &BlockPool{Config: &Config{}}
|
||||||
c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second}
|
c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second, 30 * time.Second}
|
||||||
|
|
||||||
blockPool.Config = c
|
blockPool.Config = c
|
||||||
blockPool.Start()
|
blockPool.Start()
|
||||||
@ -39,4 +40,5 @@ func TestBlockPoolOverrideConfig(t *testing.T) {
|
|||||||
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, 90*time.Second, t)
|
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, 90*time.Second, t)
|
||||||
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
|
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
|
||||||
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, 30*time.Second, t)
|
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, 30*time.Second, t)
|
||||||
|
test.CheckDuration("PeerSuspensionInterval", c.PeerSuspensionInterval, 30*time.Second, t)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/blockpool/test"
|
"github.com/ethereum/go-ethereum/blockpool/test"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
@ -45,7 +46,7 @@ func TestVerifyPoW(t *testing.T) {
|
|||||||
first := false
|
first := false
|
||||||
blockPoolTester.blockPool.verifyPoW = func(b pow.Block) bool {
|
blockPoolTester.blockPool.verifyPoW = func(b pow.Block) bool {
|
||||||
bb, _ := b.(*types.Block)
|
bb, _ := b.(*types.Block)
|
||||||
indexes := blockPoolTester.hashPool.HashesToIndexes([][]byte{bb.Hash()})
|
indexes := blockPoolTester.hashPool.HashesToIndexes([]common.Hash{bb.Hash()})
|
||||||
if indexes[0] == 2 && !first {
|
if indexes[0] == 2 && !first {
|
||||||
first = true
|
first = true
|
||||||
return false
|
return false
|
||||||
@ -122,3 +123,33 @@ func TestErrInsufficientChainInfo(t *testing.T) {
|
|||||||
t.Errorf("expected %v error, got %v", ErrInsufficientChainInfo, peer1.peerErrors)
|
t.Errorf("expected %v error, got %v", ErrInsufficientChainInfo, peer1.peerErrors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPeerSuspension(t *testing.T) {
|
||||||
|
test.LogInit()
|
||||||
|
_, blockPool, blockPoolTester := newTestBlockPool(t)
|
||||||
|
blockPool.Config.PeerSuspensionInterval = 100 * time.Millisecond
|
||||||
|
|
||||||
|
blockPool.Start()
|
||||||
|
|
||||||
|
peer1 := blockPoolTester.newPeer("peer1", 1, 3)
|
||||||
|
peer1.AddPeer()
|
||||||
|
blockPool.peers.peerError("peer1", 0, "")
|
||||||
|
bestpeer, _ := blockPool.peers.getPeer("peer1")
|
||||||
|
if bestpeer != nil {
|
||||||
|
t.Errorf("peer1 not removed on error")
|
||||||
|
}
|
||||||
|
peer1.AddPeer()
|
||||||
|
bestpeer, _ = blockPool.peers.getPeer("peer1")
|
||||||
|
if bestpeer != nil {
|
||||||
|
t.Errorf("peer1 not removed on reconnect")
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
peer1.AddPeer()
|
||||||
|
bestpeer, _ = blockPool.peers.getPeer("peer1")
|
||||||
|
if bestpeer == nil {
|
||||||
|
t.Errorf("peer1 not connected after PeerSuspensionInterval")
|
||||||
|
}
|
||||||
|
// blockPool.Wait(waitTimeout)
|
||||||
|
blockPool.Stop()
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -47,6 +47,8 @@ type peer struct {
|
|||||||
blocksRequestTimer <-chan time.Time
|
blocksRequestTimer <-chan time.Time
|
||||||
suicideC <-chan time.Time
|
suicideC <-chan time.Time
|
||||||
|
|
||||||
|
addToBlacklist func(id string)
|
||||||
|
|
||||||
idle bool
|
idle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +57,12 @@ type peer struct {
|
|||||||
type peers struct {
|
type peers struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
|
||||||
bp *BlockPool
|
bp *BlockPool
|
||||||
errors *errs.Errors
|
errors *errs.Errors
|
||||||
peers map[string]*peer
|
peers map[string]*peer
|
||||||
best *peer
|
best *peer
|
||||||
status *status
|
status *status
|
||||||
|
blacklist map[string]time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// peer constructor
|
// peer constructor
|
||||||
@ -84,26 +87,46 @@ func (self *peers) newPeer(
|
|||||||
headSectionC: make(chan *section),
|
headSectionC: make(chan *section),
|
||||||
bp: self.bp,
|
bp: self.bp,
|
||||||
idle: true,
|
idle: true,
|
||||||
|
addToBlacklist: self.addToBlacklist,
|
||||||
}
|
}
|
||||||
// at creation the peer is recorded in the peer pool
|
// at creation the peer is recorded in the peer pool
|
||||||
self.peers[id] = p
|
self.peers[id] = p
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatches an error to a peer if still connected
|
// dispatches an error to a peer if still connected, adds it to the blacklist
|
||||||
func (self *peers) peerError(id string, code int, format string, params ...interface{}) {
|
func (self *peers) peerError(id string, code int, format string, params ...interface{}) {
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
defer self.lock.RUnlock()
|
|
||||||
peer, ok := self.peers[id]
|
peer, ok := self.peers[id]
|
||||||
|
self.lock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
peer.addError(code, format, params)
|
peer.addError(code, format, params)
|
||||||
}
|
}
|
||||||
// blacklisting comes here
|
self.addToBlacklist(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *peers) addToBlacklist(id string) {
|
||||||
|
self.lock.Lock()
|
||||||
|
defer self.lock.Unlock()
|
||||||
|
self.blacklist[id] = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *peers) suspended(id string) (s bool) {
|
||||||
|
self.lock.Lock()
|
||||||
|
defer self.lock.Unlock()
|
||||||
|
if suspendedAt, ok := self.blacklist[id]; ok {
|
||||||
|
if s = suspendedAt.Add(self.bp.Config.PeerSuspensionInterval).After(time.Now()); !s {
|
||||||
|
// no longer suspended, delete entry
|
||||||
|
delete(self.blacklist, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peer) addError(code int, format string, params ...interface{}) {
|
func (self *peer) addError(code int, format string, params ...interface{}) {
|
||||||
err := self.errors.New(code, format, params...)
|
err := self.errors.New(code, format, params...)
|
||||||
self.peerError(err)
|
self.peerError(err)
|
||||||
|
self.addToBlacklist(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peer) setChainInfo(td *big.Int, c common.Hash) {
|
func (self *peer) setChainInfo(td *big.Int, c common.Hash) {
|
||||||
@ -182,9 +205,13 @@ func (self *peers) addPeer(
|
|||||||
requestBlockHashes func(common.Hash) error,
|
requestBlockHashes func(common.Hash) error,
|
||||||
requestBlocks func([]common.Hash) error,
|
requestBlocks func([]common.Hash) error,
|
||||||
peerError func(*errs.Error),
|
peerError func(*errs.Error),
|
||||||
) (best bool) {
|
) (best bool, suspended bool) {
|
||||||
|
|
||||||
var previousBlockHash common.Hash
|
var previousBlockHash common.Hash
|
||||||
|
if self.suspended(id) {
|
||||||
|
suspended = true
|
||||||
|
return
|
||||||
|
}
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
p, found := self.peers[id]
|
p, found := self.peers[id]
|
||||||
if found {
|
if found {
|
||||||
@ -213,7 +240,7 @@ func (self *peers) addPeer(
|
|||||||
if self.bp.hasBlock(currentBlockHash) {
|
if self.bp.hasBlock(currentBlockHash) {
|
||||||
// peer not ahead
|
// peer not ahead
|
||||||
plog.Debugf("addPeer: peer <%v> with td %v and current block %s is behind", id, td, hex(currentBlockHash))
|
plog.Debugf("addPeer: peer <%v> with td %v and current block %s is behind", id, td, hex(currentBlockHash))
|
||||||
return false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.best == p {
|
if self.best == p {
|
||||||
@ -248,8 +275,10 @@ func (self *peers) addPeer(
|
|||||||
|
|
||||||
// removePeer is called (via RemovePeer) by the eth protocol when the peer disconnects
|
// removePeer is called (via RemovePeer) by the eth protocol when the peer disconnects
|
||||||
func (self *peers) removePeer(id string) {
|
func (self *peers) removePeer(id string) {
|
||||||
|
plog.Debugf("addPeer: remove peer 0 <%v>", id)
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
|
plog.Debugf("addPeer: remove peer 1 <%v>", id)
|
||||||
|
|
||||||
p, found := self.peers[id]
|
p, found := self.peers[id]
|
||||||
if !found {
|
if !found {
|
||||||
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,9 +14,9 @@ func NewHashPool() *TestHashPool {
|
|||||||
return &TestHashPool{intToHash: make(intToHash), hashToInt: make(hashToInt)}
|
return &TestHashPool{intToHash: make(intToHash), hashToInt: make(hashToInt)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type intToHash map[int][]byte
|
type intToHash map[int]common.Hash
|
||||||
|
|
||||||
type hashToInt map[string]int
|
type hashToInt map[common.Hash]int
|
||||||
|
|
||||||
// hashPool is a test helper, that allows random hashes to be referred to by integers
|
// hashPool is a test helper, that allows random hashes to be referred to by integers
|
||||||
type TestHashPool struct {
|
type TestHashPool struct {
|
||||||
@ -24,11 +25,11 @@ type TestHashPool struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHash(i int) []byte {
|
func newHash(i int) common.Hash {
|
||||||
return crypto.Sha3([]byte(string(i)))
|
return common.BytesToHash(crypto.Sha3([]byte(string(i))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes [][]byte) {
|
func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes []common.Hash) {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
for _, i := range indexes {
|
for _, i := range indexes {
|
||||||
@ -36,18 +37,18 @@ func (self *TestHashPool) IndexesToHashes(indexes []int) (hashes [][]byte) {
|
|||||||
if !found {
|
if !found {
|
||||||
hash = newHash(i)
|
hash = newHash(i)
|
||||||
self.intToHash[i] = hash
|
self.intToHash[i] = hash
|
||||||
self.hashToInt[string(hash)] = i
|
self.hashToInt[hash] = i
|
||||||
}
|
}
|
||||||
hashes = append(hashes, hash)
|
hashes = append(hashes, hash)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TestHashPool) HashesToIndexes(hashes [][]byte) (indexes []int) {
|
func (self *TestHashPool) HashesToIndexes(hashes []common.Hash) (indexes []int) {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
for _, hash := range hashes {
|
for _, hash := range hashes {
|
||||||
i, found := self.hashToInt[string(hash)]
|
i, found := self.hashToInt[hash]
|
||||||
if !found {
|
if !found {
|
||||||
i = -1
|
i = -1
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ const (
|
|||||||
ErrGenesisBlockMismatch
|
ErrGenesisBlockMismatch
|
||||||
ErrNoStatusMsg
|
ErrNoStatusMsg
|
||||||
ErrExtraStatusMsg
|
ErrExtraStatusMsg
|
||||||
|
ErrSuspendedPeer
|
||||||
)
|
)
|
||||||
|
|
||||||
var errorToString = map[int]string{
|
var errorToString = map[int]string{
|
||||||
@ -53,6 +54,7 @@ var errorToString = map[int]string{
|
|||||||
ErrGenesisBlockMismatch: "Genesis block mismatch",
|
ErrGenesisBlockMismatch: "Genesis block mismatch",
|
||||||
ErrNoStatusMsg: "No status message",
|
ErrNoStatusMsg: "No status message",
|
||||||
ErrExtraStatusMsg: "Extra status message",
|
ErrExtraStatusMsg: "Extra status message",
|
||||||
|
ErrSuspendedPeer: "Suspended peer",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ethProtocol represents the ethereum wire protocol
|
// ethProtocol represents the ethereum wire protocol
|
||||||
@ -85,7 +87,7 @@ type chainManager interface {
|
|||||||
type blockPool interface {
|
type blockPool interface {
|
||||||
AddBlockHashes(next func() (common.Hash, bool), peerId string)
|
AddBlockHashes(next func() (common.Hash, bool), peerId string)
|
||||||
AddBlock(block *types.Block, peerId string)
|
AddBlock(block *types.Block, peerId string)
|
||||||
AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool)
|
AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool)
|
||||||
RemovePeer(peerId string)
|
RemovePeer(peerId string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +290,7 @@ func (self *ethProtocol) handle() error {
|
|||||||
// to simplify backend interface adding a new block
|
// to simplify backend interface adding a new block
|
||||||
// uses AddPeer followed by AddBlock only if peer is the best peer
|
// uses AddPeer followed by AddBlock only if peer is the best peer
|
||||||
// (or selected as new best peer)
|
// (or selected as new best peer)
|
||||||
if self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) {
|
if best, _ := self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect); best {
|
||||||
self.blockPool.AddBlock(request.Block, self.id)
|
self.blockPool.AddBlock(request.Block, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,9 +336,12 @@ func (self *ethProtocol) handleStatus() error {
|
|||||||
return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion)
|
return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
_, suspended := self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
|
||||||
|
if suspended {
|
||||||
|
return self.protoError(ErrSuspendedPeer, "")
|
||||||
|
}
|
||||||
|
|
||||||
self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
|
self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user