Skip to content

Commit

Permalink
feat(lib/parachain): Implement request and response message for /req_…
Browse files Browse the repository at this point in the history
…chunk/1 protocol (#3362)

- Added `ChunkFetchingRequest` and `ChunkFetchingResponse` types.

- implemented network.Message interface in `ChunkFetchingRequest` and 'network.ResponseMessage' interface in `ChunkFetchingResponse`
  • Loading branch information
axaysagathiya authored and kishansagathiya committed Jan 24, 2024
1 parent dec23c9 commit 3624908
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 0 deletions.
93 changes: 93 additions & 0 deletions lib/parachain/chunk_fetching.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package parachain

import (
"fmt"

"github.com/ChainSafe/gossamer/pkg/scale"
)

// ChunkFetchingRequest represents a request to retrieve chunks of a parachain candidate
type ChunkFetchingRequest struct {
// Hash of candidate we want a chunk for.
CandidateHash CandidateHash `scale:"1"`

// The index of the chunk to fetch.
Index ValidatorIndex `scale:"2"`
}

// Encode returns the SCALE encoding of the ChunkFetchingRequest
func (c ChunkFetchingRequest) Encode() ([]byte, error) {
return scale.Marshal(c)
}

// ChunkFetchingResponse represents the response for a requested erasure chunk
type ChunkFetchingResponse scale.VaryingDataType

// NewChunkFetchingResponse returns a new chunk fetching response varying data type
func NewChunkFetchingResponse() ChunkFetchingResponse {
vdt := scale.MustNewVaryingDataType(ChunkResponse{}, NoSuchChunk{})
return ChunkFetchingResponse(vdt)
}

// Set will set a value using the underlying varying data type
func (c *ChunkFetchingResponse) Set(val scale.VaryingDataTypeValue) (err error) {
vdt := scale.VaryingDataType(*c)
err = vdt.Set(val)
if err != nil {
return
}
*c = ChunkFetchingResponse(vdt)
return
}

// Value returns the value from the underlying varying data type
func (c *ChunkFetchingResponse) Value() (val scale.VaryingDataTypeValue, err error) {
vdt := scale.VaryingDataType(*c)
return vdt.Value()
}

// ChunkResponse represents the requested chunk data
type ChunkResponse struct {
// The erasure-encoded chunk of data belonging to the candidate block
Chunk []byte `scale:"1"`

// Proof for this chunk's branch in the Merkle tree
Proof [][]byte `scale:"2"`
}

// Index returns the index of varying data type
func (ChunkResponse) Index() uint {
return 0
}

// NoSuchChunk indicates that the requested chunk was not found
type NoSuchChunk struct{}

// Index returns the index of varying data type
func (NoSuchChunk) Index() uint {
return 1
}

// Encode returns the SCALE encoding of the ChunkFetchingResponse
func (c *ChunkFetchingResponse) Encode() ([]byte, error) {
return scale.Marshal(*c)
}

// Decode returns the SCALE decoding of the ChunkFetchingResponse.
func (c *ChunkFetchingResponse) Decode(in []byte) (err error) {
return scale.Unmarshal(in, c)
}

// String formats a ChunkFetchingResponse as a string
func (c *ChunkFetchingResponse) String() string {
if c == nil {
return "ChunkFetchingResponse=nil"
}

v, _ := c.Value()
chunkRes, ok := v.(ChunkResponse)
if !ok {
return "ChunkFetchingResponse=NoSuchChunk"
}
return fmt.Sprintf("ChunkFetchingResponse ChunkResponse=%+v", chunkRes)
}
83 changes: 83 additions & 0 deletions lib/parachain/chunk_fetching_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package parachain

import (
"testing"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/pkg/scale"
"github.com/stretchr/testify/require"
)

func TestEncodeChunkFetchingRequest(t *testing.T) {
chunkFetchingRequest := ChunkFetchingRequest{
CandidateHash: CandidateHash{
common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
},
Index: ValidatorIndex(8),
}

actualEncode, err := chunkFetchingRequest.Encode()
require.NoError(t, err)

expextedEncode := common.MustHexToBytes("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c1908000000")
require.Equal(t, expextedEncode, actualEncode)
}

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

testBytes := common.MustHexToBytes("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19")
testCases := []struct {
name string
value scale.VaryingDataTypeValue
encodeValue []byte
}{
{
name: "chunkResponse",
value: ChunkResponse{
Chunk: testBytes,
Proof: [][]byte{testBytes},
},
encodeValue: common.MustHexToBytes("0x0080677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c190480677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"), //nolint:lll
},
{
name: "NoSuchChunk",
value: NoSuchChunk{},
encodeValue: []byte{1},
},
}

for _, c := range testCases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel()

t.Run("encode", func(t *testing.T) {
t.Parallel()

chunkFetchingResponse := NewChunkFetchingResponse()
err := chunkFetchingResponse.Set(c.value)
require.NoError(t, err)

actualEncode, err := chunkFetchingResponse.Encode()
require.NoError(t, err)

require.Equal(t, c.encodeValue, actualEncode)
})

t.Run("decode", func(t *testing.T) {
t.Parallel()

chunkFetchingResponse := NewChunkFetchingResponse()
err := chunkFetchingResponse.Decode(c.encodeValue)
require.NoError(t, err)

actualData, err := chunkFetchingResponse.Value()
require.NoError(t, err)

require.EqualValues(t, c.value, actualData)
})

})
}
}

0 comments on commit 3624908

Please sign in to comment.