cmd/devp2p/internal/ethtest: use shared message types (#22315)

This updates the eth protocol test suite to use the message type
definitions of the 'production' protocol implementation in eth/protocols/eth.
This commit is contained in:
rene 2021-02-16 15:23:03 +01:00 committed by GitHub
parent 6291fc9230
commit f9445e93bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 84 deletions

View File

@ -21,6 +21,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -93,7 +94,7 @@ func TestChain_GetHeaders(t *testing.T) {
}{ }{
{ {
req: GetBlockHeaders{ req: GetBlockHeaders{
Origin: hashOrNumber{ Origin: eth.HashOrNumber{
Number: uint64(2), Number: uint64(2),
}, },
Amount: uint64(5), Amount: uint64(5),
@ -110,7 +111,7 @@ func TestChain_GetHeaders(t *testing.T) {
}, },
{ {
req: GetBlockHeaders{ req: GetBlockHeaders{
Origin: hashOrNumber{ Origin: eth.HashOrNumber{
Number: uint64(chain.Len() - 1), Number: uint64(chain.Len() - 1),
}, },
Amount: uint64(3), Amount: uint64(3),
@ -125,7 +126,7 @@ func TestChain_GetHeaders(t *testing.T) {
}, },
{ {
req: GetBlockHeaders{ req: GetBlockHeaders{
Origin: hashOrNumber{ Origin: eth.HashOrNumber{
Hash: chain.Head().Hash(), Hash: chain.Head().Hash(),
}, },
Amount: uint64(1), Amount: uint64(1),

View File

@ -24,6 +24,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/internal/utesting"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
@ -143,7 +144,7 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
// get block headers // get block headers
req := &GetBlockHeaders{ req := &GetBlockHeaders{
Origin: hashOrNumber{ Origin: eth.HashOrNumber{
Hash: s.chain.blocks[1].Hash(), Hash: s.chain.blocks[1].Hash(),
}, },
Amount: 2, Amount: 2,
@ -157,8 +158,8 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
switch msg := conn.ReadAndServe(s.chain, timeout).(type) { switch msg := conn.ReadAndServe(s.chain, timeout).(type) {
case *BlockHeaders: case *BlockHeaders:
headers := msg headers := *msg
for _, header := range *headers { for _, header := range headers {
num := header.Number.Uint64() num := header.Number.Uint64()
t.Logf("received header (%d): %s", num, pretty.Sdump(header)) t.Logf("received header (%d): %s", num, pretty.Sdump(header))
assert.Equal(t, s.chain.blocks[int(num)].Header(), header) assert.Equal(t, s.chain.blocks[int(num)].Header(), header)
@ -179,7 +180,10 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
conn.handshake(t) conn.handshake(t)
conn.statusExchange(t, s.chain, nil) conn.statusExchange(t, s.chain, nil)
// create block bodies request // create block bodies request
req := &GetBlockBodies{s.chain.blocks[54].Hash(), s.chain.blocks[75].Hash()} req := &GetBlockBodies{
s.chain.blocks[54].Hash(),
s.chain.blocks[75].Hash(),
}
if err := conn.Write(req); err != nil { if err := conn.Write(req); err != nil {
t.Fatalf("could not write to connection: %v", err) t.Fatalf("could not write to connection: %v", err)
} }
@ -357,10 +361,9 @@ func (s *Suite) waitAnnounce(t *utesting.T, conn *Conn, blockAnnouncement *NewBl
"wrong TD in announcement", "wrong TD in announcement",
) )
case *NewBlockHashes: case *NewBlockHashes:
hashes := *msg message := *msg
t.Logf("received NewBlockHashes message: %s", pretty.Sdump(hashes)) t.Logf("received NewBlockHashes message: %s", pretty.Sdump(message))
assert.Equal(t, assert.Equal(t, blockAnnouncement.Block.Hash(), message[0].Hash,
blockAnnouncement.Block.Hash(), hashes[0].Hash,
"wrong block hash in announcement", "wrong block hash in announcement",
) )
default: default:

View File

@ -32,7 +32,7 @@ func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) {
sendConn := s.setupConnection(t) sendConn := s.setupConnection(t)
t.Logf("sending tx: %v %v %v\n", tx.Hash().String(), tx.GasPrice(), tx.Gas()) t.Logf("sending tx: %v %v %v\n", tx.Hash().String(), tx.GasPrice(), tx.Gas())
// Send the transaction // Send the transaction
if err := sendConn.Write(Transactions([]*types.Transaction{tx})); err != nil { if err := sendConn.Write(&Transactions{tx}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@ -70,7 +70,7 @@ func sendFailingTx(t *utesting.T, s *Suite, tx *types.Transaction) {
t.Logf("unexpected message, logging: %v", pretty.Sdump(msg)) t.Logf("unexpected message, logging: %v", pretty.Sdump(msg))
} }
// Send the transaction // Send the transaction
if err := sendConn.Write(Transactions([]*types.Transaction{tx})); err != nil { if err := sendConn.Write(&Transactions{tx}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Wait for another transaction announcement // Wait for another transaction announcement

View File

@ -19,15 +19,12 @@ package ethtest
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"io"
"math/big"
"reflect" "reflect"
"time" "time"
"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/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/internal/utesting"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/rlpx" "github.com/ethereum/go-ethereum/p2p/rlpx"
@ -81,102 +78,48 @@ type Pong struct{}
func (p Pong) Code() int { return 0x03 } func (p Pong) Code() int { return 0x03 }
// Status is the network packet for the status message for eth/64 and later. // Status is the network packet for the status message for eth/64 and later.
type Status struct { type Status eth.StatusPacket
ProtocolVersion uint32
NetworkID uint64
TD *big.Int
Head common.Hash
Genesis common.Hash
ForkID forkid.ID
}
func (s Status) Code() int { return 16 } func (s Status) Code() int { return 16 }
// NewBlockHashes is the network packet for the block announcements. // NewBlockHashes is the network packet for the block announcements.
type NewBlockHashes []struct { type NewBlockHashes eth.NewBlockHashesPacket
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
}
func (nbh NewBlockHashes) Code() int { return 17 } func (nbh NewBlockHashes) Code() int { return 17 }
type Transactions []*types.Transaction type Transactions eth.TransactionsPacket
func (t Transactions) Code() int { return 18 } func (t Transactions) Code() int { return 18 }
// GetBlockHeaders represents a block header query. // GetBlockHeaders represents a block header query.
type GetBlockHeaders struct { type GetBlockHeaders eth.GetBlockHeadersPacket
Origin hashOrNumber // Block from which to retrieve headers
Amount uint64 // Maximum number of headers to retrieve
Skip uint64 // Blocks to skip between consecutive headers
Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
}
func (g GetBlockHeaders) Code() int { return 19 } func (g GetBlockHeaders) Code() int { return 19 }
type BlockHeaders []*types.Header type BlockHeaders eth.BlockHeadersPacket
func (bh BlockHeaders) Code() int { return 20 } func (bh BlockHeaders) Code() int { return 20 }
// GetBlockBodies represents a GetBlockBodies request // GetBlockBodies represents a GetBlockBodies request
type GetBlockBodies []common.Hash type GetBlockBodies eth.GetBlockBodiesPacket
func (gbb GetBlockBodies) Code() int { return 21 } func (gbb GetBlockBodies) Code() int { return 21 }
// BlockBodies is the network packet for block content distribution. // BlockBodies is the network packet for block content distribution.
type BlockBodies []*types.Body type BlockBodies eth.BlockBodiesPacket
func (bb BlockBodies) Code() int { return 22 } func (bb BlockBodies) Code() int { return 22 }
// NewBlock is the network packet for the block propagation message. // NewBlock is the network packet for the block propagation message.
type NewBlock struct { type NewBlock eth.NewBlockPacket
Block *types.Block
TD *big.Int
}
func (nb NewBlock) Code() int { return 23 } func (nb NewBlock) Code() int { return 23 }
// NewPooledTransactionHashes is the network packet for the tx hash propagation message. // NewPooledTransactionHashes is the network packet for the tx hash propagation message.
type NewPooledTransactionHashes [][32]byte type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket
func (nb NewPooledTransactionHashes) Code() int { return 24 } func (nb NewPooledTransactionHashes) Code() int { return 24 }
// HashOrNumber is a combined field for specifying an origin block.
type hashOrNumber struct {
Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
Number uint64 // Block hash from which to retrieve headers (excludes Hash)
}
// EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
// two contained union fields.
func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
if hn.Hash == (common.Hash{}) {
return rlp.Encode(w, hn.Number)
}
if hn.Number != 0 {
return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
}
return rlp.Encode(w, hn.Hash)
}
// DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
// into either a block hash or a block number.
func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
_, size, _ := s.Kind()
origin, err := s.Raw()
if err == nil {
switch {
case size == 32:
err = rlp.DecodeBytes(origin, &hn.Hash)
case size <= 8:
err = rlp.DecodeBytes(origin, &hn.Number)
default:
err = fmt.Errorf("invalid input size %d for origin", size)
}
}
return err
}
// Conn represents an individual connection with a peer // Conn represents an individual connection with a peer
type Conn struct { type Conn struct {
*rlpx.Conn *rlpx.Conn
@ -221,7 +164,7 @@ func (c *Conn) Read() Message {
default: default:
return errorf("invalid message code: %d", code) return errorf("invalid message code: %d", code)
} }
// if message is devp2p, decode here
if err := rlp.DecodeBytes(rawData, msg); err != nil { if err := rlp.DecodeBytes(rawData, msg); err != nil {
return errorf("could not rlp decode message: %v", err) return errorf("could not rlp decode message: %v", err)
} }
@ -256,7 +199,12 @@ func (c *Conn) ReadAndServe(chain *Chain, timeout time.Duration) Message {
} }
func (c *Conn) Write(msg Message) error { func (c *Conn) Write(msg Message) error {
payload, err := rlp.EncodeToBytes(msg) // check if message is eth protocol message
var (
payload []byte
err error
)
payload, err = rlp.EncodeToBytes(msg)
if err != nil { if err != nil {
return err return err
} }
@ -363,7 +311,7 @@ loop:
} }
} }
if err := c.Write(*status); err != nil { if err := c.Write(status); err != nil {
t.Fatalf("could not write to connection: %v", err) t.Fatalf("could not write to connection: %v", err)
} }
@ -378,7 +326,7 @@ func (c *Conn) waitForBlock(block *types.Block) error {
timeout := time.Now().Add(20 * time.Second) timeout := time.Now().Add(20 * time.Second)
c.SetReadDeadline(timeout) c.SetReadDeadline(timeout)
for { for {
req := &GetBlockHeaders{Origin: hashOrNumber{Hash: block.Hash()}, Amount: 1} req := &GetBlockHeaders{Origin: eth.HashOrNumber{Hash: block.Hash()}, Amount: 1}
if err := c.Write(req); err != nil { if err := c.Write(req); err != nil {
return err return err
} }