github.com/ethereum/go-ethereum@v1.16.1/cmd/devp2p/rlpxcmd.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "errors" 21 "fmt" 22 "net" 23 24 "github.com/ethereum/go-ethereum/cmd/devp2p/internal/ethtest" 25 "github.com/ethereum/go-ethereum/crypto" 26 "github.com/ethereum/go-ethereum/p2p" 27 "github.com/ethereum/go-ethereum/p2p/enode" 28 "github.com/ethereum/go-ethereum/p2p/rlpx" 29 "github.com/ethereum/go-ethereum/rlp" 30 "github.com/urfave/cli/v2" 31 ) 32 33 var ( 34 rlpxCommand = &cli.Command{ 35 Name: "rlpx", 36 Usage: "RLPx Commands", 37 Subcommands: []*cli.Command{ 38 rlpxPingCommand, 39 rlpxEthTestCommand, 40 rlpxSnapTestCommand, 41 }, 42 } 43 rlpxPingCommand = &cli.Command{ 44 Name: "ping", 45 Usage: "ping <node>", 46 Action: rlpxPing, 47 } 48 rlpxEthTestCommand = &cli.Command{ 49 Name: "eth-test", 50 Usage: "Runs eth protocol tests against a node", 51 ArgsUsage: "<node>", 52 Action: rlpxEthTest, 53 Flags: []cli.Flag{ 54 testPatternFlag, 55 testTAPFlag, 56 testChainDirFlag, 57 testNodeFlag, 58 testNodeJWTFlag, 59 testNodeEngineFlag, 60 }, 61 } 62 rlpxSnapTestCommand = &cli.Command{ 63 Name: "snap-test", 64 Usage: "Runs snap protocol tests against a node", 65 ArgsUsage: "", 66 Action: rlpxSnapTest, 67 Flags: []cli.Flag{ 68 testPatternFlag, 69 testTAPFlag, 70 testChainDirFlag, 71 testNodeFlag, 72 testNodeJWTFlag, 73 testNodeEngineFlag, 74 }, 75 } 76 ) 77 78 func rlpxPing(ctx *cli.Context) error { 79 n := getNodeArg(ctx) 80 tcpEndpoint, ok := n.TCPEndpoint() 81 if !ok { 82 return errors.New("node has no TCP endpoint") 83 } 84 fd, err := net.Dial("tcp", tcpEndpoint.String()) 85 if err != nil { 86 return err 87 } 88 conn := rlpx.NewConn(fd, n.Pubkey()) 89 ourKey, _ := crypto.GenerateKey() 90 _, err = conn.Handshake(ourKey) 91 if err != nil { 92 return err 93 } 94 code, data, _, err := conn.Read() 95 if err != nil { 96 return err 97 } 98 switch code { 99 case 0: 100 var h ethtest.Hello 101 if err := rlp.DecodeBytes(data, &h); err != nil { 102 return fmt.Errorf("invalid handshake: %v", err) 103 } 104 fmt.Printf("%+v\n", h) 105 case 1: 106 var msg []p2p.DiscReason 107 if rlp.DecodeBytes(data, &msg); len(msg) == 0 { 108 return errors.New("invalid disconnect message") 109 } 110 return fmt.Errorf("received disconnect message: %v", msg[0]) 111 default: 112 return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code) 113 } 114 return nil 115 } 116 117 // rlpxEthTest runs the eth protocol test suite. 118 func rlpxEthTest(ctx *cli.Context) error { 119 p := cliTestParams(ctx) 120 suite, err := ethtest.NewSuite(p.node, p.chainDir, p.engineAPI, p.jwt) 121 if err != nil { 122 exit(err) 123 } 124 return runTests(ctx, suite.EthTests()) 125 } 126 127 // rlpxSnapTest runs the snap protocol test suite. 128 func rlpxSnapTest(ctx *cli.Context) error { 129 p := cliTestParams(ctx) 130 suite, err := ethtest.NewSuite(p.node, p.chainDir, p.engineAPI, p.jwt) 131 if err != nil { 132 exit(err) 133 } 134 return runTests(ctx, suite.SnapTests()) 135 } 136 137 type testParams struct { 138 node *enode.Node 139 engineAPI string 140 jwt string 141 chainDir string 142 } 143 144 func cliTestParams(ctx *cli.Context) *testParams { 145 nodeStr := ctx.String(testNodeFlag.Name) 146 if nodeStr == "" { 147 exit(fmt.Errorf("missing -%s", testNodeFlag.Name)) 148 } 149 node, err := parseNode(nodeStr) 150 if err != nil { 151 exit(err) 152 } 153 p := testParams{ 154 node: node, 155 engineAPI: ctx.String(testNodeEngineFlag.Name), 156 jwt: ctx.String(testNodeJWTFlag.Name), 157 chainDir: ctx.String(testChainDirFlag.Name), 158 } 159 if p.engineAPI == "" { 160 exit(fmt.Errorf("missing -%s", testNodeEngineFlag.Name)) 161 } 162 if p.jwt == "" { 163 exit(fmt.Errorf("missing -%s", testNodeJWTFlag.Name)) 164 } 165 if p.chainDir == "" { 166 exit(fmt.Errorf("missing -%s", testChainDirFlag.Name)) 167 } 168 return &p 169 }