Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(network/messages): normalize from_block field to be uint or common.Hash #4191

Merged
merged 4 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
3 changes: 1 addition & 2 deletions dot/network/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/internal/log"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/common/variadic"
libp2pnetwork "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -121,7 +120,7 @@ func (s *testStreamHandler) readStream(stream libp2pnetwork.Stream,
}
}

var starting, _ = variadic.NewUint32OrHash(uint32(1))
var starting = messages.NewFromBlock(uint(1))

var one = uint32(1)

Expand Down
132 changes: 11 additions & 121 deletions dot/network/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,125 +5,15 @@ package network

import (
"encoding/hex"
"regexp"
"testing"

"github.com/ChainSafe/gossamer/dot/network/messages"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/common/variadic"

"github.com/stretchr/testify/require"
)

func TestEncodeBlockRequestMessage(t *testing.T) {
jimjbrettj marked this conversation as resolved.
Show resolved Hide resolved
t.Parallel()

expected := common.MustHexToBytes("0x0880808008280130011220dcd1346701ca8396496e52" +
"aa2785b1748deb6db09551b72159dcb3e08991025b")
genesisHash := common.MustHexToBytes("0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b")

var one uint32 = 1
bm := &messages.BlockRequestMessage{
RequestedData: 1,
StartingBlock: *variadic.NewUint32OrHashFromBytes(append([]byte{0}, genesisHash...)),
Direction: 1,
Max: &one,
}

encMsg, err := bm.Encode()
require.NoError(t, err)

require.Equal(t, expected, encMsg)

res := new(messages.BlockRequestMessage)
err = res.Decode(encMsg)
require.NoError(t, err)
require.Equal(t, bm, res)
}

func TestEncodeBlockRequestMessage_BlockHash(t *testing.T) {
t.Parallel()

genesisHash := common.MustHexToBytes("0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b")

var one uint32 = 1
bm := &messages.BlockRequestMessage{
RequestedData: 1,
StartingBlock: *variadic.NewUint32OrHashFromBytes(append([]byte{0}, genesisHash...)),
Direction: 1,
Max: &one,
}

encMsg, err := bm.Encode()
require.NoError(t, err)

res := new(messages.BlockRequestMessage)
err = res.Decode(encMsg)
require.NoError(t, err)
require.Equal(t, bm, res)
}

func TestEncodeBlockRequestMessage_BlockNumber(t *testing.T) {
t.Parallel()

var one uint32 = 1
bm := &messages.BlockRequestMessage{
RequestedData: 1,
StartingBlock: *variadic.NewUint32OrHashFromBytes([]byte{1, 1}),
Direction: 1,
Max: &one,
}

encMsg, err := bm.Encode()
require.NoError(t, err)

res := new(messages.BlockRequestMessage)
err = res.Decode(encMsg)
require.NoError(t, err)
require.Equal(t, bm, res)
}

func TestBlockRequestString(t *testing.T) {
t.Parallel()

genesisHash := common.MustHexToBytes("0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b")

bm := &messages.BlockRequestMessage{
RequestedData: 1,
StartingBlock: *variadic.NewUint32OrHashFromBytes(append([]byte{0}, genesisHash...)),
Direction: 1,
Max: nil,
}

var blockRequestStringRegex = regexp.MustCompile(
`^\ABlockRequestMessage RequestedData=[0-9]* StartingBlock={[\[0-9(\s?)]+\]} Direction=[0-9]* Max=[0-9]*\z$`) //nolint:lll

match := blockRequestStringRegex.MatchString(bm.String())
require.True(t, match)
}

func TestEncodeBlockRequestMessage_NoOptionals(t *testing.T) {
t.Parallel()

genesisHash := common.MustHexToBytes("0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b")

bm := &messages.BlockRequestMessage{
RequestedData: 1,
StartingBlock: *variadic.NewUint32OrHashFromBytes(append([]byte{0}, genesisHash...)),
Direction: 1,
Max: nil,
}

encMsg, err := bm.Encode()
require.NoError(t, err)

res := new(messages.BlockRequestMessage)
err = res.Decode(encMsg)
require.NoError(t, err)
require.Equal(t, bm, res)
}

func TestEncodeBlockResponseMessage_Empty(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -446,7 +336,7 @@ func TestAscendingBlockRequest(t *testing.T) {
expectedBlockRequestMessage: []*messages.BlockRequestMessage{
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(10)),
StartingBlock: *messages.NewFromBlock(uint(10)),
Direction: messages.Ascending,
Max: &one,
},
Expand All @@ -461,7 +351,7 @@ func TestAscendingBlockRequest(t *testing.T) {
expectedBlockRequestMessage: []*messages.BlockRequestMessage{
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(1)),
StartingBlock: *messages.NewFromBlock(uint(1)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
Expand All @@ -475,25 +365,25 @@ func TestAscendingBlockRequest(t *testing.T) {
expectedBlockRequestMessage: []*messages.BlockRequestMessage{
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(1)),
StartingBlock: *messages.NewFromBlock(uint(1)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(129)),
StartingBlock: *messages.NewFromBlock(uint(129)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(257)),
StartingBlock: *messages.NewFromBlock(uint(257)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(385)),
StartingBlock: *messages.NewFromBlock(uint(385)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
Expand All @@ -507,31 +397,31 @@ func TestAscendingBlockRequest(t *testing.T) {
expectedBlockRequestMessage: []*messages.BlockRequestMessage{
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(1)),
StartingBlock: *messages.NewFromBlock(uint(1)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(129)),
StartingBlock: *messages.NewFromBlock(uint(129)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(257)),
StartingBlock: *messages.NewFromBlock(uint(257)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(385)),
StartingBlock: *messages.NewFromBlock(uint(385)),
Direction: messages.Ascending,
Max: &maxResponseSize,
},
{
RequestedData: messages.BootstrapRequestData,
StartingBlock: *variadic.MustNewUint32OrHash(uint32(513)),
StartingBlock: *messages.NewFromBlock(uint(513)),
Direction: messages.Ascending,
Max: &three,
},
Expand Down
75 changes: 54 additions & 21 deletions dot/network/messages/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
pb "github.com/ChainSafe/gossamer/dot/network/proto"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/common/variadic"
"github.com/ChainSafe/gossamer/pkg/scale"
"google.golang.org/protobuf/proto"
)
Expand Down Expand Up @@ -50,19 +49,57 @@ var (

var (
errBlockRequestFromNumberInvalid = errors.New("block request message From number is not valid")
errInvalidStartingBlockType = errors.New("invalid StartingBlock in messsage")
ErrNilBlockInResponse = errors.New("nil block in response")
)

type fromBlockType byte

const (
fromBlockNumber fromBlockType = iota
fromBlockHash
)

type FromBlock struct {
value any
}

// NewUintOrHash returns a new variadic.Uint32OrHash given an int, uint32, or Hash
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
func NewFromBlock[T common.Hash | ~uint](value T) *FromBlock {
return &FromBlock{
value: value,
}
}

// Encode will encode a Uint32OrHash using SCALE
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
func (x *FromBlock) RawValue() any {
return x.value
}

// Encode will encode a Uint32OrHash using SCALE
func (x *FromBlock) ToProto() (fromBlockType, []byte) {
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
switch rawValue := x.value.(type) {
case uint:
startingBlockByteArray := make([]byte, 4)
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
// the protobuf number type only support 4 bytes number
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
// so we bound rawValue to the max uint32
binary.LittleEndian.PutUint32(startingBlockByteArray, uint32(rawValue&0x11111111))
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
return fromBlockNumber, startingBlockByteArray
case common.Hash:
return fromBlockHash, rawValue.ToBytes()
default:
panic(fmt.Sprintf("unsupported FromBlock type: %T", x.value))
}
}

// BlockRequestMessage is sent to request some blocks from a peer
type BlockRequestMessage struct {
RequestedData byte
StartingBlock variadic.Uint32OrHash // first byte 0 = block hash (32 byte), first byte 1 = block number (uint32)
Direction SyncDirection // 0 = ascending, 1 = descending
StartingBlock FromBlock // first byte 0 = block hash (32 byte), first byte 1 = block number (uint32)
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
Direction SyncDirection // 0 = ascending, 1 = descending
Max *uint32
}

func NewBlockRequest(startingBlock variadic.Uint32OrHash, amount uint32,
func NewBlockRequest(startingBlock FromBlock, amount uint32,
requestedData byte, direction SyncDirection) *BlockRequestMessage {
return &BlockRequestMessage{
RequestedData: requestedData,
Expand All @@ -82,7 +119,7 @@ func NewAscendingBlockRequests(startNumber, targetNumber uint, requestedData byt
// start and end block are the same, just request 1 block
if diff == 0 {
return []*BlockRequestMessage{
NewBlockRequest(*variadic.MustNewUint32OrHash(uint32(startNumber)), 1, requestedData, Ascending),
NewBlockRequest(*NewFromBlock(startNumber), 1, requestedData, Ascending),
}
}

Expand All @@ -107,8 +144,7 @@ func NewAscendingBlockRequests(startNumber, targetNumber uint, requestedData byt
max = uint32(missingBlocks)
}

start := variadic.MustNewUint32OrHash(startNumber)
reqs[i] = NewBlockRequest(*start, max, requestedData, Ascending)
reqs[i] = NewBlockRequest(*NewFromBlock(startNumber), max, requestedData, Ascending)
startNumber += uint(max)
}

Expand Down Expand Up @@ -141,19 +177,16 @@ func (bm *BlockRequestMessage) Encode() ([]byte, error) {
MaxBlocks: max,
}

if bm.StartingBlock.IsHash() {
hash := bm.StartingBlock.Hash()
protoType, encoded := bm.StartingBlock.ToProto()
switch protoType {
case fromBlockHash:
msg.FromBlock = &pb.BlockRequest_Hash{
Hash: hash[:],
Hash: encoded,
}
} else if bm.StartingBlock.IsUint32() {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, bm.StartingBlock.Uint32())
case fromBlockNumber:
msg.FromBlock = &pb.BlockRequest_Number{
Number: buf,
Number: encoded,
}
} else {
return nil, errInvalidStartingBlockType
}

return proto.Marshal(msg)
Expand All @@ -168,20 +201,20 @@ func (bm *BlockRequestMessage) Decode(in []byte) error {
}

var (
startingBlock *variadic.Uint32OrHash
startingBlock *FromBlock
max *uint32
)

switch from := msg.FromBlock.(type) {
case *pb.BlockRequest_Hash:
startingBlock, err = variadic.NewUint32OrHash(common.BytesToHash(from.Hash))
startingBlock = NewFromBlock(common.BytesToHash(from.Hash))
case *pb.BlockRequest_Number:
if len(from.Number) != 4 {
return fmt.Errorf("%w expected 4 bytes, got %d bytes", errBlockRequestFromNumberInvalid, len(from.Number))
}

number := binary.LittleEndian.Uint32(from.Number)
startingBlock, err = variadic.NewUint32OrHash(number)
number := uint(binary.LittleEndian.Uint32(from.Number))
startingBlock = NewFromBlock(number)
default:
err = errors.New("invalid StartingBlock")
}
Expand Down
Loading
Loading