交流 | 以太坊节点将交易广播到网络中的过程

eth/handler.go BroadcastTxs() 方法
input: 交易数组 txs
具体流程:
1、节点针对每个 peer 维护一个待发送交易数组 A;
2、每笔交易 tx 先判断,每个 peer 是否知晓(对应 peer.knownTxs 交易数组结构)该 tx,若不知晓则加入 A;
3、调用 eth/peer.go 中 AsyncSendTransactions() 方法,将每个 peer 待发送交易数组 A 写入 queuedTxs 通道,发送出去。之后,将 A 中交易添加至 peer.knownTxs 数组中,代表该 peer 已经知晓该 tx;
4、eth/peer.go 中 broadcast() 方法,会从 queuedTxs 通道接收 txs,调用 SendTransactions()方法,真正发送到网络中;

该过程中所涉及到的主要方法为:

// eth/handler.go
// BroadcastTxs will propagate a batch of transactions to all peers which are not known to
// already have the given transaction.
func (pm *ProtocolManager) BroadcastTxs(txs types.Transactions) {
    var txset = make(map[*peer]types.Transactions)

    // Broadcast transactions to a batch of peers not knowing about it
    for _, tx := range txs {
        peers := pm.peers.PeersWithoutTx(tx.Hash())
        for _, peer := range peers {
            txset[peer] = append(txset[peer], tx)
        }
        log.Trace("Broadcast transaction", "hash", tx.Hash(), "recipients", len(peers))
    }
    // FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))]
    for peer, txs := range txset {
        peer.AsyncSendTransactions(txs)
    }
}
// eth/peer.go
// AsyncSendTransactions queues list of transactions propagation to a remote
// peer. If the peer's broadcast queue is full, the event is silently dropped.
func (p *peer) AsyncSendTransactions(txs []*types.Transaction) {
    select {
    case p.queuedTxs <- txs:
        for _, tx := range txs {
            p.knownTxs.Add(tx.Hash())
        }
    default:
        p.Log().Debug("Dropping transaction propagation", "count", len(txs))
    }
}
// eth/peer.go
// broadcast is a write loop that multiplexes block propagations, announcements
// and transaction broadcasts into the remote peer. The goal is to have an async
// writer that does not lock up node internals.
func (p *peer) broadcast() {
    for {
        select {
        case txs := <-p.queuedTxs:
            if err := p.SendTransactions(txs); err != nil {
                return
            }
            p.Log().Trace("Broadcast transactions", "count", len(txs))

        case prop := <-p.queuedProps:
            if err := p.SendNewBlock(prop.block, prop.td); err != nil {
                return
            }
            p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td)

        case block := <-p.queuedAnns:
            if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil {
                return
            }
            p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash())

        case <-p.term:
            return
        }
    }
}
// eth/peer.go
// SendTransactions sends transactions to the peer and includes the hashes
// in its transaction hash set for future reference.
func (p *peer) SendTransactions(txs types.Transactions) error {
    for _, tx := range txs {
        p.knownTxs.Add(tx.Hash())
    }
    return p2p.Send(p.rw, TxMsg, txs)
}
// p2p/message.go
// Send writes an RLP-encoded message with the given code.
// data should encode as an RLP list.
func Send(w MsgWriter, msgcode uint64, data interface{}) error {
    size, r, err := rlp.EncodeToReader(data)
    if err != nil {
        return err
    }
    return w.WriteMsg(Msg{Code: msgcode, Size: uint32(size), Payload: r})
}

你可能感兴趣的:(以太坊,代码解读)