eth: fix data race accessing peer.recentHash

This commit is contained in:
Péter Szilágyi 2015-06-09 14:27:44 +03:00
parent 05cae69d72
commit 44147d057d
3 changed files with 32 additions and 12 deletions

@ -157,7 +157,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
} }
defer pm.removePeer(p.id) defer pm.removePeer(p.id)
if err := pm.downloader.RegisterPeer(p.id, p.recentHash, p.requestHashes, p.requestBlocks); err != nil { if err := pm.downloader.RegisterPeer(p.id, p.Head(), p.requestHashes, p.requestBlocks); err != nil {
return err return err
} }
// propagate existing transactions. new transactions appearing // propagate existing transactions. new transactions appearing
@ -303,7 +303,7 @@ func (self *ProtocolManager) handleMsg(p *peer) error {
// Mark the hashes as present at the remote node // Mark the hashes as present at the remote node
for _, hash := range hashes { for _, hash := range hashes {
p.blockHashes.Add(hash) p.blockHashes.Add(hash)
p.recentHash = hash p.SetHead(hash)
} }
// Schedule all the unknown hashes for retrieval // Schedule all the unknown hashes for retrieval
unknown := make([]common.Hash, 0, len(hashes)) unknown := make([]common.Hash, 0, len(hashes))
@ -354,7 +354,7 @@ func (pm *ProtocolManager) importBlock(p *peer, block *types.Block, td *big.Int)
// Mark the block as present at the remote node (don't duplicate already held data) // Mark the block as present at the remote node (don't duplicate already held data)
p.blockHashes.Add(hash) p.blockHashes.Add(hash)
p.recentHash = hash p.SetHead(hash)
if td != nil { if td != nil {
p.td = td p.td = td
} }

@ -40,10 +40,12 @@ type peer struct {
protv, netid int protv, netid int
recentHash common.Hash
id string id string
td *big.Int td *big.Int
head common.Hash
headLock sync.RWMutex
genesis, ourHash common.Hash genesis, ourHash common.Hash
ourTd *big.Int ourTd *big.Int
@ -51,14 +53,14 @@ type peer struct {
blockHashes *set.Set blockHashes *set.Set
} }
func newPeer(protv, netid int, genesis, recentHash common.Hash, td *big.Int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { func newPeer(protv, netid int, genesis, head common.Hash, td *big.Int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
id := p.ID() id := p.ID()
return &peer{ return &peer{
Peer: p, Peer: p,
rw: rw, rw: rw,
genesis: genesis, genesis: genesis,
ourHash: recentHash, ourHash: head,
ourTd: td, ourTd: td,
protv: protv, protv: protv,
netid: netid, netid: netid,
@ -68,6 +70,23 @@ func newPeer(protv, netid int, genesis, recentHash common.Hash, td *big.Int, p *
} }
} }
// Head retrieves a copy of the current head (most recent) hash of the peer.
func (p *peer) Head() (hash common.Hash) {
p.headLock.RLock()
defer p.headLock.RUnlock()
copy(hash[:], p.head[:])
return hash
}
// SetHead updates the head (most recent) hash of the peer.
func (p *peer) SetHead(hash common.Hash) {
p.headLock.Lock()
defer p.headLock.Unlock()
copy(p.head[:], hash[:])
}
// sendTransactions sends transactions to the peer and includes the hashes // sendTransactions sends transactions to the peer and includes the hashes
// in it's tx hash set for future reference. The tx hash will allow the // in it's tx hash set for future reference. The tx hash will allow the
// manager to check whether the peer has already received this particular // manager to check whether the peer has already received this particular
@ -160,7 +179,7 @@ func (p *peer) handleStatus() error {
// Set the total difficulty of the peer // Set the total difficulty of the peer
p.td = status.TD p.td = status.TD
// set the best hash of the peer // set the best hash of the peer
p.recentHash = status.CurrentBlock p.head = status.CurrentBlock
return <-errc return <-errc
} }

@ -214,14 +214,15 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
// FIXME if we have the hash in our chain and the TD of the peer is // FIXME if we have the hash in our chain and the TD of the peer is
// much higher than ours, something is wrong with us or the peer. // much higher than ours, something is wrong with us or the peer.
// Check if the hash is on our own chain // Check if the hash is on our own chain
if pm.chainman.HasBlock(peer.recentHash) { head := peer.Head()
if pm.chainman.HasBlock(head) {
glog.V(logger.Debug).Infoln("Synchronisation canceled: head already known") glog.V(logger.Debug).Infoln("Synchronisation canceled: head already known")
return return
} }
// Get the hashes from the peer (synchronously) // Get the hashes from the peer (synchronously)
glog.V(logger.Detail).Infof("Attempting synchronisation: %v, 0x%x", peer.id, peer.recentHash) glog.V(logger.Detail).Infof("Attempting synchronisation: %v, 0x%x", peer.id, head)
err := pm.downloader.Synchronise(peer.id, peer.recentHash) err := pm.downloader.Synchronise(peer.id, head)
switch err { switch err {
case nil: case nil:
glog.V(logger.Detail).Infof("Synchronisation completed") glog.V(logger.Detail).Infof("Synchronisation completed")