-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lib/parachain): Implement request and response message for /req_…
…chunk/1 protocol (#3362) - Added `ChunkFetchingRequest` and `ChunkFetchingResponse` types. - implemented network.Message interface in `ChunkFetchingRequest` and 'network.ResponseMessage' interface in `ChunkFetchingResponse`
- Loading branch information
1 parent
ba9f1c3
commit feaa780
Showing
2 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
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) | ||
} | ||
|
||
type ChunkFetchingResponseValues interface { | ||
ChunkResponse | NoSuchChunk | ||
} | ||
|
||
type ChunkFetchingResponse struct { | ||
inner any | ||
} | ||
|
||
func setChunkFetchingResponse[Value ChunkFetchingResponseValues](mvdt *ChunkFetchingResponse, value Value) { | ||
mvdt.inner = value | ||
} | ||
|
||
func (mvdt *ChunkFetchingResponse) SetValue(value any) (err error) { | ||
switch value := value.(type) { | ||
case ChunkResponse: | ||
setChunkFetchingResponse(mvdt, value) | ||
return | ||
|
||
case NoSuchChunk: | ||
setChunkFetchingResponse(mvdt, value) | ||
return | ||
|
||
default: | ||
return fmt.Errorf("unsupported type") | ||
} | ||
} | ||
|
||
func (mvdt ChunkFetchingResponse) IndexValue() (index uint, value any, err error) { | ||
switch mvdt.inner.(type) { | ||
case ChunkResponse: | ||
return 0, mvdt.inner, nil | ||
|
||
case NoSuchChunk: | ||
return 1, mvdt.inner, nil | ||
|
||
} | ||
return 0, nil, scale.ErrUnsupportedVaryingDataTypeValue | ||
} | ||
|
||
func (mvdt ChunkFetchingResponse) Value() (value any, err error) { | ||
_, value, err = mvdt.IndexValue() | ||
return | ||
} | ||
|
||
func (mvdt ChunkFetchingResponse) ValueAt(index uint) (value any, err error) { | ||
switch index { | ||
case 0: | ||
return *new(ChunkResponse), nil | ||
|
||
case 1: | ||
return *new(NoSuchChunk), nil | ||
|
||
} | ||
return nil, scale.ErrUnknownVaryingDataTypeValue | ||
} | ||
|
||
// NewChunkFetchingResponse returns a new chunk fetching response varying data type | ||
func NewChunkFetchingResponse() ChunkFetchingResponse { | ||
return ChunkFetchingResponse{} | ||
} | ||
|
||
// 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"` | ||
} | ||
|
||
// NoSuchChunk indicates that the requested chunk was not found | ||
type NoSuchChunk struct{} | ||
|
||
// 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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package parachain | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
"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 any | ||
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.SetValue(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) | ||
}) | ||
|
||
}) | ||
} | ||
} |