mirror of
https://github.com/tendermint/tendermint.git
synced 2026-05-31 19:36:20 +00:00
rpc: add private & unconditional to /dial_peer (#5293)
## Description Allow dialing of private and unconditional peers through the RPC Closes: #1705
This commit is contained in:
@@ -20,6 +20,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
## IMPROVEMENTS
|
||||
|
||||
- [blockchain] \#5278 Verify only +2/3 of the signatures in a block when fast syncing. (@marbar3778)
|
||||
- [rpc] \#5293 `/dial_peers` has added `private` and `unconditional` as parameters. (@marbar3778)
|
||||
|
||||
## BUG FIXES
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ func MConnConfig(cfg *config.P2PConfig) conn.MConnConfig {
|
||||
// to store peer addresses.
|
||||
type AddrBook interface {
|
||||
AddAddress(addr *NetAddress, src *NetAddress) error
|
||||
AddPrivateIDs([]string)
|
||||
AddOurAddress(*NetAddress)
|
||||
OurAddress(*NetAddress) bool
|
||||
MarkGood(ID)
|
||||
@@ -582,6 +583,21 @@ func (sw *Switch) AddUnconditionalPeerIDs(ids []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sw *Switch) AddPrivatePeerIDs(ids []string) error {
|
||||
validIDs := make([]string, 0, len(ids))
|
||||
for i, id := range ids {
|
||||
err := validateID(ID(id))
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong ID #%d: %w", i, err)
|
||||
}
|
||||
validIDs = append(validIDs, id)
|
||||
}
|
||||
|
||||
sw.addrBook.AddPrivateIDs(validIDs)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sw *Switch) IsPeerPersistent(na *NetAddress) bool {
|
||||
for _, pa := range sw.persistentPeersAddrs {
|
||||
if pa.Equals(na) {
|
||||
|
||||
@@ -98,9 +98,9 @@ func MakeSwitchPair(t testing.TB, initSwitch func(int, *Switch) *Switch) (*Switc
|
||||
}
|
||||
|
||||
func initSwitchFunc(i int, sw *Switch) *Switch {
|
||||
sw.SetAddrBook(&addrBookMock{
|
||||
addrs: make(map[string]struct{}),
|
||||
ourAddrs: make(map[string]struct{})})
|
||||
sw.SetAddrBook(&AddrBookMock{
|
||||
Addrs: make(map[string]struct{}),
|
||||
OurAddrs: make(map[string]struct{})})
|
||||
|
||||
// Make two reactors of two channels each
|
||||
sw.AddReactor("foo", NewTestReactor([]*conn.ChannelDescriptor{
|
||||
@@ -827,29 +827,3 @@ func BenchmarkSwitchBroadcast(b *testing.B) {
|
||||
|
||||
b.Logf("success: %v, failure: %v", numSuccess, numFailure)
|
||||
}
|
||||
|
||||
type addrBookMock struct {
|
||||
addrs map[string]struct{}
|
||||
ourAddrs map[string]struct{}
|
||||
}
|
||||
|
||||
var _ AddrBook = (*addrBookMock)(nil)
|
||||
|
||||
func (book *addrBookMock) AddAddress(addr *NetAddress, src *NetAddress) error {
|
||||
book.addrs[addr.String()] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
func (book *addrBookMock) AddOurAddress(addr *NetAddress) { book.ourAddrs[addr.String()] = struct{}{} }
|
||||
func (book *addrBookMock) OurAddress(addr *NetAddress) bool {
|
||||
_, ok := book.ourAddrs[addr.String()]
|
||||
return ok
|
||||
}
|
||||
func (book *addrBookMock) MarkGood(ID) {}
|
||||
func (book *addrBookMock) HasAddress(addr *NetAddress) bool {
|
||||
_, ok := book.addrs[addr.String()]
|
||||
return ok
|
||||
}
|
||||
func (book *addrBookMock) RemoveAddress(addr *NetAddress) {
|
||||
delete(book.addrs, addr.String())
|
||||
}
|
||||
func (book *addrBookMock) Save() {}
|
||||
|
||||
@@ -280,3 +280,35 @@ func getFreePort() int {
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
type AddrBookMock struct {
|
||||
Addrs map[string]struct{}
|
||||
OurAddrs map[string]struct{}
|
||||
PrivateAddrs map[string]struct{}
|
||||
}
|
||||
|
||||
var _ AddrBook = (*AddrBookMock)(nil)
|
||||
|
||||
func (book *AddrBookMock) AddAddress(addr *NetAddress, src *NetAddress) error {
|
||||
book.Addrs[addr.String()] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
func (book *AddrBookMock) AddOurAddress(addr *NetAddress) { book.OurAddrs[addr.String()] = struct{}{} }
|
||||
func (book *AddrBookMock) OurAddress(addr *NetAddress) bool {
|
||||
_, ok := book.OurAddrs[addr.String()]
|
||||
return ok
|
||||
}
|
||||
func (book *AddrBookMock) MarkGood(ID) {}
|
||||
func (book *AddrBookMock) HasAddress(addr *NetAddress) bool {
|
||||
_, ok := book.Addrs[addr.String()]
|
||||
return ok
|
||||
}
|
||||
func (book *AddrBookMock) RemoveAddress(addr *NetAddress) {
|
||||
delete(book.Addrs, addr.String())
|
||||
}
|
||||
func (book *AddrBookMock) Save() {}
|
||||
func (book *AddrBookMock) AddPrivateIDs(addrs []string) {
|
||||
for _, addr := range addrs {
|
||||
book.PrivateAddrs[addr] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ func (c *Local) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
|
||||
return core.UnsafeDialSeeds(c.ctx, seeds)
|
||||
}
|
||||
|
||||
func (c *Local) DialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(c.ctx, peers, persistent)
|
||||
func (c *Local) DialPeers(peers []string, persistent, unconditional, private bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(c.ctx, peers, persistent, unconditional, private)
|
||||
}
|
||||
|
||||
func (c *Local) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
|
||||
|
||||
@@ -138,8 +138,8 @@ func (c Client) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
|
||||
return core.UnsafeDialSeeds(&rpctypes.Context{}, seeds)
|
||||
}
|
||||
|
||||
func (c Client) DialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(&rpctypes.Context{}, peers, persistent)
|
||||
func (c Client) DialPeers(peers []string, persistent, unconditional, private bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(&rpctypes.Context{}, peers, persistent, unconditional, private)
|
||||
}
|
||||
|
||||
func (c Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
|
||||
|
||||
@@ -58,6 +58,8 @@ type transport interface {
|
||||
|
||||
type peers interface {
|
||||
AddPersistentPeers([]string) error
|
||||
AddUnconditionalPeerIDs([]string) error
|
||||
AddPrivatePeerIDs([]string) error
|
||||
DialPeersAsync([]string) error
|
||||
Peers() p2p.IPeerSet
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package core
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
@@ -51,19 +52,42 @@ func UnsafeDialSeeds(ctx *rpctypes.Context, seeds []string) (*ctypes.ResultDialS
|
||||
|
||||
// UnsafeDialPeers dials the given peers (comma-separated id@IP:PORT),
|
||||
// optionally making them persistent.
|
||||
func UnsafeDialPeers(ctx *rpctypes.Context, peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
func UnsafeDialPeers(ctx *rpctypes.Context, peers []string, persistent, unconditional, private bool) (
|
||||
*ctypes.ResultDialPeers, error) {
|
||||
if len(peers) == 0 {
|
||||
return &ctypes.ResultDialPeers{}, errors.New("no peers provided")
|
||||
}
|
||||
env.Logger.Info("DialPeers", "peers", peers, "persistent", persistent)
|
||||
|
||||
ids, err := getIDs(peers)
|
||||
if err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
|
||||
env.Logger.Info("DialPeers", "peers", peers, "persistent",
|
||||
persistent, "unconditional", unconditional, "private", private)
|
||||
|
||||
if persistent {
|
||||
if err := env.P2PPeers.AddPersistentPeers(peers); err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if private {
|
||||
if err := env.P2PPeers.AddPrivatePeerIDs(ids); err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if unconditional {
|
||||
if err := env.P2PPeers.AddUnconditionalPeerIDs(ids); err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := env.P2PPeers.DialPeersAsync(peers); err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
|
||||
return &ctypes.ResultDialPeers{Log: "Dialing peers in progress. See /net_info for details"}, nil
|
||||
}
|
||||
|
||||
@@ -72,3 +96,18 @@ func UnsafeDialPeers(ctx *rpctypes.Context, peers []string, persistent bool) (*c
|
||||
func Genesis(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) {
|
||||
return &ctypes.ResultGenesis{Genesis: env.GenDoc}, nil
|
||||
}
|
||||
|
||||
func getIDs(peers []string) ([]string, error) {
|
||||
ids := make([]string, 0, len(peers))
|
||||
|
||||
for _, peer := range peers {
|
||||
|
||||
spl := strings.Split(peer, "@")
|
||||
if len(spl) != 2 {
|
||||
return nil, p2p.ErrNetAddressNoID{Addr: peer}
|
||||
}
|
||||
ids = append(ids, spl[0])
|
||||
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ func TestUnsafeDialSeeds(t *testing.T) {
|
||||
func TestUnsafeDialPeers(t *testing.T) {
|
||||
sw := p2p.MakeSwitch(cfg.DefaultP2PConfig(), 1, "testing", "123.123.123",
|
||||
func(n int, sw *p2p.Switch) *p2p.Switch { return sw })
|
||||
sw.SetAddrBook(&p2p.AddrBookMock{
|
||||
Addrs: make(map[string]struct{}),
|
||||
OurAddrs: make(map[string]struct{}),
|
||||
PrivateAddrs: make(map[string]struct{}),
|
||||
})
|
||||
err := sw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
@@ -61,16 +66,17 @@ func TestUnsafeDialPeers(t *testing.T) {
|
||||
env.P2PPeers = sw
|
||||
|
||||
testCases := []struct {
|
||||
peers []string
|
||||
isErr bool
|
||||
peers []string
|
||||
persistence, unconditional, private bool
|
||||
isErr bool
|
||||
}{
|
||||
{[]string{}, true},
|
||||
{[]string{"d51fb70907db1c6c2d5237e78379b25cf1a37ab4@127.0.0.1:41198"}, false},
|
||||
{[]string{"127.0.0.1:41198"}, true},
|
||||
{[]string{}, false, false, false, true},
|
||||
{[]string{"d51fb70907db1c6c2d5237e78379b25cf1a37ab4@127.0.0.1:41198"}, true, true, true, false},
|
||||
{[]string{"127.0.0.1:41198"}, true, true, false, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
res, err := UnsafeDialPeers(&rpctypes.Context{}, tc.peers, false)
|
||||
res, err := UnsafeDialPeers(&rpctypes.Context{}, tc.peers, tc.persistence, tc.unconditional, tc.private)
|
||||
if tc.isErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -50,6 +50,6 @@ var Routes = map[string]*rpc.RPCFunc{
|
||||
func AddUnsafeRoutes() {
|
||||
// control API
|
||||
Routes["dial_seeds"] = rpc.NewRPCFunc(UnsafeDialSeeds, "seeds")
|
||||
Routes["dial_peers"] = rpc.NewRPCFunc(UnsafeDialPeers, "peers,persistent")
|
||||
Routes["dial_peers"] = rpc.NewRPCFunc(UnsafeDialPeers, "peers,persistent,unconditional,private")
|
||||
Routes["unsafe_flush_mempool"] = rpc.NewRPCFunc(UnsafeFlushMempool, "")
|
||||
}
|
||||
|
||||
@@ -569,6 +569,18 @@ paths:
|
||||
schema:
|
||||
type: boolean
|
||||
example: true
|
||||
- in: query
|
||||
name: unconditional
|
||||
description: Have the peers you are dialing be unconditional
|
||||
schema:
|
||||
type: boolean
|
||||
example: true
|
||||
- in: query
|
||||
name: private
|
||||
description: Have the peers you are dialing be private
|
||||
schema:
|
||||
type: boolean
|
||||
example: true
|
||||
- in: query
|
||||
name: peers
|
||||
description: array of peers to dial
|
||||
|
||||
Reference in New Issue
Block a user