aboutsummaryrefslogtreecommitdiffstats
path: root/blockpool
diff options
context:
space:
mode:
authorzelig <viktor.tron@gmail.com>2015-03-20 07:00:19 +0800
committerzelig <viktor.tron@gmail.com>2015-03-20 18:41:41 +0800
commit137a9c9365dd9ec76d4a4aab7475d716457d00ae (patch)
treebbd282f06b0559c53f9fe3ae7c7beb74e0cfe592 /blockpool
parenta9926a289dd21bcfd8e2def8f4005b43b728cb3d (diff)
downloaddexon-137a9c9365dd9ec76d4a4aab7475d716457d00ae.tar.gz
dexon-137a9c9365dd9ec76d4a4aab7475d716457d00ae.tar.zst
dexon-137a9c9365dd9ec76d4a4aab7475d716457d00ae.zip
check and penalise td misreporting
- add ErrIncorrectTD - checkTD called after insertChain successful - fix tests, use blockPoolTester.tds to map block index to TD
Diffstat (limited to 'blockpool')
-rw-r--r--blockpool/blockpool.go14
-rw-r--r--blockpool/blockpool_test.go72
-rw-r--r--blockpool/blockpool_util_test.go9
-rw-r--r--blockpool/errors_test.go28
-rw-r--r--blockpool/peers.go7
-rw-r--r--blockpool/peers_test.go18
-rw-r--r--blockpool/section.go33
7 files changed, 129 insertions, 52 deletions
diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go
index a552e1b72..df3d14542 100644
--- a/blockpool/blockpool.go
+++ b/blockpool/blockpool.go
@@ -62,6 +62,7 @@ const (
ErrUnrequestedBlock
ErrInsufficientChainInfo
ErrIdleTooLong
+ ErrIncorrectTD
)
var errorToString = map[int]string{
@@ -70,6 +71,7 @@ var errorToString = map[int]string{
ErrUnrequestedBlock: "Unrequested block",
ErrInsufficientChainInfo: "Insufficient chain info",
ErrIdleTooLong: "Idle too long",
+ ErrIncorrectTD: "Incorrect Total Difficulty",
}
// init initialises all your laundry
@@ -373,6 +375,7 @@ func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId st
block: bestpeer.currentBlock,
hashBy: peerId,
blockBy: peerId,
+ td: bestpeer.td,
}
// nodes is a list of nodes in one section ordered top-bottom (old to young)
nodes = append(nodes, node)
@@ -729,6 +732,17 @@ LOOP:
}
}
+func (self *BlockPool) checkTD(nodes ...*node) {
+ for _, n := range nodes {
+ if n.td != nil {
+ plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td)
+ if n.td.Cmp(n.block.Td) != 0 {
+ self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash)
+ }
+ }
+ }
+}
+
// must run in separate go routine, otherwise
// switchpeer -> activateChain -> activate deadlocks on section process select and peers.lock
func (self *BlockPool) requestBlocks(attempts int, hashes []common.Hash) {
diff --git a/blockpool/blockpool_test.go b/blockpool/blockpool_test.go
index d8271886f..a76cab9b6 100644
--- a/blockpool/blockpool_test.go
+++ b/blockpool/blockpool_test.go
@@ -51,9 +51,11 @@ func TestPeerPromotionByOptionalTdOnBlock(t *testing.T) {
blockPoolTester.initRefBlockChain(4)
peer0 := blockPoolTester.newPeer("peer0", 2, 2)
peer1 := blockPoolTester.newPeer("peer1", 1, 1)
- peer2 := blockPoolTester.newPeer("peer2", 3, 4)
+ peer2 := blockPoolTester.newPeer("peer2", 4, 4)
blockPool.Start()
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[3] = 3
// pool
peer0.AddPeer()
@@ -94,7 +96,7 @@ func TestSimpleChain(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 2)
+ peer1 := blockPoolTester.newPeer("peer1", 2, 2)
peer1.AddPeer()
peer1.serveBlocks(1, 2)
go peer1.serveBlockHashes(2, 1, 0)
@@ -114,7 +116,7 @@ func TestChainConnectingWithParentHash(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 3)
+ peer1 := blockPoolTester.newPeer("peer1", 3, 3)
peer1.AddPeer()
go peer1.serveBlocks(2, 3)
go peer1.serveBlockHashes(3, 2, 1)
@@ -134,7 +136,7 @@ func TestMultiSectionChain(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 5)
+ peer1 := blockPoolTester.newPeer("peer1", 5, 5)
peer1.AddPeer()
go peer1.serveBlocks(4, 5)
@@ -156,14 +158,16 @@ func TestNewBlocksOnPartialChain(t *testing.T) {
blockPoolTester.initRefBlockChain(7)
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 5)
+ peer1 := blockPoolTester.newPeer("peer1", 5, 5)
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[5] = 5
peer1.AddPeer()
go peer1.serveBlocks(4, 5) // partially complete section
go peer1.serveBlockHashes(5, 4, 3)
peer1.serveBlocks(3, 4) // partially complete section
// peer1 found new blocks
- peer1.td = 2
+ peer1.td = 7
peer1.currentBlock = 7
peer1.AddPeer()
peer1.sendBlocks(6, 7)
@@ -188,16 +192,15 @@ func TestPeerSwitchUp(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 6)
- peer2 := blockPoolTester.newPeer("peer2", 2, 7)
+ peer1 := blockPoolTester.newPeer("peer1", 6, 6)
+ peer2 := blockPoolTester.newPeer("peer2", 7, 7)
peer1.AddPeer()
go peer1.serveBlocks(5, 6)
go peer1.serveBlockHashes(6, 5, 4, 3) //
peer1.serveBlocks(2, 3) // section partially complete, block 3 will be preserved after peer demoted
peer2.AddPeer() // peer2 is promoted as best peer, peer1 is demoted
- go peer2.serveBlocks(6, 7)
- // go peer2.serveBlockHashes(7, 6) //
+ go peer2.serveBlocks(6, 7) //
go peer2.serveBlocks(4, 5) // tests that block request for earlier section is remembered
go peer1.serveBlocks(3, 4) // tests that connecting section by demoted peer is remembered and blocks are accepted from demoted peer
go peer2.serveBlockHashes(3, 2, 1, 0) // tests that known chain section is activated, hash requests from 3 is remembered
@@ -216,8 +219,8 @@ func TestPeerSwitchDownOverlapSectionWithoutRootBlock(t *testing.T) {
blockPoolTester.initRefBlockChain(6)
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 4)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ peer1 := blockPoolTester.newPeer("peer1", 4, 4)
+ peer2 := blockPoolTester.newPeer("peer2", 6, 6)
peer2.AddPeer()
peer2.serveBlocks(5, 6) // partially complete, section will be preserved
@@ -242,8 +245,8 @@ func TestPeerSwitchDownOverlapSectionWithRootBlock(t *testing.T) {
blockPoolTester.initRefBlockChain(6)
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 4)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ peer1 := blockPoolTester.newPeer("peer1", 4, 4)
+ peer2 := blockPoolTester.newPeer("peer2", 6, 6)
peer2.AddPeer()
peer2.serveBlocks(5, 6) // partially complete, section will be preserved
@@ -269,8 +272,8 @@ func TestPeerSwitchDownDisjointSection(t *testing.T) {
blockPoolTester.initRefBlockChain(3)
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 3)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ peer1 := blockPoolTester.newPeer("peer1", 3, 3)
+ peer2 := blockPoolTester.newPeer("peer2", 6, 6)
peer2.AddPeer()
peer2.serveBlocks(5, 6) // partially complete, section will be preserved
@@ -297,8 +300,8 @@ func TestPeerSwitchBack(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 2, 11)
- peer2 := blockPoolTester.newPeer("peer2", 1, 8)
+ peer1 := blockPoolTester.newPeer("peer1", 11, 11)
+ peer2 := blockPoolTester.newPeer("peer2", 8, 8)
peer2.AddPeer()
go peer2.serveBlocks(7, 8)
@@ -328,9 +331,10 @@ func TestForkSimple(t *testing.T) {
delete(blockPoolTester.refBlockChain, 6)
blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[6] = 10
+ peer1 := blockPoolTester.newPeer("peer1", 9, 9)
+ peer2 := blockPoolTester.newPeer("peer2", 10, 6)
peer1.AddPeer()
go peer1.serveBlocks(8, 9)
@@ -363,9 +367,10 @@ func TestForkSwitchBackByNewBlocks(t *testing.T) {
delete(blockPoolTester.refBlockChain, 6)
blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[6] = 10
+ peer1 := blockPoolTester.newPeer("peer1", 9, 9)
+ peer2 := blockPoolTester.newPeer("peer2", 10, 6)
peer1.AddPeer()
go peer1.serveBlocks(8, 9) //
@@ -378,7 +383,7 @@ func TestForkSwitchBackByNewBlocks(t *testing.T) {
peer2.serveBlocks(1, 2, 3, 4, 5) //
// peer1 finds new blocks
- peer1.td = 3
+ peer1.td = 11
peer1.currentBlock = 11
peer1.AddPeer()
go peer1.serveBlocks(10, 11)
@@ -410,8 +415,14 @@ func TestForkSwitchBackByPeerSwitchBack(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[6] = 10
+
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[6] = 10
+
+ peer1 := blockPoolTester.newPeer("peer1", 9, 9)
+ peer2 := blockPoolTester.newPeer("peer2", 10, 6)
peer1.AddPeer()
go peer1.serveBlocks(8, 9)
@@ -448,8 +459,11 @@ func TestForkCompleteSectionSwitchBackByPeerSwitchBack(t *testing.T) {
blockPool.Start()
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
+ blockPoolTester.tds = make(map[int]int)
+ blockPoolTester.tds[6] = 10
+
+ peer1 := blockPoolTester.newPeer("peer1", 9, 9)
+ peer2 := blockPoolTester.newPeer("peer2", 10, 6)
peer1.AddPeer()
go peer1.serveBlocks(8, 9)
diff --git a/blockpool/blockpool_util_test.go b/blockpool/blockpool_util_test.go
index a17bc584e..f4e5fec2f 100644
--- a/blockpool/blockpool_util_test.go
+++ b/blockpool/blockpool_util_test.go
@@ -40,6 +40,7 @@ type blockPoolTester struct {
blockPool *BlockPool
t *testing.T
chainEvents *event.TypeMux
+ tds map[int]int
}
func newTestBlockPool(t *testing.T) (hashPool *test.TestHashPool, blockPool *BlockPool, b *blockPoolTester) {
@@ -84,6 +85,14 @@ func (self *blockPoolTester) insertChain(blocks types.Blocks) error {
var ok bool
for _, block := range blocks {
child = self.hashPool.HashesToIndexes([]common.Hash{block.Hash()})[0]
+ var td int
+ if self.tds != nil {
+ td, ok = self.tds[child]
+ }
+ if !ok {
+ td = child
+ }
+ block.Td = big.NewInt(int64(td))
_, ok = self.blockChain[child]
if ok {
fmt.Printf("block %v already in blockchain\n", child)
diff --git a/blockpool/errors_test.go b/blockpool/errors_test.go
index 5188930f0..350d6daef 100644
--- a/blockpool/errors_test.go
+++ b/blockpool/errors_test.go
@@ -93,7 +93,6 @@ func TestUnrequestedBlock(t *testing.T) {
peer1.AddPeer()
peer1.sendBlocks(1, 2)
- // blockPool.Wait(waitTimeout)
blockPool.Stop()
if len(peer1.peerErrors) == 1 {
if peer1.peerErrors[0] != ErrUnrequestedBlock {
@@ -124,6 +123,33 @@ func TestErrInsufficientChainInfo(t *testing.T) {
}
}
+func TestIncorrectTD(t *testing.T) {
+ test.LogInit()
+ _, blockPool, blockPoolTester := newTestBlockPool(t)
+ blockPoolTester.blockChain[0] = nil
+ blockPoolTester.initRefBlockChain(3)
+
+ blockPool.Start()
+
+ peer1 := blockPoolTester.newPeer("peer1", 1, 3)
+ peer1.AddPeer()
+ go peer1.serveBlocks(2, 3)
+ go peer1.serveBlockHashes(3, 2, 1, 0)
+ peer1.serveBlocks(0, 1, 2)
+
+ blockPool.Wait(waitTimeout)
+ blockPool.Stop()
+ blockPoolTester.refBlockChain[3] = []int{}
+ blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
+ if len(peer1.peerErrors) == 1 {
+ if peer1.peerErrors[0] != ErrIncorrectTD {
+ t.Errorf("wrong error, got %v, expected %v", peer1.peerErrors[0], ErrIncorrectTD)
+ }
+ } else {
+ t.Errorf("expected %v error, got %v", ErrIncorrectTD, peer1.peerErrors)
+ }
+}
+
func TestPeerSuspension(t *testing.T) {
test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t)
diff --git a/blockpool/peers.go b/blockpool/peers.go
index b463137e3..5cc483a3b 100644
--- a/blockpool/peers.go
+++ b/blockpool/peers.go
@@ -452,8 +452,12 @@ func (self *peer) getBlockHashes() {
self.addError(ErrInvalidBlock, "%v", err)
self.bp.status.badPeers[self.id]++
} else {
+ if self.currentBlock.Td != nil {
+ if self.td.Cmp(self.currentBlock.Td) != 0 {
+ self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash)
+ }
+ }
headKey := self.parentHash.Str()
- height := self.bp.status.chain[headKey] + 1
self.bp.status.chain[self.currentBlockHash.Str()] = height
if height > self.bp.status.values.LongestChain {
self.bp.status.values.LongestChain = height
@@ -471,6 +475,7 @@ func (self *peer) getBlockHashes() {
block: self.currentBlock,
hashBy: self.id,
blockBy: self.id,
+ td: self.td,
}
self.bp.newSection([]*node{n}).activate(self)
} else {
diff --git a/blockpool/peers_test.go b/blockpool/peers_test.go
index 99dd16ba1..db83de43a 100644
--- a/blockpool/peers_test.go
+++ b/blockpool/peers_test.go
@@ -15,9 +15,9 @@ import (
func TestAddPeer(t *testing.T) {
test.LogInit()
_, blockPool, blockPoolTester := newTestBlockPool(t)
- peer0 := blockPoolTester.newPeer("peer0", 1, 0)
- peer1 := blockPoolTester.newPeer("peer1", 2, 1)
- peer2 := blockPoolTester.newPeer("peer2", 3, 2)
+ peer0 := blockPoolTester.newPeer("peer0", 1, 1)
+ peer1 := blockPoolTester.newPeer("peer1", 2, 2)
+ peer2 := blockPoolTester.newPeer("peer2", 3, 3)
var bestpeer *peer
blockPool.Start()
@@ -38,7 +38,7 @@ func TestAddPeer(t *testing.T) {
if blockPool.peers.best.id != "peer2" {
t.Errorf("peer2 (TD=3) not set as best")
}
- peer2.waitBlocksRequests(2)
+ peer2.waitBlocksRequests(3)
best = peer1.AddPeer()
if best {
@@ -52,7 +52,7 @@ func TestAddPeer(t *testing.T) {
}
peer2.td = 4
- peer2.currentBlock = 3
+ peer2.currentBlock = 4
best = peer2.AddPeer()
if !best {
t.Errorf("peer2 (TD=4) not accepted as best")
@@ -63,10 +63,10 @@ func TestAddPeer(t *testing.T) {
if blockPool.peers.best.td.Cmp(big.NewInt(int64(4))) != 0 {
t.Errorf("peer2 TD not updated")
}
- peer2.waitBlocksRequests(3)
+ peer2.waitBlocksRequests(4)
peer1.td = 3
- peer1.currentBlock = 2
+ peer1.currentBlock = 3
best = peer1.AddPeer()
if best {
t.Errorf("peer1 (TD=3) should not be set as best")
@@ -88,7 +88,7 @@ func TestAddPeer(t *testing.T) {
if blockPool.peers.best.id != "peer1" {
t.Errorf("existing peer1 (TD=3) should be set as best peer")
}
- peer1.waitBlocksRequests(2)
+ peer1.waitBlocksRequests(3)
blockPool.RemovePeer("peer1")
bestpeer, best = blockPool.peers.getPeer("peer1")
@@ -99,7 +99,7 @@ func TestAddPeer(t *testing.T) {
if blockPool.peers.best.id != "peer0" {
t.Errorf("existing peer0 (TD=1) should be set as best peer")
}
- peer0.waitBlocksRequests(0)
+ peer0.waitBlocksRequests(1)
blockPool.RemovePeer("peer0")
bestpeer, best = blockPool.peers.getPeer("peer0")
diff --git a/blockpool/section.go b/blockpool/section.go
index c73aaa6df..0304c9a04 100644
--- a/blockpool/section.go
+++ b/blockpool/section.go
@@ -83,9 +83,9 @@ func (self *BlockPool) newSection(nodes []*node) *section {
offC: make(chan bool),
}
- for i, node := range nodes {
- entry := &entry{node: node, section: sec, index: &index{i}}
- self.set(node.hash, entry)
+ for i, n := range nodes {
+ entry := &entry{node: n, section: sec, index: &index{i}}
+ self.set(n.hash, entry)
}
plog.DebugDetailf("[%s] setup section process", sectionhex(sec))
@@ -104,20 +104,22 @@ func (self *section) addSectionToBlockChain(p *peer) {
self.bp.wg.Done()
}()
- var node *node
+ var nodes []*node
+ var n *node
var keys []string
var blocks []*types.Block
for self.poolRootIndex > 0 {
- node = self.nodes[self.poolRootIndex-1]
- node.lock.RLock()
- block := node.block
- node.lock.RUnlock()
+ n = self.nodes[self.poolRootIndex-1]
+ n.lock.RLock()
+ block := n.block
+ n.lock.RUnlock()
if block == nil {
break
}
self.poolRootIndex--
keys = append(keys, node.hash.Str())
blocks = append(blocks, block)
+ nodes = append(nodes, n)
}
if len(blocks) == 0 {
@@ -134,13 +136,20 @@ func (self *section) addSectionToBlockChain(p *peer) {
err := self.bp.insertChain(blocks)
if err != nil {
self.invalid = true
- self.bp.peers.peerError(node.blockBy, ErrInvalidBlock, "%v", err)
- plog.Warnf("invalid block %x", node.hash)
- plog.Warnf("penalise peers %v (hash), %v (block)", node.hashBy, node.blockBy)
+ self.bp.peers.peerError(n.blockBy, ErrInvalidBlock, "%v", err)
+ plog.Warnf("invalid block %x", n.hash)
+ plog.Warnf("penalise peers %v (hash), %v (block)", n.hashBy, n.blockBy)
// or invalid block and the entire chain needs to be removed
self.removeChain()
} else {
+ // check tds
+ self.bp.wg.Add(1)
+ go func() {
+ plog.DebugDetailf("checking td")
+ self.bp.checkTD(nodes...)
+ self.bp.wg.Done()
+ }()
// if all blocks inserted in this section
// then need to try to insert blocks in child section
if self.poolRootIndex == 0 {
@@ -178,7 +187,7 @@ func (self *section) addSectionToBlockChain(p *peer) {
self.bp.status.values.BlocksInChain += len(blocks)
self.bp.status.values.BlocksInPool -= len(blocks)
if err != nil {
- self.bp.status.badPeers[node.blockBy]++
+ self.bp.status.badPeers[n.blockBy]++
}
self.bp.status.lock.Unlock()