diff options
Diffstat (limited to 'eth/peer.go')
-rw-r--r-- | eth/peer.go | 137 |
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 +} |