Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2d98737
feat: query witnesses
minhd-vu Jun 26, 2025
b686044
fix: update request id
minhd-vu Jun 26, 2025
4b15f7e
fix: disable tx fetching
minhd-vu Jun 26, 2025
202430a
fix: print enode
minhd-vu Jun 26, 2025
9aefca9
fix: return when EOF error
minhd-vu Jun 26, 2025
f77f485
fix: lint
minhd-vu Jun 27, 2025
426cacf
feat: use witness pagination
minhd-vu Jul 24, 2025
3ee6658
feat: request witness pages
minhd-vu Jul 29, 2025
8b2d29e
fix: requesting multiple witness pages
minhd-vu Jul 29, 2025
72c8898
fix: logging
minhd-vu Jul 29, 2025
928f266
fix: logging
minhd-vu Jul 29, 2025
510138c
Merge branch 'main' into minhd-vu/witness
minhd-vu Sep 24, 2025
574a3ea
fix: undo comments
minhd-vu Sep 26, 2025
a7d7d33
feat: ping private key flags
minhd-vu Sep 26, 2025
a358828
fix: flag set
minhd-vu Sep 26, 2025
3bfcc3e
feat: add DialOpts
minhd-vu Sep 26, 2025
b672734
fix: remove duplicate listen flag
minhd-vu Sep 26, 2025
6c34ad0
fix: remove unnecessary int cast
minhd-vu Sep 26, 2025
1061c48
fix: listen flag desc
minhd-vu Sep 26, 2025
ebb19c6
docs: make gen-doc
minhd-vu Sep 26, 2025
f6ce099
fix: remove unused log
minhd-vu Sep 29, 2025
9aeccac
fix: remove log import
minhd-vu Sep 29, 2025
fdb49ae
feat: add key file flags to p2p query
minhd-vu Sep 29, 2025
e6be4bc
fix: mark query key flags mutex
minhd-vu Sep 29, 2025
7b71a4a
Merge branch 'main' into minhd-vu/witness
minhd-vu Sep 29, 2025
78679d7
fix: p2p query conflicting `a` shorthand
minhd-vu Sep 29, 2025
edd0b16
docs: make gen-doc
minhd-vu Sep 29, 2025
c1b23c4
Merge branch 'main' into minhd-vu/witness
minhd-vu Sep 29, 2025
0682787
fix: clean up logs
minhd-vu Sep 30, 2025
2969051
feat: handle enabling caps
minhd-vu Sep 30, 2025
eaf9850
Merge branch 'main' into minhd-vu/witness
leovct Oct 2, 2025
29e675b
Merge branch 'main' into minhd-vu/witness
minhd-vu Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/p2p/crawl/crawl_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (c *crawler) updateNode(n *enode.Node) int {
c.mu.Unlock()
}()

conn, dialErr := p2p.Dial(n)
conn, dialErr := p2p.Dial(n, p2p.NewDialOpts())
if err = dialErr; err != nil {
log.Error().Err(err).Msg("Dial failed")
return nodeDialErr
Expand Down
32 changes: 31 additions & 1 deletion cmd/p2p/ping/ping.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ping

import (
"crypto/ecdsa"
"net"
"sync"
"time"

Expand All @@ -17,6 +19,13 @@ type (
OutputFile string
NodesFile string
Listen bool
Port int
Addr net.IP
KeyFile string
PrivateKey string
EnableWit bool

privateKey *ecdsa.PrivateKey
}
)

Expand All @@ -34,6 +43,14 @@ Status messages and output JSON. If providing a enode/enr rather than a nodes
file, then the connection will remain open by default (--listen=true), and you
can see other messages the peer sends (e.g. blocks, transactions, etc.).`,
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
inputPingParams.privateKey, err = p2p.ParsePrivateKey(inputPingParams.KeyFile, inputPingParams.PrivateKey)
if err != nil {
return err
}

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
nodes := []*enode.Node{}
if input, err := p2p.ReadNodeSet(args[0]); err == nil {
Expand Down Expand Up @@ -81,7 +98,14 @@ can see other messages the peer sends (e.g. blocks, transactions, etc.).`,
status *p2p.Status
)

conn, err := p2p.Dial(node)
opts := p2p.DialOpts{
EnableWit: inputPingParams.EnableWit,
Port: inputPingParams.Port,
Addr: inputPingParams.Addr,
PrivateKey: inputPingParams.privateKey,
}

conn, err := p2p.Dial(node, opts)
if err != nil {
log.Error().Err(err).Msg("Dial failed")
} else {
Expand Down Expand Up @@ -133,4 +157,10 @@ func init() {
f.BoolVarP(&inputPingParams.Listen, "listen", "l", true,
`keep connection open and listen to peer. This only works if first
argument is an enode/enr, not a nodes file`)
f.BoolVarP(&inputPingParams.EnableWit, "wit", "w", false, "enable wit/1 capability")
f.IntVarP(&inputPingParams.Port, "port", "P", 30303, "port for discovery protocol")
f.IPVarP(&inputPingParams.Addr, "addr", "a", net.ParseIP("127.0.0.1"), "address to bind discovery listener")
f.StringVarP(&inputPingParams.KeyFile, "key-file", "k", "", "private key file (cannot be set with --key)")
f.StringVar(&inputPingParams.PrivateKey, "key", "", "hex-encoded private key (cannot be set with --key-file)")
PingCmd.MarkFlagsMutuallyExclusive("key-file", "key")
}
34 changes: 30 additions & 4 deletions cmd/p2p/query/query.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package query

import (
"crypto/ecdsa"
"fmt"
"net"

"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/rs/zerolog/log"
Expand All @@ -14,6 +16,12 @@ type (
queryParams struct {
StartBlock uint64
Amount uint64
Port int
Addr net.IP
KeyFile string
PrivateKey string

privateKey *ecdsa.PrivateKey
}
)

Expand All @@ -30,10 +38,16 @@ This command will initially establish a handshake and exchange status message
from the peer. Then, it will query the node for block(s) given the start block
and the amount of blocks to query and print the results.`,
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
if inputQueryParams.Amount < 1 {
return fmt.Errorf("amount must be greater than 0")
}

inputQueryParams.privateKey, err = p2p.ParsePrivateKey(inputQueryParams.KeyFile, inputQueryParams.PrivateKey)
if err != nil {
return err
}

return nil
},
Run: func(cmd *cobra.Command, args []string) {
Expand All @@ -50,7 +64,13 @@ and the amount of blocks to query and print the results.`,
amount uint64 = inputQueryParams.Amount
)

conn, err := p2p.Dial(node)
opts := p2p.DialOpts{
Port: inputQueryParams.Port,
Addr: inputQueryParams.Addr,
PrivateKey: inputQueryParams.privateKey,
}

conn, err := p2p.Dial(node, opts)
if err != nil {
log.Error().Err(err).Msg("Dial failed")
return
Expand Down Expand Up @@ -104,8 +124,14 @@ func print(headers eth.BlockHeadersRequest) {
}

func init() {
QueryCmd.Flags().Uint64VarP(&inputQueryParams.StartBlock, "start-block", "s", 0, "block number to start querying from")
QueryCmd.Flags().Uint64VarP(&inputQueryParams.Amount, "amount", "a", 1, "amount of blocks to query")
f := QueryCmd.Flags()
f.Uint64VarP(&inputQueryParams.StartBlock, "start-block", "s", 0, "block number to start querying from")
f.Uint64VarP(&inputQueryParams.Amount, "amount", "a", 1, "amount of blocks to query")
f.IntVarP(&inputQueryParams.Port, "port", "P", 30303, "port for discovery protocol")
f.IPVar(&inputQueryParams.Addr, "addr", net.ParseIP("127.0.0.1"), "address to bind discovery listener")
f.StringVarP(&inputQueryParams.KeyFile, "key-file", "k", "", "private key file (cannot be set with --key)")
f.StringVar(&inputQueryParams.PrivateKey, "key", "", "hex-encoded private key (cannot be set with --key-file)")
QueryCmd.MarkFlagsMutuallyExclusive("key-file", "key")
if err := QueryCmd.MarkFlagRequired("start-block"); err != nil {
log.Error().Err(err).Msg("Failed to mark start-block as required flag")
}
Expand Down
15 changes: 10 additions & 5 deletions doc/polycli_p2p_ping.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ can see other messages the peer sends (e.g. blocks, transactions, etc.).
## Flags

```bash
-h, --help help for ping
-l, --listen keep connection open and listen to peer. This only works if first
argument is an enode/enr, not a nodes file (default true)
-o, --output string write ping results to output file (default stdout)
-p, --parallel int how many parallel pings to attempt (default 16)
-a, --addr ip address to bind discovery listener (default 127.0.0.1)
-h, --help help for ping
--key string hex-encoded private key (cannot be set with --key-file)
-k, --key-file string private key file (cannot be set with --key)
-l, --listen keep connection open and listen to peer. This only works if first
argument is an enode/enr, not a nodes file (default true)
-o, --output string write ping results to output file (default stdout)
-p, --parallel int how many parallel pings to attempt (default 16)
-P, --port int port for discovery protocol (default 30303)
-w, --wit enable wit/1 capability
```

The command also inherits flags from parent commands.
Expand Down
4 changes: 4 additions & 0 deletions doc/polycli_p2p_query.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ and the amount of blocks to query and print the results.
## Flags

```bash
--addr ip address to bind discovery listener (default 127.0.0.1)
-a, --amount uint amount of blocks to query (default 1)
-h, --help help for query
--key string hex-encoded private key (cannot be set with --key-file)
-k, --key-file string private key file (cannot be set with --key)
-P, --port int port for discovery protocol (default 30303)
-s, --start-block uint block number to start querying from
```

Expand Down
12 changes: 12 additions & 0 deletions p2p/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ type MessageCount struct {
Pings int64 `json:"pings,omitempty"`
Errors int64 `json:"errors,omitempty"`
Disconnects int64 `json:"disconnects,omitempty"`
NewWitness int64 `json:"new_witness,omitempty"`
NewWitnessHashes int64 `json:"new_witness_hashes,omitempty"`
GetWitnessRequest int64 `json:"get_witness_request,omitempty"`
Witness int64 `json:"witness,omitempty"`
}

// Load takes a snapshot of all the counts in a thread-safe manner. Make sure
Expand All @@ -39,6 +43,10 @@ func (count *MessageCount) Load() MessageCount {
Pings: atomic.LoadInt64(&count.Pings),
Errors: atomic.LoadInt64(&count.Errors),
Disconnects: atomic.LoadInt64(&count.Disconnects),
NewWitness: atomic.LoadInt64(&count.NewWitness),
NewWitnessHashes: atomic.LoadInt64(&count.NewWitnessHashes),
GetWitnessRequest: atomic.LoadInt64(&count.GetWitnessRequest),
Witness: atomic.LoadInt64(&count.Witness),
}
}

Expand All @@ -56,6 +64,10 @@ func (count *MessageCount) Clear() {
atomic.StoreInt64(&count.Pings, 0)
atomic.StoreInt64(&count.Errors, 0)
atomic.StoreInt64(&count.Disconnects, 0)
atomic.StoreInt64(&count.NewWitness, 0)
atomic.StoreInt64(&count.NewWitnessHashes, 0)
atomic.StoreInt64(&count.GetWitnessRequest, 0)
atomic.StoreInt64(&count.Witness, 0)
}

// IsEmpty checks whether the sum of all the counts is empty. Make sure to call
Expand Down
43 changes: 43 additions & 0 deletions p2p/p2p.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package p2p

import (
"bytes"
"crypto/ecdsa"
"encoding/base64"
"encoding/hex"
"fmt"
"net"
"strings"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/rlp"
"github.com/rs/zerolog/log"
)

func Listen(ln *enode.LocalNode) (*net.UDPConn, error) {
Expand Down Expand Up @@ -101,3 +104,43 @@ func ParseBootnodes(bootnodes string) ([]*enode.Node, error) {

return nodes, nil
}

// ParsePrivateKey loads a private key from a file path or hex string.
// If file is provided, it attempts to load from the file path first.
// If the file doesn't exist, it generates a new key and saves it to the file.
// If key is provided instead, it parses the hex-encoded private key string.
// If neither file nor key is provided, it generates and returns a new private key.
func ParsePrivateKey(file string, key string) (*ecdsa.PrivateKey, error) {
if len(file) > 0 {
privateKey, err := crypto.LoadECDSA(file)
if err == nil {
return privateKey, nil
}

log.Warn().Err(err).Msg("Key file was not found, generating a new key file")

privateKey, err = crypto.GenerateKey()
if err != nil {
log.Error().Err(err).Msg("Failed to generate new private key")
return nil, err
}

if err := crypto.SaveECDSA(file, privateKey); err != nil {
log.Error().Err(err).Msg("Failed to save private key to file")
return nil, err
}

return privateKey, nil
}

if len(key) > 0 {
privateKey, err := crypto.HexToECDSA(key)
if err != nil {
log.Error().Err(err).Msg("Failed to parse private key")
return nil, err
}
return privateKey, nil
}

return crypto.GenerateKey()
}
Loading
Loading