aboutsummaryrefslogtreecommitdiffstats
path: root/blockpool/blockpool.go
diff options
context:
space:
mode:
authorzelig <viktor.tron@gmail.com>2015-04-10 23:31:00 +0800
committerzelig <viktor.tron@gmail.com>2015-04-10 23:36:40 +0800
commitda7332a7317bda9003e5e8a4aaa4b1710c69b664 (patch)
tree7c4fc11a84c18946b105bf778aa7243dd70e54ec /blockpool/blockpool.go
parentfc1d1f9afd155fab1f614c6a0340233f90afafd6 (diff)
downloaddexon-da7332a7317bda9003e5e8a4aaa4b1710c69b664.tar.gz
dexon-da7332a7317bda9003e5e8a4aaa4b1710c69b664.tar.zst
dexon-da7332a7317bda9003e5e8a4aaa4b1710c69b664.zip
td update from node
- reorg and simplify AddBlock - introduce nodeCache - TestPeerPromotionByTdOnBlock unskipped and passes - move switchC/idleC channel creation around: solves deadlock (now respects the contract with section process: either can activate or complete at any one time)
Diffstat (limited to 'blockpool/blockpool.go')
-rw-r--r--blockpool/blockpool.go189
1 files changed, 85 insertions, 104 deletions
diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go
index f442259e0..3ed2e92c7 100644
--- a/blockpool/blockpool.go
+++ b/blockpool/blockpool.go
@@ -169,6 +169,9 @@ type BlockPool struct {
// alloc-easy pool of hash slices
hashSlicePool chan []common.Hash
+ nodeCache map[common.Hash]*node
+ nodeCacheLock sync.RWMutex
+
// waitgroup is used in tests to wait for result-critical routines
// as well as in determining idle / syncing status
wg sync.WaitGroup //
@@ -210,6 +213,7 @@ func (self *BlockPool) Start() {
self.Config.init()
self.hashSlicePool = make(chan []common.Hash, 150)
+ self.nodeCache = make(map[common.Hash]*node)
self.status = newStatus()
self.quit = make(chan bool)
self.pool = make(map[common.Hash]*entry)
@@ -615,127 +619,104 @@ LOOP:
If the block received is the head block of the current best peer, signal it to the head section process
*/
func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
- hash := block.Hash()
-
- sender, _ := self.peers.getPeer(peerId)
- if sender == nil {
- return
- }
self.status.lock.Lock()
self.status.activePeers[peerId]++
self.status.lock.Unlock()
- entry := self.get(hash)
- blockIsCurrentHead := false
- sender.lock.RLock()
- currentBlockHash := sender.currentBlockHash
- currentBlock := sender.currentBlock
- currentBlockC := sender.currentBlockC
- switchC := sender.switchC
- sender.lock.RUnlock()
-
- // a peer's current head block is appearing the first time
- if hash == currentBlockHash {
- // this happens when block came in a newblock message but
- // also if sent in a blockmsg (for instance, if we requested, only if we
- // dont apply on blockrequests the restriction of flood control)
- blockIsCurrentHead = true
- if currentBlock == nil {
- sender.lock.Lock()
- sender.setChainInfoFromBlock(block)
- sender.lock.Unlock()
-
- self.status.lock.Lock()
- self.status.values.BlockHashes++
- self.status.values.Blocks++
- self.status.values.BlocksInPool++
- self.status.lock.Unlock()
- // signal to head section process
- select {
- case currentBlockC <- block:
- case <-switchC:
- }
- } else {
- plog.DebugDetailf("AddBlock: head block %s for peer <%s> (head: %s) already known", hex(hash), peerId, hex(currentBlockHash))
- }
- } else {
-
- plog.DebugDetailf("AddBlock: block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(currentBlockHash))
-
- /* @zelig !!!
- requested 5 hashes from both A & B. A responds sooner then B, process blocks. Close section.
- delayed B sends you block ... UNREQUESTED. Blocked
- if entry == nil {
- plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
- sender.addError(ErrUnrequestedBlock, "%x", hash)
-
- self.status.lock.Lock()
- self.status.badPeers[peerId]++
- self.status.lock.Unlock()
- return
- }
- */
- }
+ hash := block.Hash()
- if entry == nil {
- // FIXME: here check the cache find or create node -
- // put peer as blockBy!
+ // check if block is already inserted in the blockchain
+ if self.hasBlock(hash) {
return
}
- node := entry.node
- node.lock.Lock()
- defer node.lock.Unlock()
-
- // register peer on node as source
- if node.peers == nil {
- node.peers = make(map[string]bool)
- }
- FoundBlockCurrentHead, found := node.peers[sender.id]
- if !found || FoundBlockCurrentHead {
- // if found but not FoundBlockCurrentHead, then no update
- // necessary (||)
- node.peers[sender.id] = blockIsCurrentHead
- // for those that are false, TD will update their head
- // for those that are true, TD is checked !
- // this is checked at the time of TD calculation in checkTD
- }
- // check if block already received
- if node.block != nil {
- plog.DebugDetailf("AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> ", hex(hash), peerId, hex(sender.currentBlockHash), node.blockBy)
- }
-
- // check if block is already inserted in the blockchain
- if self.hasBlock(hash) {
- plog.DebugDetailf("AddBlock: block %s from peer <%s> (head: %s) already in the blockchain", hex(hash), peerId, hex(sender.currentBlockHash))
+ sender, _ := self.peers.getPeer(peerId)
+ if sender == nil {
return
}
+ tdFromCurrentHead, currentBlockHash := sender.setChainInfoFromBlock(block)
- /*
- @zelig needs discussing
- Viktor: pow check can be delayed in a go routine and therefore cache
- creation is not blocking
- // validate block for PoW
- if !self.verifyPoW(block) {
- plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
- sender.addError(ErrInvalidPoW, "%x", hash)
+ entry := self.get(hash)
- self.status.lock.Lock()
- self.status.badPeers[peerId]++
- self.status.lock.Unlock()
+ /* @zelig !!!
+ requested 5 hashes from both A & B. A responds sooner then B, process blocks. Close section.
+ delayed B sends you block ... UNREQUESTED. Blocked
+ if entry == nil {
+ plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
+ sender.addError(ErrUnrequestedBlock, "%x", hash)
+
+ self.status.lock.Lock()
+ self.status.badPeers[peerId]++
+ self.status.lock.Unlock()
+ return
+ }
+ */
- return
+ var bnode *node
+ if entry == nil {
+ self.nodeCacheLock.Lock()
+ bnode, _ = self.nodeCache[hash]
+ if bnode == nil {
+ bnode = &node{
+ hash: currentBlockHash,
+ block: block,
+ hashBy: peerId,
+ blockBy: peerId,
+ td: tdFromCurrentHead,
}
- */
+ self.nodeCache[hash] = bnode
+ }
+ self.nodeCacheLock.Unlock()
+ } else {
+ bnode = entry.node
+ }
- node.block = block
- node.blockBy = peerId
+ bnode.lock.Lock()
+ defer bnode.lock.Unlock()
- self.status.lock.Lock()
- self.status.values.Blocks++
- self.status.values.BlocksInPool++
- self.status.lock.Unlock()
+ // check if block already received
+ if bnode.block != nil {
+ plog.DebugDetailf("AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> ", hex(hash), peerId, hex(sender.currentBlockHash), bnode.blockBy)
+ // register peer on node as source
+ if bnode.peers == nil {
+ bnode.peers = make(map[string]bool)
+ }
+ foundBlockCurrentHead, found := bnode.peers[sender.id]
+ if !found || foundBlockCurrentHead {
+ // if found but not FoundBlockCurrentHead, then no update
+ // necessary (||)
+ bnode.peers[sender.id] = (currentBlockHash == hash)
+ // for those that are false, TD will update their head
+ // for those that are true, TD is checked !
+ // this is checked at the time of TD calculation in checkTD
+ }
+ sender.setChainInfoFromNode(bnode)
+ } else {
+ /*
+ @zelig needs discussing
+ Viktor: pow check can be delayed in a go routine and therefore cache
+ creation is not blocking
+ // validate block for PoW
+ if !self.verifyPoW(block) {
+ plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
+ sender.addError(ErrInvalidPoW, "%x", hash)
+
+ self.status.lock.Lock()
+ self.status.badPeers[peerId]++
+ self.status.lock.Unlock()
+
+ return
+ }
+ */
+ bnode.block = block
+ bnode.blockBy = peerId
+ bnode.td = tdFromCurrentHead
+ self.status.lock.Lock()
+ self.status.values.Blocks++
+ self.status.values.BlocksInPool++
+ self.status.lock.Unlock()
+ }
}