aboutsummaryrefslogtreecommitdiffstats
path: root/eth/peer.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/peer.go')
-rw-r--r--eth/peer.go137
1 files changed, 137 insertions, 0 deletions
diff --git a/eth/peer.go b/eth/peer.go
new file mode 100644
index 000000000..db7fea7a7
--- /dev/null
+++ b/eth/peer.go
@@ -0,0 +1,137 @@
+package eth
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/p2p"
+ "gopkg.in/fatih/set.v0"
+)
+
+type statusMsgData struct {
+ ProtocolVersion uint32
+ NetworkId uint32
+ TD *big.Int
+ CurrentBlock common.Hash
+ GenesisBlock common.Hash
+}
+
+type getBlockHashesMsgData struct {
+ Hash common.Hash
+ Amount uint64
+}
+
+type peer struct {
+ *p2p.Peer
+
+ rw p2p.MsgReadWriter
+
+ protv, netid int
+
+ currentHash common.Hash
+ id string
+ td *big.Int
+
+ genesis, ourHash common.Hash
+ ourTd *big.Int
+
+ txHashes *set.Set
+ blockHashes *set.Set
+}
+
+func newPeer(protv, netid int, genesis, currentHash common.Hash, td *big.Int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
+ id := p.ID()
+
+ return &peer{
+ Peer: p,
+ rw: rw,
+ genesis: genesis,
+ ourHash: currentHash,
+ ourTd: td,
+ protv: protv,
+ netid: netid,
+ id: fmt.Sprintf("%x", id[:8]),
+ txHashes: set.New(),
+ blockHashes: set.New(),
+ }
+}
+
+// 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
+// manager to check whether the peer has already received this particular
+// transaction
+func (p *peer) sendTransactions(txs types.Transactions) error {
+ for _, tx := range txs {
+ p.txHashes.Add(tx.Hash())
+ }
+
+ return p2p.Send(p.rw, TxMsg, txs)
+}
+
+func (p *peer) sendBlockHashes(hashes []common.Hash) error {
+ return p2p.Send(p.rw, BlockHashesMsg, hashes)
+}
+
+func (p *peer) sendBlocks(blocks []*types.Block) error {
+ return p2p.Send(p.rw, BlocksMsg, blocks)
+}
+
+func (p *peer) requestHashes(from common.Hash) error {
+ p.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4])
+ return p2p.Send(p.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes})
+}
+
+func (p *peer) requestBlocks(hashes []common.Hash) error {
+ p.Debugf("fetching %v blocks", len(hashes))
+ return p2p.Send(p.rw, GetBlocksMsg, hashes)
+}
+
+func (p *peer) handleStatus() error {
+ errc := make(chan error, 1)
+ go func() {
+ errc <- p2p.Send(p.rw, StatusMsg, &statusMsgData{
+ ProtocolVersion: uint32(p.protv),
+ NetworkId: uint32(p.netid),
+ TD: p.ourTd,
+ CurrentBlock: p.ourHash,
+ GenesisBlock: p.genesis,
+ })
+ }()
+
+ // read and handle remote status
+ msg, err := p.rw.ReadMsg()
+ if err != nil {
+ return err
+ }
+ if msg.Code != StatusMsg {
+ return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
+ }
+ if msg.Size > ProtocolMaxMsgSize {
+ return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
+ }
+
+ var status statusMsgData
+ if err := msg.Decode(&status); err != nil {
+ return errResp(ErrDecode, "msg %v: %v", msg, err)
+ }
+
+ if status.GenesisBlock != p.genesis {
+ return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, p.genesis)
+ }
+
+ if int(status.NetworkId) != p.netid {
+ return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, p.netid)
+ }
+
+ if int(status.ProtocolVersion) != p.protv {
+ return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.protv)
+ }
+ // Set the total difficulty of the peer
+ p.td = status.TD
+ // set the best hash of the peer
+ p.currentHash = status.CurrentBlock
+
+ return <-errc
+}