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
…available_data/1 protocol (#3368)

- Added AvailableDataFetchingRequest and AvailableDataFetchingResponse types.
- Implemented 'network.Message' interface in AvailableDataFetchingRequest and 'network.ResponseMessage' interface in AvailableDataFetchingResponse as they will be passed into this function as req and res.
  • Loading branch information
axaysagathiya authored and kishansagathiya committed Jul 12, 2023
1 parent d377156 commit 1612456
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 0 deletions.
119 changes: 119 additions & 0 deletions lib/parachain/available_data_fetching.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package parachain

import (
"fmt"

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

// AvailableDataFetchingRequest represents a request to retrieve all available data for a specific candidate.
type AvailableDataFetchingRequest struct {
// Hash of the candidate for which the available data is requested.
CandidateHash CandidateHash
}

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

// AvailableDataFetchingResponse represents the possible responses to an available data fetching request.
type AvailableDataFetchingResponse scale.VaryingDataType

// NewAvailableDataFetchingResponse returns a new available data fetching response varying data type
func NewAvailableDataFetchingResponse() AvailableDataFetchingResponse {
vdt := scale.MustNewVaryingDataType(AvailableData{}, NoSuchData{})
return AvailableDataFetchingResponse(vdt)
}

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

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

// AvailableData represents the data that is kept available for each candidate included in the relay chain.
type AvailableData struct {
// The Proof-of-Validation (PoV) of the candidate
PoV Pov `scale:"1"`

// The persisted validation data needed for approval checks
ValidationData PersistedValidationData `scale:"2"`
}

// Pov represents a Proof-of-Validity block (PoV block) or a parachain block.
// It contains the necessary data for the parachain specific state transition logic.
type Pov struct {
BlockData BlockData `scale:"1"`
}

// BlockData represents parachain block data.
// It contains everything required to validate para-block, may contain block and witness data.
type BlockData []byte

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

// PersistedValidationData provides information about how to create the inputs for the validation
// of a candidate by calling the Runtime.
// This information is derived from the parachain state and will vary from parachain to parachain,
// although some of the fields may be the same for every parachain.
type PersistedValidationData struct {
// The parent head-data
ParentHead headData `scale:"1"`

// The relay-chain block number this is in the context of
RelayParentNumber BlockNumber `scale:"2"`

// The relay-chain block storage root this is in the context of
RelayParentStorageRoot common.Hash `scale:"3"`

// The maximum legal size of a POV block, in bytes
MaxPovSize uint32 `scale:"4"`
}

// NoSuchData indicates that the requested data was not found.
type NoSuchData struct{}

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

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

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

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

v, _ := p.Value()
availableData, ok := v.(AvailableData)
if !ok {
return "AvailableDataFetchingResponse=NoSuchData"
}
return fmt.Sprintf("AvailableDataFetchingResponse AvailableData=%+v", availableData)
}
90 changes: 90 additions & 0 deletions lib/parachain/available_data_fetching_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package parachain

import (
"testing"

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

func TestEncodeAvailableDataFetchingRequest(t *testing.T) {
availableDataFetchingRequest := AvailableDataFetchingRequest{
CandidateHash: CandidateHash{
common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
},
}

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

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

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

testHash := common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19")
testBytes := testHash.ToBytes()
availableData := AvailableData{
PoV: Pov{BlockData: testBytes},
ValidationData: PersistedValidationData{
ParentHead: testBytes,
RelayParentNumber: BlockNumber(4),
RelayParentStorageRoot: testHash,
MaxPovSize: 6,
},
}

testCases := []struct {
name string
value scale.VaryingDataTypeValue
encodeValue []byte
}{
{
name: "AvailableData",
value: availableData,
encodeValue: common.MustHexToBytes("0x0080677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c1980677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c1904000000677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c1906000000"), //nolint:lll
},
{
name: "NoSuchData",
value: NoSuchData{},
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()

availableDataFetchingResponse := NewAvailableDataFetchingResponse()
err := availableDataFetchingResponse.Set(c.value)
require.NoError(t, err)

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

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

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

availableDataFetchingResponse := NewAvailableDataFetchingResponse()
err := availableDataFetchingResponse.Decode(c.encodeValue)
require.NoError(t, err)

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

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

})
}
}

0 comments on commit 1612456

Please sign in to comment.