aboutsummaryrefslogtreecommitdiffstats
path: root/eth/downloader/peer.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/downloader/peer.go')
-rw-r--r--eth/downloader/peer.go97
1 files changed, 97 insertions, 0 deletions
diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go
new file mode 100644
index 000000000..f66e5afd8
--- /dev/null
+++ b/eth/downloader/peer.go
@@ -0,0 +1,97 @@
+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
+}