a8a2b2a488
When a parent is missing in the block list an attempt should be made to fetch the missing parent and grandparents.
98 lines
1.8 KiB
Go
98 lines
1.8 KiB
Go
package downloader
|
|
|
|
import (
|
|
"errors"
|
|
"math/big"
|
|
"sync"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
)
|
|
|
|
const (
|
|
workingState = 2
|
|
idleState = 4
|
|
)
|
|
|
|
type hashFetcherFn func(common.Hash) error
|
|
type blockFetcherFn func([]common.Hash) error
|
|
|
|
// XXX make threadsafe!!!!
|
|
type peers map[string]*peer
|
|
|
|
func (p peers) get(state int) []*peer {
|
|
var peers []*peer
|
|
for _, peer := range p {
|
|
peer.mu.RLock()
|
|
if peer.state == state {
|
|
peers = append(peers, peer)
|
|
}
|
|
peer.mu.RUnlock()
|
|
}
|
|
|
|
return peers
|
|
}
|
|
|
|
func (p peers) setState(id string, state int) {
|
|
if peer, exist := p[id]; exist {
|
|
peer.mu.Lock()
|
|
defer peer.mu.Unlock()
|
|
peer.state = state
|
|
}
|
|
}
|
|
|
|
func (p peers) getPeer(id string) *peer {
|
|
return p[id]
|
|
}
|
|
|
|
func (p peers) bestPeer() *peer {
|
|
var peer *peer
|
|
for _, cp := range p {
|
|
if peer == nil || cp.td.Cmp(peer.td) > 0 {
|
|
peer = cp
|
|
}
|
|
}
|
|
return peer
|
|
}
|
|
|
|
// peer represents an active peer
|
|
type peer struct {
|
|
state int // Peer state (working, idle)
|
|
rep int // TODO peer reputation
|
|
|
|
mu sync.RWMutex
|
|
id string
|
|
td *big.Int
|
|
recentHash common.Hash
|
|
|
|
getHashes hashFetcherFn
|
|
getBlocks blockFetcherFn
|
|
}
|
|
|
|
// create a new peer
|
|
func newPeer(id string, td *big.Int, hash common.Hash, getHashes hashFetcherFn, getBlocks blockFetcherFn) *peer {
|
|
return &peer{id: id, td: td, recentHash: hash, getHashes: getHashes, getBlocks: getBlocks, state: idleState}
|
|
}
|
|
|
|
// fetch a chunk using the peer
|
|
func (p *peer) fetch(chunk *chunk) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
if p.state == workingState {
|
|
return errors.New("peer already fetching chunk")
|
|
}
|
|
|
|
// set working state
|
|
p.state = workingState
|
|
// convert the set to a fetchable slice
|
|
hashes, i := make([]common.Hash, chunk.hashes.Size()), 0
|
|
chunk.hashes.Each(func(v interface{}) bool {
|
|
hashes[i] = v.(common.Hash)
|
|
i++
|
|
return true
|
|
})
|
|
p.getBlocks(hashes)
|
|
|
|
return nil
|
|
}
|