Node Side: Receive pending transactions
If we want to broadcast our transactions to the network in Ethereum, two RPC
calls are involved:
- https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction
- https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction
So let’s follow those two calls to track how a transaction is broadcasted.
Those two corresponding implementations are defined at internal/ethapi/api.go
:
And both of them are pointing to SubmitTransaction, which calls SendTx to put transaction into the txpool
by calling:
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
return b.eth.txPool.AddLocal(signedTx)
}
Miner Side: Execute pending transactions
Miner start here at cmd/geth/main.go
, which is calling:
- *EthAPIBackend.StartMining
- *Ethereum.StartMining
- *Miner.Start -> miner.worker.start()
- *worker.start -> <-startCh -> commit -> <-newWorkCh
- *worker.commitWork
- *worker.fillTransactions sealing pending transactions in txpool to a block.
- *worker.commitTransactions
- *worker.commitTransaction executing transaction
- core.ApplyTransaction
- *worker.commitTransactions
- *worker.commit
- *worker.engine.FinalizeAndAssemble
- *beacon.FinalizeAndAssemble
- *worker.updateSnapshot ->
w.snapshotBlock
/w.snapshotReceipts
/w.snapshotState
- *worker.fillTransactions sealing pending transactions in txpool to a block.
- *Miner.Pending <-
w.snapshotBlock
/w.snapshotReceipts
/w.snapshotState
Remote Transactions
Here we can see that we loaded some transactions from remote in *worker.fillTransactions
:
// Split the pending transactions into locals and remotes
// Fill the block with all available pending transactions.
pending := w.eth.TxPool().Pending(true)
localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending
The w.eth
here is the Ethereum structure, and its TxPool
returns core.txpool.TxPool1 structure.
The remote transactions should be added by calling *TxPool.AddRemotes, so let’s check where is calling it.
- handleSendTx in
les
2 package. - Which will be used in RegisterEthService at
cmd/utils
package. - And then will be used in makeFullNode.
- Finally will be started in geth.
P2P Side: Exchange pending transactions
Ethereum Wire Protocol defined how transactions are exchanged between nodes.
Nodes use GetPooledTransactions (0x09)
3 message to pull pending transactions from the peer.
Which peers anwsered here:
func answerGetPooledTransactions(backend Backend, query GetPooledTransactionsPacket, peer *Peer) ([]common.Hash, []rlp.RawValue) {
// Gather transactions until the fetch or network limits is reached
var (
bytes int
hashes []common.Hash
txs []rlp.RawValue
)
for _, hash := range query {
if bytes >= softResponseLimit {
break
}
// Retrieve the requested transaction, skipping if unknown to us
tx := backend.TxPool().Get(hash)
if tx == nil {
continue
}
// If known, encode and queue for response packet
if encoded, err := rlp.EncodeToBytes(tx); err != nil {
log.Error("Failed to encode transaction", "err", err)
} else {
hashes = append(hashes, hash)
txs = append(txs, encoded)
bytes += len(encoded)
}
}
return hashes, txs
}
Conclusion
- The
node
provide JSONRPC API to receive transaction from client side, and then put it into thetxpool
; - The
miner
extracts transctions fromtxpool
and executes them, and then seals the transactions into a pending block.