mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
cmd/devp2p, eth: advertise 0 TD on eth/status, ignore received one
This commit is contained in:
parent
776d8ec1c1
commit
89a5e1a29b
12 changed files with 20 additions and 117 deletions
|
|
@ -143,11 +143,7 @@ func (c *Chain) ForkID() forkid.ID {
|
||||||
// TD calculates the total difficulty of the chain at the
|
// TD calculates the total difficulty of the chain at the
|
||||||
// chain head.
|
// chain head.
|
||||||
func (c *Chain) TD() *big.Int {
|
func (c *Chain) TD() *big.Int {
|
||||||
sum := new(big.Int)
|
return new(big.Int)
|
||||||
for _, block := range c.blocks[:c.Len()] {
|
|
||||||
sum.Add(sum, block.Difficulty())
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock returns the block at the specified number.
|
// GetBlock returns the block at the specified number.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package ethtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"math/big"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -74,7 +73,6 @@ func (s *Suite) EthTests() []utesting.Test {
|
||||||
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
|
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
|
||||||
// // malicious handshakes + status
|
// // malicious handshakes + status
|
||||||
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
|
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
|
||||||
{Name: "MaliciousStatus", Fn: s.TestMaliciousStatus},
|
|
||||||
// test transactions
|
// test transactions
|
||||||
{Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true},
|
{Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true},
|
||||||
{Name: "Transaction", Fn: s.TestTransaction},
|
{Name: "Transaction", Fn: s.TestTransaction},
|
||||||
|
|
@ -453,42 +451,6 @@ func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite) TestMaliciousStatus(t *utesting.T) {
|
|
||||||
t.Log(`This test sends a malicious eth Status message to the node and expects a disconnect.`)
|
|
||||||
|
|
||||||
conn, err := s.dial()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
if err := conn.handshake(); err != nil {
|
|
||||||
t.Fatalf("handshake failed: %v", err)
|
|
||||||
}
|
|
||||||
// Create status with large total difficulty.
|
|
||||||
status := ð.StatusPacket{
|
|
||||||
ProtocolVersion: uint32(conn.negotiatedProtoVersion),
|
|
||||||
NetworkID: s.chain.config.ChainID.Uint64(),
|
|
||||||
TD: new(big.Int).SetBytes(randBuf(2048)),
|
|
||||||
Head: s.chain.Head().Hash(),
|
|
||||||
Genesis: s.chain.GetBlock(0).Hash(),
|
|
||||||
ForkID: s.chain.ForkID(),
|
|
||||||
}
|
|
||||||
if err := conn.statusExchange(s.chain, status); err != nil {
|
|
||||||
t.Fatalf("status exchange failed: %v", err)
|
|
||||||
}
|
|
||||||
// Wait for disconnect.
|
|
||||||
code, _, err := conn.Read()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error reading from connection: %v", err)
|
|
||||||
}
|
|
||||||
switch code {
|
|
||||||
case discMsg:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
t.Fatalf("expected disconnect, got: %d", code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) TestTransaction(t *utesting.T) {
|
func (s *Suite) TestTransaction(t *utesting.T) {
|
||||||
t.Log(`This test sends a valid transaction to the node and checks if the
|
t.Log(`This test sends a valid transaction to the node and checks if the
|
||||||
transaction gets propagated.`)
|
transaction gets propagated.`)
|
||||||
|
|
|
||||||
|
|
@ -242,13 +242,6 @@ func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash, number ui
|
||||||
return rawdb.ReadLogs(b.eth.chainDb, hash, number), nil
|
return rawdb.ReadLogs(b.eth.chainDb, hash, number), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
|
||||||
if header := b.eth.blockchain.GetHeaderByHash(hash); header != nil {
|
|
||||||
return b.eth.blockchain.GetTd(hash, header.Number.Uint64())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
|
func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
|
||||||
if vmConfig == nil {
|
if vmConfig == nil {
|
||||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ package downloader
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -164,9 +163,6 @@ type BlockChain interface {
|
||||||
// CurrentHeader retrieves the head header from the local chain.
|
// CurrentHeader retrieves the head header from the local chain.
|
||||||
CurrentHeader() *types.Header
|
CurrentHeader() *types.Header
|
||||||
|
|
||||||
// GetTd returns the total difficulty of a local block.
|
|
||||||
GetTd(common.Hash, uint64) *big.Int
|
|
||||||
|
|
||||||
// InsertHeaderChain inserts a batch of headers into the local chain.
|
// InsertHeaderChain inserts a batch of headers into the local chain.
|
||||||
InsertHeaderChain([]*types.Header) (int, error)
|
InsertHeaderChain([]*types.Header) (int, error)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,13 +126,6 @@ type downloadTesterPeer struct {
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head constructs a function to retrieve a peer's current head hash
|
|
||||||
// and total difficulty.
|
|
||||||
func (dlp *downloadTesterPeer) Head() (common.Hash, *big.Int) {
|
|
||||||
head := dlp.chain.CurrentBlock()
|
|
||||||
return head.Hash(), dlp.chain.GetTd(head.Hash(), head.Number.Uint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmarshalRlpHeaders(rlpdata []rlp.RawValue) []*types.Header {
|
func unmarshalRlpHeaders(rlpdata []rlp.RawValue) []*types.Header {
|
||||||
var headers = make([]*types.Header, len(rlpdata))
|
var headers = make([]*types.Header, len(rlpdata))
|
||||||
for i, data := range rlpdata {
|
for i, data := range rlpdata {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ package downloader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -57,7 +56,6 @@ type peerConnection struct {
|
||||||
|
|
||||||
// Peer encapsulates the methods required to synchronise with a remote full peer.
|
// Peer encapsulates the methods required to synchronise with a remote full peer.
|
||||||
type Peer interface {
|
type Peer interface {
|
||||||
Head() (common.Hash, *big.Int)
|
|
||||||
RequestHeadersByHash(common.Hash, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
RequestHeadersByHash(common.Hash, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
||||||
RequestHeadersByNumber(uint64, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
RequestHeadersByNumber(uint64, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -253,10 +253,9 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
|
||||||
head = h.chain.CurrentHeader()
|
head = h.chain.CurrentHeader()
|
||||||
hash = head.Hash()
|
hash = head.Hash()
|
||||||
number = head.Number.Uint64()
|
number = head.Number.Uint64()
|
||||||
td = h.chain.GetTd(hash, number)
|
|
||||||
)
|
)
|
||||||
forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time)
|
forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time)
|
||||||
if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil {
|
if err := peer.Handshake(h.networkID, hash, genesis.Hash(), forkID, h.forkFilter); err != nil {
|
||||||
peer.Log().Debug("Ethereum handshake failed", "err", err)
|
peer.Log().Debug("Ethereum handshake failed", "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -260,9 +260,8 @@ func testRecvTransactions(t *testing.T, protocol uint) {
|
||||||
var (
|
var (
|
||||||
genesis = handler.chain.Genesis()
|
genesis = handler.chain.Genesis()
|
||||||
head = handler.chain.CurrentBlock()
|
head = handler.chain.CurrentBlock()
|
||||||
td = handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
|
||||||
)
|
)
|
||||||
if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
if err := src.Handshake(1, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||||
t.Fatalf("failed to run protocol handshake")
|
t.Fatalf("failed to run protocol handshake")
|
||||||
}
|
}
|
||||||
// Send the transaction to the sink and verify that it's added to the tx pool
|
// Send the transaction to the sink and verify that it's added to the tx pool
|
||||||
|
|
@ -320,9 +319,8 @@ func testSendTransactions(t *testing.T, protocol uint) {
|
||||||
var (
|
var (
|
||||||
genesis = handler.chain.Genesis()
|
genesis = handler.chain.Genesis()
|
||||||
head = handler.chain.CurrentBlock()
|
head = handler.chain.CurrentBlock()
|
||||||
td = handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
|
||||||
)
|
)
|
||||||
if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
if err := sink.Handshake(1, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||||
t.Fatalf("failed to run protocol handshake")
|
t.Fatalf("failed to run protocol handshake")
|
||||||
}
|
}
|
||||||
// After the handshake completes, the source handler should stream the sink
|
// After the handshake completes, the source handler should stream the sink
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -121,7 +120,6 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2
|
||||||
// known about the host peer.
|
// known about the host peer.
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000)
|
Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000)
|
||||||
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
|
|
||||||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||||
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
||||||
Head common.Hash `json:"head"` // Hex hash of the host's best owned block
|
Head common.Hash `json:"head"` // Hex hash of the host's best owned block
|
||||||
|
|
@ -134,7 +132,6 @@ func nodeInfo(chain *core.BlockChain, network uint64) *NodeInfo {
|
||||||
|
|
||||||
return &NodeInfo{
|
return &NodeInfo{
|
||||||
Network: network,
|
Network: network,
|
||||||
Difficulty: chain.GetTd(hash, head.Number.Uint64()),
|
|
||||||
Genesis: chain.Genesis().Hash(),
|
Genesis: chain.Genesis().Hash(),
|
||||||
Config: chain.Config(),
|
Config: chain.Config(),
|
||||||
Head: hash,
|
Head: hash,
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const (
|
||||||
|
|
||||||
// Handshake executes the eth protocol handshake, negotiating version number,
|
// Handshake executes the eth protocol handshake, negotiating version number,
|
||||||
// network IDs, difficulties, head and genesis blocks.
|
// 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 {
|
func (p *Peer) Handshake(network uint64, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error {
|
||||||
// Send out own handshake in a new thread
|
// Send out own handshake in a new thread
|
||||||
errc := make(chan error, 2)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis
|
||||||
errc <- p2p.Send(p.rw, StatusMsg, &StatusPacket{
|
errc <- p2p.Send(p.rw, StatusMsg, &StatusPacket{
|
||||||
ProtocolVersion: uint32(p.version),
|
ProtocolVersion: uint32(p.version),
|
||||||
NetworkID: network,
|
NetworkID: network,
|
||||||
TD: td,
|
TD: new(big.Int), // unknown for post-merge tail=pruned networks
|
||||||
Head: head,
|
Head: head,
|
||||||
Genesis: genesis,
|
Genesis: genesis,
|
||||||
ForkID: forkID,
|
ForkID: forkID,
|
||||||
|
|
@ -69,13 +69,6 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis
|
||||||
return p2p.DiscReadTimeout
|
return p2p.DiscReadTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.td, p.head = status.TD, status.Head
|
|
||||||
|
|
||||||
// TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times
|
|
||||||
// larger, it will still fit within 100 bits
|
|
||||||
if tdlen := p.td.BitLen(); tdlen > 100 {
|
|
||||||
return fmt.Errorf("too large total difficulty: bitlen %d", tdlen)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -39,7 +40,6 @@ func testHandshake(t *testing.T, protocol uint) {
|
||||||
var (
|
var (
|
||||||
genesis = backend.chain.Genesis()
|
genesis = backend.chain.Genesis()
|
||||||
head = backend.chain.CurrentBlock()
|
head = backend.chain.CurrentBlock()
|
||||||
td = backend.chain.GetTd(head.Hash(), head.Number.Uint64())
|
|
||||||
forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time)
|
forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time)
|
||||||
)
|
)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|
@ -52,19 +52,19 @@ func testHandshake(t *testing.T, protocol uint) {
|
||||||
want: errNoStatusMsg,
|
want: errNoStatusMsg,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: StatusMsg, data: StatusPacket{10, 1, td, head.Hash(), genesis.Hash(), forkID},
|
code: StatusMsg, data: StatusPacket{10, 1, new(big.Int), head.Hash(), genesis.Hash(), forkID},
|
||||||
want: errProtocolVersionMismatch,
|
want: errProtocolVersionMismatch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 999, td, head.Hash(), genesis.Hash(), forkID},
|
code: StatusMsg, data: StatusPacket{uint32(protocol), 999, new(big.Int), head.Hash(), genesis.Hash(), forkID},
|
||||||
want: errNetworkIDMismatch,
|
want: errNetworkIDMismatch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, td, head.Hash(), common.Hash{3}, forkID},
|
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, new(big.Int), head.Hash(), common.Hash{3}, forkID},
|
||||||
want: errGenesisMismatch,
|
want: errGenesisMismatch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, td, head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}},
|
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, new(big.Int), head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}},
|
||||||
want: errForkIDRejected,
|
want: errForkIDRejected,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ func testHandshake(t *testing.T, protocol uint) {
|
||||||
// Send the junk test with one peer, check the handshake failure
|
// Send the junk test with one peer, check the handshake failure
|
||||||
go p2p.Send(app, test.code, test.data)
|
go p2p.Send(app, test.code, test.data)
|
||||||
|
|
||||||
err := peer.Handshake(1, td, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain))
|
err := peer.Handshake(1, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test %d: protocol returned nil error, want %q", i, test.want)
|
t.Errorf("test %d: protocol returned nil error, want %q", i, test.want)
|
||||||
} else if !errors.Is(err, test.want) {
|
} else if !errors.Is(err, test.want) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -50,9 +49,6 @@ type Peer struct {
|
||||||
rw p2p.MsgReadWriter // Input/output streams for snap
|
rw p2p.MsgReadWriter // Input/output streams for snap
|
||||||
version uint // Protocol version negotiated
|
version uint // Protocol version negotiated
|
||||||
|
|
||||||
head common.Hash // Latest advertised head block hash
|
|
||||||
td *big.Int // Latest advertised head block total difficulty
|
|
||||||
|
|
||||||
txpool TxPool // Transaction pool used by the broadcasters for liveness checks
|
txpool TxPool // Transaction pool used by the broadcasters for liveness checks
|
||||||
knownTxs *knownCache // Set of transaction hashes known to be known by this peer
|
knownTxs *knownCache // Set of transaction hashes known to be known by this peer
|
||||||
txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests
|
txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests
|
||||||
|
|
@ -108,24 +104,6 @@ func (p *Peer) Version() uint {
|
||||||
return p.version
|
return p.version
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head retrieves the current head hash and total difficulty of the peer.
|
|
||||||
func (p *Peer) Head() (hash common.Hash, td *big.Int) {
|
|
||||||
p.lock.RLock()
|
|
||||||
defer p.lock.RUnlock()
|
|
||||||
|
|
||||||
copy(hash[:], p.head[:])
|
|
||||||
return hash, new(big.Int).Set(p.td)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetHead updates the head hash and total difficulty of the peer.
|
|
||||||
func (p *Peer) SetHead(hash common.Hash, td *big.Int) {
|
|
||||||
p.lock.Lock()
|
|
||||||
defer p.lock.Unlock()
|
|
||||||
|
|
||||||
copy(p.head[:], hash[:])
|
|
||||||
p.td.Set(td)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KnownTransaction returns whether peer is known to already have a transaction.
|
// KnownTransaction returns whether peer is known to already have a transaction.
|
||||||
func (p *Peer) KnownTransaction(hash common.Hash) bool {
|
func (p *Peer) KnownTransaction(hash common.Hash) bool {
|
||||||
return p.knownTxs.Contains(hash)
|
return p.knownTxs.Contains(hash)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue