Skip to content

Commit

Permalink
feat(prospective-parachains) handle GetMinimumRelayParents signal
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielDDHM committed Dec 3, 2024
1 parent 355b363 commit 08e2288
Showing 1 changed file with 268 additions and 0 deletions.
268 changes: 268 additions & 0 deletions dot/parachain/prospective-parachains/prospective-parachains_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
package prospectiveparachains

import (
"bytes"
"context"
"sync"
"testing"

fragmentchain "github.com/ChainSafe/gossamer/dot/parachain/prospective-parachains/fragment-chain"
parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types"
inclusionemulator "github.com/ChainSafe/gossamer/dot/parachain/util/inclusion-emulator"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/stretchr/testify/assert"
)

const MAX_POV_SIZE = 1_000_000

func dummyPVD(parentHead parachaintypes.HeadData, relayParentNumber uint32) parachaintypes.PersistedValidationData {
return parachaintypes.PersistedValidationData{
ParentHead: parentHead,
RelayParentNumber: relayParentNumber,
RelayParentStorageRoot: common.EmptyHash,
MaxPovSize: MAX_POV_SIZE,
}
}

func dummyCandidateReceiptBadSig(
relayParentHash common.Hash,
commitments *common.Hash,
) parachaintypes.CandidateReceipt {
var commitmentsHash common.Hash

if commitments != nil {
commitmentsHash = *commitments
} else {
commitmentsHash = common.EmptyHash // TODO:
}

descriptor := parachaintypes.CandidateDescriptor{
ParaID: parachaintypes.ParaID(0),
RelayParent: relayParentHash,
Collator: parachaintypes.CollatorID{},
PovHash: common.EmptyHash,
ErasureRoot: common.EmptyHash,
Signature: parachaintypes.CollatorSignature{},
ParaHead: common.EmptyHash,
ValidationCodeHash: parachaintypes.ValidationCodeHash{},
PersistedValidationDataHash: common.EmptyHash,
}

return parachaintypes.CandidateReceipt{
CommitmentsHash: commitmentsHash,
Descriptor: descriptor,
}
}

func MakeCandidate(
relayParent common.Hash,
relayParentNumber uint32,
paraID parachaintypes.ParaID,
parentHead parachaintypes.HeadData,
headData parachaintypes.HeadData,
validationCodeHash parachaintypes.ValidationCodeHash,
) parachaintypes.CommittedCandidateReceipt {
pvd := dummyPVD(parentHead, relayParentNumber)

commitments := parachaintypes.CandidateCommitments{
HeadData: headData,
HorizontalMessages: []parachaintypes.OutboundHrmpMessage{},
UpwardMessages: []parachaintypes.UpwardMessage{},
NewValidationCode: nil,
ProcessedDownwardMessages: 0,
HrmpWatermark: relayParentNumber,
}

commitmentsHash := commitments.Hash()

candidate := dummyCandidateReceiptBadSig(relayParent, &commitmentsHash)
candidate.CommitmentsHash = commitments.Hash()
candidate.Descriptor.ParaID = paraID

pvdh, err := pvd.Hash()

if err != nil {
panic(err)
}

candidate.Descriptor.PersistedValidationDataHash = pvdh
candidate.Descriptor.ValidationCodeHash = validationCodeHash

result := parachaintypes.CommittedCandidateReceipt{
Descriptor: candidate.Descriptor,
Commitments: commitments,
}

return result
}

// TestAnswerMinimumRelayParentsRequest ensures that AnswerMinimumRelayParentsRequest
// processes the relay parent hash and correctly sends the output via the channel
func TestAnswerMinimumRelayParentsRequest(t *testing.T) {
// Setup a mock View with active leaves and relay parent data

mockRelayParent := inclusionemulator.RelayChainBlockInfo{
Hash: common.Hash([]byte("active_hash")),
Number: 10,
}

ancestors := []inclusionemulator.RelayChainBlockInfo{
{
Hash: common.Hash([]byte("active_hash_7")),
Number: 9,
},
{
Hash: common.Hash([]byte("active_hash_8")),
Number: 8,
},
{
Hash: common.Hash([]byte("active_hash_9")),
Number: 7,
},
}

baseConstraints := &inclusionemulator.Constraints{
MinRelayParentNumber: 5,
}

mockScope, err := fragmentchain.NewScopeWithAncestors(mockRelayParent, baseConstraints, nil, 10, ancestors)
assert.NoError(t, err)

mockScope2, err := fragmentchain.NewScopeWithAncestors(mockRelayParent, baseConstraints, nil, 10, nil)
assert.NoError(t, err)

mockView := &View{
ActiveLeaves: map[common.Hash]bool{
common.BytesToHash([]byte("active_hash")): true,
},
PerRelayParent: map[common.Hash]*RelayParentData{
common.BytesToHash([]byte("active_hash")): {
FragmentChains: map[parachaintypes.ParaID]*fragmentchain.FragmentChain{
parachaintypes.ParaID(1): fragmentchain.NewFragmentChain(mockScope, fragmentchain.NewCandidateStorage()),
parachaintypes.ParaID(2): fragmentchain.NewFragmentChain(mockScope2, fragmentchain.NewCandidateStorage()),
},
},
},
}

// Initialize ProspectiveParachains with the mock view
pp := &ProspectiveParachains{
View: mockView,
}

// Create a channel to capture the output
sender := make(chan []ParaIDBlockNumber, 1)

// Execute the method under test
pp.AnswerMinimumRelayParentsRequest(common.BytesToHash([]byte("active_hash")), sender)

expected := []ParaIDBlockNumber{
{
ParaId: 1,
BlockNumber: 7,
},
{
ParaId: 2,
BlockNumber: 10,
},
}
// Validate the results
result := <-sender
assert.Len(t, result, 2)
assert.Equal(t, expected, result)
}

// TestAnswerMinimumRelayParentsRequest_NoActiveLeaves ensures that AnswerMinimumRelayParentsRequest
// correctly handles the case where there are no active leaves.
func TestAnswerMinimumRelayParentsRequest_NoActiveLeaves(t *testing.T) {
mockView := &View{
ActiveLeaves: map[common.Hash]bool{},
PerRelayParent: map[common.Hash]*RelayParentData{},
}

// Initialize ProspectiveParachains with the mock view
pp := &ProspectiveParachains{
View: mockView,
}

// Create a channel to capture the output
sender := make(chan []ParaIDBlockNumber, 1)

// Execute the method under test
pp.AnswerMinimumRelayParentsRequest(common.BytesToHash([]byte("active_hash")), sender)
// Validate the results
result := <-sender
assert.Empty(t, result, "Expected result to be empty when no active leaves are present")
}

func TestHandleAnswerMinimumRelayParentsRequest(
t *testing.T,
) {
candidateRelayParent := common.Hash{0x01}
paraId := parachaintypes.ParaID(1)
parentHead := parachaintypes.HeadData{
Data: bytes.Repeat([]byte{0x01}, 32),
}
headData := parachaintypes.HeadData{
Data: bytes.Repeat([]byte{0x02}, 32),
}
validationCodeHash := parachaintypes.ValidationCodeHash{0x01}
candidateRelayParentNumber := uint32(0)

candidate := MakeCandidate(
candidateRelayParent,
candidateRelayParentNumber,
paraId,
parentHead,
headData,
validationCodeHash,
)

subsystemToOverseer := make(chan any)
overseerToSubsystem := make(chan any)

prospectiveParachains := NewProspectiveParachains(subsystemToOverseer)

relayParent := inclusionemulator.RelayChainBlockInfo{
Hash: candidateRelayParent,
Number: 0,
StorageRoot: common.Hash{0x00},
}

baseConstraints := &inclusionemulator.Constraints{
RequiredParent: parachaintypes.HeadData{Data: bytes.Repeat([]byte{0x01}, 32)},
MinRelayParentNumber: 0,
ValidationCodeHash: validationCodeHash,
MaxPoVSize: 1000000,
}

scope, err := fragmentchain.NewScopeWithAncestors(relayParent, baseConstraints, nil, 10, nil)
assert.NoError(t, err)

prospectiveParachains.View.PerRelayParent[candidateRelayParent] = &RelayParentData{
FragmentChains: map[parachaintypes.ParaID]*fragmentchain.FragmentChain{
paraId: fragmentchain.NewFragmentChain(scope, fragmentchain.NewCandidateStorage()),
},
}

var wg sync.WaitGroup

wg.Add(1)
go func(wg *sync.WaitGroup) {
defer wg.Done()
prospectiveParachains.Run(context.Background(), overseerToSubsystem)
}(&wg)

sender := make(chan []ParaIDBlockNumber, 1)

prospectiveParachains.AnswerMinimumRelayParentsRequest(candidateRelayParent, sender)

result := <-sender

assert.Len(t, result, 1, "Expected one ParaIDBlockNumber in the result")
assert.Equal(t, paraId, result[0].ParaId, "ParaId mismatch in the result")
assert.Equal(t, uint32(7), result[0].BlockNumber, "BlockNumber mismatch in the result")

_, err = candidate.Hash()
assert.NoError(t, err)
}

0 comments on commit 08e2288

Please sign in to comment.