eth: rework tx fetcher to use O(1) ops + manage network requests
This commit is contained in:
parent
049e17116e
commit
9938d954c8
@ -18,7 +18,6 @@ package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
@ -53,6 +52,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrAlreadyKnown is returned if the transactions is already contained
|
||||
// within the pool.
|
||||
ErrAlreadyKnown = errors.New("already known")
|
||||
|
||||
// ErrInvalidSender is returned if the transaction contains an invalid signature.
|
||||
ErrInvalidSender = errors.New("invalid sender")
|
||||
|
||||
@ -579,7 +582,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||
if pool.all.Get(hash) != nil {
|
||||
log.Trace("Discarding already known transaction", "hash", hash)
|
||||
knownTxMeter.Mark(1)
|
||||
return false, fmt.Errorf("known transaction: %x", hash)
|
||||
return false, ErrAlreadyKnown
|
||||
}
|
||||
// If the transaction fails basic validation, discard it
|
||||
if err := pool.validateTx(tx, local); err != nil {
|
||||
@ -786,7 +789,7 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
|
||||
for i, tx := range txs {
|
||||
// If the transaction is known, pre-set the error slot
|
||||
if pool.all.Get(tx.Hash()) != nil {
|
||||
errs[i] = fmt.Errorf("known transaction: %x", tx.Hash())
|
||||
errs[i] = ErrAlreadyKnown
|
||||
knownTxMeter.Mark(1)
|
||||
continue
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -42,6 +43,26 @@ const (
|
||||
blockLimit = 64 // Maximum number of unique blocks a peer may have delivered
|
||||
)
|
||||
|
||||
var (
|
||||
blockAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/in", nil)
|
||||
blockAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/block/announces/out", nil)
|
||||
blockAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/drop", nil)
|
||||
blockAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/block/announces/dos", nil)
|
||||
|
||||
blockBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/in", nil)
|
||||
blockBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/block/broadcasts/out", nil)
|
||||
blockBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/drop", nil)
|
||||
blockBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/block/broadcasts/dos", nil)
|
||||
|
||||
headerFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/block/headers", nil)
|
||||
bodyFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/block/bodies", nil)
|
||||
|
||||
headerFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/headers/in", nil)
|
||||
headerFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/headers/out", nil)
|
||||
bodyFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/in", nil)
|
||||
bodyFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/out", nil)
|
||||
)
|
||||
|
||||
var (
|
||||
errTerminated = errors.New("terminated")
|
||||
)
|
||||
|
@ -1,54 +0,0 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Contains the metrics collected by the fetcher.
|
||||
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
blockAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/announces/in", nil)
|
||||
blockAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/block/announces/out", nil)
|
||||
blockAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/announces/drop", nil)
|
||||
blockAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/announces/dos", nil)
|
||||
|
||||
blockBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/broadcasts/in", nil)
|
||||
blockBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/block/broadcasts/out", nil)
|
||||
blockBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/broadcasts/drop", nil)
|
||||
blockBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/block/broadcasts/dos", nil)
|
||||
|
||||
headerFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/headers", nil)
|
||||
bodyFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/bodies", nil)
|
||||
|
||||
headerFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/headers/in", nil)
|
||||
headerFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/headers/out", nil)
|
||||
bodyFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/bodies/in", nil)
|
||||
bodyFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/bodies/out", nil)
|
||||
|
||||
txAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/transaction/announces/in", nil)
|
||||
txAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/transaction/announces/dos", nil)
|
||||
txAnnounceSkipMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/transaction/announces/skip", nil)
|
||||
txAnnounceUnderpriceMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/transaction/announces/underprice", nil)
|
||||
txBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/transaction/broadcasts/in", nil)
|
||||
txFetchOutMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/transaction/out", nil)
|
||||
txFetchSuccessMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/transaction/success", nil)
|
||||
txFetchTimeoutMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/transaction/timeout", nil)
|
||||
txFetchInvalidMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/transaction/invalid", nil)
|
||||
txFetchDurationTimer = metrics.NewRegisteredTimer("eth/fetcher/fetch/transaction/duration", nil)
|
||||
)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@ const (
|
||||
// The number is referenced from the size of tx pool.
|
||||
txChanSize = 4096
|
||||
|
||||
// minimim number of peers to broadcast new blocks to
|
||||
// minimim number of peers to broadcast entire blocks and transactions too.
|
||||
minBroadcastPeers = 4
|
||||
)
|
||||
|
||||
@ -192,7 +192,15 @@ func NewProtocolManager(config *params.ChainConfig, checkpoint *params.TrustedCh
|
||||
return n, err
|
||||
}
|
||||
manager.blockFetcher = fetcher.NewBlockFetcher(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, manager.removePeer)
|
||||
manager.txFetcher = fetcher.NewTxFetcher(txpool.Has, txpool.AddRemotes, manager.removePeer)
|
||||
|
||||
fetchTx := func(peer string, hashes []common.Hash) error {
|
||||
p := manager.peers.Peer(peer)
|
||||
if p == nil {
|
||||
return errors.New("unknown peer")
|
||||
}
|
||||
return p.RequestTxs(hashes)
|
||||
}
|
||||
manager.txFetcher = fetcher.NewTxFetcher(txpool.Has, txpool.AddRemotes, fetchTx)
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
@ -240,6 +248,8 @@ func (pm *ProtocolManager) removePeer(id string) {
|
||||
|
||||
// Unregister the peer from the downloader and Ethereum peer set
|
||||
pm.downloader.UnregisterPeer(id)
|
||||
pm.txFetcher.Drop(id)
|
||||
|
||||
if err := pm.peers.Unregister(id); err != nil {
|
||||
log.Error("Peer removal failed", "peer", id, "err", err)
|
||||
}
|
||||
@ -263,7 +273,7 @@ func (pm *ProtocolManager) Start(maxPeers int) {
|
||||
|
||||
// start sync handlers
|
||||
go pm.syncer()
|
||||
go pm.txsyncLoop()
|
||||
go pm.txsyncLoop64() // TODO(karalabe): Legacy initial tx echange, drop with eth/64.
|
||||
}
|
||||
|
||||
func (pm *ProtocolManager) Stop() {
|
||||
@ -292,7 +302,7 @@ func (pm *ProtocolManager) Stop() {
|
||||
}
|
||||
|
||||
func (pm *ProtocolManager) newPeer(pv int, p *p2p.Peer, rw p2p.MsgReadWriter, getPooledTx func(hash common.Hash) *types.Transaction) *peer {
|
||||
return newPeer(pv, p, newMeteredMsgWriter(rw), getPooledTx)
|
||||
return newPeer(pv, p, rw, getPooledTx)
|
||||
}
|
||||
|
||||
// handle is the callback invoked to manage the life cycle of an eth peer. When
|
||||
@ -316,9 +326,6 @@ func (pm *ProtocolManager) handle(p *peer) error {
|
||||
p.Log().Debug("Ethereum handshake failed", "err", err)
|
||||
return err
|
||||
}
|
||||
if rw, ok := p.rw.(*meteredMsgReadWriter); ok {
|
||||
rw.Init(p.version)
|
||||
}
|
||||
// Register the peer locally
|
||||
if err := pm.peers.Register(p); err != nil {
|
||||
p.Log().Error("Ethereum peer registration failed", "err", err)
|
||||
@ -740,20 +747,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
return errResp(ErrDecode, "msg %v: %v", msg, err)
|
||||
}
|
||||
// Schedule all the unknown hashes for retrieval
|
||||
var unknown []common.Hash
|
||||
for _, hash := range hashes {
|
||||
// Mark the hashes as present at the remote node
|
||||
p.MarkTransaction(hash)
|
||||
|
||||
// Filter duplicated transaction announcement.
|
||||
// Notably we only dedupliate announcement in txpool, check the rationale
|
||||
// behind in EIP https://github.com/ethereum/EIPs/pull/2464.
|
||||
if pm.txpool.Has(hash) {
|
||||
continue
|
||||
}
|
||||
unknown = append(unknown, hash)
|
||||
}
|
||||
pm.txFetcher.Notify(p.id, unknown, time.Now(), p.AsyncRequestTxs)
|
||||
pm.txFetcher.Notify(p.id, hashes)
|
||||
|
||||
case msg.Code == GetPooledTransactionsMsg && p.version >= eth65:
|
||||
// Decode the retrieval message
|
||||
@ -763,9 +760,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
}
|
||||
// Gather transactions until the fetch or network limits is reached
|
||||
var (
|
||||
hash common.Hash
|
||||
bytes int
|
||||
txs []rlp.RawValue
|
||||
hash common.Hash
|
||||
bytes int
|
||||
hashes []common.Hash
|
||||
txs []rlp.RawValue
|
||||
)
|
||||
for bytes < softResponseLimit {
|
||||
// Retrieve the hash of the next block
|
||||
@ -783,13 +781,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
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 p.SendTransactionRLP(txs)
|
||||
return p.SendPooledTransactionsRLP(hashes, txs)
|
||||
|
||||
case msg.Code == TxMsg:
|
||||
case msg.Code == TransactionMsg || (msg.Code == PooledTransactionsMsg && p.version >= eth65):
|
||||
// Transactions arrived, make sure we have a valid and fresh chain to handle them
|
||||
if atomic.LoadUint32(&pm.acceptTxs) == 0 {
|
||||
break
|
||||
@ -806,7 +805,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
}
|
||||
p.MarkTransaction(tx.Hash())
|
||||
}
|
||||
pm.txFetcher.EnqueueTxs(p.id, txs)
|
||||
pm.txFetcher.Enqueue(p.id, txs, msg.Code == PooledTransactionsMsg)
|
||||
|
||||
default:
|
||||
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
|
||||
@ -854,9 +853,9 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// BroadcastTxs will propagate a batch of transactions to all peers which are not known to
|
||||
// BroadcastTransactions 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, propagate bool) {
|
||||
func (pm *ProtocolManager) BroadcastTransactions(txs types.Transactions, propagate bool) {
|
||||
var (
|
||||
txset = make(map[*peer][]common.Hash)
|
||||
annos = make(map[*peer][]common.Hash)
|
||||
@ -894,7 +893,7 @@ func (pm *ProtocolManager) BroadcastTxs(txs types.Transactions, propagate bool)
|
||||
}
|
||||
for peer, hashes := range annos {
|
||||
if peer.version >= eth65 {
|
||||
peer.AsyncSendTransactionHashes(hashes)
|
||||
peer.AsyncSendPooledTransactionHashes(hashes)
|
||||
} else {
|
||||
peer.AsyncSendTransactions(hashes)
|
||||
}
|
||||
@ -918,11 +917,11 @@ func (pm *ProtocolManager) txBroadcastLoop() {
|
||||
case event := <-pm.txsCh:
|
||||
// For testing purpose only, disable propagation
|
||||
if pm.broadcastTxAnnouncesOnly {
|
||||
pm.BroadcastTxs(event.Txs, false)
|
||||
pm.BroadcastTransactions(event.Txs, false)
|
||||
continue
|
||||
}
|
||||
pm.BroadcastTxs(event.Txs, true) // First propagate transactions to peers
|
||||
pm.BroadcastTxs(event.Txs, false) // Only then announce to the rest
|
||||
pm.BroadcastTransactions(event.Txs, true) // First propagate transactions to peers
|
||||
pm.BroadcastTransactions(event.Txs, false) // Only then announce to the rest
|
||||
|
||||
// Err() channel will be closed when unsubscribing.
|
||||
case <-pm.txsSub.Err():
|
||||
|
139
eth/metrics.go
139
eth/metrics.go
@ -1,139 +0,0 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package eth
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
)
|
||||
|
||||
var (
|
||||
propTxnInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/txns/in/packets", nil)
|
||||
propTxnInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/txns/in/traffic", nil)
|
||||
propTxnOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/txns/out/packets", nil)
|
||||
propTxnOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/txns/out/traffic", nil)
|
||||
propHashInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/hashes/in/packets", nil)
|
||||
propHashInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/hashes/in/traffic", nil)
|
||||
propHashOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/hashes/out/packets", nil)
|
||||
propHashOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/hashes/out/traffic", nil)
|
||||
propBlockInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/blocks/in/packets", nil)
|
||||
propBlockInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/blocks/in/traffic", nil)
|
||||
propBlockOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/blocks/out/packets", nil)
|
||||
propBlockOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/blocks/out/traffic", nil)
|
||||
reqHeaderInPacketsMeter = metrics.NewRegisteredMeter("eth/req/headers/in/packets", nil)
|
||||
reqHeaderInTrafficMeter = metrics.NewRegisteredMeter("eth/req/headers/in/traffic", nil)
|
||||
reqHeaderOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/headers/out/packets", nil)
|
||||
reqHeaderOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/headers/out/traffic", nil)
|
||||
reqBodyInPacketsMeter = metrics.NewRegisteredMeter("eth/req/bodies/in/packets", nil)
|
||||
reqBodyInTrafficMeter = metrics.NewRegisteredMeter("eth/req/bodies/in/traffic", nil)
|
||||
reqBodyOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/bodies/out/packets", nil)
|
||||
reqBodyOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/bodies/out/traffic", nil)
|
||||
reqStateInPacketsMeter = metrics.NewRegisteredMeter("eth/req/states/in/packets", nil)
|
||||
reqStateInTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/in/traffic", nil)
|
||||
reqStateOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/states/out/packets", nil)
|
||||
reqStateOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/out/traffic", nil)
|
||||
reqReceiptInPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/packets", nil)
|
||||
reqReceiptInTrafficMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/traffic", nil)
|
||||
reqReceiptOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/out/packets", nil)
|
||||
reqReceiptOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/receipts/out/traffic", nil)
|
||||
miscInPacketsMeter = metrics.NewRegisteredMeter("eth/misc/in/packets", nil)
|
||||
miscInTrafficMeter = metrics.NewRegisteredMeter("eth/misc/in/traffic", nil)
|
||||
miscOutPacketsMeter = metrics.NewRegisteredMeter("eth/misc/out/packets", nil)
|
||||
miscOutTrafficMeter = metrics.NewRegisteredMeter("eth/misc/out/traffic", nil)
|
||||
)
|
||||
|
||||
// meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of
|
||||
// accumulating the above defined metrics based on the data stream contents.
|
||||
type meteredMsgReadWriter struct {
|
||||
p2p.MsgReadWriter // Wrapped message stream to meter
|
||||
version int // Protocol version to select correct meters
|
||||
}
|
||||
|
||||
// newMeteredMsgWriter wraps a p2p MsgReadWriter with metering support. If the
|
||||
// metrics system is disabled, this function returns the original object.
|
||||
func newMeteredMsgWriter(rw p2p.MsgReadWriter) p2p.MsgReadWriter {
|
||||
if !metrics.Enabled {
|
||||
return rw
|
||||
}
|
||||
return &meteredMsgReadWriter{MsgReadWriter: rw}
|
||||
}
|
||||
|
||||
// Init sets the protocol version used by the stream to know which meters to
|
||||
// increment in case of overlapping message ids between protocol versions.
|
||||
func (rw *meteredMsgReadWriter) Init(version int) {
|
||||
rw.version = version
|
||||
}
|
||||
|
||||
func (rw *meteredMsgReadWriter) ReadMsg() (p2p.Msg, error) {
|
||||
// Read the message and short circuit in case of an error
|
||||
msg, err := rw.MsgReadWriter.ReadMsg()
|
||||
if err != nil {
|
||||
return msg, err
|
||||
}
|
||||
// Account for the data traffic
|
||||
packets, traffic := miscInPacketsMeter, miscInTrafficMeter
|
||||
switch {
|
||||
case msg.Code == BlockHeadersMsg:
|
||||
packets, traffic = reqHeaderInPacketsMeter, reqHeaderInTrafficMeter
|
||||
case msg.Code == BlockBodiesMsg:
|
||||
packets, traffic = reqBodyInPacketsMeter, reqBodyInTrafficMeter
|
||||
|
||||
case rw.version >= eth63 && msg.Code == NodeDataMsg:
|
||||
packets, traffic = reqStateInPacketsMeter, reqStateInTrafficMeter
|
||||
case rw.version >= eth63 && msg.Code == ReceiptsMsg:
|
||||
packets, traffic = reqReceiptInPacketsMeter, reqReceiptInTrafficMeter
|
||||
|
||||
case msg.Code == NewBlockHashesMsg:
|
||||
packets, traffic = propHashInPacketsMeter, propHashInTrafficMeter
|
||||
case msg.Code == NewBlockMsg:
|
||||
packets, traffic = propBlockInPacketsMeter, propBlockInTrafficMeter
|
||||
case msg.Code == TxMsg:
|
||||
packets, traffic = propTxnInPacketsMeter, propTxnInTrafficMeter
|
||||
}
|
||||
packets.Mark(1)
|
||||
traffic.Mark(int64(msg.Size))
|
||||
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (rw *meteredMsgReadWriter) WriteMsg(msg p2p.Msg) error {
|
||||
// Account for the data traffic
|
||||
packets, traffic := miscOutPacketsMeter, miscOutTrafficMeter
|
||||
switch {
|
||||
case msg.Code == BlockHeadersMsg:
|
||||
packets, traffic = reqHeaderOutPacketsMeter, reqHeaderOutTrafficMeter
|
||||
case msg.Code == BlockBodiesMsg:
|
||||
packets, traffic = reqBodyOutPacketsMeter, reqBodyOutTrafficMeter
|
||||
|
||||
case rw.version >= eth63 && msg.Code == NodeDataMsg:
|
||||
packets, traffic = reqStateOutPacketsMeter, reqStateOutTrafficMeter
|
||||
case rw.version >= eth63 && msg.Code == ReceiptsMsg:
|
||||
packets, traffic = reqReceiptOutPacketsMeter, reqReceiptOutTrafficMeter
|
||||
|
||||
case msg.Code == NewBlockHashesMsg:
|
||||
packets, traffic = propHashOutPacketsMeter, propHashOutTrafficMeter
|
||||
case msg.Code == NewBlockMsg:
|
||||
packets, traffic = propBlockOutPacketsMeter, propBlockOutTrafficMeter
|
||||
case msg.Code == TxMsg:
|
||||
packets, traffic = propTxnOutPacketsMeter, propTxnOutTrafficMeter
|
||||
}
|
||||
packets.Mark(1)
|
||||
traffic.Mark(int64(msg.Size))
|
||||
|
||||
// Send the packet to the p2p layer
|
||||
return rw.MsgReadWriter.WriteMsg(msg)
|
||||
}
|
318
eth/peer.go
318
eth/peer.go
@ -27,7 +27,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/forkid"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/fetcher"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
@ -43,17 +42,13 @@ const (
|
||||
maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS)
|
||||
|
||||
// maxQueuedTxs is the maximum number of transactions to queue up before dropping
|
||||
// broadcasts.
|
||||
// older broadcasts.
|
||||
maxQueuedTxs = 4096
|
||||
|
||||
// maxQueuedTxAnns is the maximum number of transaction announcements to queue up
|
||||
// before dropping broadcasts.
|
||||
// before dropping older announcements.
|
||||
maxQueuedTxAnns = 4096
|
||||
|
||||
// maxQueuedTxRetrieval is the maximum number of tx retrieval requests to queue up
|
||||
// before dropping requests.
|
||||
maxQueuedTxRetrieval = 4096
|
||||
|
||||
// maxQueuedBlocks is the maximum number of block propagations to queue up before
|
||||
// dropping broadcasts. There's not much point in queueing stale blocks, so a few
|
||||
// that might cover uncles should be enough.
|
||||
@ -102,15 +97,16 @@ type peer struct {
|
||||
td *big.Int
|
||||
lock sync.RWMutex
|
||||
|
||||
knownTxs mapset.Set // Set of transaction hashes known to be known by this peer
|
||||
knownBlocks mapset.Set // Set of block hashes known to be known by this peer
|
||||
queuedBlocks chan *propEvent // Queue of blocks to broadcast to the peer
|
||||
queuedBlockAnns chan *types.Block // Queue of blocks to announce to the peer
|
||||
txPropagation chan []common.Hash // Channel used to queue transaction propagation requests
|
||||
txAnnounce chan []common.Hash // Channel used to queue transaction announcement requests
|
||||
txRetrieval chan []common.Hash // Channel used to queue transaction retrieval requests
|
||||
getPooledTx func(common.Hash) *types.Transaction // Callback used to retrieve transaction from txpool
|
||||
term chan struct{} // Termination channel to stop the broadcaster
|
||||
knownBlocks mapset.Set // Set of block hashes known to be known by this peer
|
||||
queuedBlocks chan *propEvent // Queue of blocks to broadcast to the peer
|
||||
queuedBlockAnns chan *types.Block // Queue of blocks to announce to the peer
|
||||
|
||||
knownTxs mapset.Set // Set of transaction hashes known to be known by this peer
|
||||
txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests
|
||||
txAnnounce chan []common.Hash // Channel used to queue transaction announcement requests
|
||||
getPooledTx func(common.Hash) *types.Transaction // Callback used to retrieve transaction from txpool
|
||||
|
||||
term chan struct{} // Termination channel to stop the broadcaster
|
||||
}
|
||||
|
||||
func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter, getPooledTx func(hash common.Hash) *types.Transaction) *peer {
|
||||
@ -123,17 +119,16 @@ func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter, getPooledTx func(ha
|
||||
knownBlocks: mapset.NewSet(),
|
||||
queuedBlocks: make(chan *propEvent, maxQueuedBlocks),
|
||||
queuedBlockAnns: make(chan *types.Block, maxQueuedBlockAnns),
|
||||
txPropagation: make(chan []common.Hash),
|
||||
txBroadcast: make(chan []common.Hash),
|
||||
txAnnounce: make(chan []common.Hash),
|
||||
txRetrieval: make(chan []common.Hash),
|
||||
getPooledTx: getPooledTx,
|
||||
term: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// broadcastBlocks is a write loop that multiplexes block propagations,
|
||||
// announcements into the remote peer. The goal is to have an async writer
|
||||
// that does not lock up node internals.
|
||||
// broadcastBlocks is a write loop that multiplexes blocks and block accouncements
|
||||
// to the remote peer. The goal is to have an async writer that does not lock up
|
||||
// node internals and at the same time rate limits queued data.
|
||||
func (p *peer) broadcastBlocks() {
|
||||
for {
|
||||
select {
|
||||
@ -155,105 +150,60 @@ func (p *peer) broadcastBlocks() {
|
||||
}
|
||||
}
|
||||
|
||||
// broadcastTxs is a write loop that multiplexes transaction propagations,
|
||||
// announcements into the remote peer. The goal is to have an async writer
|
||||
// that does not lock up node internals.
|
||||
func (p *peer) broadcastTxs() {
|
||||
// broadcastTransactions is a write loop that schedules transaction broadcasts
|
||||
// to the remote peer. The goal is to have an async writer that does not lock up
|
||||
// node internals and at the same time rate limits queued data.
|
||||
func (p *peer) broadcastTransactions() {
|
||||
var (
|
||||
txProps []common.Hash // Queue of transaction propagations to the peer
|
||||
txAnnos []common.Hash // Queue of transaction announcements to the peer
|
||||
done chan struct{} // Non-nil if background network sender routine is active.
|
||||
errch = make(chan error) // Channel used to receive network error
|
||||
queue []common.Hash // Queue of hashes to broadcast as full transactions
|
||||
done chan struct{} // Non-nil if background broadcaster is running
|
||||
fail = make(chan error) // Channel used to receive network error
|
||||
)
|
||||
scheduleTask := func() {
|
||||
// Short circuit if there already has a inflight task.
|
||||
if done != nil {
|
||||
return
|
||||
}
|
||||
// Spin up transaction propagation task if there is any
|
||||
// queued hashes.
|
||||
if len(txProps) > 0 {
|
||||
for {
|
||||
// If there's no in-flight broadcast running, check if a new one is needed
|
||||
if done == nil && len(queue) > 0 {
|
||||
// Pile transaction until we reach our allowed network limit
|
||||
var (
|
||||
hashes []common.Hash
|
||||
txs []*types.Transaction
|
||||
size common.StorageSize
|
||||
)
|
||||
for i := 0; i < len(txProps) && size < txsyncPackSize; i++ {
|
||||
if tx := p.getPooledTx(txProps[i]); tx != nil {
|
||||
for i := 0; i < len(queue) && size < txsyncPackSize; i++ {
|
||||
if tx := p.getPooledTx(queue[i]); tx != nil {
|
||||
txs = append(txs, tx)
|
||||
size += tx.Size()
|
||||
}
|
||||
hashes = append(hashes, txProps[i])
|
||||
hashes = append(hashes, queue[i])
|
||||
}
|
||||
txProps = txProps[:copy(txProps, txProps[len(hashes):])]
|
||||
queue = queue[:copy(queue, queue[len(hashes):])]
|
||||
|
||||
// If there's anything available to transfer, fire up an async writer
|
||||
if len(txs) > 0 {
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
if err := p.SendNewTransactions(txs); err != nil {
|
||||
errch <- err
|
||||
if err := p.sendTransactions(txs); err != nil {
|
||||
fail <- err
|
||||
return
|
||||
}
|
||||
close(done)
|
||||
p.Log().Trace("Sent transactions", "count", len(txs))
|
||||
}()
|
||||
return
|
||||
}
|
||||
}
|
||||
// Spin up transaction announcement task if there is any
|
||||
// queued hashes.
|
||||
if len(txAnnos) > 0 {
|
||||
var (
|
||||
hashes []common.Hash
|
||||
pending []common.Hash
|
||||
size common.StorageSize
|
||||
)
|
||||
for i := 0; i < len(txAnnos) && size < txsyncPackSize; i++ {
|
||||
if tx := p.getPooledTx(txAnnos[i]); tx != nil {
|
||||
pending = append(pending, txAnnos[i])
|
||||
size += common.HashLength
|
||||
}
|
||||
hashes = append(hashes, txAnnos[i])
|
||||
}
|
||||
txAnnos = txAnnos[:copy(txAnnos, txAnnos[len(hashes):])]
|
||||
if len(pending) > 0 {
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
if err := p.SendNewTransactionHashes(pending); err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
close(done)
|
||||
p.Log().Trace("Sent transaction announcements", "count", len(pending))
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
scheduleTask()
|
||||
// Transfer goroutine may or may not have been started, listen for events
|
||||
select {
|
||||
case hashes := <-p.txPropagation:
|
||||
if len(txProps) == maxQueuedTxs {
|
||||
continue
|
||||
case hashes := <-p.txBroadcast:
|
||||
// New batch of transactions to be broadcast, queue them (with cap)
|
||||
queue = append(queue, hashes...)
|
||||
if len(queue) > maxQueuedTxs {
|
||||
// Fancy copy and resize to ensure buffer doesn't grow indefinitely
|
||||
queue = queue[:copy(queue, queue[len(queue)-maxQueuedTxs:])]
|
||||
}
|
||||
if len(txProps)+len(hashes) > maxQueuedTxs {
|
||||
hashes = hashes[:maxQueuedTxs-len(txProps)]
|
||||
}
|
||||
txProps = append(txProps, hashes...)
|
||||
|
||||
case hashes := <-p.txAnnounce:
|
||||
if len(txAnnos) == maxQueuedTxAnns {
|
||||
continue
|
||||
}
|
||||
if len(txAnnos)+len(hashes) > maxQueuedTxAnns {
|
||||
hashes = hashes[:maxQueuedTxAnns-len(txAnnos)]
|
||||
}
|
||||
txAnnos = append(txAnnos, hashes...)
|
||||
|
||||
case <-done:
|
||||
done = nil
|
||||
|
||||
case <-errch:
|
||||
case <-fail:
|
||||
return
|
||||
|
||||
case <-p.term:
|
||||
@ -262,60 +212,60 @@ func (p *peer) broadcastTxs() {
|
||||
}
|
||||
}
|
||||
|
||||
// retrievalTxs is a write loop which is responsible for retrieving transaction
|
||||
// from the remote peer. The goal is to have an async writer that does not lock
|
||||
// up node internals. If there are too many requests queued, then new arrival
|
||||
// requests will be dropped silently so that we can ensure the memory assumption
|
||||
// is fixed for each peer.
|
||||
func (p *peer) retrievalTxs() {
|
||||
// announceTransactions is a write loop that schedules transaction broadcasts
|
||||
// to the remote peer. The goal is to have an async writer that does not lock up
|
||||
// node internals and at the same time rate limits queued data.
|
||||
func (p *peer) announceTransactions() {
|
||||
var (
|
||||
requests []common.Hash // Queue of transaction requests to the peer
|
||||
done chan struct{} // Non-nil if background network sender routine is active.
|
||||
errch = make(chan error) // Channel used to receive network error
|
||||
queue []common.Hash // Queue of hashes to announce as transaction stubs
|
||||
done chan struct{} // Non-nil if background announcer is running
|
||||
fail = make(chan error) // Channel used to receive network error
|
||||
)
|
||||
// pick chooses a reasonble number of transaction hashes for retrieval.
|
||||
pick := func() []common.Hash {
|
||||
var ret []common.Hash
|
||||
if len(requests) > fetcher.MaxTransactionFetch {
|
||||
ret = requests[:fetcher.MaxTransactionFetch]
|
||||
} else {
|
||||
ret = requests[:]
|
||||
}
|
||||
requests = requests[:copy(requests, requests[len(ret):])]
|
||||
return ret
|
||||
}
|
||||
// send sends transactions retrieval request.
|
||||
send := func(hashes []common.Hash, done chan struct{}) {
|
||||
if err := p.RequestTxs(hashes); err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
close(done)
|
||||
p.Log().Trace("Sent transaction retrieval request", "count", len(hashes))
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case hashes := <-p.txRetrieval:
|
||||
if len(requests) == maxQueuedTxRetrieval {
|
||||
continue
|
||||
// If there's no in-flight announce running, check if a new one is needed
|
||||
if done == nil && len(queue) > 0 {
|
||||
// Pile transaction hashes until we reach our allowed network limit
|
||||
var (
|
||||
hashes []common.Hash
|
||||
pending []common.Hash
|
||||
size common.StorageSize
|
||||
)
|
||||
for i := 0; i < len(queue) && size < txsyncPackSize; i++ {
|
||||
if p.getPooledTx(queue[i]) != nil {
|
||||
pending = append(pending, queue[i])
|
||||
size += common.HashLength
|
||||
}
|
||||
hashes = append(hashes, queue[i])
|
||||
}
|
||||
if len(requests)+len(hashes) > maxQueuedTxRetrieval {
|
||||
hashes = hashes[:maxQueuedTxRetrieval-len(requests)]
|
||||
}
|
||||
requests = append(requests, hashes...)
|
||||
if done == nil {
|
||||
queue = queue[:copy(queue, queue[len(hashes):])]
|
||||
|
||||
// If there's anything available to transfer, fire up an async writer
|
||||
if len(pending) > 0 {
|
||||
done = make(chan struct{})
|
||||
go send(pick(), done)
|
||||
go func() {
|
||||
if err := p.sendPooledTransactionHashes(pending); err != nil {
|
||||
fail <- err
|
||||
return
|
||||
}
|
||||
close(done)
|
||||
p.Log().Trace("Sent transaction announcements", "count", len(pending))
|
||||
}()
|
||||
}
|
||||
}
|
||||
// Transfer goroutine may or may not have been started, listen for events
|
||||
select {
|
||||
case hashes := <-p.txAnnounce:
|
||||
// New batch of transactions to be broadcast, queue them (with cap)
|
||||
queue = append(queue, hashes...)
|
||||
if len(queue) > maxQueuedTxAnns {
|
||||
// Fancy copy and resize to ensure buffer doesn't grow indefinitely
|
||||
queue = queue[:copy(queue, queue[len(queue)-maxQueuedTxs:])]
|
||||
}
|
||||
|
||||
case <-done:
|
||||
done = nil
|
||||
if pending := pick(); len(pending) > 0 {
|
||||
done = make(chan struct{})
|
||||
go send(pending, done)
|
||||
}
|
||||
|
||||
case <- errch:
|
||||
case <-fail:
|
||||
return
|
||||
|
||||
case <-p.term:
|
||||
@ -379,22 +329,22 @@ func (p *peer) MarkTransaction(hash common.Hash) {
|
||||
p.knownTxs.Add(hash)
|
||||
}
|
||||
|
||||
// SendNewTransactionHashes sends a batch of transaction hashes to the peer and
|
||||
// includes the hashes in its transaction hash set for future reference.
|
||||
func (p *peer) SendNewTransactionHashes(hashes []common.Hash) error {
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) {
|
||||
p.knownTxs.Pop()
|
||||
}
|
||||
for _, hash := range hashes {
|
||||
p.knownTxs.Add(hash)
|
||||
}
|
||||
return p2p.Send(p.rw, NewPooledTransactionHashesMsg, hashes)
|
||||
// SendTransactions64 sends transactions to the peer and includes the hashes
|
||||
// in its transaction hash set for future reference.
|
||||
//
|
||||
// This method is legacy support for initial transaction exchange in eth/64 and
|
||||
// prior. For eth/65 and higher use SendPooledTransactionHashes.
|
||||
func (p *peer) SendTransactions64(txs types.Transactions) error {
|
||||
return p.sendTransactions(txs)
|
||||
}
|
||||
|
||||
// SendNewTransactions sends transactions to the peer and includes the hashes
|
||||
// sendTransactions sends transactions to the peer and includes the hashes
|
||||
// in its transaction hash set for future reference.
|
||||
func (p *peer) SendNewTransactions(txs types.Transactions) error {
|
||||
//
|
||||
// This method is a helper used by the async transaction sender. Don't call it
|
||||
// directly as the queueing (memory) and transmission (bandwidth) costs should
|
||||
// not be managed directly.
|
||||
func (p *peer) sendTransactions(txs types.Transactions) error {
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(txs)) {
|
||||
p.knownTxs.Pop()
|
||||
@ -402,18 +352,15 @@ func (p *peer) SendNewTransactions(txs types.Transactions) error {
|
||||
for _, tx := range txs {
|
||||
p.knownTxs.Add(tx.Hash())
|
||||
}
|
||||
return p2p.Send(p.rw, TxMsg, txs)
|
||||
return p2p.Send(p.rw, TransactionMsg, txs)
|
||||
}
|
||||
|
||||
func (p *peer) SendTransactionRLP(txs []rlp.RawValue) error {
|
||||
return p2p.Send(p.rw, TxMsg, txs)
|
||||
}
|
||||
|
||||
// AsyncSendTransactions queues list of transactions propagation to a remote
|
||||
// peer. If the peer's broadcast queue is full, the event is silently dropped.
|
||||
// AsyncSendTransactions queues a list of transactions (by hash) to eventually
|
||||
// propagate to a remote peer. The number of pending sends are capped (new ones
|
||||
// will force old sends to be dropped)
|
||||
func (p *peer) AsyncSendTransactions(hashes []common.Hash) {
|
||||
select {
|
||||
case p.txPropagation <- hashes:
|
||||
case p.txBroadcast <- hashes:
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) {
|
||||
p.knownTxs.Pop()
|
||||
@ -426,9 +373,27 @@ func (p *peer) AsyncSendTransactions(hashes []common.Hash) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) AsyncSendTransactionHashes(hashes []common.Hash) {
|
||||
// sendPooledTransactionHashes sends transaction hashes to the peer and includes
|
||||
// them in its transaction hash set for future reference.
|
||||
//
|
||||
// This method is a helper used by the async transaction announcer. Don't call it
|
||||
// directly as the queueing (memory) and transmission (bandwidth) costs should
|
||||
// not be managed directly.
|
||||
func (p *peer) sendPooledTransactionHashes(hashes []common.Hash) error {
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) {
|
||||
p.knownTxs.Pop()
|
||||
}
|
||||
for _, hash := range hashes {
|
||||
p.knownTxs.Add(hash)
|
||||
}
|
||||
return p2p.Send(p.rw, NewPooledTransactionHashesMsg, hashes)
|
||||
}
|
||||
|
||||
// AsyncSendPooledTransactionHashes queues a list of transactions hashes to eventually
|
||||
// announce to a remote peer. The number of pending sends are capped (new ones
|
||||
// will force old sends to be dropped)
|
||||
func (p *peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) {
|
||||
select {
|
||||
case p.txAnnounce <- hashes:
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
@ -443,6 +408,22 @@ func (p *peer) AsyncSendTransactionHashes(hashes []common.Hash) {
|
||||
}
|
||||
}
|
||||
|
||||
// SendPooledTransactionsRLP sends requested transactions to the peer and adds the
|
||||
// hashes in its transaction hash set for future reference.
|
||||
//
|
||||
// Note, the method assumes the hashes are correct and correspond to the list of
|
||||
// transactions being sent.
|
||||
func (p *peer) SendPooledTransactionsRLP(hashes []common.Hash, txs []rlp.RawValue) error {
|
||||
// Mark all the transactions as known, but ensure we don't overflow our limits
|
||||
for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) {
|
||||
p.knownTxs.Pop()
|
||||
}
|
||||
for _, hash := range hashes {
|
||||
p.knownTxs.Add(hash)
|
||||
}
|
||||
return p2p.Send(p.rw, PooledTransactionsMsg, txs)
|
||||
}
|
||||
|
||||
// SendNewBlockHashes announces the availability of a number of blocks through
|
||||
// a hash notification.
|
||||
func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error {
|
||||
@ -577,16 +558,6 @@ func (p *peer) RequestTxs(hashes []common.Hash) error {
|
||||
return p2p.Send(p.rw, GetPooledTransactionsMsg, hashes)
|
||||
}
|
||||
|
||||
// AsyncRequestTxs queues a tx retrieval request to a remote peer. If
|
||||
// the peer's retrieval queue is full, the event is silently dropped.
|
||||
func (p *peer) AsyncRequestTxs(hashes []common.Hash) {
|
||||
select {
|
||||
case p.txRetrieval <- hashes:
|
||||
case <-p.term:
|
||||
p.Log().Debug("Dropping transaction retrieval request", "count", len(hashes))
|
||||
}
|
||||
}
|
||||
|
||||
// Handshake executes the eth protocol handshake, negotiating version number,
|
||||
// network IDs, difficulties, head and genesis blocks.
|
||||
func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error {
|
||||
@ -746,9 +717,10 @@ func (ps *peerSet) Register(p *peer) error {
|
||||
return errAlreadyRegistered
|
||||
}
|
||||
ps.peers[p.id] = p
|
||||
|
||||
go p.broadcastBlocks()
|
||||
go p.broadcastTxs()
|
||||
go p.retrievalTxs()
|
||||
go p.broadcastTransactions()
|
||||
go p.announceTransactions()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ const protocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a prot
|
||||
const (
|
||||
StatusMsg = 0x00
|
||||
NewBlockHashesMsg = 0x01
|
||||
TxMsg = 0x02
|
||||
TransactionMsg = 0x02
|
||||
GetBlockHeadersMsg = 0x03
|
||||
BlockHeadersMsg = 0x04
|
||||
GetBlockBodiesMsg = 0x05
|
||||
@ -64,10 +64,11 @@ const (
|
||||
|
||||
// New protocol message codes introduced in eth65
|
||||
//
|
||||
// Previously these message ids(0x08, 0x09) were used by some
|
||||
// legacy and unsupported eth protocols, reown them here.
|
||||
// Previously these message ids were used by some legacy and unsupported
|
||||
// eth protocols, reown them here.
|
||||
NewPooledTransactionHashesMsg = 0x08
|
||||
GetPooledTransactionsMsg = 0x09
|
||||
PooledTransactionsMsg = 0x0a
|
||||
)
|
||||
|
||||
type errCode int
|
||||
|
@ -62,7 +62,7 @@ func TestStatusMsgErrors63(t *testing.T) {
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
code: TxMsg, data: []interface{}{},
|
||||
code: TransactionMsg, data: []interface{}{},
|
||||
wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"),
|
||||
},
|
||||
{
|
||||
@ -114,7 +114,7 @@ func TestStatusMsgErrors64(t *testing.T) {
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
code: TxMsg, data: []interface{}{},
|
||||
code: TransactionMsg, data: []interface{}{},
|
||||
wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"),
|
||||
},
|
||||
{
|
||||
@ -258,7 +258,7 @@ func testRecvTransactions(t *testing.T, protocol int) {
|
||||
defer p.close()
|
||||
|
||||
tx := newTestTransaction(testAccount, 0, 0)
|
||||
if err := p2p.Send(p.app, TxMsg, []interface{}{tx}); err != nil {
|
||||
if err := p2p.Send(p.app, TransactionMsg, []interface{}{tx}); err != nil {
|
||||
t.Fatalf("send error: %v", err)
|
||||
}
|
||||
select {
|
||||
@ -282,13 +282,16 @@ func testSendTransactions(t *testing.T, protocol int) {
|
||||
pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil)
|
||||
defer pm.Stop()
|
||||
|
||||
// Fill the pool with big transactions.
|
||||
// Fill the pool with big transactions (use a subscription to wait until all
|
||||
// the transactions are announced to avoid spurious events causing extra
|
||||
// broadcasts).
|
||||
const txsize = txsyncPackSize / 10
|
||||
alltxs := make([]*types.Transaction, 100)
|
||||
for nonce := range alltxs {
|
||||
alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), txsize)
|
||||
}
|
||||
pm.txpool.AddRemotes(alltxs)
|
||||
time.Sleep(100 * time.Millisecond) // Wait until new tx even gets out of the system (lame)
|
||||
|
||||
// Connect several peers. They should all receive the pending transactions.
|
||||
var wg sync.WaitGroup
|
||||
@ -300,8 +303,6 @@ func testSendTransactions(t *testing.T, protocol int) {
|
||||
seen[tx.Hash()] = false
|
||||
}
|
||||
for n := 0; n < len(alltxs) && !t.Failed(); {
|
||||
var txs []*types.Transaction
|
||||
var hashes []common.Hash
|
||||
var forAllHashes func(callback func(hash common.Hash))
|
||||
switch protocol {
|
||||
case 63:
|
||||
@ -310,11 +311,15 @@ func testSendTransactions(t *testing.T, protocol int) {
|
||||
msg, err := p.app.ReadMsg()
|
||||
if err != nil {
|
||||
t.Errorf("%v: read error: %v", p.Peer, err)
|
||||
} else if msg.Code != TxMsg {
|
||||
continue
|
||||
} else if msg.Code != TransactionMsg {
|
||||
t.Errorf("%v: got code %d, want TxMsg", p.Peer, msg.Code)
|
||||
continue
|
||||
}
|
||||
var txs []*types.Transaction
|
||||
if err := msg.Decode(&txs); err != nil {
|
||||
t.Errorf("%v: %v", p.Peer, err)
|
||||
continue
|
||||
}
|
||||
forAllHashes = func(callback func(hash common.Hash)) {
|
||||
for _, tx := range txs {
|
||||
@ -325,11 +330,15 @@ func testSendTransactions(t *testing.T, protocol int) {
|
||||
msg, err := p.app.ReadMsg()
|
||||
if err != nil {
|
||||
t.Errorf("%v: read error: %v", p.Peer, err)
|
||||
continue
|
||||
} else if msg.Code != NewPooledTransactionHashesMsg {
|
||||
t.Errorf("%v: got code %d, want TxMsg", p.Peer, msg.Code)
|
||||
t.Errorf("%v: got code %d, want NewPooledTransactionHashesMsg", p.Peer, msg.Code)
|
||||
continue
|
||||
}
|
||||
var hashes []common.Hash
|
||||
if err := msg.Decode(&hashes); err != nil {
|
||||
t.Errorf("%v: %v", p.Peer, err)
|
||||
continue
|
||||
}
|
||||
forAllHashes = func(callback func(hash common.Hash)) {
|
||||
for _, h := range hashes {
|
||||
|
75
eth/sync.go
75
eth/sync.go
@ -38,13 +38,18 @@ const (
|
||||
)
|
||||
|
||||
type txsync struct {
|
||||
p *peer
|
||||
hashes []common.Hash
|
||||
txs []*types.Transaction
|
||||
p *peer
|
||||
txs []*types.Transaction
|
||||
}
|
||||
|
||||
// syncTransactions starts sending all currently pending transactions to the given peer.
|
||||
func (pm *ProtocolManager) syncTransactions(p *peer) {
|
||||
// Assemble the set of transaction to broadcast or announce to the remote
|
||||
// peer. Fun fact, this is quite an expensive operation as it needs to sort
|
||||
// the transactions if the sorting is not cached yet. However, with a random
|
||||
// order, insertions could overflow the non-executable queues and get dropped.
|
||||
//
|
||||
// TODO(karalabe): Figure out if we could get away with random order somehow
|
||||
var txs types.Transactions
|
||||
pending, _ := pm.txpool.Pending()
|
||||
for _, batch := range pending {
|
||||
@ -53,17 +58,29 @@ func (pm *ProtocolManager) syncTransactions(p *peer) {
|
||||
if len(txs) == 0 {
|
||||
return
|
||||
}
|
||||
// The eth/65 protocol introduces proper transaction announcements, so instead
|
||||
// of dripping transactions across multiple peers, just send the entire list as
|
||||
// an announcement and let the remote side decide what they need (likely nothing).
|
||||
if p.version >= eth65 {
|
||||
hashes := make([]common.Hash, len(txs))
|
||||
for i, tx := range txs {
|
||||
hashes[i] = tx.Hash()
|
||||
}
|
||||
p.AsyncSendPooledTransactionHashes(hashes)
|
||||
return
|
||||
}
|
||||
// Out of luck, peer is running legacy protocols, drop the txs over
|
||||
select {
|
||||
case pm.txsyncCh <- &txsync{p: p, txs: txs}:
|
||||
case <-pm.quitSync:
|
||||
}
|
||||
}
|
||||
|
||||
// txsyncLoop takes care of the initial transaction sync for each new
|
||||
// txsyncLoop64 takes care of the initial transaction sync for each new
|
||||
// connection. When a new peer appears, we relay all currently pending
|
||||
// transactions. In order to minimise egress bandwidth usage, we send
|
||||
// the transactions in small packs to one peer at a time.
|
||||
func (pm *ProtocolManager) txsyncLoop() {
|
||||
func (pm *ProtocolManager) txsyncLoop64() {
|
||||
var (
|
||||
pending = make(map[enode.ID]*txsync)
|
||||
sending = false // whether a send is active
|
||||
@ -72,44 +89,26 @@ func (pm *ProtocolManager) txsyncLoop() {
|
||||
)
|
||||
// send starts a sending a pack of transactions from the sync.
|
||||
send := func(s *txsync) {
|
||||
if s.p.version >= eth65 {
|
||||
panic("initial transaction syncer running on eth/65+")
|
||||
}
|
||||
// Fill pack with transactions up to the target size.
|
||||
size := common.StorageSize(0)
|
||||
pack.p = s.p
|
||||
pack.hashes = pack.hashes[:0]
|
||||
pack.txs = pack.txs[:0]
|
||||
if s.p.version >= eth65 {
|
||||
// Eth65 introduces transaction announcement https://github.com/ethereum/EIPs/pull/2464,
|
||||
// only txhashes are transferred here.
|
||||
for i := 0; i < len(s.txs) && size < txsyncPackSize; i++ {
|
||||
pack.hashes = append(pack.hashes, s.txs[i].Hash())
|
||||
size += common.HashLength
|
||||
}
|
||||
// Remove the transactions that will be sent.
|
||||
s.txs = s.txs[:copy(s.txs, s.txs[len(pack.hashes):])]
|
||||
if len(s.txs) == 0 {
|
||||
delete(pending, s.p.ID())
|
||||
}
|
||||
// Send the pack in the background.
|
||||
s.p.Log().Trace("Sending batch of transaction announcements", "count", len(pack.hashes), "bytes", size)
|
||||
sending = true
|
||||
go func() { done <- pack.p.SendNewTransactionHashes(pack.hashes) }()
|
||||
} else {
|
||||
// Legacy eth protocol doesn't have transaction announcement protocol
|
||||
// message, transfer the whole pending transaction slice.
|
||||
for i := 0; i < len(s.txs) && size < txsyncPackSize; i++ {
|
||||
pack.txs = append(pack.txs, s.txs[i])
|
||||
size += s.txs[i].Size()
|
||||
}
|
||||
// Remove the transactions that will be sent.
|
||||
s.txs = s.txs[:copy(s.txs, s.txs[len(pack.txs):])]
|
||||
if len(s.txs) == 0 {
|
||||
delete(pending, s.p.ID())
|
||||
}
|
||||
// Send the pack in the background.
|
||||
s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size)
|
||||
sending = true
|
||||
go func() { done <- pack.p.SendNewTransactions(pack.txs) }()
|
||||
for i := 0; i < len(s.txs) && size < txsyncPackSize; i++ {
|
||||
pack.txs = append(pack.txs, s.txs[i])
|
||||
size += s.txs[i].Size()
|
||||
}
|
||||
// Remove the transactions that will be sent.
|
||||
s.txs = s.txs[:copy(s.txs, s.txs[len(pack.txs):])]
|
||||
if len(s.txs) == 0 {
|
||||
delete(pending, s.p.ID())
|
||||
}
|
||||
// Send the pack in the background.
|
||||
s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size)
|
||||
sending = true
|
||||
go func() { done <- pack.p.SendTransactions64(pack.txs) }()
|
||||
}
|
||||
|
||||
// pick chooses the next pending sync.
|
||||
|
@ -26,6 +26,14 @@ targets:
|
||||
function: Fuzz
|
||||
package: github.com/ethereum/go-ethereum/tests/fuzzers/trie
|
||||
checkout: github.com/ethereum/go-ethereum/
|
||||
- name: txfetcher
|
||||
language: go
|
||||
version: "1.13"
|
||||
corpus: ./fuzzers/txfetcher/corpus
|
||||
harness:
|
||||
function: Fuzz
|
||||
package: github.com/ethereum/go-ethereum/tests/fuzzers/txfetcher
|
||||
checkout: github.com/ethereum/go-ethereum/
|
||||
- name: whisperv6
|
||||
language: go
|
||||
version: "1.13"
|
||||
|
@ -0,0 +1 @@
|
||||
ソス
|
Binary file not shown.
@ -0,0 +1,12 @@
|
||||
TESTING KEY-----
|
||||
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
|
||||
SjY1bIw4iAJm2gsvvZhIrCHS3l6afab4pZB
|
||||
l2+XsDlrKBxKKtDrGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTtqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tuV6ef6anZzus1s1Y1Clb6HbnWWF/wbZGOpet
|
||||
3m4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKZTXtdZrh+k7hx0nTP8Jcb
|
||||
uqFk541awmMogY/EfbWd6IOkp+4xqjlFBEDytgbIECQQDvH/6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz84SHEg1Ak/7KCxmD/sfgS5TeuNi8DoUBEmiSJwm7FX
|
||||
ftxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su43sjXNueLKH8+ph2UfQuU9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xl/DoCzjA0CQQDU
|
||||
y2pGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtI痂Ⅴ
|
||||
qUn3Xh9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JMhNRcVFMO8dDaFo
|
||||
f9Oeos0UotgiDktdQHxdNEwLjQlJBz+OtwwA=---E RATTIEY-
|
@ -0,0 +1,15 @@
|
||||
¸&^£áo‡È—-----BEGIN RSA TESTING KEY-----
|
||||
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
|
||||
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
|
||||
l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
|
||||
qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
|
||||
f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
|
||||
-----END RSA TESTING KEY-----Q_
|
@ -0,0 +1 @@
|
||||
π½apοΏοοοΏ½οΏ½οΏοΏΏ½½½ΏΏ½½οΏ½οΏ½Ώ½οΏοΏ½οΏοΣΜV½Ώ½οοοΏοΏ½#οΏοΏ½&οΏ½οΏ½
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,11 @@
|
||||
TAKBgDuLnQA3gey3VBznB39JUtxjeE6myuDkM/uGlfjb
|
||||
S1w4iA5sBzzh8uxEbi4nW91IJm2gsvvZhICHS3l6ab4pZB
|
||||
l2DulrKBxKKtD1rGxlG4LncabFn9vLZad2bSysqz/qTAUSTvqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Z4vMXc7jpTLryzTQIvVdfQbRc6+MUVeLKZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk54MogxEcfbWd6IOkp+4xqFLBEDtgbIECnk+hgN4H
|
||||
qzzxxr397vWrjrIgbJpQvBv8QeeuNi8DoUBEmiSJwa7FXY
|
||||
FUtxuvL7XvjwjN5B30pEbc6Iuyt7y4MQJBAIt21su4b3sjphy2tuUE9xblTu14qgHZ6+AiZovGKU--FfYAqVXVlxtIX
|
||||
qyU3X9ps8ZfjLZ45l6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
|
||||
f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
|
||||
-----END RSA T
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
<EFBFBD>&
|
@ -0,0 +1,3 @@
|
||||
DtQvfQ+MULKZTXk78c
|
||||
/fWkpxlQQ/+hgNzVtx9vWgJsafG7b0dA4AFjwVbFLmQcj2PprIMmPNQrooX
|
||||
L
|
Binary file not shown.
@ -0,0 +1,12 @@
|
||||
4txjeVE6myuDqkM/uGlfjb9
|
||||
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZeIrCHS3l6afab4pZB
|
||||
l2+XsDlrKBxKKtD1rGxlG4jncdabFn9gvLZad2bSysqz/qTAUSTvqJQIDAQAB
|
||||
AoGAGRzwwXvBOAy5tM/uV6e+Zf6aZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Z4vD6Mc7pLryzTQIVdfQbRc6+MUVeLKZaTXtdZru+Jk70PJJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+gN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQ2PprIMPcQroo8vpjSHg1Ev14KxmQeDydfsgeuN8UBESJwm7F
|
||||
UtuL7Xvjw50pNEbc6Iuyty4QJA21su4sjXNueLQphy2U
|
||||
fQtuUE9txblTu14qN7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6ARYiZPYj1oGUFfYAVVxtI
|
||||
qyBnu3X9pfLZOAkEAlT4R5Yl6cJQYZHOde3JEhNRcVFMO8dJFo
|
||||
f9Oeos0UUhgiDkQxdEwLjQf7lJJz5OtwC=
|
||||
-NRSA TESINGKEY-Q_
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,10 @@
|
||||
jXbnWWF/wbZGOpet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xl/DoCzjA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6Yj013sovGKUFfYAqVXVlxtIX
|
||||
qyUBnu3Xh9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dDaFeo
|
||||
f9Oeos0UotgiDktdQHxdNEwLjQfl
|
@ -0,0 +1,15 @@
|
||||
¸^áo‡È—----BEGIN RA TTING KEY-----
|
||||
IIXgIBAAKBQDuLnQI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
|
||||
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJmgsvvZhrCHSl6afab4pZB
|
||||
l2+XsDulrKBxKKtD1rGxlG4LjcdabF9gvLZad2bSysqz/qTAUStTvqJQDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Z4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj043sovGKUFfYAqVXVlxtIX
|
||||
qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
|
||||
f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
|
||||
-----END RSA TESTING KEY-----Q_
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
<EFBFBD>
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
|
||||
lGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
カネ哿ソス<03>スツ<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス <01>ス
|
||||
<01>ス<01>ス<01>ス
<01>ス<01>ス<01>ス<01><01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス<01>ス <01>ス!<01>ス"<01>ス#<01>ス$<01>ス%<01>ス&<01>ス'<01>ス(<01>ス)<01>ス*<01>ス+<01>ス,<01>ス-<01>ス.<01>ス/ソス0
|
@ -0,0 +1 @@
|
||||
LvhaJQHOe3EhRcdaFofeoogkjQfJB
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
И&^Ѓсo<D181>
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
đ˝apfffffffffffffffffffffffffffffffebadce6f48a0ź_3bbfd2364
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
DtQvfQ+MULKZTXk78c
|
||||
/fWkpxlyEQQ/+hgNzVtx9vWgJsafG7b0dA4AFjwVbFLmQcj2PprIMmPNQg1Ak/7KCxmDgS5TDEmSJwFX
|
||||
txLjbt4xTgeXVlXsjLZ
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
ð½ï½ï¿½Ù¯0,1,2,3,4,5,6,7,-3420794409,(2,a)
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
88242871'392752200424491531672177074144720616417147514758635765020556616ソ
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
21888242871'392752200424452601091531672177074144720616417147514758635765020556616ソス
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
ソス
|
@ -0,0 +1 @@
|
||||
LvhaJcdaFofenogkjQfJB
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
DtQvfQ+MULKZTXk78c
|
||||
/fWkpxlyEQQ/+hgNzVtx9vWgJsafG7b0dA4AFjwVbFLmQcj2PprIMmPNQg1AkS5TDEmSJwFVlXsjLZ
|
Binary file not shown.
@ -0,0 +1,14 @@
|
||||
TESTING KEY-----
|
||||
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
|
||||
SjY1bIw4iAJm2gsvvZhIrCHS3l6afab4pZB
|
||||
l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xl/DoCzjA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
|
||||
qyUBnu3Xh9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dDaFeo
|
||||
f9Oeos0UotgiDktdQHxdNEwLjQflJJBzV+5OtwswCA=----EN RATESTI EY-----Q
|
@ -0,0 +1,10 @@
|
||||
l6afab4pZB
|
||||
l2+XsDlrKBxKKtDrGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTtqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tuV6ef6anZzus1s1Y1Clb6HbnWWF/wbZGOpet
|
||||
3m4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKZTXtdZrh+k7hx0nTP8Jcb
|
||||
uqFk541awmMogY/EfbWd6IOkp+4xqjlFBEDytgbIECQQDvH/6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz84SHEg1Ak/7KCxmD/sfgS5TeuNi8DoUBEmiSJwm7FX
|
||||
ftxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su43sjXNueLKH8+ph2UfQuU9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xl/DoCzjA0CQQDU
|
||||
y2pGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj13sovGKUFfYAqVXVlxtI痂Ⅴ
|
||||
qUn3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JMhNRcVFMO8dDaFo
|
||||
f9Oeos0UotgiDktdQHxdNEwLjQlJBz+OtwwA=---E ATTIEY-
|
@ -0,0 +1,9 @@
|
||||
|
||||
l2+DulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
|
@ -0,0 +1 @@
|
||||
KKtDlbjVeLKwZatTXtdZrhu+Jk7hx0xxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLQcmPcQETT YQ
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
<EFBFBD>
|
@ -0,0 +1 @@
|
||||
<EFBFBD>39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319<EFBFBD><EFBFBD>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
l2+DulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
|
||||
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpwVbFLmQet
|
||||
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
|
||||
qzzVtxxr397vWrjr
|
@ -0,0 +1,2 @@
|
||||
&<26><>w<EFBFBD><77><03><01><01><01><01><01><01><01><01><01> <01>
|
||||
<01><01><01>
<01><01><01><01><><01><01><01><><7F><EFBFBD><01><01><01><01><01><01><01><01><01><01><01> <01>!<01>"<01>#<01>$<01>%<01>&<01>'<01>(<01>)<01>*<01>+<01>,<01>-<01>.<01>/<01><>0
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
lxtIX
|
||||
qyU3X9ps8ZfjLZ45l6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFe
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0000000000000
|
@ -0,0 +1,8 @@
|
||||
9pmM gY/xEcfbWd6IOkp+4xqjlFLBEDytgbparsing /E6nk+hgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprLANGcQrooz8vp
|
||||
jy4SHEg1AkEA/v13/@M47K9vCxb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
|
||||
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
|
||||
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xl/DoCz<43> jA0CQQDU
|
||||
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6Yj013sovGKUFfYAqVXVlxtIX
|
||||
qyUBnu3Xh9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYFZHOde3JEMhNRcVFMO8dDaFeo
|
||||
f9Oeos0Uot
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
&<26>o<EFBFBD>
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1 @@
|
||||
<EFBFBD>
|
@ -0,0 +1,2 @@
|
||||
4LZmbRc6+MUVeLKXtdZr+Jk7hhgN4H
|
||||
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLQcmPcQ SN_
|
@ -0,0 +1,4 @@
|
||||
|
||||
Xc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
|
||||
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nhgN4H
|
||||
qzzVtxx7vWrjrIgPbJpvfb
|
@ -0,0 +1,2 @@
|
||||
&Ƚ<01><01> <01>
|
||||
<01><01><01>
<01><01><01><01><><01><01><01><><7F><EFBFBD><01><01><01><01><01><01><01><01><01><01><01> <01>!<01>"<01>#<01>$<01>%<01>&<01>'<01>(<01>)<01>*<01>+<01>,<01>-<01>.<01>/<01><>0
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user