-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(parachain): Create struct for Approval Distribution Message (#3326)
- Loading branch information
1 parent
f585dff
commit 1c04418
Showing
2 changed files
with
381 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,179 @@ | ||
// Copyright 2021 ChainSafe Systems (ON) | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
package parachain | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
"github.com/ChainSafe/gossamer/lib/crypto/sr25519" | ||
"github.com/ChainSafe/gossamer/pkg/scale" | ||
) | ||
|
||
// AssignmentCertKind different kinds of input or criteria that can prove a validator's assignment | ||
// to check a particular parachain. | ||
type AssignmentCertKind scale.VaryingDataType | ||
|
||
// New will enable scale to create new instance when needed | ||
func (ack AssignmentCertKind) New() AssignmentCertKind { | ||
return NewAssignmentCertKindVDT() | ||
} | ||
|
||
// Set will set VaryingDataTypeValue using undurlying VaryingDataType | ||
func (ack *AssignmentCertKind) Set(val scale.VaryingDataTypeValue) (err error) { | ||
vdt := scale.VaryingDataType(*ack) | ||
err = vdt.Set(val) | ||
if err != nil { | ||
return fmt.Errorf("setting value te varying data type: %w", err) | ||
} | ||
*ack = AssignmentCertKind(vdt) | ||
return nil | ||
} | ||
|
||
// Value returns the value from the underlying VaryingDataType | ||
func (ack *AssignmentCertKind) Value() (scale.VaryingDataTypeValue, error) { | ||
vdt := scale.VaryingDataType(*ack) | ||
return vdt.Value() | ||
} | ||
|
||
// NewAssignmentCertKindVDT constructor for AssignmentCertKind | ||
func NewAssignmentCertKindVDT() AssignmentCertKind { | ||
vdt, err := scale.NewVaryingDataType(NewRelayVRFModulo(), NewVRFDelay()) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return AssignmentCertKind(vdt) | ||
} | ||
|
||
// RelayVRFModulo an assignment story based on the VRF that authorized the relay-chain block where the | ||
// candidate was included combined with a sample number. | ||
type RelayVRFModulo struct { | ||
// Sample the sample number used in this cert. | ||
Sample uint32 | ||
} | ||
|
||
// NewRelayVRFModulo constructor for RelayVRFModulo | ||
func NewRelayVRFModulo() RelayVRFModulo { | ||
return RelayVRFModulo{} | ||
} | ||
|
||
// Index returns varying data type index | ||
func (rvm RelayVRFModulo) Index() uint { | ||
return 0 | ||
} | ||
|
||
// RelayVRFDelay an assignment story based on the VRF that authorized the relay-chain block where the | ||
// candidate was included combined with the index of a particular core. | ||
type RelayVRFDelay struct { | ||
// CoreIndex the unique (during session) index of a core. | ||
CoreIndex uint32 | ||
} | ||
|
||
// NewVRFDelay constructor for RelayVRFDelay | ||
func NewVRFDelay() RelayVRFDelay { | ||
return RelayVRFDelay{} | ||
} | ||
|
||
// Index returns varying data type index | ||
func (rvd RelayVRFDelay) Index() uint { | ||
return 1 | ||
} | ||
|
||
// VrfSignature represents VRF signature, which itself consists of a VRF pre-output and DLEQ proof | ||
type VrfSignature struct { | ||
// Output VRF output | ||
Output [sr25519.VRFOutputLength]byte `scale:"1"` | ||
// Proof VRF proof | ||
Proof [sr25519.VRFProofLength]byte `scale:"2"` | ||
} | ||
|
||
// AssignmentCert is a certification of assignment | ||
type AssignmentCert struct { | ||
// Kind the criterion which is claimed to be met by this cert. | ||
Kind AssignmentCertKind `scale:"1"` | ||
// Vrf the VRF signature showing the criterion is met. | ||
Vrf VrfSignature `scale:"2"` | ||
} | ||
|
||
// IndirectAssignmentCert is an assignment criterion which refers to the candidate under which the assignment is | ||
// relevant by block hash. | ||
type IndirectAssignmentCert struct { | ||
// BlockHash a block hash where the canidate appears. | ||
BlockHash common.Hash `scale:"1"` | ||
// Validator the validator index. | ||
Validator ValidatorIndex `scale:"2"` | ||
// Cert the cert itself. | ||
Cert AssignmentCert `scale:"3"` | ||
} | ||
|
||
// CandidateIndex represents the index of the candidate in the list of candidates fully included as-of the block. | ||
type CandidateIndex uint32 | ||
|
||
// Assignment holds indirect assignment cert and candidate index | ||
type Assignment struct { | ||
IndirectAssignmentCert IndirectAssignmentCert `scale:"1"` | ||
CandidateIndex CandidateIndex `scale:"2"` | ||
} | ||
|
||
// Assignments for candidates in recent, unfinalized blocks. | ||
type Assignments []Assignment | ||
|
||
// Index returns varying data type index | ||
func (a Assignments) Index() uint { | ||
return 0 | ||
} | ||
|
||
// IndirectSignedApprovalVote represents a signed approval vote which references the candidate indirectly via the block. | ||
type IndirectSignedApprovalVote struct { | ||
// BlockHash a block hash where the candidate appears. | ||
BlockHash common.Hash `scale:"1"` | ||
// CandidateIndex the index of the candidate in the list of candidates fully included as-of the block. | ||
CandidateIndex CandidateIndex `scale:"2"` | ||
// ValidatorIndex the validator index. | ||
ValidatorIndex ValidatorIndex `scale:"3"` | ||
// Signature the signature of the validator. | ||
Signature ValidatorSignature `scale:"4"` | ||
} | ||
|
||
// Approvals for candidates in some recent, unfinalized block. | ||
type Approvals []IndirectSignedApprovalVote | ||
|
||
// Index returns varying data type index | ||
func (ap Approvals) Index() uint { | ||
return 1 | ||
} | ||
|
||
// ApprovalDistributionMessage network messages used by approval distribution subsystem. | ||
type ApprovalDistributionMessage scale.VaryingDataType | ||
|
||
// Set will set a VoryingDataTypeValue using the underlying VaryingDataType | ||
func (adm *ApprovalDistributionMessage) Set(val scale.VaryingDataTypeValue) (err error) { | ||
vdt := scale.VaryingDataType(*adm) | ||
err = vdt.Set(val) | ||
if err != nil { | ||
return fmt.Errorf("setting value to varying data type: %w", err) | ||
} | ||
*adm = ApprovalDistributionMessage(vdt) | ||
return nil | ||
} | ||
|
||
// Value returns the value from the underlying VaryingDataType | ||
func (adm *ApprovalDistributionMessage) Value() (scale.VaryingDataTypeValue, error) { | ||
vdt := scale.VaryingDataType(*adm) | ||
return vdt.Value() | ||
} | ||
|
||
// New returns new ApprovalDistributionMessage VDT | ||
func (adm ApprovalDistributionMessage) New() ApprovalDistributionMessage { | ||
return NewApprovalDistributionMessageVDT() | ||
} | ||
|
||
// NewApprovalDistributionMessageVDT ruturns a new ApprovalDistributionMessage VaryingDataType | ||
func NewApprovalDistributionMessageVDT() ApprovalDistributionMessage { | ||
vdt, err := scale.NewVaryingDataType(Assignments{}, Approvals{}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return ApprovalDistributionMessage(vdt) | ||
} |
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,202 @@ | ||
// Copyright 2021 ChainSafe Systems (ON) | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
package parachain | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
"github.com/ChainSafe/gossamer/pkg/scale" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var hash = common.MustHexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") | ||
|
||
func TestEncodeApprovalDistributionMessageAssignmentModulo(t *testing.T) { | ||
approvalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
// expected encoding is generated by running rust test code: | ||
// fn try_msg_assignments_encode() { | ||
// let hash = Hash::repeat_byte(0xAA); | ||
// | ||
// let validator_index = ValidatorIndex(1); | ||
// let cert = fake_assignment_cert(hash, validator_index); | ||
// let assignments = vec![(cert.clone(), 4u32)]; | ||
// let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); | ||
// | ||
// let emsg = msg.encode(); | ||
// println!("encode: {:?}", emsg); | ||
//} | ||
expectedEncoding := []byte{0, 4, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, | ||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, | ||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, | ||
58, 59, 60, 61, 62, 63, 64, 4, 0, 0, 0} | ||
|
||
approvalDistributionMessage.Set(Assignments{ | ||
Assignment{ | ||
IndirectAssignmentCert: fakeAssignmentCert(hash, ValidatorIndex(1), false), | ||
CandidateIndex: 4, | ||
}, | ||
}) | ||
|
||
encodedMessage, err := scale.Marshal(approvalDistributionMessage) | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, expectedEncoding, encodedMessage) | ||
|
||
approvalDistributionMessageDecodedTest := NewApprovalDistributionMessageVDT() | ||
scale.Unmarshal(encodedMessage, &approvalDistributionMessageDecodedTest) | ||
require.Equal(t, approvalDistributionMessage, approvalDistributionMessageDecodedTest) | ||
} | ||
|
||
func TestEncodeApprovalDistributionMessageAssignmentDelay(t *testing.T) { | ||
approvalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
|
||
expectedEncoding := []byte{0, 4, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, | ||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 2, 0, 0, 0, 1, 1, 0, 0, 0, 1, 2, | ||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, | ||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, | ||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, | ||
59, 60, 61, 62, 63, 64, 2, 0, 0, 0} | ||
|
||
approvalDistributionMessage.Set(Assignments{ | ||
Assignment{ | ||
IndirectAssignmentCert: fakeAssignmentCert(hash, ValidatorIndex(2), true), | ||
CandidateIndex: 2, | ||
}, | ||
}) | ||
|
||
encodedMessage, err := scale.Marshal(approvalDistributionMessage) | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, expectedEncoding, encodedMessage) | ||
} | ||
|
||
func TestEncodeAssignmentCertKindModulo(t *testing.T) { | ||
assignmentCertKind := NewAssignmentCertKindVDT() | ||
assignmentCertKind.Set(RelayVRFModulo{Sample: 4}) | ||
expectedEncoding := []byte{0, 4, 0, 0, 0} | ||
encodedAssignmentCertKind, err := scale.Marshal(assignmentCertKind) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedEncoding, encodedAssignmentCertKind) | ||
|
||
assignmentCertTest := NewAssignmentCertKindVDT() | ||
err = scale.Unmarshal(encodedAssignmentCertKind, &assignmentCertTest) | ||
require.NoError(t, err) | ||
require.Equal(t, assignmentCertKind, assignmentCertTest) | ||
} | ||
|
||
func TestEncodeAssignmentCertKindDelay(t *testing.T) { | ||
assignmentCertKind := NewAssignmentCertKindVDT() | ||
assignmentCertKind.Set(RelayVRFDelay{CoreIndex: 5}) | ||
expectedEncoding := []byte{1, 5, 0, 0, 0} | ||
encodedAssignmentCertKind, err := scale.Marshal(assignmentCertKind) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedEncoding, encodedAssignmentCertKind) | ||
|
||
assignmentCertTest := NewAssignmentCertKindVDT() | ||
err = scale.Unmarshal(encodedAssignmentCertKind, &assignmentCertTest) | ||
require.NoError(t, err) | ||
require.Equal(t, assignmentCertKind, assignmentCertTest) | ||
} | ||
|
||
func TestEncodeApprovalDistributionMessageApprovals(t *testing.T) { | ||
approvalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
|
||
expectedEncoding := []byte{1, 4, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, | ||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 2, 0, 0, 0, 3, 0, 0, 0, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} | ||
|
||
approvalDistributionMessage.Set(Approvals{ | ||
IndirectSignedApprovalVote{ | ||
BlockHash: hash, | ||
CandidateIndex: CandidateIndex(2), | ||
ValidatorIndex: ValidatorIndex(3), | ||
Signature: ValidatorSignature{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1}, | ||
}, | ||
}) | ||
|
||
encodedMessage, err := scale.Marshal(approvalDistributionMessage) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedEncoding, encodedMessage) | ||
} | ||
|
||
func TestDecodeApprovalDistributionMessageAssignmentModulo(t *testing.T) { | ||
encoding := []byte{0, 4, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, | ||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 2, 0, 0, 0, 0, 2, 0, 0, 0, 1, 2, 3, 4, | ||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, | ||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, | ||
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, | ||
61, 62, 63, 64, 4, 0, 0, 0} | ||
approvalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
err := scale.Unmarshal(encoding, &approvalDistributionMessage) | ||
require.NoError(t, err) | ||
|
||
expectedApprovalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
expectedApprovalDistributionMessage.Set(Assignments{ | ||
Assignment{ | ||
IndirectAssignmentCert: fakeAssignmentCert(hash, ValidatorIndex(2), false), | ||
CandidateIndex: 4, | ||
}, | ||
}) | ||
|
||
approvalValue, err := approvalDistributionMessage.Value() | ||
require.NoError(t, err) | ||
expectedValue, err := expectedApprovalDistributionMessage.Value() | ||
require.NoError(t, err) | ||
require.Equal(t, expectedValue, approvalValue) | ||
} | ||
|
||
func TestDecodeApprovalDistributionMessageApprovals(t *testing.T) { | ||
encoding := []byte{1, 4, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, | ||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 2, 0, 0, 0, 3, 0, 0, 0, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} | ||
expectedApprovalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
expectedApprovalDistributionMessage.Set(Approvals{ | ||
IndirectSignedApprovalVote{ | ||
BlockHash: hash, | ||
CandidateIndex: CandidateIndex(2), | ||
ValidatorIndex: ValidatorIndex(3), | ||
Signature: ValidatorSignature{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
1, 1, 1, 1, 1, 1}, | ||
}, | ||
}) | ||
|
||
approvalDistributionMessage := NewApprovalDistributionMessageVDT() | ||
err := scale.Unmarshal(encoding, &approvalDistributionMessage) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedApprovalDistributionMessage, approvalDistributionMessage) | ||
} | ||
|
||
func fakeAssignmentCert(blockHash common.Hash, validator ValidatorIndex, useDelay bool) IndirectAssignmentCert { | ||
output := [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, | ||
27, 28, 29, 30, 31, 32} | ||
proof := [64]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, | ||
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, | ||
55, 56, 57, 58, 59, 60, 61, 62, 63, 64} | ||
assignmentCertKind := NewAssignmentCertKindVDT() | ||
if useDelay { | ||
assignmentCertKind.Set(RelayVRFDelay{CoreIndex: 1}) | ||
} else { | ||
assignmentCertKind.Set(RelayVRFModulo{Sample: 2}) | ||
} | ||
|
||
return IndirectAssignmentCert{ | ||
BlockHash: blockHash, | ||
Validator: validator, | ||
Cert: AssignmentCert{ | ||
Kind: assignmentCertKind, | ||
Vrf: VrfSignature{ | ||
Output: output, | ||
Proof: proof, | ||
}, | ||
}, | ||
} | ||
} |