Skip to content

Commit

Permalink
feat(parachain): Implement request and response message for /req_stat…
Browse files Browse the repository at this point in the history
…ement/1 protocol (#3354)

- Added `StatementFetchingRequest` and `StatementFetchingResponse`  varying data types.

- implemented 'network.Message` interface in `StatementFetchingRequest` and 'network.ResponseMessage` interface in `StatementFetchingResponse` as they will be passed into `func (rrp *RequestResponseProtocol) Do(to peer.ID, req Message, res ResponseMessage) error` function as `req` and `res`.

- I didn't want to create a new YAML file here. so I decided to rename the YAML file name and variable(in which data of the YAML file getting unmarshalled) name so that I can use them in this PR.
  • Loading branch information
axaysagathiya authored and kishansagathiya committed Aug 22, 2023
1 parent 8d0aa03 commit 5dfe5c5
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 13 deletions.
2 changes: 1 addition & 1 deletion lib/parachain/collation_protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestCollationProtocol(t *testing.T) {
copy(collatorID[:], tempCollatID)

var collatorSignature CollatorSignature
tempSignature := common.MustHexToBytes(testSDMHex["collatorSignature"])
tempSignature := common.MustHexToBytes(testDataStatement["collatorSignature"])
copy(collatorSignature[:], tempSignature)

var validatorSignature ValidatorSignature
Expand Down
16 changes: 8 additions & 8 deletions lib/parachain/statement_distribution_message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (
"gopkg.in/yaml.v3"
)

//go:embed testdata/statement_distribution_message.yaml
var testSDMHexRaw string
//go:embed testdata/statement.yaml
var testDataStatementRaw string

var testSDMHex map[string]string
var testDataStatement map[string]string

func init() {
err := yaml.Unmarshal([]byte(testSDMHexRaw), &testSDMHex)
err := yaml.Unmarshal([]byte(testDataStatementRaw), &testDataStatement)
if err != nil {
fmt.Printf("Error unmarshaling test data: %s\n", err)
return
Expand All @@ -28,7 +28,7 @@ func TestStatementDistributionMessage(t *testing.T) {
t.Parallel()

var collatorSignature CollatorSignature
tempSignature := common.MustHexToBytes(testSDMHex["collatorSignature"])
tempSignature := common.MustHexToBytes(testDataStatement["collatorSignature"])
copy(collatorSignature[:], tempSignature)

var validatorSignature ValidatorSignature
Expand Down Expand Up @@ -166,17 +166,17 @@ func TestStatementDistributionMessage(t *testing.T) {
{
name: "SignedFullStatement with valid statement",
enumValue: signedFullStatementWithValid,
encodingValue: common.MustHexToBytes(testSDMHex["sfsValid"]),
encodingValue: common.MustHexToBytes(testDataStatement["sfsValid"]),
},
{
name: "SignedFullStatement with Seconded statement",
enumValue: signedFullStatementWithSeconded,
encodingValue: common.MustHexToBytes(testSDMHex["sfsSeconded"]),
encodingValue: common.MustHexToBytes(testDataStatement["sfsSeconded"]),
},
{
name: "Seconded Statement With LargePayload",
enumValue: secondedStatementWithLargePayload,
encodingValue: common.MustHexToBytes(testSDMHex["statementWithLargePayload"]),
encodingValue: common.MustHexToBytes(testDataStatement["statementWithLargePayload"]),
},
}

Expand Down
81 changes: 81 additions & 0 deletions lib/parachain/statement_fetching.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package parachain

import (
"fmt"

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

// StatementFetchingRequest represents a request for fetching a large statement via request/response.
type StatementFetchingRequest struct {
// Data needed to locate and identify the needed statement.
RelayParent common.Hash `scale:"1"`

// Hash of candidate that was used create the `CommitedCandidateRecept`.
CandidateHash CandidateHash `scale:"2"`
}

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

// StatementFetchingResponse represents the statement fetching response is
// sent by nodes to the clients who issued a collation fetching request.
//
// Respond with found full statement.
type StatementFetchingResponse scale.VaryingDataType

// MissingDataInStatement represents the data missing to reconstruct the full signed statement.
type MissingDataInStatement CommittedCandidateReceipt

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

// NewStatementFetchingResponse returns a new statement fetching response varying data type
func NewStatementFetchingResponse() StatementFetchingResponse {
vdt := scale.MustNewVaryingDataType(MissingDataInStatement{})
return StatementFetchingResponse(vdt)
}

// Set will set a value using the underlying varying data type
func (s *StatementFetchingResponse) Set(val scale.VaryingDataTypeValue) (err error) {
vdt := scale.VaryingDataType(*s)
err = vdt.Set(val)
if err != nil {
return fmt.Errorf("setting value to varying data type: %w", err)
}

*s = StatementFetchingResponse(vdt)
return nil
}

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

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

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

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

v, _ := s.Value()
missingData := v.(MissingDataInStatement)
return fmt.Sprintf("StatementFetchingResponse MissingDataInStatement=%+v", missingData)
}
130 changes: 130 additions & 0 deletions lib/parachain/statement_fetching_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package parachain

import (
"testing"

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

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

testCases := []struct {
name string
request StatementFetchingRequest
expectedEncode []byte
}{
{
// expected encoding is generated by running rust test code:
// fn statement_request() {
// let hash4 = Hash::repeat_byte(4);
// let statement_fetching_request = StatementFetchingRequest{
// relay_parent: hash4,
// candidate_hash: CandidateHash(hash4)
// };
// println!(
// "statement_fetching_request encode => {:?}\n\n",
// statement_fetching_request.encode()
// );
// }
name: "all_4_in_hash",
request: StatementFetchingRequest{
RelayParent: getDummyHash(4),
CandidateHash: CandidateHash{Value: getDummyHash(4)},
},
expectedEncode: common.MustHexToBytes(testDataStatement["all4InCommonHash"]),
},
{
name: "all_7_in_hash",
request: StatementFetchingRequest{
RelayParent: getDummyHash(7),
CandidateHash: CandidateHash{Value: getDummyHash(7)},
},
expectedEncode: common.MustHexToBytes(testDataStatement["all7InCommonHash"]),
},
{
name: "random_hash",
request: StatementFetchingRequest{
RelayParent: common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
CandidateHash: CandidateHash{
Value: common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
},
},
expectedEncode: common.MustHexToBytes(testDataStatement["hexOfStatementFetchingRequest"]),
},
}

for _, c := range testCases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel()
actualEncode, err := c.request.Encode()
require.NoError(t, err)
require.Equal(t, c.expectedEncode, actualEncode)
})
}
}

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

testHash := common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19")

var collatorID CollatorID
tempCollatID := common.MustHexToBytes("0x48215b9d322601e5b1a95164cea0dc4626f545f98343d07f1551eb9543c4b147")
copy(collatorID[:], tempCollatID)

var collatorSignature CollatorSignature
tempSignature := common.MustHexToBytes(testDataStatement["collatorSignature"])
copy(collatorSignature[:], tempSignature)

missingDataInStatement := MissingDataInStatement{
Descriptor: CandidateDescriptor{
ParaID: uint32(1),
RelayParent: testHash,
Collator: collatorID,
PersistedValidationDataHash: testHash,
PovHash: testHash,
ErasureRoot: testHash,
Signature: collatorSignature,
ParaHead: testHash,
ValidationCodeHash: ValidationCodeHash(testHash),
},
Commitments: CandidateCommitments{
UpwardMessages: []UpwardMessage{{1, 2, 3}},
NewValidationCode: &ValidationCode{1, 2, 3},
HeadData: headData{1, 2, 3},
ProcessedDownwardMessages: uint32(5),
HrmpWatermark: uint32(0),
},
}

encodedValue := common.MustHexToBytes(testDataStatement["hexOfStatementFetchingResponse"])

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

response := NewStatementFetchingResponse()
err := response.Set(missingDataInStatement)
require.NoError(t, err)

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

require.Equal(t, encodedValue, actualEncode)
})

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

response := NewStatementFetchingResponse()
err := response.Decode(encodedValue)
require.NoError(t, err)

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

require.EqualValues(t, missingDataInStatement, actualData)
})
}
5 changes: 2 additions & 3 deletions lib/parachain/statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestStatement(t *testing.T) {
copy(collatorID[:], tempCollatID)

var collatorSignature CollatorSignature
tempSignature := common.MustHexToBytes(testSDMHex["collatorSignature"])
tempSignature := common.MustHexToBytes(testDataStatement["collatorSignature"])
copy(collatorSignature[:], tempSignature)

hash5 := getDummyHash(5)
Expand Down Expand Up @@ -59,8 +59,7 @@ func TestStatement(t *testing.T) {
{
name: "Seconded",
enumValue: secondedEnumValue,
encodingValue: common.MustHexToBytes(testSDMHex["statementSeconded"]),
// expected Hex stored in statement_distribution_message.yaml
encodingValue: common.MustHexToBytes(testDataStatement["statementSeconded"]),
},
{
name: "Valid",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

# ==========| statement distribution message |==========


collatorSignature: "0xc67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b86"

# Seconded
Expand All @@ -10,4 +14,20 @@ sfsValid: "0x0005050505050505050505050505050505050505050505050505050505050505050
sfsSeconded: "0x0005050505050505050505050505050505050505050505050505050505050505050101000000050505050505050505050505050505050505050505050505050505050505050548215b9d322601e5b1a95164cea0dc4626f545f98343d07f1551eb9543c4b147050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505c67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b8605050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505040c01020300010c0102030c010203050000000000000005000000c67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b86"

# Seconded Statement With LargePayload
statementWithLargePayload: "0x010505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000000c67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b86"
statementWithLargePayload: "0x010505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000000c67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b86"



# ==========| statement fetching request and response |==========


# hex of a common.Hash where all 32 bytes are set to 4.
all4InCommonHash: "0x04040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"

# hex of a common.Hash where all 32 bytes are set to 7.
all7InCommonHash: "0x07070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707"

# hex of statement fetching response
hexOfStatementFetchingResponse: "0x0001000000677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c1948215b9d322601e5b1a95164cea0dc4626f545f98343d07f1551eb9543c4b147677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19c67cb93bf0a36fcee3d29de8a6a69a759659680acf486475e0a2552a5fbed87e45adce5f290698d8596095722b33599227f7461f51af8617c8be74b894cf1b86677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19040c01020300010c0102030c0102030500000000000000"

hexOfStatementFetchingRequest: "0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"

0 comments on commit 5dfe5c5

Please sign in to comment.