From 50cc3abef6e96b290e13e015299e2a53cdbf2fae Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 10 Jul 2024 16:55:45 -0400 Subject: [PATCH 01/30] add pvf worker pool skeleton --- dot/parachain/pvf/host.go | 30 ++++++++++ dot/parachain/pvf/host_test.go | 26 ++++++++ dot/parachain/pvf/worker.go | 48 +++++++++++++++ dot/parachain/pvf/worker_pool.go | 86 +++++++++++++++++++++++++++ dot/parachain/pvf/worker_pool_test.go | 42 +++++++++++++ dot/parachain/pvf/worker_test.go | 45 ++++++++++++++ 6 files changed, 277 insertions(+) create mode 100644 dot/parachain/pvf/host.go create mode 100644 dot/parachain/pvf/host_test.go create mode 100644 dot/parachain/pvf/worker.go create mode 100644 dot/parachain/pvf/worker_pool.go create mode 100644 dot/parachain/pvf/worker_pool_test.go create mode 100644 dot/parachain/pvf/worker_test.go diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go new file mode 100644 index 0000000000..5e483d8001 --- /dev/null +++ b/dot/parachain/pvf/host.go @@ -0,0 +1,30 @@ +package pvf + +import ( + "sync" + + "github.com/ChainSafe/gossamer/internal/log" +) + +var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) + +type validationHost struct { + wg sync.WaitGroup + stopCh chan struct{} + + workerPool *validationWorkerPool +} + +func (v *validationHost) start() { + + v.wg.Add(1) + logger.Debug("Starting validation host") + go func() { + defer v.wg.Done() + }() +} + +func (v *validationHost) stop() { + close(v.stopCh) + v.wg.Wait() +} diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go new file mode 100644 index 0000000000..4e142ea3ed --- /dev/null +++ b/dot/parachain/pvf/host_test.go @@ -0,0 +1,26 @@ +package pvf + +import "testing" + +func Test_validationHost_start(t *testing.T) { + type fields struct { + workerPool *validationWorkerPool + } + tests := map[string]struct { + name string + fields fields + }{ + "test": { + name: "test", + }, + } + for tname, tt := range tests { + tt := tt + t.Run(tname, func(t *testing.T) { + v := &validationHost{ + workerPool: tt.fields.workerPool, + } + v.start() + }) + } +} diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go new file mode 100644 index 0000000000..9b710d88d2 --- /dev/null +++ b/dot/parachain/pvf/worker.go @@ -0,0 +1,48 @@ +package pvf + +import ( + "sync" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" +) + +type worker struct { + workerID parachaintypes.ValidationCodeHash + sharedGuard chan struct{} +} + +func newWorker(pID parachaintypes.ValidationCodeHash, sharedGuard chan struct{}) *worker { + return &worker{ + workerID: pID, + sharedGuard: sharedGuard, + } +} + +func (w *worker) run(queue chan *validationTask, wg *sync.WaitGroup) { + defer func() { + logger.Debugf("[STOPPED] worker %x", w.workerID) + wg.Done() + }() + + for task := range queue { + executeRequest(w.workerID, task, w.sharedGuard) + } +} + +func executeRequest(who parachaintypes.ValidationCodeHash, task *validationTask, sharedGuard chan struct{}) { + defer func() { + <-sharedGuard + }() + + sharedGuard <- struct{}{} + + request := task.request + logger.Debugf("[EXECUTING] worker %x, block request: %s", who, request) + + task.resultCh <- &validationTaskResult{ + who: who, + result: request + " result", + } + + logger.Debugf("[FINISHED] worker %x", who) +} diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go new file mode 100644 index 0000000000..627fb7a026 --- /dev/null +++ b/dot/parachain/pvf/worker_pool.go @@ -0,0 +1,86 @@ +package pvf + +import ( + "fmt" + "sync" + "time" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" +) + +const ( + maxRequestsAllowed uint = 60 +) + +type validationWorkerPool struct { + mtx sync.RWMutex + wg sync.WaitGroup + + workers map[parachaintypes.ValidationCodeHash]*validationWorker + sharedGuard chan struct{} +} + +type validationTask struct { + request string + resultCh chan<- *validationTaskResult +} + +type validationTaskResult struct { + who parachaintypes.ValidationCodeHash + result string +} + +type validationWorker struct { + worker *worker + queue chan *validationTask +} + +func newValidationWorkerPool() *validationWorkerPool { + return &validationWorkerPool{ + workers: make(map[parachaintypes.ValidationCodeHash]*validationWorker), + sharedGuard: make(chan struct{}, maxRequestsAllowed), + } +} + +// stop will shutdown all the available workers goroutines +func (v *validationWorkerPool) stop() error { + v.mtx.RLock() + defer v.mtx.RUnlock() + + for _, sw := range v.workers { + close(sw.queue) + } + + allWorkersDoneCh := make(chan struct{}) + go func() { + defer close(allWorkersDoneCh) + v.wg.Wait() + }() + + timeoutTimer := time.NewTimer(30 * time.Second) + select { + case <-timeoutTimer.C: + return fmt.Errorf("timeout reached while finishing workers") + case <-allWorkersDoneCh: + if !timeoutTimer.Stop() { + <-timeoutTimer.C + } + + return nil + } +} + +func (v *validationWorkerPool) newValidationWorker(who parachaintypes.ValidationCodeHash) { + + worker := newWorker(who, v.sharedGuard) + workerQueue := make(chan *validationTask, maxRequestsAllowed) + + v.wg.Add(1) + go worker.run(workerQueue, &v.wg) + + v.workers[who] = &validationWorker{ + worker: worker, + queue: workerQueue, + } + logger.Tracef("potential worker added, total in the pool %d", len(v.workers)) +} diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/pvf/worker_pool_test.go new file mode 100644 index 0000000000..88ea789209 --- /dev/null +++ b/dot/parachain/pvf/worker_pool_test.go @@ -0,0 +1,42 @@ +package pvf + +import ( + "testing" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" +) + +func TestValidationWorkerPool_newValidationWorker(t *testing.T) { + t.Parallel() + cases := map[string]struct { + setupWorkerPool func(t *testing.T) *validationWorkerPool + expectedWorkers []parachaintypes.ValidationCodeHash + }{ + "add_one_worker": { + setupWorkerPool: func(t *testing.T) *validationWorkerPool { + pool := newValidationWorkerPool() + pool.newValidationWorker(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) + return pool + }, + expectedWorkers: []parachaintypes.ValidationCodeHash{ + {1, 2, 3, 4}, + }, + }, + } + + for tname, tt := range cases { + tt := tt + t.Run(tname, func(t *testing.T) { + t.Parallel() + + workerPool := tt.setupWorkerPool(t) + defer workerPool.stop() + + require.ElementsMatch(t, + maps.Keys(workerPool.workers), + tt.expectedWorkers) + }) + } +} diff --git a/dot/parachain/pvf/worker_test.go b/dot/parachain/pvf/worker_test.go new file mode 100644 index 0000000000..d3e0638add --- /dev/null +++ b/dot/parachain/pvf/worker_test.go @@ -0,0 +1,45 @@ +package pvf + +import ( + "sync" + "testing" + "time" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/stretchr/testify/require" +) + +func TestWorker(t *testing.T) { + workerID1 := parachaintypes.ValidationCodeHash{1, 2, 3, 4} + + sharedGuard := make(chan struct{}, 1) + w := newWorker(workerID1, sharedGuard) + + wg := sync.WaitGroup{} + queue := make(chan *validationTask, 2) + + wg.Add(1) + go w.run(queue, &wg) + + resultCh := make(chan *validationTaskResult) + defer close(resultCh) + + queue <- &validationTask{ + resultCh: resultCh, + } + + queue <- &validationTask{ + resultCh: resultCh, + } + + time.Sleep(500 * time.Millisecond) + require.Equal(t, 1, len(sharedGuard)) + <-resultCh + + time.Sleep(500 * time.Millisecond) + require.Equal(t, 1, len(sharedGuard)) + <-resultCh + + close(queue) + wg.Wait() +} From 3427da05017d958a80eeabca51304350fa6c070c Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 19 Jul 2024 13:12:11 -0400 Subject: [PATCH 02/30] add test to validation host --- .../candidate_validation.go | 6 +++ dot/parachain/pvf/host.go | 28 +++++++++-- dot/parachain/pvf/host_test.go | 15 ++++-- dot/parachain/pvf/worker_pool.go | 46 +++++++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index fcfb837cfd..1ea499c8d4 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" "sync" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" @@ -32,12 +33,14 @@ type CandidateValidation struct { SubsystemToOverseer chan<- any OverseerToSubsystem <-chan any ValidationHost parachainruntime.ValidationHost + pvfHost *pvf.ValidationHost } // NewCandidateValidation creates a new CandidateValidation subsystem func NewCandidateValidation(overseerChan chan<- any) *CandidateValidation { candidateValidation := CandidateValidation{ SubsystemToOverseer: overseerChan, + pvfHost: pvf.NewValidationHost(), } return &candidateValidation } @@ -45,6 +48,7 @@ func NewCandidateValidation(overseerChan chan<- any) *CandidateValidation { // Run starts the CandidateValidation subsystem func (cv *CandidateValidation) Run(context.Context, chan any, chan any) { cv.wg.Add(1) + go cv.pvfHost.Start() go cv.processMessages(&cv.wg) } @@ -67,6 +71,7 @@ func (*CandidateValidation) ProcessBlockFinalizedSignal(parachaintypes.BlockFina // Stop stops the CandidateValidation subsystem func (cv *CandidateValidation) Stop() { + cv.pvfHost.Stop() close(cv.stopChan) cv.wg.Wait() } @@ -82,6 +87,7 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { case ValidateFromChainState: // TODO: implement functionality to handle ValidateFromChainState, see issue #3919 case ValidateFromExhaustive: + rTest := cv.pvfHost.Validate(msg.ValidationCode) result, err := validateFromExhaustive(cv.ValidationHost, msg.PersistedValidationData, msg.ValidationCode, msg.CandidateReceipt, msg.PoV) if err != nil { diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 5e483d8001..810577dce5 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -1,6 +1,7 @@ package pvf import ( + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "sync" "github.com/ChainSafe/gossamer/internal/log" @@ -8,14 +9,14 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) -type validationHost struct { +type ValidationHost struct { wg sync.WaitGroup stopCh chan struct{} workerPool *validationWorkerPool } -func (v *validationHost) start() { +func (v *ValidationHost) Start() { v.wg.Add(1) logger.Debug("Starting validation host") @@ -24,7 +25,28 @@ func (v *validationHost) start() { }() } -func (v *validationHost) stop() { +func (v *ValidationHost) Stop() { close(v.stopCh) v.wg.Wait() } + +func NewValidationHost() *ValidationHost { + return &ValidationHost{ + stopCh: make(chan struct{}), + workerPool: newValidationWorkerPool(), + } +} + +func (v *ValidationHost) Validate(workerID parachaintypes.ValidationCodeHash) { + logger.Debugf("Validating worker", "workerID", workerID) + + resultCh := make(chan *validationTaskResult) + + //task := &validationTask{ + // request: "test", + // resultCh: resultCh, + //} + v.workerPool.submitRequest("test", &workerID, resultCh) + + <-resultCh +} diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index 4e142ea3ed..013471f53d 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -1,6 +1,9 @@ package pvf -import "testing" +import ( + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "testing" +) func Test_validationHost_start(t *testing.T) { type fields struct { @@ -17,10 +20,16 @@ func Test_validationHost_start(t *testing.T) { for tname, tt := range tests { tt := tt t.Run(tname, func(t *testing.T) { - v := &validationHost{ + v := &ValidationHost{ workerPool: tt.fields.workerPool, } - v.start() + v.Start() }) } } + +func TestValidationHost(t *testing.T) { + v := NewValidationHost() + v.workerPool.newValidationWorker(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) + v.Validate(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) +} diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 627fb7a026..37be9f7b02 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -1,7 +1,10 @@ package pvf import ( + "crypto/rand" "fmt" + "golang.org/x/exp/maps" + "math/big" "sync" "time" @@ -84,3 +87,46 @@ func (v *validationWorkerPool) newValidationWorker(who parachaintypes.Validation } logger.Tracef("potential worker added, total in the pool %d", len(v.workers)) } + +// submitRequest given a request, the worker pool will get the peer given the peer.ID +// parameter or if nil the very first available worker or +// to perform the request, the response will be dispatch in the resultCh. +func (v *validationWorkerPool) submitRequest(request string, + who *parachaintypes.ValidationCodeHash, resultCh chan<- *validationTaskResult) { + + task := &validationTask{ + request: request, + resultCh: resultCh, + } + + // if the request is bounded to a specific peer then just + // request it and sent through its queue otherwise send + // the request in the general queue where all worker are + // listening on + v.mtx.RLock() + defer v.mtx.RUnlock() + + if who != nil { + syncWorker, inMap := v.workers[*who] + if inMap { + if syncWorker == nil { + panic("sync worker should not be nil") + } + syncWorker.queue <- task + return + } + } + + // if the exact peer is not specified then + // randomly select a worker and assign the + // task to it, if the amount of workers is + var selectedWorkerIdx int + workers := maps.Values(v.workers) + nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(workers)))) + if err != nil { + panic(fmt.Errorf("fail to get a random number: %w", err)) + } + selectedWorkerIdx = int(nBig.Int64()) + selectedWorker := workers[selectedWorkerIdx] + selectedWorker.queue <- task +} From 65371044346e909f1ecf97eeebb43de681efd0bf Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 23 Jul 2024 11:59:53 -0400 Subject: [PATCH 03/30] create worker pool skeleton for PVF host --- .../backing/candidate_backing_test.go | 15 +- .../backing/per_relay_parent_state.go | 3 +- .../candidate_validation.go | 53 ++++--- .../candidate_validation_test.go | 66 ++++---- .../candidate-validation/messages.go | 89 +---------- dot/parachain/pvf/host.go | 23 ++- dot/parachain/pvf/host_test.go | 18 ++- dot/parachain/pvf/worker.go | 38 +++-- dot/parachain/pvf/worker_pool.go | 142 +++++++++++++++--- dot/parachain/pvf/worker_test.go | 18 +-- 10 files changed, 250 insertions(+), 215 deletions(-) diff --git a/dot/parachain/backing/candidate_backing_test.go b/dot/parachain/backing/candidate_backing_test.go index f2bbcb7ee7..f7d01926ac 100644 --- a/dot/parachain/backing/candidate_backing_test.go +++ b/dot/parachain/backing/candidate_backing_test.go @@ -11,6 +11,7 @@ import ( availabilitystore "github.com/ChainSafe/gossamer/dot/parachain/availability-store" candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" @@ -692,7 +693,7 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ Err: errors.New("mock error getting validation result"), } default: @@ -728,9 +729,9 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - ci := candidatevalidation.ExecutionError - data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ + ci := pvf.ExecutionError + data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ InvalidResult: &ci, }, } @@ -766,9 +767,9 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{}, + data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{}, }, } case availabilitystore.StoreAvailableData: diff --git a/dot/parachain/backing/per_relay_parent_state.go b/dot/parachain/backing/per_relay_parent_state.go index 775257b3b9..779050dc9c 100644 --- a/dot/parachain/backing/per_relay_parent_state.go +++ b/dot/parachain/backing/per_relay_parent_state.go @@ -11,6 +11,7 @@ import ( availabilitystore "github.com/ChainSafe/gossamer/dot/parachain/availability-store" candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/runtime" wazero_runtime "github.com/ChainSafe/gossamer/lib/runtime/wazero" @@ -296,7 +297,7 @@ func (rpState *perRelayParentState) validateAndMakeAvailable( return fmt.Errorf("setting pvfExecTimeoutKind: %w", err) } - chValidationResultRes := make(chan parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]) + chValidationResultRes := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) subSystemToOverseer <- candidatevalidation.ValidateFromExhaustive{ PersistedValidationData: pvd, ValidationCode: *validationCode, diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 1ea499c8d4..25cce11368 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -8,9 +8,9 @@ import ( "context" "errors" "fmt" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" "sync" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/internal/log" @@ -87,16 +87,33 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { case ValidateFromChainState: // TODO: implement functionality to handle ValidateFromChainState, see issue #3919 case ValidateFromExhaustive: - rTest := cv.pvfHost.Validate(msg.ValidationCode) + // This is the skeleton to hook up the PVF host to the candidate validation subsystem + // This is currently WIP, pending moving the validation logic to the PVF host + validationCodeHash := msg.ValidationCode.Hash() + taskResult := make(chan *pvf.ValidationTaskResult) + validationTask := &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{}, + WorkerID: &validationCodeHash, + CandidateReceipt: &msg.CandidateReceipt, + PoV: msg.PoV, + ExecutorParams: nil, + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + ResultCh: taskResult, + } + cv.pvfHost.Validate(validationTask) + fmt.Printf("Validation result: %v", <-taskResult) + + // WIP: This is the current implementation of the validation logic, it will be replaced by the PVF host + // when the validation logic is moved to the PVF host result, err := validateFromExhaustive(cv.ValidationHost, msg.PersistedValidationData, msg.ValidationCode, msg.CandidateReceipt, msg.PoV) if err != nil { logger.Errorf("failed to validate from exhaustive: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ Err: err, } } else { - msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ Data: *result, } } @@ -244,7 +261,7 @@ func validateFromExhaustive(validationHost parachainruntime.ValidationHost, persistedValidationData parachaintypes.PersistedValidationData, validationCode parachaintypes.ValidationCode, candidateReceipt parachaintypes.CandidateReceipt, pov parachaintypes.PoV) ( - *ValidationResult, error) { + *pvf.ValidationResult, error) { validationCodeHash := validationCode.Hash() // basic checks @@ -256,7 +273,7 @@ func validateFromExhaustive(validationHost parachainruntime.ValidationHost, } if validationErr != nil { - validationResult := &ValidationResult{ + validationResult := &pvf.ValidationResult{ InvalidResult: validationErr, } return validationResult, nil //nolint: nilerr @@ -281,8 +298,8 @@ func validateFromExhaustive(validationHost parachainruntime.ValidationHost, } if headDataHash != candidateReceipt.Descriptor.ParaHead { - ci := ParaHeadHashMismatch - return &ValidationResult{InvalidResult: &ci}, nil + ci := pvf.ParaHeadHashMismatch + return &pvf.ValidationResult{InvalidResult: &ci}, nil } candidateCommitments := parachaintypes.CandidateCommitments{ UpwardMessages: validationResult.UpwardMessages, @@ -295,11 +312,11 @@ func validateFromExhaustive(validationHost parachainruntime.ValidationHost, // if validation produced a new set of commitments, we treat the candidate as invalid if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { - ci := CommitmentsHashMismatch - return &ValidationResult{InvalidResult: &ci}, nil + ci := pvf.CommitmentsHashMismatch + return &pvf.ValidationResult{InvalidResult: &ci}, nil } - return &ValidationResult{ - ValidResult: &ValidValidationResult{ + return &pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: candidateCommitments, PersistedValidationData: persistedValidationData, }, @@ -310,8 +327,8 @@ func validateFromExhaustive(validationHost parachainruntime.ValidationHost, // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. // Returns ReasonForInvalidity and internal error if any. func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, - pov parachaintypes.PoV, validationCodeHash parachaintypes.ValidationCodeHash) (validationError *ReasonForInvalidity, - internalError error) { + pov parachaintypes.PoV, validationCodeHash parachaintypes.ValidationCodeHash) (validationError *pvf. + ReasonForInvalidity, internalError error) { povHash, err := pov.Hash() if err != nil { return nil, fmt.Errorf("hashing PoV: %w", err) @@ -324,23 +341,23 @@ func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSiz encodedPoVSize := uint32(len(encodedPoV)) if encodedPoVSize > maxPoVSize { - ci := ParamsTooLarge + ci := pvf.ParamsTooLarge return &ci, nil } if povHash != candidate.PovHash { - ci := PoVHashMismatch + ci := pvf.PoVHashMismatch return &ci, nil } if validationCodeHash != candidate.ValidationCodeHash { - ci := CodeHashMismatch + ci := pvf.CodeHashMismatch return &ci, nil } err = candidate.CheckCollatorSignature() if err != nil { - ci := BadSignature + ci := pvf.BadSignature return &ci, nil } return nil, nil diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 7891fac445..6a0a2d89cf 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" @@ -170,11 +171,11 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { testValidationHost, err := parachainruntime.SetupVM(validationCode) require.NoError(t, err) - povHashMismatch := PoVHashMismatch - paramsTooLarge := ParamsTooLarge - codeHashMismatch := CodeHashMismatch - paraHedHashMismatch := ParaHeadHashMismatch - commitmentsHashMismatch := CommitmentsHashMismatch + povHashMismatch := pvf.PoVHashMismatch + paramsTooLarge := pvf.ParamsTooLarge + codeHashMismatch := pvf.CodeHashMismatch + paraHedHashMismatch := pvf.ParaHeadHashMismatch + commitmentsHashMismatch := pvf.CommitmentsHashMismatch ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) @@ -214,7 +215,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { } tests := map[string]struct { args args - want *ValidationResult + want *pvf.ValidationResult expectedError error isValid bool }{ @@ -230,7 +231,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceipt2, pov: pov, }, - want: &ValidationResult{ + want: &pvf.ValidationResult{ InvalidResult: &povHashMismatch, }, isValid: false, @@ -247,7 +248,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceipt, pov: pov, }, - want: &ValidationResult{ + want: &pvf.ValidationResult{ InvalidResult: ¶msTooLarge, }, }, @@ -263,7 +264,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceipt, pov: pov, }, - want: &ValidationResult{ + want: &pvf.ValidationResult{ InvalidResult: &codeHashMismatch, }, isValid: false, @@ -315,7 +316,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceiptParaHeadMismatch, pov: pov, }, - want: &ValidationResult{ + want: &pvf.ValidationResult{ InvalidResult: ¶HedHashMismatch, }, isValid: false, @@ -333,7 +334,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceiptCommitmentsMismatch, pov: pov, }, - want: &ValidationResult{ + want: &pvf.ValidationResult{ InvalidResult: &commitmentsHashMismatch, }, isValid: false, @@ -351,8 +352,8 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceipt: candidateReceipt, pov: pov, }, - want: &ValidationResult{ - ValidResult: &ValidValidationResult{ + want: &pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ UpwardMessages: nil, HorizontalMessages: nil, @@ -408,9 +409,9 @@ func TestCandidateValidation_wasm_invalid_magic_number(t *testing.T) { } func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) { - povHashMismatch := PoVHashMismatch - paramsTooLarge := ParamsTooLarge - codeHashMismatch := CodeHashMismatch + povHashMismatch := pvf.PoVHashMismatch + paramsTooLarge := pvf.ParamsTooLarge + codeHashMismatch := pvf.CodeHashMismatch candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) candidateReceipt2 := candidateReceipt @@ -442,12 +443,13 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) require.NoError(t, err) toSubsystem := make(chan any) - sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) + sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) stopChan := make(chan struct{}) candidateValidationSubsystem := CandidateValidation{ OverseerToSubsystem: toSubsystem, stopChan: stopChan, ValidationHost: testValidationHost, + pvfHost: pvf.NewValidationHost(), } defer candidateValidationSubsystem.Stop() @@ -455,7 +457,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) tests := map[string]struct { msg ValidateFromExhaustive - want parachaintypes.OverseerFuncRes[ValidationResult] + want parachaintypes.OverseerFuncRes[pvf.ValidationResult] }{ "invalid_pov_hash": { msg: ValidateFromExhaustive{ @@ -470,8 +472,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[ValidationResult]{ - Data: ValidationResult{ + want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ InvalidResult: &povHashMismatch, }, Err: nil, @@ -490,8 +492,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[ValidationResult]{ - Data: ValidationResult{ + want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ InvalidResult: ¶msTooLarge, }, }, @@ -509,8 +511,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[ValidationResult]{ - Data: ValidationResult{ + want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ InvalidResult: &codeHashMismatch, }, }, @@ -528,9 +530,9 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[ValidationResult]{ - Data: ValidationResult{ - ValidResult: &ValidValidationResult{ + want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, @@ -567,10 +569,10 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) } func Test_performBasicChecks(t *testing.T) { - paramsTooLarge := ParamsTooLarge - povHashMismatch := PoVHashMismatch - codeHashMismatch := CodeHashMismatch - badSignature := BadSignature + paramsTooLarge := pvf.ParamsTooLarge + povHashMismatch := pvf.PoVHashMismatch + codeHashMismatch := pvf.CodeHashMismatch + badSignature := pvf.BadSignature pov := parachaintypes.PoV{ BlockData: []byte{1, 2, 3, 4, 5, 6, 7, 8}, @@ -620,7 +622,7 @@ func Test_performBasicChecks(t *testing.T) { } tests := map[string]struct { args args - expectedError *ReasonForInvalidity + expectedError *pvf.ReasonForInvalidity }{ "params_too_large": { args: args{ diff --git a/dot/parachain/candidate-validation/messages.go b/dot/parachain/candidate-validation/messages.go index 055705f6d5..010c53b945 100644 --- a/dot/parachain/candidate-validation/messages.go +++ b/dot/parachain/candidate-validation/messages.go @@ -4,6 +4,7 @@ package candidatevalidation import ( + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" ) @@ -28,93 +29,7 @@ type ValidateFromExhaustive struct { PoV parachaintypes.PoV ExecutorParams parachaintypes.ExecutorParams PvfExecTimeoutKind parachaintypes.PvfExecTimeoutKind - Ch chan parachaintypes.OverseerFuncRes[ValidationResult] -} - -// ValidationResult represents the result coming from the candidate validation subsystem. -// Validation results can be either a ValidValidationResult or InvalidValidationResult. -// -// If the result is invalid, -// store the reason for invalidity in the InvalidResult field of ValidationResult. -// -// If the result is valid, -// set the values of the ValidResult field of ValidValidationResult. -type ValidationResult struct { - ValidResult *ValidValidationResult - InvalidResult *ReasonForInvalidity -} - -func (vr ValidationResult) IsValid() bool { - return vr.ValidResult != nil -} - -type ValidValidationResult struct { - CandidateCommitments parachaintypes.CandidateCommitments - PersistedValidationData parachaintypes.PersistedValidationData -} - -type ReasonForInvalidity byte - -const ( - // ExecutionError Failed to execute `validate_block`. This includes function panicking. - ExecutionError ReasonForInvalidity = iota - // InvalidOutputs Validation outputs check doesn't pass. - InvalidOutputs - // Timeout Execution timeout. - Timeout - // ParamsTooLarge Validation input is over the limit. - ParamsTooLarge - // CodeTooLarge Code size is over the limit. - CodeTooLarge - // PoVDecompressionFailure PoV does not decompress correctly. - PoVDecompressionFailure - // BadReturn Validation function returned invalid data. - BadReturn - // BadParent Invalid relay chain parent. - BadParent - // PoVHashMismatch POV hash does not match. - PoVHashMismatch - // BadSignature Bad collator signature. - BadSignature - // ParaHeadHashMismatch Para head hash does not match. - ParaHeadHashMismatch - // CodeHashMismatch Validation code hash does not match. - CodeHashMismatch - // CommitmentsHashMismatch Validation has generated different candidate commitments. - CommitmentsHashMismatch -) - -func (ci ReasonForInvalidity) Error() string { - switch ci { - case ExecutionError: - return "failed to execute `validate_block`" - case InvalidOutputs: - return "validation outputs check doesn't pass" - case Timeout: - return "execution timeout" - case ParamsTooLarge: - return "validation input is over the limit" - case CodeTooLarge: - return "code size is over the limit" - case PoVDecompressionFailure: - return "PoV does not decompress correctly" - case BadReturn: - return "validation function returned invalid data" - case BadParent: - return "invalid relay chain parent" - case PoVHashMismatch: - return "PoV hash does not match" - case BadSignature: - return "bad collator signature" - case ParaHeadHashMismatch: - return "para head hash does not match" - case CodeHashMismatch: - return "validation code hash does not match" - case CommitmentsHashMismatch: - return "validation has generated different candidate commitments" - default: - return "unknown invalidity reason" - } + Ch chan parachaintypes.OverseerFuncRes[pvf.ValidationResult] } // PreCheck try to compile the given validation code and return the result diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 810577dce5..0c335bb5c7 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -1,7 +1,7 @@ package pvf import ( - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "fmt" "sync" "github.com/ChainSafe/gossamer/internal/log" @@ -17,7 +17,7 @@ type ValidationHost struct { } func (v *ValidationHost) Start() { - + fmt.Printf("v.wg %v\n", v) v.wg.Add(1) logger.Debug("Starting validation host") go func() { @@ -37,16 +37,13 @@ func NewValidationHost() *ValidationHost { } } -func (v *ValidationHost) Validate(workerID parachaintypes.ValidationCodeHash) { - logger.Debugf("Validating worker", "workerID", workerID) - - resultCh := make(chan *validationTaskResult) +func (v *ValidationHost) Validate(msg *ValidationTask) { + logger.Debugf("Validating worker", "workerID", msg.WorkerID) - //task := &validationTask{ - // request: "test", - // resultCh: resultCh, - //} - v.workerPool.submitRequest("test", &workerID, resultCh) - - <-resultCh + logger.Debugf("submitting request for worker", "workerID", msg.WorkerID) + hasWorker := v.workerPool.containsWorker(*msg.WorkerID) + if !hasWorker { + v.workerPool.newValidationWorker(*msg.WorkerID) + } + v.workerPool.submitRequest(msg) } diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index 013471f53d..dd691ea2c9 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -1,8 +1,10 @@ package pvf import ( - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "fmt" "testing" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) func Test_validationHost_start(t *testing.T) { @@ -30,6 +32,18 @@ func Test_validationHost_start(t *testing.T) { func TestValidationHost(t *testing.T) { v := NewValidationHost() + v.Start() v.workerPool.newValidationWorker(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) - v.Validate(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) + + resCh := make(chan *ValidationTaskResult) + + requestMsg := &ValidationTask{ + WorkerID: ¶chaintypes.ValidationCodeHash{1, 2, 3, 4}, + ResultCh: resCh, + } + + v.Validate(requestMsg) + + res := <-resCh + fmt.Printf("Validation result: %v", res) } diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index 9b710d88d2..bbe2ddb089 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -2,47 +2,43 @@ package pvf import ( "sync" + "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) type worker struct { - workerID parachaintypes.ValidationCodeHash - sharedGuard chan struct{} + workerID parachaintypes.ValidationCodeHash } -func newWorker(pID parachaintypes.ValidationCodeHash, sharedGuard chan struct{}) *worker { +func newWorker(pID parachaintypes.ValidationCodeHash) *worker { return &worker{ - workerID: pID, - sharedGuard: sharedGuard, + workerID: pID, } } -func (w *worker) run(queue chan *validationTask, wg *sync.WaitGroup) { +func (w *worker) run(queue chan *ValidationTask, wg *sync.WaitGroup) { defer func() { logger.Debugf("[STOPPED] worker %x", w.workerID) wg.Done() }() for task := range queue { - executeRequest(w.workerID, task, w.sharedGuard) + executeRequest(task) } } -func executeRequest(who parachaintypes.ValidationCodeHash, task *validationTask, sharedGuard chan struct{}) { - defer func() { - <-sharedGuard - }() - - sharedGuard <- struct{}{} - - request := task.request - logger.Debugf("[EXECUTING] worker %x, block request: %s", who, request) - - task.resultCh <- &validationTaskResult{ - who: who, - result: request + " result", +func executeRequest(task *ValidationTask) { + // WIP: This is a dummy implementation of the worker execution for the validation task. The logic for + // validating the parachain block request should be implemented here. + request := task.PoV + logger.Debugf("[EXECUTING] worker %x, block request: %s", task.WorkerID, request) + time.Sleep(500 * time.Millisecond) + dummyResult := &ValidationResult{} + task.ResultCh <- &ValidationTaskResult{ + who: *task.WorkerID, + result: dummyResult, } - logger.Debugf("[FINISHED] worker %x", who) + logger.Debugf("[FINISHED] worker %x", task.WorkerID) } diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 37be9f7b02..fc63b9b412 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -3,12 +3,12 @@ package pvf import ( "crypto/rand" "fmt" - "golang.org/x/exp/maps" "math/big" "sync" "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "golang.org/x/exp/maps" ) const ( @@ -19,29 +19,118 @@ type validationWorkerPool struct { mtx sync.RWMutex wg sync.WaitGroup - workers map[parachaintypes.ValidationCodeHash]*validationWorker - sharedGuard chan struct{} + workers map[parachaintypes.ValidationCodeHash]*validationWorker } -type validationTask struct { - request string - resultCh chan<- *validationTaskResult +type ValidationTask struct { + PersistedValidationData parachaintypes.PersistedValidationData + WorkerID *parachaintypes.ValidationCodeHash + CandidateReceipt *parachaintypes.CandidateReceipt + PoV parachaintypes.PoV + ExecutorParams parachaintypes.ExecutorParams + PvfExecTimeoutKind parachaintypes.PvfExecTimeoutKind + ResultCh chan<- *ValidationTaskResult } -type validationTaskResult struct { +type ValidationTaskResult struct { who parachaintypes.ValidationCodeHash - result string + result *ValidationResult +} + +// ValidationResult represents the result coming from the candidate validation subsystem. +// Validation results can be either a ValidValidationResult or InvalidValidationResult. +// +// If the result is invalid, +// store the reason for invalidity in the InvalidResult field of ValidationResult. +// +// If the result is valid, +// set the values of the ValidResult field of ValidValidationResult. +type ValidationResult struct { + ValidResult *ValidValidationResult + InvalidResult *ReasonForInvalidity +} + +func (vr ValidationResult) IsValid() bool { + return vr.ValidResult != nil +} + +type ValidValidationResult struct { + CandidateCommitments parachaintypes.CandidateCommitments + PersistedValidationData parachaintypes.PersistedValidationData +} + +type ReasonForInvalidity byte + +const ( + // ExecutionError Failed to execute `validate_block`. This includes function panicking. + ExecutionError ReasonForInvalidity = iota + // InvalidOutputs Validation outputs check doesn't pass. + InvalidOutputs + // Timeout Execution timeout. + Timeout + // ParamsTooLarge Validation input is over the limit. + ParamsTooLarge + // CodeTooLarge Code size is over the limit. + CodeTooLarge + // PoVDecompressionFailure PoV does not decompress correctly. + PoVDecompressionFailure + // BadReturn Validation function returned invalid data. + BadReturn + // BadParent Invalid relay chain parent. + BadParent + // PoVHashMismatch POV hash does not match. + PoVHashMismatch + // BadSignature Bad collator signature. + BadSignature + // ParaHeadHashMismatch Para head hash does not match. + ParaHeadHashMismatch + // CodeHashMismatch Validation code hash does not match. + CodeHashMismatch + // CommitmentsHashMismatch Validation has generated different candidate commitments. + CommitmentsHashMismatch +) + +func (ci ReasonForInvalidity) Error() string { + switch ci { + case ExecutionError: + return "failed to execute `validate_block`" + case InvalidOutputs: + return "validation outputs check doesn't pass" + case Timeout: + return "execution timeout" + case ParamsTooLarge: + return "validation input is over the limit" + case CodeTooLarge: + return "code size is over the limit" + case PoVDecompressionFailure: + return "PoV does not decompress correctly" + case BadReturn: + return "validation function returned invalid data" + case BadParent: + return "invalid relay chain parent" + case PoVHashMismatch: + return "PoV hash does not match" + case BadSignature: + return "bad collator signature" + case ParaHeadHashMismatch: + return "para head hash does not match" + case CodeHashMismatch: + return "validation code hash does not match" + case CommitmentsHashMismatch: + return "validation has generated different candidate commitments" + default: + return "unknown invalidity reason" + } } type validationWorker struct { worker *worker - queue chan *validationTask + queue chan *ValidationTask } func newValidationWorkerPool() *validationWorkerPool { return &validationWorkerPool{ - workers: make(map[parachaintypes.ValidationCodeHash]*validationWorker), - sharedGuard: make(chan struct{}, maxRequestsAllowed), + workers: make(map[parachaintypes.ValidationCodeHash]*validationWorker), } } @@ -75,8 +164,8 @@ func (v *validationWorkerPool) stop() error { func (v *validationWorkerPool) newValidationWorker(who parachaintypes.ValidationCodeHash) { - worker := newWorker(who, v.sharedGuard) - workerQueue := make(chan *validationTask, maxRequestsAllowed) + worker := newWorker(who) + workerQueue := make(chan *ValidationTask, maxRequestsAllowed) v.wg.Add(1) go worker.run(workerQueue, &v.wg) @@ -91,13 +180,12 @@ func (v *validationWorkerPool) newValidationWorker(who parachaintypes.Validation // submitRequest given a request, the worker pool will get the peer given the peer.ID // parameter or if nil the very first available worker or // to perform the request, the response will be dispatch in the resultCh. -func (v *validationWorkerPool) submitRequest(request string, - who *parachaintypes.ValidationCodeHash, resultCh chan<- *validationTaskResult) { +func (v *validationWorkerPool) submitRequest(request *ValidationTask) { - task := &validationTask{ - request: request, - resultCh: resultCh, - } + //task := &validationTask{ + // request: request, + // resultCh: resultCh, + //} // if the request is bounded to a specific peer then just // request it and sent through its queue otherwise send @@ -106,13 +194,13 @@ func (v *validationWorkerPool) submitRequest(request string, v.mtx.RLock() defer v.mtx.RUnlock() - if who != nil { - syncWorker, inMap := v.workers[*who] + if request.WorkerID != nil { + syncWorker, inMap := v.workers[*request.WorkerID] if inMap { if syncWorker == nil { panic("sync worker should not be nil") } - syncWorker.queue <- task + syncWorker.queue <- request return } } @@ -128,5 +216,13 @@ func (v *validationWorkerPool) submitRequest(request string, } selectedWorkerIdx = int(nBig.Int64()) selectedWorker := workers[selectedWorkerIdx] - selectedWorker.queue <- task + selectedWorker.queue <- request +} + +func (v *validationWorkerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { + v.mtx.RLock() + defer v.mtx.RUnlock() + + _, inMap := v.workers[workerID] + return inMap } diff --git a/dot/parachain/pvf/worker_test.go b/dot/parachain/pvf/worker_test.go index d3e0638add..893671dc71 100644 --- a/dot/parachain/pvf/worker_test.go +++ b/dot/parachain/pvf/worker_test.go @@ -6,38 +6,34 @@ import ( "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "github.com/stretchr/testify/require" ) func TestWorker(t *testing.T) { workerID1 := parachaintypes.ValidationCodeHash{1, 2, 3, 4} - sharedGuard := make(chan struct{}, 1) - w := newWorker(workerID1, sharedGuard) + w := newWorker(workerID1) wg := sync.WaitGroup{} - queue := make(chan *validationTask, 2) + queue := make(chan *ValidationTask, 2) wg.Add(1) go w.run(queue, &wg) - resultCh := make(chan *validationTaskResult) + resultCh := make(chan *ValidationTaskResult) defer close(resultCh) - queue <- &validationTask{ - resultCh: resultCh, + queue <- &ValidationTask{ + ResultCh: resultCh, } - queue <- &validationTask{ - resultCh: resultCh, + queue <- &ValidationTask{ + ResultCh: resultCh, } time.Sleep(500 * time.Millisecond) - require.Equal(t, 1, len(sharedGuard)) <-resultCh time.Sleep(500 * time.Millisecond) - require.Equal(t, 1, len(sharedGuard)) <-resultCh close(queue) From 7e314f390fa1c5143a84f7069d56101b59349d98 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 6 Aug 2024 17:25:19 -0400 Subject: [PATCH 04/30] add validation logic to workers --- dot/parachain/backing/integration_test.go | 13 +-- .../candidate_validation.go | 45 ++++----- dot/parachain/pvf/host.go | 93 ++++++++++++++++++- dot/parachain/pvf/host_test.go | 2 +- dot/parachain/pvf/worker.go | 92 ++++++++++++++---- dot/parachain/pvf/worker_pool.go | 81 ++++++---------- dot/parachain/pvf/worker_pool_test.go | 2 +- dot/parachain/pvf/worker_test.go | 13 ++- 8 files changed, 235 insertions(+), 106 deletions(-) diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index 9cdc09af0d..df6e5ac431 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -4,6 +4,7 @@ package backing_test import ( + "github.com/ChainSafe/gossamer/dot/parachain/pvf" "testing" "time" @@ -275,9 +276,9 @@ func TestSecondsValidCandidate(t *testing.T) { return false } - badReturn := candidatevalidation.BadReturn - validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ + badReturn := pvf.BadReturn + validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ InvalidResult: &badReturn, }, } @@ -339,9 +340,9 @@ func TestSecondsValidCandidate(t *testing.T) { return false } - validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{ + validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ UpwardMessages: []parachaintypes.UpwardMessage{}, HorizontalMessages: []parachaintypes.OutboundHrmpMessage{}, diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 25cce11368..ac03e208f4 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -89,33 +89,36 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { case ValidateFromExhaustive: // This is the skeleton to hook up the PVF host to the candidate validation subsystem // This is currently WIP, pending moving the validation logic to the PVF host - validationCodeHash := msg.ValidationCode.Hash() taskResult := make(chan *pvf.ValidationTaskResult) validationTask := &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{}, - WorkerID: &validationCodeHash, - CandidateReceipt: &msg.CandidateReceipt, - PoV: msg.PoV, - ExecutorParams: nil, - PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, - ResultCh: taskResult, + PersistedValidationData: msg.PersistedValidationData, + //WorkerID: &validationCodeHash, + ValidationCode: &msg.ValidationCode, + CandidateReceipt: &msg.CandidateReceipt, + PoV: msg.PoV, + ExecutorParams: nil, + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + ResultCh: taskResult, } - cv.pvfHost.Validate(validationTask) - fmt.Printf("Validation result: %v", <-taskResult) + go cv.pvfHost.Validate(validationTask) + + result := <-taskResult + fmt.Printf("Validation result: %v", result) + // TODO(ed): determine how to handle this error and result // WIP: This is the current implementation of the validation logic, it will be replaced by the PVF host // when the validation logic is moved to the PVF host - result, err := validateFromExhaustive(cv.ValidationHost, msg.PersistedValidationData, - msg.ValidationCode, msg.CandidateReceipt, msg.PoV) - if err != nil { - logger.Errorf("failed to validate from exhaustive: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: err, - } - } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result, - } + //result, err := validateFromExhaustive(cv.ValidationHost, msg.PersistedValidationData, + // msg.ValidationCode, msg.CandidateReceipt, msg.PoV) + //if err != nil { + // logger.Errorf("failed to validate from exhaustive: %w", err) + // msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + // Err: err, + // } + //} else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, + //} } case PreCheck: diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 0c335bb5c7..c2a44f5429 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -2,6 +2,9 @@ package pvf import ( "fmt" + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/ChainSafe/gossamer/pkg/scale" "sync" "github.com/ChainSafe/gossamer/internal/log" @@ -40,10 +43,90 @@ func NewValidationHost() *ValidationHost { func (v *ValidationHost) Validate(msg *ValidationTask) { logger.Debugf("Validating worker", "workerID", msg.WorkerID) - logger.Debugf("submitting request for worker", "workerID", msg.WorkerID) - hasWorker := v.workerPool.containsWorker(*msg.WorkerID) - if !hasWorker { - v.workerPool.newValidationWorker(*msg.WorkerID) + validationCodeHash := msg.ValidationCode.Hash() + // basic checks + validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, + msg.PersistedValidationData.MaxPovSize, + msg.PoV, + validationCodeHash) + // TODO(ed): confirm how to handle internal errors + if internalErr != nil { + logger.Errorf("performing basic checks: %w", internalErr) } - v.workerPool.submitRequest(msg) + + if validationErr != nil { + valErr := &ValidationTaskResult{ + who: validationCodeHash, + Result: &ValidationResult{ + InvalidResult: validationErr, + }, + } + msg.ResultCh <- valErr + return + } + + workerID := v.poolContainsWorker(msg) + validationParams := parachainruntime.ValidationParameters{ + ParentHeadData: msg.PersistedValidationData.ParentHead, + BlockData: msg.PoV.BlockData, + RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, + RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, + } + workTask := &workerTask{ + work: validationParams, + maxPoVSize: msg.PersistedValidationData.MaxPovSize, + ResultCh: msg.ResultCh, + } + v.workerPool.submitRequest(workerID, workTask) +} + +func (v *ValidationHost) poolContainsWorker(msg *ValidationTask) parachaintypes.ValidationCodeHash { + if msg.WorkerID != nil { + return *msg.WorkerID + } + if v.workerPool.containsWorker(msg.ValidationCode.Hash()) { + return msg.ValidationCode.Hash() + } else { + v.workerPool.newValidationWorker(*msg.ValidationCode) + return msg.ValidationCode.Hash() + } +} + +// performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. +// Returns ReasonForInvalidity and internal error if any. +func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, + pov parachaintypes.PoV, validationCodeHash parachaintypes.ValidationCodeHash) ( + validationError *ReasonForInvalidity, internalError error) { + povHash, err := pov.Hash() + if err != nil { + return nil, fmt.Errorf("hashing PoV: %w", err) + } + + encodedPoV, err := scale.Marshal(pov) + if err != nil { + return nil, fmt.Errorf("encoding PoV: %w", err) + } + encodedPoVSize := uint32(len(encodedPoV)) + + if encodedPoVSize > maxPoVSize { + ci := ParamsTooLarge + return &ci, nil + } + + if povHash != candidate.PovHash { + ci := PoVHashMismatch + return &ci, nil + } + + if validationCodeHash != candidate.ValidationCodeHash { + ci := CodeHashMismatch + return &ci, nil + } + + err = candidate.CheckCollatorSignature() + if err != nil { + ci := BadSignature + return &ci, nil + } + return nil, nil } diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index dd691ea2c9..bf30b255d9 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -33,7 +33,7 @@ func Test_validationHost_start(t *testing.T) { func TestValidationHost(t *testing.T) { v := NewValidationHost() v.Start() - v.workerPool.newValidationWorker(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) + v.workerPool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) resCh := make(chan *ValidationTaskResult) diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index bbe2ddb089..e366ce16f9 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -1,44 +1,104 @@ package pvf import ( - "sync" - "time" - + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "sync" ) type worker struct { workerID parachaintypes.ValidationCodeHash + instance *parachainruntime.Instance + queue chan *workerTask } -func newWorker(pID parachaintypes.ValidationCodeHash) *worker { - return &worker{ - workerID: pID, +type workerTask struct { + work parachainruntime.ValidationParameters + maxPoVSize uint32 + ResultCh chan<- *ValidationTaskResult +} + +func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerTask) (*worker, error) { + validationRuntime, err := parachainruntime.SetupVM(validationCode) + + if err != nil { + return nil, err } + return &worker{ + workerID: validationCode.Hash(), + instance: validationRuntime, + queue: queue, + }, nil } -func (w *worker) run(queue chan *ValidationTask, wg *sync.WaitGroup) { +func (w *worker) run(queue chan *workerTask, wg *sync.WaitGroup) { defer func() { logger.Debugf("[STOPPED] worker %x", w.workerID) wg.Done() }() for task := range queue { - executeRequest(task) + w.executeRequest(task) } } -func executeRequest(task *ValidationTask) { +func (w *worker) executeRequest(task *workerTask) { // WIP: This is a dummy implementation of the worker execution for the validation task. The logic for // validating the parachain block request should be implemented here. - request := task.PoV - logger.Debugf("[EXECUTING] worker %x, block request: %s", task.WorkerID, request) - time.Sleep(500 * time.Millisecond) - dummyResult := &ValidationResult{} + logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) + + // todo do basic checks + + validationResult, err := w.instance.ValidateBlock(task.work) + + /////////////////////////////// + //if err != nil { + // return nil, fmt.Errorf("executing validate_block: %w", err) + //} + + //headDataHash, err := validationResult.HeadData.Hash() + //if err != nil { + // return nil, fmt.Errorf("hashing head data: %w", err) + //} + // + //if headDataHash != candidateReceipt.Descriptor.ParaHead { + // ci := pvf.ParaHeadHashMismatch + // return &pvf.ValidationResult{InvalidResult: &ci}, nil + //} + candidateCommitments := parachaintypes.CandidateCommitments{ + UpwardMessages: validationResult.UpwardMessages, + HorizontalMessages: validationResult.HorizontalMessages, + NewValidationCode: validationResult.NewValidationCode, + HeadData: validationResult.HeadData, + ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, + HrmpWatermark: validationResult.HrmpWatermark, + } + + // if validation produced a new set of commitments, we treat the candidate as invalid + //if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { + // ci := CommitmentsHashMismatch + // return &ValidationResult{InvalidResult: &ci}, nil + //} + pvd := parachaintypes.PersistedValidationData{ + ParentHead: task.work.ParentHeadData, + RelayParentNumber: task.work.RelayParentNumber, + RelayParentStorageRoot: task.work.RelayParentStorageRoot, + MaxPovSize: task.maxPoVSize, + } + dummyResilt := &ValidationResult{ + ValidResult: &ValidValidationResult{ + CandidateCommitments: candidateCommitments, + PersistedValidationData: pvd, + }, + } + ////////////////////////// + + logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, dummyResilt, err) + task.ResultCh <- &ValidationTaskResult{ - who: *task.WorkerID, - result: dummyResult, + who: w.workerID, + Result: dummyResilt, } - logger.Debugf("[FINISHED] worker %x", task.WorkerID) + //logger.Debugf("[FINISHED] worker %v, error: %s", validationResult, err) } diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index fc63b9b412..6b9d1328c5 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -1,14 +1,11 @@ package pvf import ( - "crypto/rand" "fmt" - "math/big" "sync" "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "golang.org/x/exp/maps" ) const ( @@ -19,7 +16,7 @@ type validationWorkerPool struct { mtx sync.RWMutex wg sync.WaitGroup - workers map[parachaintypes.ValidationCodeHash]*validationWorker + workers map[parachaintypes.ValidationCodeHash]*worker } type ValidationTask struct { @@ -29,12 +26,13 @@ type ValidationTask struct { PoV parachaintypes.PoV ExecutorParams parachaintypes.ExecutorParams PvfExecTimeoutKind parachaintypes.PvfExecTimeoutKind + ValidationCode *parachaintypes.ValidationCode ResultCh chan<- *ValidationTaskResult } type ValidationTaskResult struct { who parachaintypes.ValidationCodeHash - result *ValidationResult + Result *ValidationResult } // ValidationResult represents the result coming from the candidate validation subsystem. @@ -123,14 +121,14 @@ func (ci ReasonForInvalidity) Error() string { } } -type validationWorker struct { - worker *worker - queue chan *ValidationTask -} +//type validationWorker struct { +// worker *worker +// queue chan *workerTask +//} func newValidationWorkerPool() *validationWorkerPool { return &validationWorkerPool{ - workers: make(map[parachaintypes.ValidationCodeHash]*validationWorker), + workers: make(map[parachaintypes.ValidationCodeHash]*worker), } } @@ -162,61 +160,42 @@ func (v *validationWorkerPool) stop() error { } } -func (v *validationWorkerPool) newValidationWorker(who parachaintypes.ValidationCodeHash) { - - worker := newWorker(who) - workerQueue := make(chan *ValidationTask, maxRequestsAllowed) +func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) parachaintypes.ValidationCodeHash { + workerQueue := make(chan *workerTask, maxRequestsAllowed) + worker, err := newWorker(validationCode, workerQueue) + if err != nil { + // TODO(ed): handle this error + logger.Errorf("failed to create a new worker: %w", err) + } v.wg.Add(1) go worker.run(workerQueue, &v.wg) - v.workers[who] = &validationWorker{ - worker: worker, - queue: workerQueue, - } - logger.Tracef("potential worker added, total in the pool %d", len(v.workers)) + v.workers[worker.workerID] = worker + + return worker.workerID } // submitRequest given a request, the worker pool will get the peer given the peer.ID // parameter or if nil the very first available worker or // to perform the request, the response will be dispatch in the resultCh. -func (v *validationWorkerPool) submitRequest(request *ValidationTask) { - - //task := &validationTask{ - // request: request, - // resultCh: resultCh, - //} - - // if the request is bounded to a specific peer then just - // request it and sent through its queue otherwise send - // the request in the general queue where all worker are - // listening on +func (v *validationWorkerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, request *workerTask) { v.mtx.RLock() defer v.mtx.RUnlock() + logger.Debugf("pool submit request workerID %x", workerID) - if request.WorkerID != nil { - syncWorker, inMap := v.workers[*request.WorkerID] - if inMap { - if syncWorker == nil { - panic("sync worker should not be nil") - } - syncWorker.queue <- request - return + //if request.WorkerID != nil { + syncWorker, inMap := v.workers[workerID] + if inMap { + if syncWorker == nil { + panic("sync worker should not be nil") } + logger.Debugf("sending request", workerID) + syncWorker.queue <- request + return } - - // if the exact peer is not specified then - // randomly select a worker and assign the - // task to it, if the amount of workers is - var selectedWorkerIdx int - workers := maps.Values(v.workers) - nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(workers)))) - if err != nil { - panic(fmt.Errorf("fail to get a random number: %w", err)) - } - selectedWorkerIdx = int(nBig.Int64()) - selectedWorker := workers[selectedWorkerIdx] - selectedWorker.queue <- request + // TODO(ed): handle this case + logger.Errorf("workerID %x not found in the pool", workerID) } func (v *validationWorkerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/pvf/worker_pool_test.go index 88ea789209..23f5becc2c 100644 --- a/dot/parachain/pvf/worker_pool_test.go +++ b/dot/parachain/pvf/worker_pool_test.go @@ -17,7 +17,7 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { "add_one_worker": { setupWorkerPool: func(t *testing.T) *validationWorkerPool { pool := newValidationWorkerPool() - pool.newValidationWorker(parachaintypes.ValidationCodeHash{1, 2, 3, 4}) + pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) return pool }, expectedWorkers: []parachaintypes.ValidationCodeHash{ diff --git a/dot/parachain/pvf/worker_test.go b/dot/parachain/pvf/worker_test.go index 893671dc71..05f3abf089 100644 --- a/dot/parachain/pvf/worker_test.go +++ b/dot/parachain/pvf/worker_test.go @@ -1,6 +1,7 @@ package pvf import ( + "github.com/stretchr/testify/require" "sync" "testing" "time" @@ -9,12 +10,14 @@ import ( ) func TestWorker(t *testing.T) { - workerID1 := parachaintypes.ValidationCodeHash{1, 2, 3, 4} + workerID1 := parachaintypes.ValidationCode{1, 2, 3, 4} - w := newWorker(workerID1) + workerQueue := make(chan *workerTask, maxRequestsAllowed) + w, err := newWorker(workerID1, workerQueue) + require.NoError(t, err) wg := sync.WaitGroup{} - queue := make(chan *ValidationTask, 2) + queue := make(chan *workerTask, 2) wg.Add(1) go w.run(queue, &wg) @@ -22,11 +25,11 @@ func TestWorker(t *testing.T) { resultCh := make(chan *ValidationTaskResult) defer close(resultCh) - queue <- &ValidationTask{ + queue <- &workerTask{ ResultCh: resultCh, } - queue <- &ValidationTask{ + queue <- &workerTask{ ResultCh: resultCh, } From 0b2b5fc38aa48753d7bb154b32c9627a7629fbb3 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 6 Aug 2024 17:35:06 -0400 Subject: [PATCH 05/30] address lint issues. --- dot/parachain/backing/integration_test.go | 2 +- dot/parachain/pvf/host.go | 9 ++++----- dot/parachain/pvf/worker.go | 3 ++- dot/parachain/pvf/worker_pool.go | 3 ++- dot/parachain/pvf/worker_test.go | 2 +- go.mod | 1 + go.sum | 3 +++ 7 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index df6e5ac431..1fbd28756a 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -4,7 +4,6 @@ package backing_test import ( - "github.com/ChainSafe/gossamer/dot/parachain/pvf" "testing" "time" @@ -13,6 +12,7 @@ import ( candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" "github.com/ChainSafe/gossamer/dot/parachain/overseer" + "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto" diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index c2a44f5429..67278dc932 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -2,12 +2,12 @@ package pvf import ( "fmt" - parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "github.com/ChainSafe/gossamer/pkg/scale" "sync" + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/internal/log" + "github.com/ChainSafe/gossamer/pkg/scale" ) var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) @@ -87,8 +87,7 @@ func (v *ValidationHost) poolContainsWorker(msg *ValidationTask) parachaintypes. if v.workerPool.containsWorker(msg.ValidationCode.Hash()) { return msg.ValidationCode.Hash() } else { - v.workerPool.newValidationWorker(*msg.ValidationCode) - return msg.ValidationCode.Hash() + return v.workerPool.newValidationWorker(*msg.ValidationCode) } } diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index e366ce16f9..07b392ab5b 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -1,9 +1,10 @@ package pvf import ( + "sync" + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "sync" ) type worker struct { diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 6b9d1328c5..46c4538ba2 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -160,7 +160,8 @@ func (v *validationWorkerPool) stop() error { } } -func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) parachaintypes.ValidationCodeHash { +func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) parachaintypes. + ValidationCodeHash { workerQueue := make(chan *workerTask, maxRequestsAllowed) worker, err := newWorker(validationCode, workerQueue) diff --git a/dot/parachain/pvf/worker_test.go b/dot/parachain/pvf/worker_test.go index 05f3abf089..cbdd5a5680 100644 --- a/dot/parachain/pvf/worker_test.go +++ b/dot/parachain/pvf/worker_test.go @@ -1,12 +1,12 @@ package pvf import ( - "github.com/stretchr/testify/require" "sync" "testing" "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/stretchr/testify/require" ) func TestWorker(t *testing.T) { diff --git a/go.mod b/go.mod index d9d9ebbf39..f585b2c749 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/fatih/color v1.17.0 github.com/gammazero/deque v0.2.1 github.com/go-playground/validator/v10 v10.21.0 + github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 diff --git a/go.sum b/go.sum index 03ec8f0ac3..990d74d772 100644 --- a/go.sum +++ b/go.sum @@ -206,6 +206,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -797,6 +799,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= From 20fd4c4efba64ffad478603f4ffa4dce337c2da5 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Sat, 10 Aug 2024 14:36:57 -0400 Subject: [PATCH 06/30] add functionality for validate from chainstate to pvf host and tests --- .../candidate_validation.go | 361 +++++++++------ .../candidate_validation_test.go | 432 +++++++++++------- .../candidate-validation/messages.go | 2 +- .../mocks_generate_test.go | 3 +- .../mocks_runtime_test.go | 139 ------ .../overseer/mock_runtime_instance_test.go | 2 +- dot/parachain/pvf/host.go | 9 +- dot/parachain/pvf/worker.go | 87 ++-- dot/parachain/runtime/instance.go | 8 +- dot/parachain/service.go | 2 +- 10 files changed, 554 insertions(+), 491 deletions(-) delete mode 100644 dot/parachain/candidate-validation/mocks_runtime_test.go diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index ac03e208f4..189610b11e 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -4,7 +4,6 @@ package candidatevalidation import ( - "bytes" "context" "errors" "fmt" @@ -15,6 +14,7 @@ import ( parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/runtime" "github.com/ChainSafe/gossamer/pkg/scale" ) @@ -32,15 +32,20 @@ type CandidateValidation struct { SubsystemToOverseer chan<- any OverseerToSubsystem <-chan any - ValidationHost parachainruntime.ValidationHost + BlockState BlockState pvfHost *pvf.ValidationHost } +type BlockState interface { + GetRuntime(blockHash common.Hash) (instance runtime.Instance, err error) +} + // NewCandidateValidation creates a new CandidateValidation subsystem -func NewCandidateValidation(overseerChan chan<- any) *CandidateValidation { +func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *CandidateValidation { candidateValidation := CandidateValidation{ SubsystemToOverseer: overseerChan, pvfHost: pvf.NewValidationHost(), + BlockState: blockState, } return &candidateValidation } @@ -85,20 +90,19 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { logger.Debugf("received message %v", msg) switch msg := msg.(type) { case ValidateFromChainState: - // TODO: implement functionality to handle ValidateFromChainState, see issue #3919 + fmt.Printf("ValidateFromChainState: %v", msg) + cv.validateFromChainState(msg) + case ValidateFromExhaustive: - // This is the skeleton to hook up the PVF host to the candidate validation subsystem - // This is currently WIP, pending moving the validation logic to the PVF host taskResult := make(chan *pvf.ValidationTaskResult) validationTask := &pvf.ValidationTask{ PersistedValidationData: msg.PersistedValidationData, - //WorkerID: &validationCodeHash, - ValidationCode: &msg.ValidationCode, - CandidateReceipt: &msg.CandidateReceipt, - PoV: msg.PoV, - ExecutorParams: nil, - PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, - ResultCh: taskResult, + ValidationCode: &msg.ValidationCode, + CandidateReceipt: &msg.CandidateReceipt, + PoV: msg.PoV, + ExecutorParams: msg.ExecutorParams, + PvfExecTimeoutKind: msg.PvfExecTimeoutKind, + ResultCh: taskResult, } go cv.pvfHost.Validate(validationTask) @@ -179,154 +183,213 @@ func getValidationData(runtimeInstance parachainruntime.RuntimeInstance, paraID return nil, nil, fmt.Errorf("getting persisted validation data: %w", mergedError) } -// validateFromChainState validates a candidate parachain block with provided parameters using relay-chain -// state and using the parachain runtime. -func validateFromChainState(runtimeInstance parachainruntime.RuntimeInstance, povRequestor PoVRequestor, - candidateReceipt parachaintypes.CandidateReceipt) ( - *parachaintypes.CandidateCommitments, *parachaintypes.PersistedValidationData, bool, error) { - - persistedValidationData, validationCode, err := getValidationData(runtimeInstance, candidateReceipt.Descriptor.ParaID) - if err != nil { - return nil, nil, false, fmt.Errorf("getting validation data: %w", err) - } - - // check that the candidate does not exceed any parameters in the persisted validation data - pov := povRequestor.RequestPoV(candidateReceipt.Descriptor.PovHash) - - // basic checks - - // check if encoded size of pov is less than max pov size - buffer := bytes.NewBuffer(nil) - encoder := scale.NewEncoder(buffer) - err = encoder.Encode(pov) - if err != nil { - return nil, nil, false, fmt.Errorf("encoding pov: %w", err) - } - encodedPoVSize := buffer.Len() - if encodedPoVSize > int(persistedValidationData.MaxPovSize) { - return nil, nil, false, fmt.Errorf("%w, limit: %d, got: %d", ErrValidationInputOverLimit, - persistedValidationData.MaxPovSize, encodedPoVSize) - } - - validationCodeHash, err := common.Blake2bHash([]byte(*validationCode)) - if err != nil { - return nil, nil, false, fmt.Errorf("hashing validation code: %w", err) - } - - if validationCodeHash != common.Hash(candidateReceipt.Descriptor.ValidationCodeHash) { - return nil, nil, false, fmt.Errorf("%w, expected: %s, got %s", ErrValidationCodeMismatch, - candidateReceipt.Descriptor.ValidationCodeHash, validationCodeHash) - } - - // check candidate signature - err = candidateReceipt.Descriptor.CheckCollatorSignature() - if err != nil { - return nil, nil, false, fmt.Errorf("verifying collator signature: %w", err) - } - - validationParams := parachainruntime.ValidationParameters{ - ParentHeadData: persistedValidationData.ParentHead, - BlockData: pov.BlockData, - RelayParentNumber: persistedValidationData.RelayParentNumber, - RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, - } - - parachainRuntimeInstance, err := parachainruntime.SetupVM(*validationCode) +func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState) { + runtimeInstance, err := cv.BlockState.GetRuntime(msg.CandidateReceipt.Descriptor.RelayParent) if err != nil { - return nil, nil, false, fmt.Errorf("setting up VM: %w", err) - } - - validationResults, err := parachainRuntimeInstance.ValidateBlock(validationParams) - if err != nil { - return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) - } - - candidateCommitments := parachaintypes.CandidateCommitments{ - UpwardMessages: validationResults.UpwardMessages, - HorizontalMessages: validationResults.HorizontalMessages, - NewValidationCode: validationResults.NewValidationCode, - HeadData: validationResults.HeadData, - ProcessedDownwardMessages: validationResults.ProcessedDownwardMessages, - HrmpWatermark: validationResults.HrmpWatermark, - } - - isValid, err := runtimeInstance.ParachainHostCheckValidationOutputs( - candidateReceipt.Descriptor.ParaID, candidateCommitments) - if err != nil { - return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) - } - - return &candidateCommitments, persistedValidationData, isValid, nil -} - -// validateFromExhaustive validates a candidate parachain block with provided parameters -func validateFromExhaustive(validationHost parachainruntime.ValidationHost, - persistedValidationData parachaintypes.PersistedValidationData, - validationCode parachaintypes.ValidationCode, - candidateReceipt parachaintypes.CandidateReceipt, pov parachaintypes.PoV) ( - *pvf.ValidationResult, error) { - - validationCodeHash := validationCode.Hash() - // basic checks - validationErr, internalErr := performBasicChecks(&candidateReceipt.Descriptor, persistedValidationData.MaxPovSize, - pov, - validationCodeHash) - if internalErr != nil { - return nil, fmt.Errorf("performing basic checks: %w", internalErr) - } - - if validationErr != nil { - validationResult := &pvf.ValidationResult{ - InvalidResult: validationErr, + logger.Errorf("getting runtime instance: %w", err) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: err, } - return validationResult, nil //nolint: nilerr - } - - validationParams := parachainruntime.ValidationParameters{ - ParentHeadData: persistedValidationData.ParentHead, - BlockData: pov.BlockData, - RelayParentNumber: persistedValidationData.RelayParentNumber, - RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, - } - - validationResult, err := validationHost.ValidateBlock(validationParams) - // TODO: implement functionality to parse errors generated by the runtime when PVF host is implemented, issue #3934 - if err != nil { - return nil, fmt.Errorf("executing validate_block: %w", err) + return } - headDataHash, err := validationResult.HeadData.Hash() + persistedValidationData, validationCode, err := getValidationData(runtimeInstance, + msg.CandidateReceipt.Descriptor.ParaID) if err != nil { - return nil, fmt.Errorf("hashing head data: %w", err) + logger.Errorf("getting validation data: %w", err) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: err, + } + return } - if headDataHash != candidateReceipt.Descriptor.ParaHead { - ci := pvf.ParaHeadHashMismatch - return &pvf.ValidationResult{InvalidResult: &ci}, nil - } - candidateCommitments := parachaintypes.CandidateCommitments{ - UpwardMessages: validationResult.UpwardMessages, - HorizontalMessages: validationResult.HorizontalMessages, - NewValidationCode: validationResult.NewValidationCode, - HeadData: validationResult.HeadData, - ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, - HrmpWatermark: validationResult.HrmpWatermark, + taskResult := make(chan *pvf.ValidationTaskResult) + validationTask := &pvf.ValidationTask{ + PersistedValidationData: *persistedValidationData, + ValidationCode: validationCode, + CandidateReceipt: &msg.CandidateReceipt, + PoV: msg.Pov, + ExecutorParams: msg.ExecutorParams, + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + ResultCh: taskResult, } + go cv.pvfHost.Validate(validationTask) - // if validation produced a new set of commitments, we treat the candidate as invalid - if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { - ci := pvf.CommitmentsHashMismatch - return &pvf.ValidationResult{InvalidResult: &ci}, nil + result := <-taskResult + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, } - return &pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ - CandidateCommitments: candidateCommitments, - PersistedValidationData: persistedValidationData, - }, - }, nil - } +// todo confirm that all the functionality of these has been implemented in pvf host +// validateFromChainState validates a candidate parachain block with provided parameters using relay-chain +// state and using the parachain runtime. +//func validateFromChainState(runtimeInstance parachainruntime.RuntimeInstance, pov parachaintypes.PoV, +// candidateReceipt parachaintypes.CandidateReceipt) (*pvf.ValidationResult, error) { +// +// persistedValidationData, validationCode, err := getValidationData(runtimeInstance, +// candidateReceipt.Descriptor.ParaID) +// if err != nil { +// return nil, fmt.Errorf("getting validation data: %w", err) +// } +// +// parachainRuntimeInstance, err := parachainruntime.SetupVM(*validationCode) +// if err != nil { +// return nil, fmt.Errorf("setting up VM: %w", err) +// } +// +// taskResult := make(chan *pvf.ValidationTaskResult) +// validationTask := &pvf.ValidationTask{ +// PersistedValidationData: msg.PersistedValidationData, +// ValidationCode: &msg.ValidationCode, +// CandidateReceipt: &msg.CandidateReceipt, +// PoV: msg.PoV, +// ExecutorParams: nil, +// PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, +// ResultCh: taskResult, +// } +// go cv.pvfHost.Validate(validationTask) +// +// result := <-taskResult +// +// //validationResults, err := validateFromExhaustive +// //// check that the candidate does not exceed any parameters in the persisted validation data +// //pov := povRequestor.RequestPoV(candidateReceipt.Descriptor.PovHash) +// // +// //// basic checks +// // +// //// check if encoded size of pov is less than max pov size +// //buffer := bytes.NewBuffer(nil) +// //encoder := scale.NewEncoder(buffer) +// //err = encoder.Encode(pov) +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("encoding pov: %w", err) +// //} +// //encodedPoVSize := buffer.Len() +// //if encodedPoVSize > int(persistedValidationData.MaxPovSize) { +// // return nil, nil, false, fmt.Errorf("%w, limit: %d, got: %d", ErrValidationInputOverLimit, +// // persistedValidationData.MaxPovSize, encodedPoVSize) +// //} +// // +// //validationCodeHash, err := common.Blake2bHash([]byte(*validationCode)) +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("hashing validation code: %w", err) +// //} +// // +// //if validationCodeHash != common.Hash(candidateReceipt.Descriptor.ValidationCodeHash) { +// // return nil, nil, false, fmt.Errorf("%w, expected: %s, got %s", ErrValidationCodeMismatch, +// // candidateReceipt.Descriptor.ValidationCodeHash, validationCodeHash) +// //} +// // +// //// check candidate signature +// //err = candidateReceipt.Descriptor.CheckCollatorSignature() +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("verifying collator signature: %w", err) +// //} +// // +// //validationParams := parachainruntime.ValidationParameters{ +// // ParentHeadData: persistedValidationData.ParentHead, +// // BlockData: pov.BlockData, +// // RelayParentNumber: persistedValidationData.RelayParentNumber, +// // RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, +// //} +// // +// //parachainRuntimeInstance, err := parachainruntime.SetupVM(*validationCode) +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("setting up VM: %w", err) +// //} +// // +// //validationResults, err := parachainRuntimeInstance.ValidateBlock(validationParams) +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) +// //} +// // +// //candidateCommitments := parachaintypes.CandidateCommitments{ +// // UpwardMessages: validationResults.UpwardMessages, +// // HorizontalMessages: validationResults.HorizontalMessages, +// // NewValidationCode: validationResults.NewValidationCode, +// // HeadData: validationResults.HeadData, +// // ProcessedDownwardMessages: validationResults.ProcessedDownwardMessages, +// // HrmpWatermark: validationResults.HrmpWatermark, +// //} +// // +// //isValid, err := runtimeInstance.ParachainHostCheckValidationOutputs( +// // candidateReceipt.Descriptor.ParaID, candidateCommitments) +// //if err != nil { +// // return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) +// //} +// // +// //return &candidateCommitments, persistedValidationData, isValid, nil +//} + +//// validateFromExhaustive validates a candidate parachain block with provided parameters +//func validateFromExhaustive(validationHost parachainruntime.ValidationHost, +// persistedValidationData parachaintypes.PersistedValidationData, +// validationCode parachaintypes.ValidationCode, +// candidateReceipt parachaintypes.CandidateReceipt, pov parachaintypes.PoV) ( +// *pvf.ValidationResult, error) { +// +// validationCodeHash := validationCode.Hash() +// // basic checks +// validationErr, internalErr := performBasicChecks(&candidateReceipt.Descriptor, persistedValidationData.MaxPovSize, +// pov, +// validationCodeHash) +// if internalErr != nil { +// return nil, fmt.Errorf("performing basic checks: %w", internalErr) +// } +// +// if validationErr != nil { +// validationResult := &pvf.ValidationResult{ +// InvalidResult: validationErr, +// } +// return validationResult, nil //nolint: nilerr +// } +// +// validationParams := parachainruntime.ValidationParameters{ +// ParentHeadData: persistedValidationData.ParentHead, +// BlockData: pov.BlockData, +// RelayParentNumber: persistedValidationData.RelayParentNumber, +// RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, +// } +// +// validationResult, err := validationHost.ValidateBlock(validationParams) +// // TODO: implement functionality to parse errors generated by the runtime when PVF host is implemented, issue #3934 +// if err != nil { +// return nil, fmt.Errorf("executing validate_block: %w", err) +// } +// +// headDataHash, err := validationResult.HeadData.Hash() +// if err != nil { +// return nil, fmt.Errorf("hashing head data: %w", err) +// } +// +// if headDataHash != candidateReceipt.Descriptor.ParaHead { +// ci := pvf.ParaHeadHashMismatch +// return &pvf.ValidationResult{InvalidResult: &ci}, nil +// } +// candidateCommitments := parachaintypes.CandidateCommitments{ +// UpwardMessages: validationResult.UpwardMessages, +// HorizontalMessages: validationResult.HorizontalMessages, +// NewValidationCode: validationResult.NewValidationCode, +// HeadData: validationResult.HeadData, +// ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, +// HrmpWatermark: validationResult.HrmpWatermark, +// } +// +// // if validation produced a new set of commitments, we treat the candidate as invalid +// if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { +// ci := pvf.CommitmentsHashMismatch +// return &pvf.ValidationResult{InvalidResult: &ci}, nil +// } +// return &pvf.ValidationResult{ +// ValidResult: &pvf.ValidValidationResult{ +// CandidateCommitments: candidateCommitments, +// PersistedValidationData: persistedValidationData, +// }, +// }, nil +// +//} + // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. // Returns ReasonForInvalidity and internal error if any. func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 6a0a2d89cf..8a70e978c2 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -5,8 +5,6 @@ package candidatevalidation import ( "context" - "errors" - "fmt" "os" "testing" "time" @@ -83,68 +81,6 @@ func makeValidCandidateDescriptor(t *testing.T, paraID uint32, relayParent commo return descriptor } -func TestValidateFromChainState(t *testing.T) { - - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) - - bd, err := scale.Marshal(BlockDataInAdderParachain{ - State: uint64(1), - Add: uint64(1), - }) - require.NoError(t, err) - - pov := parachaintypes.PoV{ - BlockData: bd, - } - - // NOTE: adder parachain internally compares postState with bd.State in it's validate_block, - // so following is necessary. - encodedState, err := scale.Marshal(uint64(1)) - require.NoError(t, err) - postState, err := common.Keccak256(encodedState) - require.NoError(t, err) - - hd, err := scale.Marshal(HeadDataInAdderParachain{ - Number: uint64(1), - ParentHash: common.MustHexToHash("0x0102030405060708090001020304050607080900010203040506070809000102"), - PostState: postState, - }) - require.NoError(t, err) - - expectedPersistedValidationData := parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - } - - ctrl := gomock.NewController(t) - - mockInstance := NewMockRuntimeInstance(ctrl) - mockInstance.EXPECT(). - ParachainHostPersistedValidationData( - uint32(1000), - gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). - Return(&expectedPersistedValidationData, nil) - mockInstance.EXPECT(). - ParachainHostValidationCode(uint32(1000), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). - Return(&validationCode, nil) - mockInstance.EXPECT(). - ParachainHostCheckValidationOutputs(uint32(1000), gomock.AssignableToTypeOf(parachaintypes.CandidateCommitments{})). - Return(true, nil) - - mockPoVRequestor := NewMockPoVRequestor(ctrl) - mockPoVRequestor.EXPECT(). - RequestPoV(common.MustHexToHash("0xb608991ffc48dd405fd4b10e92eaebe2b5a2eedf44d0c3efb8997fdee8bebed9")).Return(pov) - - candidateCommitments, persistedValidationData, isValid, err := validateFromChainState( - mockInstance, mockPoVRequestor, candidateReceipt) - require.NoError(t, err) - require.True(t, isValid) - require.NotNil(t, candidateCommitments) - require.Equal(t, expectedPersistedValidationData, *persistedValidationData) -} - type HeadDataInAdderParachain struct { Number uint64 ParentHash [32]byte @@ -168,21 +104,21 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { candidateReceiptCommitmentsMismatch := candidateReceipt candidateReceiptCommitmentsMismatch.CommitmentsHash = common.MustHexToHash( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") - testValidationHost, err := parachainruntime.SetupVM(validationCode) - require.NoError(t, err) povHashMismatch := pvf.PoVHashMismatch paramsTooLarge := pvf.ParamsTooLarge codeHashMismatch := pvf.CodeHashMismatch paraHedHashMismatch := pvf.ParaHeadHashMismatch commitmentsHashMismatch := pvf.CommitmentsHashMismatch + executionError := pvf.ExecutionError + + pvfHost := pvf.NewValidationHost() + pvfHost.Start() + defer pvfHost.Stop() ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) - mockValidationHost := NewMockValidationHost(ctrl) - mockValidationHost.EXPECT().ValidateBlock(gomock.Any()).Return(nil, parachainruntime.ErrHardTimeout).AnyTimes() - bd, err := scale.Marshal(BlockDataInAdderParachain{ State: uint64(1), Add: uint64(1), @@ -206,30 +142,23 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { }) require.NoError(t, err) - type args struct { - validationHost parachainruntime.ValidationHost - persistedValidationData parachaintypes.PersistedValidationData - validationCode parachaintypes.ValidationCode - candidateReceipt parachaintypes.CandidateReceipt - pov parachaintypes.PoV - } tests := map[string]struct { - args args - want *pvf.ValidationResult - expectedError error - isValid bool + validationTask *pvf.ValidationTask + want *pvf.ValidationResult + isValid bool }{ "invalid_pov_hash": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(2048), }, - validationCode: validationCode, - candidateReceipt: candidateReceipt2, - pov: pov, + CandidateReceipt: &candidateReceipt2, + PoV: pov, + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + ValidationCode: &validationCode, }, want: &pvf.ValidationResult{ InvalidResult: &povHashMismatch, @@ -237,84 +166,62 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { isValid: false, }, "invalid_pov_size": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(10), }, - validationCode: validationCode, - candidateReceipt: candidateReceipt, - pov: pov, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, }, want: &pvf.ValidationResult{ InvalidResult: ¶msTooLarge, }, }, "code_mismatch": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(2048), }, - validationCode: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - candidateReceipt: candidateReceipt, - pov: pov, + ValidationCode: ¶chaintypes.ValidationCode{1, 2, 3, 4, 5, 6, 7, 8}, + CandidateReceipt: &candidateReceipt, + PoV: pov, }, want: &pvf.ValidationResult{ InvalidResult: &codeHashMismatch, }, isValid: false, }, - "mock_test": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - validationHost: mockValidationHost, - validationCode: validationCode, - candidateReceipt: candidateReceipt, - pov: pov, - }, - want: nil, - expectedError: fmt.Errorf("executing validate_block: %w", parachainruntime.ErrHardTimeout), - }, "wasm_error_unreachable": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ MaxPovSize: uint32(2048), }, - validationHost: testValidationHost, - validationCode: validationCode, - candidateReceipt: candidateReceipt, - pov: pov, - }, - want: nil, - expectedError: errors.New("executing validate_block: running runtime function: wasm error: unreachable" + - "\nwasm stack trace:\n\t.rust_begin_unwind(i32)\n\t._ZN4core9panicking9panic_fmt17h55a9886e2bf4227aE(" + - "i32,i32)\n\t\t0xcbc: /rustc/1c42cb4ef0544fbfaa500216e53382d6b079c001/library/core/src/panicking." + - "rs:67:14\n\t._ZN4core6result13unwrap_failed17h18cc772327ac51f6E(i32,i32,i32,i32," + - "i32)\n\t\t0xfe9: /rustc/1c42cb4ef0544fbfaa500216e53382d6b079c001/library/core/src/result." + - "rs:1651:5\n\t.validate_block(i32,i32) i64"), + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, + }, + want: &pvf.ValidationResult{ + InvalidResult: &executionError, + }, }, "para_head_hash_mismatch": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(2048), }, - validationHost: testValidationHost, - validationCode: validationCode, - candidateReceipt: candidateReceiptParaHeadMismatch, - pov: pov, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceiptParaHeadMismatch, + PoV: pov, }, want: &pvf.ValidationResult{ InvalidResult: ¶HedHashMismatch, @@ -322,17 +229,16 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { isValid: false, }, "commitments_hash_mismatch": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(2048), }, - validationHost: testValidationHost, - validationCode: validationCode, - candidateReceipt: candidateReceiptCommitmentsMismatch, - pov: pov, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceiptCommitmentsMismatch, + PoV: pov, }, want: &pvf.ValidationResult{ InvalidResult: &commitmentsHashMismatch, @@ -340,17 +246,16 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { isValid: false, }, "happy_path": { - args: args{ - persistedValidationData: parachaintypes.PersistedValidationData{ + validationTask: &pvf.ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: hd}, RelayParentNumber: uint32(1), RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), MaxPovSize: uint32(2048), }, - validationHost: testValidationHost, - validationCode: validationCode, - candidateReceipt: candidateReceipt, - pov: pov, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, }, want: &pvf.ValidationResult{ ValidResult: &pvf.ValidValidationResult{ @@ -385,18 +290,16 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { tt := tt t.Run(name, func(t *testing.T) { t.Parallel() - got, err := validateFromExhaustive(tt.args.validationHost, tt.args.persistedValidationData, - tt.args.validationCode, - tt.args.candidateReceipt, tt.args.pov) - if tt.expectedError != nil { - require.EqualError(t, err, tt.expectedError.Error()) - } else { - require.NoError(t, err) - } - require.Equal(t, tt.want, got) - if got != nil { - require.Equal(t, tt.isValid, got.IsValid()) - } + + taskResult := make(chan *pvf.ValidationTaskResult) + defer close(taskResult) + tt.validationTask.ResultCh = taskResult + + go pvfHost.Validate(tt.validationTask) + + result := <-taskResult + require.Equal(t, tt.want, result.Result) + require.Equal(t, tt.isValid, result.Result.IsValid()) }) } } @@ -417,8 +320,6 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") - testValidationHost, err := parachainruntime.SetupVM(validationCode) - require.NoError(t, err) bd, err := scale.Marshal(BlockDataInAdderParachain{ State: uint64(1), @@ -448,7 +349,6 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) candidateValidationSubsystem := CandidateValidation{ OverseerToSubsystem: toSubsystem, stopChan: stopChan, - ValidationHost: testValidationHost, pvfHost: pvf.NewValidationHost(), } defer candidateValidationSubsystem.Stop() @@ -679,3 +579,219 @@ func Test_performBasicChecks(t *testing.T) { }) } } + +func TestCandidateValidation_validateFromChainState(t *testing.T) { + // todo figure out why this doesn't work with t.Parallel() + //t.Parallel() + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt2 := candidateReceipt + candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + candidateReceipt2.Descriptor.ParaID = 2 + + candidateReceipt3 := candidateReceipt + candidateReceipt3.Descriptor.ParaID = 3 + + candidateReceipt4 := candidateReceipt + candidateReceipt4.Descriptor.ParaID = 4 + candidateReceipt4.Descriptor.ValidationCodeHash = parachaintypes.ValidationCodeHash(common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")) + + candidateReceipt5 := candidateReceipt + candidateReceipt5.Descriptor.ParaID = 5 + + povHashMismatch := pvf.PoVHashMismatch + paramsTooLarge := pvf.ParamsTooLarge + codeHashMismatch := pvf.CodeHashMismatch + badSignature := pvf.BadSignature + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + + //NOTE: adder parachain internally compares postState with bd.State in it's validate_block, + //so following is necessary. + encodedState, err := scale.Marshal(uint64(1)) + require.NoError(t, err) + postState, err := common.Keccak256(encodedState) + require.NoError(t, err) + + hd, err := scale.Marshal(HeadDataInAdderParachain{ + Number: uint64(1), + ParentHash: common.MustHexToHash("0x0102030405060708090001020304050607080900010203040506070809000102"), + PostState: postState, + }) + require.NoError(t, err) + + expectedPersistedValidationData := parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + } + + expectedPersistedValidationDataSmallMax := parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(10), + } + + mockInstance := NewMockInstance(ctrl) + mockInstance.EXPECT(). + ParachainHostPersistedValidationData( + uint32(1000), + gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationData, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(1000), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + + mockInstance.EXPECT(). + ParachainHostPersistedValidationData( + uint32(2), + gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationData, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(2), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + + mockInstance.EXPECT(). + ParachainHostPersistedValidationData( + uint32(3), + gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationDataSmallMax, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(3), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + + mockInstance.EXPECT(). + ParachainHostPersistedValidationData( + uint32(4), + gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationData, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(4), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + + mockInstance.EXPECT(). + ParachainHostPersistedValidationData( + uint32(5), + gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationData, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(5), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + + mockBlockState := NewMockBlockState(ctrl) + mockBlockState.EXPECT().GetRuntime(common.MustHexToHash( + "0xded542bacb3ca6c033a57676f94ae7c8f36834511deb44e3164256fd3b1c0de0")).Return(mockInstance, nil).Times(5) + + bd, err := scale.Marshal(BlockDataInAdderParachain{ + State: uint64(1), + Add: uint64(1), + }) + require.NoError(t, err) + pov := parachaintypes.PoV{ + BlockData: bd, + } + + toSubsystem := make(chan any) + sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) + stopChan := make(chan struct{}) + candidateValidationSubsystem := CandidateValidation{ + OverseerToSubsystem: toSubsystem, + stopChan: stopChan, + pvfHost: pvf.NewValidationHost(), + BlockState: mockBlockState, + } + defer candidateValidationSubsystem.Stop() + + candidateValidationSubsystem.Run(context.Background(), nil, nil) + + tests := map[string]struct { + msg ValidateFromChainState + want *pvf.ValidationResult + expectedError error + }{ + "invalid_pov_hash": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt2, + Pov: pov, + Ch: sender, + }, + want: &pvf.ValidationResult{ + InvalidResult: &povHashMismatch, + }, + }, + "invalid_pov_size": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt3, + Pov: pov, + Ch: sender, + }, + want: &pvf.ValidationResult{ + InvalidResult: ¶msTooLarge, + }, + }, + "code_mismatch": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt4, + Pov: pov, + Ch: sender, + }, + want: &pvf.ValidationResult{ + InvalidResult: &codeHashMismatch, + }, + }, + "bad_signature": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt5, + Pov: pov, + Ch: sender, + }, + want: &pvf.ValidationResult{ + InvalidResult: &badSignature, + }, + }, + "happy_path": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt, + Pov: pov, + Ch: sender, + }, + want: &pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ + CandidateCommitments: parachaintypes.CandidateCommitments{ + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + }, + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, + 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, + 15, 1, 168, 127, 226}}, + RelayParentNumber: 1, + RelayParentStorageRoot: common.MustHexToHash( + "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: 2048, + }, + }, + }, + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + time.Sleep(100 * time.Millisecond) + toSubsystem <- tt.msg + time.Sleep(100 * time.Millisecond) + result := <-sender + require.Equal(t, tt.want, &result.Data) + }) + } +} diff --git a/dot/parachain/candidate-validation/messages.go b/dot/parachain/candidate-validation/messages.go index 010c53b945..76f974d2aa 100644 --- a/dot/parachain/candidate-validation/messages.go +++ b/dot/parachain/candidate-validation/messages.go @@ -15,7 +15,7 @@ type ValidateFromChainState struct { Pov parachaintypes.PoV ExecutorParams parachaintypes.ExecutorParams ExecKind parachaintypes.PvfExecTimeoutKind - Sender chan ValidateFromExhaustive + Ch chan parachaintypes.OverseerFuncRes[pvf.ValidationResult] } // ValidateFromExhaustive performs full validation of a candidate with provided parameters, diff --git a/dot/parachain/candidate-validation/mocks_generate_test.go b/dot/parachain/candidate-validation/mocks_generate_test.go index 7bdd10bed1..4cab5225ad 100644 --- a/dot/parachain/candidate-validation/mocks_generate_test.go +++ b/dot/parachain/candidate-validation/mocks_generate_test.go @@ -4,4 +4,5 @@ package candidatevalidation //go:generate mockgen -destination=mocks_test.go -package=$GOPACKAGE . PoVRequestor -//go:generate mockgen -destination=mocks_runtime_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/dot/parachain/runtime RuntimeInstance,ValidationHost +//go:generate mockgen -destination=mocks_blockstate_test.go -package=$GOPACKAGE . BlockState +//go:generate mockgen -destination=mocks_instance_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/lib/runtime Instance diff --git a/dot/parachain/candidate-validation/mocks_runtime_test.go b/dot/parachain/candidate-validation/mocks_runtime_test.go deleted file mode 100644 index 367d30e01b..0000000000 --- a/dot/parachain/candidate-validation/mocks_runtime_test.go +++ /dev/null @@ -1,139 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ChainSafe/gossamer/dot/parachain/runtime (interfaces: RuntimeInstance,ValidationHost) -// -// Generated by this command: -// -// mockgen -destination=mocks_runtime_test.go -package candidatevalidation github.com/ChainSafe/gossamer/dot/parachain/runtime RuntimeInstance,ValidationHost -// - -// Package candidatevalidation is a generated GoMock package. -package candidatevalidation - -import ( - reflect "reflect" - - parachain "github.com/ChainSafe/gossamer/dot/parachain/runtime" - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - gomock "go.uber.org/mock/gomock" -) - -// MockRuntimeInstance is a mock of RuntimeInstance interface. -type MockRuntimeInstance struct { - ctrl *gomock.Controller - recorder *MockRuntimeInstanceMockRecorder -} - -// MockRuntimeInstanceMockRecorder is the mock recorder for MockRuntimeInstance. -type MockRuntimeInstanceMockRecorder struct { - mock *MockRuntimeInstance -} - -// NewMockRuntimeInstance creates a new mock instance. -func NewMockRuntimeInstance(ctrl *gomock.Controller) *MockRuntimeInstance { - mock := &MockRuntimeInstance{ctrl: ctrl} - mock.recorder = &MockRuntimeInstanceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockRuntimeInstance) EXPECT() *MockRuntimeInstanceMockRecorder { - return m.recorder -} - -// ParachainHostCandidateEvents mocks base method. -func (m *MockRuntimeInstance) ParachainHostCandidateEvents() ([]parachaintypes.CandidateEvent, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostCandidateEvents") - ret0, _ := ret[0].([]parachaintypes.CandidateEvent) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostCandidateEvents indicates an expected call of ParachainHostCandidateEvents. -func (mr *MockRuntimeInstanceMockRecorder) ParachainHostCandidateEvents() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidateEvents", reflect.TypeOf((*MockRuntimeInstance)(nil).ParachainHostCandidateEvents)) -} - -// ParachainHostCheckValidationOutputs mocks base method. -func (m *MockRuntimeInstance) ParachainHostCheckValidationOutputs(arg0 uint32, arg1 parachaintypes.CandidateCommitments) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostCheckValidationOutputs", arg0, arg1) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostCheckValidationOutputs indicates an expected call of ParachainHostCheckValidationOutputs. -func (mr *MockRuntimeInstanceMockRecorder) ParachainHostCheckValidationOutputs(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCheckValidationOutputs", reflect.TypeOf((*MockRuntimeInstance)(nil).ParachainHostCheckValidationOutputs), arg0, arg1) -} - -// ParachainHostPersistedValidationData mocks base method. -func (m *MockRuntimeInstance) ParachainHostPersistedValidationData(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.PersistedValidationData, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostPersistedValidationData", arg0, arg1) - ret0, _ := ret[0].(*parachaintypes.PersistedValidationData) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostPersistedValidationData indicates an expected call of ParachainHostPersistedValidationData. -func (mr *MockRuntimeInstanceMockRecorder) ParachainHostPersistedValidationData(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostPersistedValidationData", reflect.TypeOf((*MockRuntimeInstance)(nil).ParachainHostPersistedValidationData), arg0, arg1) -} - -// ParachainHostValidationCode mocks base method. -func (m *MockRuntimeInstance) ParachainHostValidationCode(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.ValidationCode, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostValidationCode", arg0, arg1) - ret0, _ := ret[0].(*parachaintypes.ValidationCode) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostValidationCode indicates an expected call of ParachainHostValidationCode. -func (mr *MockRuntimeInstanceMockRecorder) ParachainHostValidationCode(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCode", reflect.TypeOf((*MockRuntimeInstance)(nil).ParachainHostValidationCode), arg0, arg1) -} - -// MockValidationHost is a mock of ValidationHost interface. -type MockValidationHost struct { - ctrl *gomock.Controller - recorder *MockValidationHostMockRecorder -} - -// MockValidationHostMockRecorder is the mock recorder for MockValidationHost. -type MockValidationHostMockRecorder struct { - mock *MockValidationHost -} - -// NewMockValidationHost creates a new mock instance. -func NewMockValidationHost(ctrl *gomock.Controller) *MockValidationHost { - mock := &MockValidationHost{ctrl: ctrl} - mock.recorder = &MockValidationHostMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockValidationHost) EXPECT() *MockValidationHostMockRecorder { - return m.recorder -} - -// ValidateBlock mocks base method. -func (m *MockValidationHost) ValidateBlock(arg0 parachain.ValidationParameters) (*parachain.ValidationResult, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateBlock", arg0) - ret0, _ := ret[0].(*parachain.ValidationResult) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ValidateBlock indicates an expected call of ValidateBlock. -func (mr *MockValidationHostMockRecorder) ValidateBlock(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateBlock", reflect.TypeOf((*MockValidationHost)(nil).ValidateBlock), arg0) -} diff --git a/dot/parachain/overseer/mock_runtime_instance_test.go b/dot/parachain/overseer/mock_runtime_instance_test.go index 7b892fabcf..ea8aa49824 100644 --- a/dot/parachain/overseer/mock_runtime_instance_test.go +++ b/dot/parachain/overseer/mock_runtime_instance_test.go @@ -55,7 +55,7 @@ func (mr *MockRuntimeInstanceMockRecorder) ParachainHostCandidateEvents() *gomoc } // ParachainHostCheckValidationOutputs mocks base method. -func (m *MockRuntimeInstance) ParachainHostCheckValidationOutputs(arg0 uint32, arg1 parachaintypes.CandidateCommitments) (bool, error) { +func (m *MockRuntimeInstance) ParachainHostCheckValidationOutputs(arg0 parachaintypes.ParaID, arg1 parachaintypes.CandidateCommitments) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ParachainHostCheckValidationOutputs", arg0, arg1) ret0, _ := ret[0].(bool) diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 67278dc932..4756945fbe 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -41,7 +41,7 @@ func NewValidationHost() *ValidationHost { } func (v *ValidationHost) Validate(msg *ValidationTask) { - logger.Debugf("Validating worker", "workerID", msg.WorkerID) + logger.Debugf("Validating worker %x", msg.WorkerID) validationCodeHash := msg.ValidationCode.Hash() // basic checks @@ -73,9 +73,10 @@ func (v *ValidationHost) Validate(msg *ValidationTask) { RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, } workTask := &workerTask{ - work: validationParams, - maxPoVSize: msg.PersistedValidationData.MaxPovSize, - ResultCh: msg.ResultCh, + work: validationParams, + maxPoVSize: msg.PersistedValidationData.MaxPovSize, + candidateReceipt: msg.CandidateReceipt, + ResultCh: msg.ResultCh, } v.workerPool.submitRequest(workerID, workTask) } diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index 07b392ab5b..5db740cbdf 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -14,9 +14,10 @@ type worker struct { } type workerTask struct { - work parachainruntime.ValidationParameters - maxPoVSize uint32 - ResultCh chan<- *ValidationTaskResult + work parachainruntime.ValidationParameters + maxPoVSize uint32 + candidateReceipt *parachaintypes.CandidateReceipt + ResultCh chan<- *ValidationTaskResult } func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerTask) (*worker, error) { @@ -44,28 +45,48 @@ func (w *worker) run(queue chan *workerTask, wg *sync.WaitGroup) { } func (w *worker) executeRequest(task *workerTask) { - // WIP: This is a dummy implementation of the worker execution for the validation task. The logic for - // validating the parachain block request should be implemented here. logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) - // todo do basic checks - validationResult, err := w.instance.ValidateBlock(task.work) - /////////////////////////////// - //if err != nil { - // return nil, fmt.Errorf("executing validate_block: %w", err) - //} - - //headDataHash, err := validationResult.HeadData.Hash() - //if err != nil { - // return nil, fmt.Errorf("hashing head data: %w", err) - //} - // - //if headDataHash != candidateReceipt.Descriptor.ParaHead { - // ci := pvf.ParaHeadHashMismatch - // return &pvf.ValidationResult{InvalidResult: &ci}, nil - //} + if err != nil { + logger.Errorf("executing validate_block: %w", err) + reasonForInvalidity := ExecutionError + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + task.ResultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return + } + + headDataHash, err := validationResult.HeadData.Hash() + if err != nil { + logger.Errorf("hashing head data: %w", err) + reasonForInvalidity := ExecutionError + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + task.ResultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return + } + + if headDataHash != task.candidateReceipt.Descriptor.ParaHead { + reasonForInvalidity := ParaHeadHashMismatch + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + task.ResultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return + } candidateCommitments := parachaintypes.CandidateCommitments{ UpwardMessages: validationResult.UpwardMessages, HorizontalMessages: validationResult.HorizontalMessages, @@ -76,30 +97,34 @@ func (w *worker) executeRequest(task *workerTask) { } // if validation produced a new set of commitments, we treat the candidate as invalid - //if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { - // ci := CommitmentsHashMismatch - // return &ValidationResult{InvalidResult: &ci}, nil - //} + if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { + reasonForInvalidity := CommitmentsHashMismatch + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + task.ResultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return + } pvd := parachaintypes.PersistedValidationData{ ParentHead: task.work.ParentHeadData, RelayParentNumber: task.work.RelayParentNumber, RelayParentStorageRoot: task.work.RelayParentStorageRoot, MaxPovSize: task.maxPoVSize, } - dummyResilt := &ValidationResult{ + validResult := &ValidationResult{ ValidResult: &ValidValidationResult{ CandidateCommitments: candidateCommitments, PersistedValidationData: pvd, }, } - ////////////////////////// - logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, dummyResilt, err) + logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, validResult, err) task.ResultCh <- &ValidationTaskResult{ who: w.workerID, - Result: dummyResilt, + Result: validResult, } - - //logger.Debugf("[FINISHED] worker %v, error: %s", validationResult, err) } diff --git a/dot/parachain/runtime/instance.go b/dot/parachain/runtime/instance.go index f668255c0b..41b01bfff5 100644 --- a/dot/parachain/runtime/instance.go +++ b/dot/parachain/runtime/instance.go @@ -89,18 +89,14 @@ func (in *Instance) ValidateBlock(params ValidationParameters) ( return &validationResult, nil } -type ValidationHost interface { - // ValidateBlock validates a block by calling parachain runtime's validate_block call and returns the result. - ValidateBlock(params ValidationParameters) (*ValidationResult, error) -} - // RuntimeInstance for runtime methods type RuntimeInstance interface { ParachainHostPersistedValidationData(parachaidID uint32, assumption parachaintypes.OccupiedCoreAssumption, ) (*parachaintypes.PersistedValidationData, error) ParachainHostValidationCode(parachaidID uint32, assumption parachaintypes.OccupiedCoreAssumption, ) (*parachaintypes.ValidationCode, error) - ParachainHostCheckValidationOutputs(parachainID uint32, outputs parachaintypes.CandidateCommitments) (bool, error) + ParachainHostCheckValidationOutputs(parachainID parachaintypes.ParaID, outputs parachaintypes.CandidateCommitments) ( + bool, error) ParachainHostCandidateEvents() ([]parachaintypes.CandidateEvent, error) } diff --git a/dot/parachain/service.go b/dot/parachain/service.go index 2908c5bed2..bc7d0391a0 100644 --- a/dot/parachain/service.go +++ b/dot/parachain/service.go @@ -78,7 +78,7 @@ func NewService(net Network, forkID string, st *state.Service, ks keystore.Keyst cpvs.OverseerToSubSystem = overseer.RegisterSubsystem(cpvs) // register candidate validation subsystem - candidateValidationSubsystem := candidatevalidation.NewCandidateValidation(overseer.SubsystemsToOverseer) + candidateValidationSubsystem := candidatevalidation.NewCandidateValidation(overseer.SubsystemsToOverseer, st.Block) candidateValidationSubsystem.OverseerToSubsystem = overseer.RegisterSubsystem(candidateValidationSubsystem) From 6c05d8239ec8f6d2d33890a856a56c81142a2ecc Mon Sep 17 00:00:00 2001 From: edwardmack Date: Sat, 10 Aug 2024 14:45:40 -0400 Subject: [PATCH 07/30] add updated mock files --- .../mocks_blockstate_test.go | 56 ++ .../mocks_instance_test.go | 650 ++++++++++++++++++ 2 files changed, 706 insertions(+) create mode 100644 dot/parachain/candidate-validation/mocks_blockstate_test.go create mode 100644 dot/parachain/candidate-validation/mocks_instance_test.go diff --git a/dot/parachain/candidate-validation/mocks_blockstate_test.go b/dot/parachain/candidate-validation/mocks_blockstate_test.go new file mode 100644 index 0000000000..fe0d7c587f --- /dev/null +++ b/dot/parachain/candidate-validation/mocks_blockstate_test.go @@ -0,0 +1,56 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/dot/parachain/candidate-validation (interfaces: BlockState) +// +// Generated by this command: +// +// mockgen -destination=mocks_blockstate_test.go -package=candidatevalidation . BlockState +// + +// Package candidatevalidation is a generated GoMock package. +package candidatevalidation + +import ( + reflect "reflect" + + common "github.com/ChainSafe/gossamer/lib/common" + runtime "github.com/ChainSafe/gossamer/lib/runtime" + gomock "go.uber.org/mock/gomock" +) + +// MockBlockState is a mock of BlockState interface. +type MockBlockState struct { + ctrl *gomock.Controller + recorder *MockBlockStateMockRecorder +} + +// MockBlockStateMockRecorder is the mock recorder for MockBlockState. +type MockBlockStateMockRecorder struct { + mock *MockBlockState +} + +// NewMockBlockState creates a new mock instance. +func NewMockBlockState(ctrl *gomock.Controller) *MockBlockState { + mock := &MockBlockState{ctrl: ctrl} + mock.recorder = &MockBlockStateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBlockState) EXPECT() *MockBlockStateMockRecorder { + return m.recorder +} + +// GetRuntime mocks base method. +func (m *MockBlockState) GetRuntime(arg0 common.Hash) (runtime.Instance, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRuntime", arg0) + ret0, _ := ret[0].(runtime.Instance) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRuntime indicates an expected call of GetRuntime. +func (mr *MockBlockStateMockRecorder) GetRuntime(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRuntime", reflect.TypeOf((*MockBlockState)(nil).GetRuntime), arg0) +} diff --git a/dot/parachain/candidate-validation/mocks_instance_test.go b/dot/parachain/candidate-validation/mocks_instance_test.go new file mode 100644 index 0000000000..22efc588d2 --- /dev/null +++ b/dot/parachain/candidate-validation/mocks_instance_test.go @@ -0,0 +1,650 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/lib/runtime (interfaces: Instance) +// +// Generated by this command: +// +// mockgen -destination=mocks_instance_test.go -package candidatevalidation github.com/ChainSafe/gossamer/lib/runtime Instance +// + +// Package candidatevalidation is a generated GoMock package. +package candidatevalidation + +import ( + reflect "reflect" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + types "github.com/ChainSafe/gossamer/dot/types" + common "github.com/ChainSafe/gossamer/lib/common" + ed25519 "github.com/ChainSafe/gossamer/lib/crypto/ed25519" + keystore "github.com/ChainSafe/gossamer/lib/keystore" + runtime "github.com/ChainSafe/gossamer/lib/runtime" + transaction "github.com/ChainSafe/gossamer/lib/transaction" + gomock "go.uber.org/mock/gomock" +) + +// MockInstance is a mock of Instance interface. +type MockInstance struct { + ctrl *gomock.Controller + recorder *MockInstanceMockRecorder +} + +// MockInstanceMockRecorder is the mock recorder for MockInstance. +type MockInstanceMockRecorder struct { + mock *MockInstance +} + +// NewMockInstance creates a new mock instance. +func NewMockInstance(ctrl *gomock.Controller) *MockInstance { + mock := &MockInstance{ctrl: ctrl} + mock.recorder = &MockInstanceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockInstance) EXPECT() *MockInstanceMockRecorder { + return m.recorder +} + +// ApplyExtrinsic mocks base method. +func (m *MockInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyExtrinsic", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ApplyExtrinsic indicates an expected call of ApplyExtrinsic. +func (mr *MockInstanceMockRecorder) ApplyExtrinsic(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockInstance)(nil).ApplyExtrinsic), arg0) +} + +// BabeConfiguration mocks base method. +func (m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeConfiguration") + ret0, _ := ret[0].(*types.BabeConfiguration) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeConfiguration indicates an expected call of BabeConfiguration. +func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) +} + +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + +// CheckInherents mocks base method. +func (m *MockInstance) CheckInherents() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "CheckInherents") +} + +// CheckInherents indicates an expected call of CheckInherents. +func (mr *MockInstanceMockRecorder) CheckInherents() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockInstance)(nil).CheckInherents)) +} + +// DecodeSessionKeys mocks base method. +func (m *MockInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecodeSessionKeys", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DecodeSessionKeys indicates an expected call of DecodeSessionKeys. +func (mr *MockInstanceMockRecorder) DecodeSessionKeys(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockInstance)(nil).DecodeSessionKeys), arg0) +} + +// Exec mocks base method. +func (m *MockInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exec", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exec indicates an expected call of Exec. +func (mr *MockInstanceMockRecorder) Exec(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockInstance)(nil).Exec), arg0, arg1) +} + +// ExecuteBlock mocks base method. +func (m *MockInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteBlock", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteBlock indicates an expected call of ExecuteBlock. +func (mr *MockInstanceMockRecorder) ExecuteBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockInstance)(nil).ExecuteBlock), arg0) +} + +// FinalizeBlock mocks base method. +func (m *MockInstance) FinalizeBlock() (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FinalizeBlock") + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FinalizeBlock indicates an expected call of FinalizeBlock. +func (mr *MockInstanceMockRecorder) FinalizeBlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockInstance)(nil).FinalizeBlock)) +} + +// GenerateSessionKeys mocks base method. +func (m *MockInstance) GenerateSessionKeys() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GenerateSessionKeys") +} + +// GenerateSessionKeys indicates an expected call of GenerateSessionKeys. +func (mr *MockInstanceMockRecorder) GenerateSessionKeys() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockInstance)(nil).GenerateSessionKeys)) +} + +// GetCodeHash mocks base method. +func (m *MockInstance) GetCodeHash() common.Hash { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCodeHash") + ret0, _ := ret[0].(common.Hash) + return ret0 +} + +// GetCodeHash indicates an expected call of GetCodeHash. +func (mr *MockInstanceMockRecorder) GetCodeHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockInstance)(nil).GetCodeHash)) +} + +// GrandpaAuthorities mocks base method. +func (m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaAuthorities") + ret0, _ := ret[0].([]types.Authority) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GrandpaAuthorities indicates an expected call of GrandpaAuthorities. +func (mr *MockInstanceMockRecorder) GrandpaAuthorities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockInstance)(nil).GrandpaAuthorities)) +} + +// GrandpaGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) GrandpaGenerateKeyOwnershipProof(arg0 uint64, arg1 ed25519.PublicKeyBytes) (types.GrandpaOpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.GrandpaOpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GrandpaGenerateKeyOwnershipProof indicates an expected call of GrandpaGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) GrandpaGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).GrandpaGenerateKeyOwnershipProof), arg0, arg1) +} + +// GrandpaSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0 types.GrandpaEquivocationProof, arg1 types.GrandpaOpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// GrandpaSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of GrandpaSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).GrandpaSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + +// InherentExtrinsics mocks base method. +func (m *MockInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InherentExtrinsics", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InherentExtrinsics indicates an expected call of InherentExtrinsics. +func (mr *MockInstanceMockRecorder) InherentExtrinsics(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockInstance)(nil).InherentExtrinsics), arg0) +} + +// InitializeBlock mocks base method. +func (m *MockInstance) InitializeBlock(arg0 *types.Header) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitializeBlock", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// InitializeBlock indicates an expected call of InitializeBlock. +func (mr *MockInstanceMockRecorder) InitializeBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockInstance)(nil).InitializeBlock), arg0) +} + +// Keystore mocks base method. +func (m *MockInstance) Keystore() *keystore.GlobalKeystore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Keystore") + ret0, _ := ret[0].(*keystore.GlobalKeystore) + return ret0 +} + +// Keystore indicates an expected call of Keystore. +func (mr *MockInstanceMockRecorder) Keystore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockInstance)(nil).Keystore)) +} + +// Metadata mocks base method. +func (m *MockInstance) Metadata() ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Metadata") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Metadata indicates an expected call of Metadata. +func (mr *MockInstanceMockRecorder) Metadata() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockInstance)(nil).Metadata)) +} + +// NetworkService mocks base method. +func (m *MockInstance) NetworkService() runtime.BasicNetwork { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkService") + ret0, _ := ret[0].(runtime.BasicNetwork) + return ret0 +} + +// NetworkService indicates an expected call of NetworkService. +func (mr *MockInstanceMockRecorder) NetworkService() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockInstance)(nil).NetworkService)) +} + +// NodeStorage mocks base method. +func (m *MockInstance) NodeStorage() runtime.NodeStorage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NodeStorage") + ret0, _ := ret[0].(runtime.NodeStorage) + return ret0 +} + +// NodeStorage indicates an expected call of NodeStorage. +func (mr *MockInstanceMockRecorder) NodeStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockInstance)(nil).NodeStorage)) +} + +// OffchainWorker mocks base method. +func (m *MockInstance) OffchainWorker() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OffchainWorker") +} + +// OffchainWorker indicates an expected call of OffchainWorker. +func (mr *MockInstanceMockRecorder) OffchainWorker() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockInstance)(nil).OffchainWorker)) +} + +// ParachainHostAsyncBackingParams mocks base method. +func (m *MockInstance) ParachainHostAsyncBackingParams() (*parachaintypes.AsyncBackingParams, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostAsyncBackingParams") + ret0, _ := ret[0].(*parachaintypes.AsyncBackingParams) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostAsyncBackingParams indicates an expected call of ParachainHostAsyncBackingParams. +func (mr *MockInstanceMockRecorder) ParachainHostAsyncBackingParams() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAsyncBackingParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostAsyncBackingParams)) +} + +// ParachainHostAvailabilityCores mocks base method. +func (m *MockInstance) ParachainHostAvailabilityCores() ([]parachaintypes.CoreState, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostAvailabilityCores") + ret0, _ := ret[0].([]parachaintypes.CoreState) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostAvailabilityCores indicates an expected call of ParachainHostAvailabilityCores. +func (mr *MockInstanceMockRecorder) ParachainHostAvailabilityCores() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAvailabilityCores", reflect.TypeOf((*MockInstance)(nil).ParachainHostAvailabilityCores)) +} + +// ParachainHostCandidateEvents mocks base method. +func (m *MockInstance) ParachainHostCandidateEvents() ([]parachaintypes.CandidateEvent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCandidateEvents") + ret0, _ := ret[0].([]parachaintypes.CandidateEvent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCandidateEvents indicates an expected call of ParachainHostCandidateEvents. +func (mr *MockInstanceMockRecorder) ParachainHostCandidateEvents() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidateEvents", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidateEvents)) +} + +// ParachainHostCandidatePendingAvailability mocks base method. +func (m *MockInstance) ParachainHostCandidatePendingAvailability(arg0 parachaintypes.ParaID) (*parachaintypes.CommittedCandidateReceipt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCandidatePendingAvailability", arg0) + ret0, _ := ret[0].(*parachaintypes.CommittedCandidateReceipt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCandidatePendingAvailability indicates an expected call of ParachainHostCandidatePendingAvailability. +func (mr *MockInstanceMockRecorder) ParachainHostCandidatePendingAvailability(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidatePendingAvailability", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidatePendingAvailability), arg0) +} + +// ParachainHostCheckValidationOutputs mocks base method. +func (m *MockInstance) ParachainHostCheckValidationOutputs(arg0 parachaintypes.ParaID, arg1 parachaintypes.CandidateCommitments) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCheckValidationOutputs", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCheckValidationOutputs indicates an expected call of ParachainHostCheckValidationOutputs. +func (mr *MockInstanceMockRecorder) ParachainHostCheckValidationOutputs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCheckValidationOutputs", reflect.TypeOf((*MockInstance)(nil).ParachainHostCheckValidationOutputs), arg0, arg1) +} + +// ParachainHostMinimumBackingVotes mocks base method. +func (m *MockInstance) ParachainHostMinimumBackingVotes() (uint32, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostMinimumBackingVotes") + ret0, _ := ret[0].(uint32) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostMinimumBackingVotes indicates an expected call of ParachainHostMinimumBackingVotes. +func (mr *MockInstanceMockRecorder) ParachainHostMinimumBackingVotes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostMinimumBackingVotes", reflect.TypeOf((*MockInstance)(nil).ParachainHostMinimumBackingVotes)) +} + +// ParachainHostPersistedValidationData mocks base method. +func (m *MockInstance) ParachainHostPersistedValidationData(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.PersistedValidationData, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostPersistedValidationData", arg0, arg1) + ret0, _ := ret[0].(*parachaintypes.PersistedValidationData) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostPersistedValidationData indicates an expected call of ParachainHostPersistedValidationData. +func (mr *MockInstanceMockRecorder) ParachainHostPersistedValidationData(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostPersistedValidationData", reflect.TypeOf((*MockInstance)(nil).ParachainHostPersistedValidationData), arg0, arg1) +} + +// ParachainHostSessionExecutorParams mocks base method. +func (m *MockInstance) ParachainHostSessionExecutorParams(arg0 parachaintypes.SessionIndex) (*parachaintypes.ExecutorParams, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionExecutorParams", arg0) + ret0, _ := ret[0].(*parachaintypes.ExecutorParams) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionExecutorParams indicates an expected call of ParachainHostSessionExecutorParams. +func (mr *MockInstanceMockRecorder) ParachainHostSessionExecutorParams(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionExecutorParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionExecutorParams), arg0) +} + +// ParachainHostSessionIndexForChild mocks base method. +func (m *MockInstance) ParachainHostSessionIndexForChild() (parachaintypes.SessionIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionIndexForChild") + ret0, _ := ret[0].(parachaintypes.SessionIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionIndexForChild indicates an expected call of ParachainHostSessionIndexForChild. +func (mr *MockInstanceMockRecorder) ParachainHostSessionIndexForChild() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionIndexForChild", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionIndexForChild)) +} + +// ParachainHostSessionInfo mocks base method. +func (m *MockInstance) ParachainHostSessionInfo(arg0 parachaintypes.SessionIndex) (*parachaintypes.SessionInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionInfo", arg0) + ret0, _ := ret[0].(*parachaintypes.SessionInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionInfo indicates an expected call of ParachainHostSessionInfo. +func (mr *MockInstanceMockRecorder) ParachainHostSessionInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionInfo", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionInfo), arg0) +} + +// ParachainHostValidationCode mocks base method. +func (m *MockInstance) ParachainHostValidationCode(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.ValidationCode, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidationCode", arg0, arg1) + ret0, _ := ret[0].(*parachaintypes.ValidationCode) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidationCode indicates an expected call of ParachainHostValidationCode. +func (mr *MockInstanceMockRecorder) ParachainHostValidationCode(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCode", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCode), arg0, arg1) +} + +// ParachainHostValidationCodeByHash mocks base method. +func (m *MockInstance) ParachainHostValidationCodeByHash(arg0 common.Hash) (*parachaintypes.ValidationCode, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidationCodeByHash", arg0) + ret0, _ := ret[0].(*parachaintypes.ValidationCode) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidationCodeByHash indicates an expected call of ParachainHostValidationCodeByHash. +func (mr *MockInstanceMockRecorder) ParachainHostValidationCodeByHash(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCodeByHash", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCodeByHash), arg0) +} + +// ParachainHostValidatorGroups mocks base method. +func (m *MockInstance) ParachainHostValidatorGroups() (*parachaintypes.ValidatorGroups, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidatorGroups") + ret0, _ := ret[0].(*parachaintypes.ValidatorGroups) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidatorGroups indicates an expected call of ParachainHostValidatorGroups. +func (mr *MockInstanceMockRecorder) ParachainHostValidatorGroups() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidatorGroups", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidatorGroups)) +} + +// ParachainHostValidators mocks base method. +func (m *MockInstance) ParachainHostValidators() ([]parachaintypes.ValidatorID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidators") + ret0, _ := ret[0].([]parachaintypes.ValidatorID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidators indicates an expected call of ParachainHostValidators. +func (mr *MockInstanceMockRecorder) ParachainHostValidators() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidators", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidators)) +} + +// PaymentQueryInfo mocks base method. +func (m *MockInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PaymentQueryInfo", arg0) + ret0, _ := ret[0].(*types.RuntimeDispatchInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PaymentQueryInfo indicates an expected call of PaymentQueryInfo. +func (mr *MockInstanceMockRecorder) PaymentQueryInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockInstance)(nil).PaymentQueryInfo), arg0) +} + +// RandomSeed mocks base method. +func (m *MockInstance) RandomSeed() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RandomSeed") +} + +// RandomSeed indicates an expected call of RandomSeed. +func (mr *MockInstanceMockRecorder) RandomSeed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockInstance)(nil).RandomSeed)) +} + +// SetContextStorage mocks base method. +func (m *MockInstance) SetContextStorage(arg0 runtime.Storage) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetContextStorage", arg0) +} + +// SetContextStorage indicates an expected call of SetContextStorage. +func (mr *MockInstanceMockRecorder) SetContextStorage(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockInstance)(nil).SetContextStorage), arg0) +} + +// Stop mocks base method. +func (m *MockInstance) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockInstanceMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockInstance)(nil).Stop)) +} + +// ValidateTransaction mocks base method. +func (m *MockInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateTransaction", arg0) + ret0, _ := ret[0].(*transaction.Validity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateTransaction indicates an expected call of ValidateTransaction. +func (mr *MockInstanceMockRecorder) ValidateTransaction(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockInstance)(nil).ValidateTransaction), arg0) +} + +// Validator mocks base method. +func (m *MockInstance) Validator() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validator") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Validator indicates an expected call of Validator. +func (mr *MockInstanceMockRecorder) Validator() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockInstance)(nil).Validator)) +} + +// Version mocks base method. +func (m *MockInstance) Version() (runtime.Version, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Version") + ret0, _ := ret[0].(runtime.Version) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Version indicates an expected call of Version. +func (mr *MockInstanceMockRecorder) Version() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockInstance)(nil).Version)) +} From a6b2652ba0d6f3e48beea35e2c9fae57348b1a74 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Mon, 12 Aug 2024 10:20:09 -0400 Subject: [PATCH 08/30] clean-up unused comments --- .../candidate_validation.go | 206 ++---------------- .../candidate_validation_test.go | 11 +- dot/parachain/pvf/host.go | 32 ++- dot/parachain/pvf/host_test.go | 21 -- dot/parachain/pvf/worker_pool.go | 20 +- 5 files changed, 57 insertions(+), 233 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 189610b11e..ecc4174c94 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -90,7 +90,6 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { logger.Debugf("received message %v", msg) switch msg := msg.(type) { case ValidateFromChainState: - fmt.Printf("ValidateFromChainState: %v", msg) cv.validateFromChainState(msg) case ValidateFromExhaustive: @@ -107,22 +106,15 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { go cv.pvfHost.Validate(validationTask) result := <-taskResult - fmt.Printf("Validation result: %v", result) - // TODO(ed): determine how to handle this error and result - - // WIP: This is the current implementation of the validation logic, it will be replaced by the PVF host - // when the validation logic is moved to the PVF host - //result, err := validateFromExhaustive(cv.ValidationHost, msg.PersistedValidationData, - // msg.ValidationCode, msg.CandidateReceipt, msg.PoV) - //if err != nil { - // logger.Errorf("failed to validate from exhaustive: %w", err) - // msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - // Err: err, - // } - //} else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, - //} + if result.InternalError != nil { + logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: result.InternalError, + } + } else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, + } } case PreCheck: @@ -216,180 +208,18 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState go cv.pvfHost.Validate(validationTask) result := <-taskResult - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, + if result.InternalError != nil { + logger.Errorf("failed to validate from chain state: %w", result.InternalError) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: result.InternalError, + } + } else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, + } } } -// todo confirm that all the functionality of these has been implemented in pvf host -// validateFromChainState validates a candidate parachain block with provided parameters using relay-chain -// state and using the parachain runtime. -//func validateFromChainState(runtimeInstance parachainruntime.RuntimeInstance, pov parachaintypes.PoV, -// candidateReceipt parachaintypes.CandidateReceipt) (*pvf.ValidationResult, error) { -// -// persistedValidationData, validationCode, err := getValidationData(runtimeInstance, -// candidateReceipt.Descriptor.ParaID) -// if err != nil { -// return nil, fmt.Errorf("getting validation data: %w", err) -// } -// -// parachainRuntimeInstance, err := parachainruntime.SetupVM(*validationCode) -// if err != nil { -// return nil, fmt.Errorf("setting up VM: %w", err) -// } -// -// taskResult := make(chan *pvf.ValidationTaskResult) -// validationTask := &pvf.ValidationTask{ -// PersistedValidationData: msg.PersistedValidationData, -// ValidationCode: &msg.ValidationCode, -// CandidateReceipt: &msg.CandidateReceipt, -// PoV: msg.PoV, -// ExecutorParams: nil, -// PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, -// ResultCh: taskResult, -// } -// go cv.pvfHost.Validate(validationTask) -// -// result := <-taskResult -// -// //validationResults, err := validateFromExhaustive -// //// check that the candidate does not exceed any parameters in the persisted validation data -// //pov := povRequestor.RequestPoV(candidateReceipt.Descriptor.PovHash) -// // -// //// basic checks -// // -// //// check if encoded size of pov is less than max pov size -// //buffer := bytes.NewBuffer(nil) -// //encoder := scale.NewEncoder(buffer) -// //err = encoder.Encode(pov) -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("encoding pov: %w", err) -// //} -// //encodedPoVSize := buffer.Len() -// //if encodedPoVSize > int(persistedValidationData.MaxPovSize) { -// // return nil, nil, false, fmt.Errorf("%w, limit: %d, got: %d", ErrValidationInputOverLimit, -// // persistedValidationData.MaxPovSize, encodedPoVSize) -// //} -// // -// //validationCodeHash, err := common.Blake2bHash([]byte(*validationCode)) -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("hashing validation code: %w", err) -// //} -// // -// //if validationCodeHash != common.Hash(candidateReceipt.Descriptor.ValidationCodeHash) { -// // return nil, nil, false, fmt.Errorf("%w, expected: %s, got %s", ErrValidationCodeMismatch, -// // candidateReceipt.Descriptor.ValidationCodeHash, validationCodeHash) -// //} -// // -// //// check candidate signature -// //err = candidateReceipt.Descriptor.CheckCollatorSignature() -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("verifying collator signature: %w", err) -// //} -// // -// //validationParams := parachainruntime.ValidationParameters{ -// // ParentHeadData: persistedValidationData.ParentHead, -// // BlockData: pov.BlockData, -// // RelayParentNumber: persistedValidationData.RelayParentNumber, -// // RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, -// //} -// // -// //parachainRuntimeInstance, err := parachainruntime.SetupVM(*validationCode) -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("setting up VM: %w", err) -// //} -// // -// //validationResults, err := parachainRuntimeInstance.ValidateBlock(validationParams) -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) -// //} -// // -// //candidateCommitments := parachaintypes.CandidateCommitments{ -// // UpwardMessages: validationResults.UpwardMessages, -// // HorizontalMessages: validationResults.HorizontalMessages, -// // NewValidationCode: validationResults.NewValidationCode, -// // HeadData: validationResults.HeadData, -// // ProcessedDownwardMessages: validationResults.ProcessedDownwardMessages, -// // HrmpWatermark: validationResults.HrmpWatermark, -// //} -// // -// //isValid, err := runtimeInstance.ParachainHostCheckValidationOutputs( -// // candidateReceipt.Descriptor.ParaID, candidateCommitments) -// //if err != nil { -// // return nil, nil, false, fmt.Errorf("executing validate_block: %w", err) -// //} -// // -// //return &candidateCommitments, persistedValidationData, isValid, nil -//} - -//// validateFromExhaustive validates a candidate parachain block with provided parameters -//func validateFromExhaustive(validationHost parachainruntime.ValidationHost, -// persistedValidationData parachaintypes.PersistedValidationData, -// validationCode parachaintypes.ValidationCode, -// candidateReceipt parachaintypes.CandidateReceipt, pov parachaintypes.PoV) ( -// *pvf.ValidationResult, error) { -// -// validationCodeHash := validationCode.Hash() -// // basic checks -// validationErr, internalErr := performBasicChecks(&candidateReceipt.Descriptor, persistedValidationData.MaxPovSize, -// pov, -// validationCodeHash) -// if internalErr != nil { -// return nil, fmt.Errorf("performing basic checks: %w", internalErr) -// } -// -// if validationErr != nil { -// validationResult := &pvf.ValidationResult{ -// InvalidResult: validationErr, -// } -// return validationResult, nil //nolint: nilerr -// } -// -// validationParams := parachainruntime.ValidationParameters{ -// ParentHeadData: persistedValidationData.ParentHead, -// BlockData: pov.BlockData, -// RelayParentNumber: persistedValidationData.RelayParentNumber, -// RelayParentStorageRoot: persistedValidationData.RelayParentStorageRoot, -// } -// -// validationResult, err := validationHost.ValidateBlock(validationParams) -// // TODO: implement functionality to parse errors generated by the runtime when PVF host is implemented, issue #3934 -// if err != nil { -// return nil, fmt.Errorf("executing validate_block: %w", err) -// } -// -// headDataHash, err := validationResult.HeadData.Hash() -// if err != nil { -// return nil, fmt.Errorf("hashing head data: %w", err) -// } -// -// if headDataHash != candidateReceipt.Descriptor.ParaHead { -// ci := pvf.ParaHeadHashMismatch -// return &pvf.ValidationResult{InvalidResult: &ci}, nil -// } -// candidateCommitments := parachaintypes.CandidateCommitments{ -// UpwardMessages: validationResult.UpwardMessages, -// HorizontalMessages: validationResult.HorizontalMessages, -// NewValidationCode: validationResult.NewValidationCode, -// HeadData: validationResult.HeadData, -// ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, -// HrmpWatermark: validationResult.HrmpWatermark, -// } -// -// // if validation produced a new set of commitments, we treat the candidate as invalid -// if candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { -// ci := pvf.CommitmentsHashMismatch -// return &pvf.ValidationResult{InvalidResult: &ci}, nil -// } -// return &pvf.ValidationResult{ -// ValidResult: &pvf.ValidValidationResult{ -// CandidateCommitments: candidateCommitments, -// PersistedValidationData: persistedValidationData, -// }, -// }, nil -// -//} - // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. // Returns ReasonForInvalidity and internal error if any. func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 8a70e978c2..0fd2a1ba05 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -581,8 +581,6 @@ func Test_performBasicChecks(t *testing.T) { } func TestCandidateValidation_validateFromChainState(t *testing.T) { - // todo figure out why this doesn't work with t.Parallel() - //t.Parallel() candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( @@ -696,7 +694,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { } toSubsystem := make(chan any) - sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) stopChan := make(chan struct{}) candidateValidationSubsystem := CandidateValidation{ OverseerToSubsystem: toSubsystem, @@ -717,7 +714,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt2, Pov: pov, - Ch: sender, }, want: &pvf.ValidationResult{ InvalidResult: &povHashMismatch, @@ -727,7 +723,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt3, Pov: pov, - Ch: sender, }, want: &pvf.ValidationResult{ InvalidResult: ¶msTooLarge, @@ -737,7 +732,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt4, Pov: pov, - Ch: sender, }, want: &pvf.ValidationResult{ InvalidResult: &codeHashMismatch, @@ -747,7 +741,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt5, Pov: pov, - Ch: sender, }, want: &pvf.ValidationResult{ InvalidResult: &badSignature, @@ -757,7 +750,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt, Pov: pov, - Ch: sender, }, want: &pvf.ValidationResult{ ValidResult: &pvf.ValidValidationResult{ @@ -787,6 +779,9 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { for name, tt := range tests { tt := tt t.Run(name, func(t *testing.T) { + sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) + defer close(sender) + tt.msg.Ch = sender time.Sleep(100 * time.Millisecond) toSubsystem <- tt.msg time.Sleep(100 * time.Millisecond) diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 4756945fbe..2acf7d7aa9 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -20,7 +20,6 @@ type ValidationHost struct { } func (v *ValidationHost) Start() { - fmt.Printf("v.wg %v\n", v) v.wg.Add(1) logger.Debug("Starting validation host") go func() { @@ -49,9 +48,15 @@ func (v *ValidationHost) Validate(msg *ValidationTask) { msg.PersistedValidationData.MaxPovSize, msg.PoV, validationCodeHash) - // TODO(ed): confirm how to handle internal errors + if internalErr != nil { logger.Errorf("performing basic checks: %w", internalErr) + intErr := &ValidationTaskResult{ + who: validationCodeHash, + InternalError: internalErr, + } + msg.ResultCh <- intErr + return } if validationErr != nil { @@ -65,7 +70,16 @@ func (v *ValidationHost) Validate(msg *ValidationTask) { return } - workerID := v.poolContainsWorker(msg) + workerID, err := v.poolContainsWorker(msg) + if err != nil { + logger.Errorf("pool contains worker: %w", err) + intErr := &ValidationTaskResult{ + who: validationCodeHash, + InternalError: err, + } + msg.ResultCh <- intErr + return + } validationParams := parachainruntime.ValidationParameters{ ParentHeadData: msg.PersistedValidationData.ParentHead, BlockData: msg.PoV.BlockData, @@ -78,15 +92,17 @@ func (v *ValidationHost) Validate(msg *ValidationTask) { candidateReceipt: msg.CandidateReceipt, ResultCh: msg.ResultCh, } - v.workerPool.submitRequest(workerID, workTask) + v.workerPool.submitRequest(*workerID, workTask) } -func (v *ValidationHost) poolContainsWorker(msg *ValidationTask) parachaintypes.ValidationCodeHash { +func (v *ValidationHost) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { if msg.WorkerID != nil { - return *msg.WorkerID + return msg.WorkerID, nil } - if v.workerPool.containsWorker(msg.ValidationCode.Hash()) { - return msg.ValidationCode.Hash() + validationCodeHash := msg.ValidationCode.Hash() + if v.workerPool.containsWorker(validationCodeHash) { + + return &validationCodeHash, nil } else { return v.workerPool.newValidationWorker(*msg.ValidationCode) } diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index bf30b255d9..9070a9a55b 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -1,10 +1,7 @@ package pvf import ( - "fmt" "testing" - - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) func Test_validationHost_start(t *testing.T) { @@ -29,21 +26,3 @@ func Test_validationHost_start(t *testing.T) { }) } } - -func TestValidationHost(t *testing.T) { - v := NewValidationHost() - v.Start() - v.workerPool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) - - resCh := make(chan *ValidationTaskResult) - - requestMsg := &ValidationTask{ - WorkerID: ¶chaintypes.ValidationCodeHash{1, 2, 3, 4}, - ResultCh: resCh, - } - - v.Validate(requestMsg) - - res := <-resCh - fmt.Printf("Validation result: %v", res) -} diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 46c4538ba2..85d0f3b528 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -31,8 +31,9 @@ type ValidationTask struct { } type ValidationTaskResult struct { - who parachaintypes.ValidationCodeHash - Result *ValidationResult + who parachaintypes.ValidationCodeHash + Result *ValidationResult + InternalError error } // ValidationResult represents the result coming from the candidate validation subsystem. @@ -160,21 +161,21 @@ func (v *validationWorkerPool) stop() error { } } -func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) parachaintypes. - ValidationCodeHash { +func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. + ValidationCodeHash, error) { workerQueue := make(chan *workerTask, maxRequestsAllowed) worker, err := newWorker(validationCode, workerQueue) if err != nil { - // TODO(ed): handle this error logger.Errorf("failed to create a new worker: %w", err) + return nil, err } v.wg.Add(1) go worker.run(workerQueue, &v.wg) v.workers[worker.workerID] = worker - return worker.workerID + return &worker.workerID, nil } // submitRequest given a request, the worker pool will get the peer given the peer.ID @@ -185,7 +186,6 @@ func (v *validationWorkerPool) submitRequest(workerID parachaintypes.ValidationC defer v.mtx.RUnlock() logger.Debugf("pool submit request workerID %x", workerID) - //if request.WorkerID != nil { syncWorker, inMap := v.workers[workerID] if inMap { if syncWorker == nil { @@ -195,8 +195,12 @@ func (v *validationWorkerPool) submitRequest(workerID parachaintypes.ValidationC syncWorker.queue <- request return } - // TODO(ed): handle this case + logger.Errorf("workerID %x not found in the pool", workerID) + request.ResultCh <- &ValidationTaskResult{ + who: workerID, + InternalError: fmt.Errorf("workerID %x not found in the pool", workerID), + } } func (v *validationWorkerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { From 0655dd3475e0bab17f076df7c390228ea36401fc Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 16 Aug 2024 16:24:34 -0400 Subject: [PATCH 09/30] address merge conflicts --- dot/parachain/backing/integration_test.go | 8 ++--- dot/parachain/pvf/worker_pool_test.go | 29 +++++++++++++-- dot/parachain/pvf/worker_test.go | 44 ----------------------- 3 files changed, 30 insertions(+), 51 deletions(-) delete mode 100644 dot/parachain/pvf/worker_test.go diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index 369ad7b9f7..3c871ab75b 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -526,9 +526,9 @@ func TestCandidateReachesQuorum(t *testing.T) { return false } - msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{ + msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: headData, UpwardMessages: []parachaintypes.UpwardMessage{}, @@ -744,7 +744,7 @@ func TestValidationFailDoesNotStopSubsystem(t *testing.T) { return false } - msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ Err: errors.New("some internal error"), } return true diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/pvf/worker_pool_test.go index 23f5becc2c..a692ae76ff 100644 --- a/dot/parachain/pvf/worker_pool_test.go +++ b/dot/parachain/pvf/worker_pool_test.go @@ -1,6 +1,7 @@ package pvf import ( + "os" "testing" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" @@ -8,20 +9,42 @@ import ( "golang.org/x/exp/maps" ) +func createTestValidationCode(t *testing.T) parachaintypes.ValidationCode { + // this wasm was achieved by building polkadot's adder test parachain + runtimeFilePath := "./testdata/test_parachain_adder.wasm" + validationCodeBytes, err := os.ReadFile(runtimeFilePath) + require.NoError(t, err) + + return parachaintypes.ValidationCode(validationCodeBytes) + +} + func TestValidationWorkerPool_newValidationWorker(t *testing.T) { t.Parallel() + testValidationCode := createTestValidationCode(t) + cases := map[string]struct { setupWorkerPool func(t *testing.T) *validationWorkerPool expectedWorkers []parachaintypes.ValidationCodeHash }{ - "add_one_worker": { + "add_one_invalid_worker": { + setupWorkerPool: func(t *testing.T) *validationWorkerPool { + pool := newValidationWorkerPool() + _, err := pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) + require.Error(t, err) + return pool + }, + expectedWorkers: []parachaintypes.ValidationCodeHash{}, + }, + "add_one_valid_worker": { setupWorkerPool: func(t *testing.T) *validationWorkerPool { pool := newValidationWorkerPool() - pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) + _, err := pool.newValidationWorker(testValidationCode) + require.NoError(t, err) return pool }, expectedWorkers: []parachaintypes.ValidationCodeHash{ - {1, 2, 3, 4}, + testValidationCode.Hash(), }, }, } diff --git a/dot/parachain/pvf/worker_test.go b/dot/parachain/pvf/worker_test.go deleted file mode 100644 index cbdd5a5680..0000000000 --- a/dot/parachain/pvf/worker_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package pvf - -import ( - "sync" - "testing" - "time" - - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "github.com/stretchr/testify/require" -) - -func TestWorker(t *testing.T) { - workerID1 := parachaintypes.ValidationCode{1, 2, 3, 4} - - workerQueue := make(chan *workerTask, maxRequestsAllowed) - w, err := newWorker(workerID1, workerQueue) - require.NoError(t, err) - - wg := sync.WaitGroup{} - queue := make(chan *workerTask, 2) - - wg.Add(1) - go w.run(queue, &wg) - - resultCh := make(chan *ValidationTaskResult) - defer close(resultCh) - - queue <- &workerTask{ - ResultCh: resultCh, - } - - queue <- &workerTask{ - ResultCh: resultCh, - } - - time.Sleep(500 * time.Millisecond) - <-resultCh - - time.Sleep(500 * time.Millisecond) - <-resultCh - - close(queue) - wg.Wait() -} From 01905af4298d6a62404d49f57664d810abc56ad2 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 21 Aug 2024 17:34:49 -0400 Subject: [PATCH 10/30] resolve merge conflicts --- .../candidate-validation/candidate_validation.go | 11 +++++++---- .../candidate-validation/candidate_validation_test.go | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 5283a087e7..df3a240b0f 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -7,6 +7,7 @@ import ( "context" "errors" "fmt" + "sync" "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" @@ -26,6 +27,8 @@ var ( // CandidateValidation is a parachain subsystem that validates candidate parachain blocks type CandidateValidation struct { + wg sync.WaitGroup + stopChan chan struct{} SubsystemToOverseer chan<- any OverseerToSubsystem <-chan any BlockState BlockState @@ -125,12 +128,12 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { default: logger.Errorf("%w: %T", parachaintypes.ErrUnknownOverseerMessage, msg) } - case <-cv.stopChan: - return + case <-cv.stopChan: + return } - } + } } - + // PoVRequestor gets proof of validity by issuing network requests to validators of the current backing group. // TODO: Implement PoV requestor, issue #3919 type PoVRequestor interface { diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index b1c6a81fbd..b550343e08 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -354,7 +354,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) defer candidateValidationSubsystem.Stop() ctx := context.Background() - go candidateValidationSubsystem.Run(ctx, overseerToSubsystem) + go candidateValidationSubsystem.Run(ctx, toSubsystem, nil) tests := map[string]struct { msg ValidateFromExhaustive @@ -461,7 +461,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) for name, tt := range tests { t.Run(name, func(t *testing.T) { time.Sleep(100 * time.Millisecond) - overseerToSubsystem <- tt.msg + toSubsystem <- tt.msg time.Sleep(100 * time.Millisecond) result := <-sender require.Equal(t, tt.want, result) From afde6fd4703f097ebc071f9e511ca627e34f4486 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 21 Aug 2024 17:58:30 -0400 Subject: [PATCH 11/30] refactor ValidationHost to Host, and validationWorkerPool to workerPool --- .../candidate_validation.go | 4 ++-- .../candidate_validation_test.go | 4 ++-- dot/parachain/pvf/host.go | 17 +++++++-------- dot/parachain/pvf/host_test.go | 4 ++-- dot/parachain/pvf/worker.go | 4 ++-- dot/parachain/pvf/worker_pool.go | 21 +++++++------------ dot/parachain/pvf/worker_pool_test.go | 6 +++--- go.mod | 1 + go.sum | 3 +++ 9 files changed, 31 insertions(+), 33 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index df3a240b0f..2ae102f73f 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -32,7 +32,7 @@ type CandidateValidation struct { SubsystemToOverseer chan<- any OverseerToSubsystem <-chan any BlockState BlockState - pvfHost *pvf.ValidationHost + pvfHost *pvf.Host } type BlockState interface { @@ -50,7 +50,7 @@ func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *Can } // Run starts the CandidateValidation subsystem -func (cv *CandidateValidation) Run(context.Context, chan any, chan any) { +func (cv *CandidateValidation) Run(context.Context, <-chan any) { cv.wg.Add(1) go cv.pvfHost.Start() go cv.processMessages(&cv.wg) diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index b550343e08..40ccc483b7 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -354,7 +354,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) defer candidateValidationSubsystem.Stop() ctx := context.Background() - go candidateValidationSubsystem.Run(ctx, toSubsystem, nil) + go candidateValidationSubsystem.Run(ctx, toSubsystem) tests := map[string]struct { msg ValidateFromExhaustive @@ -704,7 +704,7 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { } defer candidateValidationSubsystem.Stop() - candidateValidationSubsystem.Run(context.Background(), nil, nil) + candidateValidationSubsystem.Run(context.Background(), nil) tests := map[string]struct { msg ValidateFromChainState diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 2acf7d7aa9..5e9b3381c7 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -12,14 +12,14 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) -type ValidationHost struct { +type Host struct { wg sync.WaitGroup stopCh chan struct{} - workerPool *validationWorkerPool + workerPool *workerPool } -func (v *ValidationHost) Start() { +func (v *Host) Start() { v.wg.Add(1) logger.Debug("Starting validation host") go func() { @@ -27,19 +27,19 @@ func (v *ValidationHost) Start() { }() } -func (v *ValidationHost) Stop() { +func (v *Host) Stop() { close(v.stopCh) v.wg.Wait() } -func NewValidationHost() *ValidationHost { - return &ValidationHost{ +func NewValidationHost() *Host { + return &Host{ stopCh: make(chan struct{}), workerPool: newValidationWorkerPool(), } } -func (v *ValidationHost) Validate(msg *ValidationTask) { +func (v *Host) Validate(msg *ValidationTask) { logger.Debugf("Validating worker %x", msg.WorkerID) validationCodeHash := msg.ValidationCode.Hash() @@ -95,13 +95,12 @@ func (v *ValidationHost) Validate(msg *ValidationTask) { v.workerPool.submitRequest(*workerID, workTask) } -func (v *ValidationHost) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { +func (v *Host) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { if msg.WorkerID != nil { return msg.WorkerID, nil } validationCodeHash := msg.ValidationCode.Hash() if v.workerPool.containsWorker(validationCodeHash) { - return &validationCodeHash, nil } else { return v.workerPool.newValidationWorker(*msg.ValidationCode) diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index 9070a9a55b..fd27f9322a 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -6,7 +6,7 @@ import ( func Test_validationHost_start(t *testing.T) { type fields struct { - workerPool *validationWorkerPool + workerPool *workerPool } tests := map[string]struct { name string @@ -19,7 +19,7 @@ func Test_validationHost_start(t *testing.T) { for tname, tt := range tests { tt := tt t.Run(tname, func(t *testing.T) { - v := &ValidationHost{ + v := &Host{ workerPool: tt.fields.workerPool, } v.Start() diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index 5db740cbdf..3ace8af006 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -33,13 +33,13 @@ func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerT }, nil } -func (w *worker) run(queue chan *workerTask, wg *sync.WaitGroup) { +func (w *worker) run(wg *sync.WaitGroup) { defer func() { logger.Debugf("[STOPPED] worker %x", w.workerID) wg.Done() }() - for task := range queue { + for task := range w.queue { w.executeRequest(task) } } diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 85d0f3b528..9b98ba7ef2 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -12,7 +12,7 @@ const ( maxRequestsAllowed uint = 60 ) -type validationWorkerPool struct { +type workerPool struct { mtx sync.RWMutex wg sync.WaitGroup @@ -122,19 +122,14 @@ func (ci ReasonForInvalidity) Error() string { } } -//type validationWorker struct { -// worker *worker -// queue chan *workerTask -//} - -func newValidationWorkerPool() *validationWorkerPool { - return &validationWorkerPool{ +func newValidationWorkerPool() *workerPool { + return &workerPool{ workers: make(map[parachaintypes.ValidationCodeHash]*worker), } } // stop will shutdown all the available workers goroutines -func (v *validationWorkerPool) stop() error { +func (v *workerPool) stop() error { v.mtx.RLock() defer v.mtx.RUnlock() @@ -161,7 +156,7 @@ func (v *validationWorkerPool) stop() error { } } -func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. +func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. ValidationCodeHash, error) { workerQueue := make(chan *workerTask, maxRequestsAllowed) @@ -171,7 +166,7 @@ func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes return nil, err } v.wg.Add(1) - go worker.run(workerQueue, &v.wg) + go worker.run(&v.wg) v.workers[worker.workerID] = worker @@ -181,7 +176,7 @@ func (v *validationWorkerPool) newValidationWorker(validationCode parachaintypes // submitRequest given a request, the worker pool will get the peer given the peer.ID // parameter or if nil the very first available worker or // to perform the request, the response will be dispatch in the resultCh. -func (v *validationWorkerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, request *workerTask) { +func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, request *workerTask) { v.mtx.RLock() defer v.mtx.RUnlock() logger.Debugf("pool submit request workerID %x", workerID) @@ -203,7 +198,7 @@ func (v *validationWorkerPool) submitRequest(workerID parachaintypes.ValidationC } } -func (v *validationWorkerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { +func (v *workerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { v.mtx.RLock() defer v.mtx.RUnlock() diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/pvf/worker_pool_test.go index a692ae76ff..c81621145f 100644 --- a/dot/parachain/pvf/worker_pool_test.go +++ b/dot/parachain/pvf/worker_pool_test.go @@ -24,11 +24,11 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { testValidationCode := createTestValidationCode(t) cases := map[string]struct { - setupWorkerPool func(t *testing.T) *validationWorkerPool + setupWorkerPool func(t *testing.T) *workerPool expectedWorkers []parachaintypes.ValidationCodeHash }{ "add_one_invalid_worker": { - setupWorkerPool: func(t *testing.T) *validationWorkerPool { + setupWorkerPool: func(t *testing.T) *workerPool { pool := newValidationWorkerPool() _, err := pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) require.Error(t, err) @@ -37,7 +37,7 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { expectedWorkers: []parachaintypes.ValidationCodeHash{}, }, "add_one_valid_worker": { - setupWorkerPool: func(t *testing.T) *validationWorkerPool { + setupWorkerPool: func(t *testing.T) *workerPool { pool := newValidationWorkerPool() _, err := pool.newValidationWorker(testValidationCode) require.NoError(t, err) diff --git a/go.mod b/go.mod index d9d9ebbf39..f585b2c749 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/fatih/color v1.17.0 github.com/gammazero/deque v0.2.1 github.com/go-playground/validator/v10 v10.21.0 + github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 diff --git a/go.sum b/go.sum index 03ec8f0ac3..990d74d772 100644 --- a/go.sum +++ b/go.sum @@ -206,6 +206,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -797,6 +799,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= From dbf3cf8d0ded2b22672dbcac4497702fa51d1523 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 28 Aug 2024 15:59:17 -0400 Subject: [PATCH 12/30] refactor go concurrancy --- dot/parachain/backing/integration_test.go | 73 +------ .../candidate_validation.go | 37 ++-- .../candidate_validation_test.go | 4 +- dot/parachain/pvf/host.go | 122 ++++++------ dot/parachain/pvf/host_test.go | 2 +- dot/parachain/pvf/worker.go | 181 +++++++++--------- dot/parachain/pvf/worker_pool.go | 55 +----- dot/parachain/pvf/worker_pool_test.go | 1 - 8 files changed, 185 insertions(+), 290 deletions(-) diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index f6bccca4a9..b970173ade 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -226,9 +226,9 @@ func validResponseForValidateFromExhaustive( return false } - msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ - Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{ + msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: pvf.ValidationResult{ + ValidResult: &pvf.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: headData, UpwardMessages: []parachaintypes.UpwardMessage{}, @@ -393,38 +393,7 @@ func TestSecondsValidCandidate(t *testing.T) { mockRuntime.EXPECT().ParachainHostValidationCodeByHash(gomock.AssignableToTypeOf(common.Hash{})). Return(&validationCode2, nil) - validate2 := func(msg any) bool { - validateFromExhaustive, ok := msg.(candidatevalidation.ValidateFromExhaustive) - if !ok { - return false - } - - validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ - CandidateCommitments: parachaintypes.CandidateCommitments{ - UpwardMessages: []parachaintypes.UpwardMessage{}, - HorizontalMessages: []parachaintypes.OutboundHrmpMessage{}, - NewValidationCode: nil, - HeadData: candidate2.Commitments.HeadData, - ProcessedDownwardMessages: 0, - HrmpWatermark: 0, - }, - PersistedValidationData: pvd2, - }, - }, - } - return true - } - - storeAvailableData := func(msg any) bool { - store, ok := msg.(availabilitystore.StoreAvailableData) - if !ok { - return false - } - store.Sender <- nil - return true - } + validate2 := validResponseForValidateFromExhaustive(candidate2.Commitments.HeadData, pvd2) distribute := func(msg any) bool { // we have seconded a candidate and shared the statement to peers @@ -568,39 +537,7 @@ func TestCandidateReachesQuorum(t *testing.T) { return true } - validate1 := func(msg any) bool { - msgValidate, ok := msg.(candidatevalidation.ValidateFromExhaustive) - if !ok { - return false - } - - msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ - CandidateCommitments: parachaintypes.CandidateCommitments{ - HeadData: headData, - UpwardMessages: []parachaintypes.UpwardMessage{}, - HorizontalMessages: []parachaintypes.OutboundHrmpMessage{}, - NewValidationCode: nil, - ProcessedDownwardMessages: 0, - HrmpWatermark: 0, - }, - PersistedValidationData: pvd, - }, - }, - } - return true - } - - storeData := func(msg any) bool { - store, ok := msg.(availabilitystore.StoreAvailableData) - if !ok { - return false - } - - store.Sender <- nil - return true - } + validate := validResponseForValidateFromExhaustive(headData, pvd) distribute := func(msg any) bool { _, ok := msg.(parachaintypes.StatementDistributionMessageShare) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 2ae102f73f..94a385f4f2 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -52,7 +52,6 @@ func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *Can // Run starts the CandidateValidation subsystem func (cv *CandidateValidation) Run(context.Context, <-chan any) { cv.wg.Add(1) - go cv.pvfHost.Start() go cv.processMessages(&cv.wg) } @@ -75,7 +74,6 @@ func (*CandidateValidation) ProcessBlockFinalizedSignal(parachaintypes.BlockFina // Stop stops the CandidateValidation subsystem func (cv *CandidateValidation) Stop() { - cv.pvfHost.Stop() close(cv.stopChan) cv.wg.Wait() } @@ -92,7 +90,6 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { cv.validateFromChainState(msg) case ValidateFromExhaustive: - taskResult := make(chan *pvf.ValidationTaskResult) validationTask := &pvf.ValidationTask{ PersistedValidationData: msg.PersistedValidationData, ValidationCode: &msg.ValidationCode, @@ -100,22 +97,24 @@ func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { PoV: msg.PoV, ExecutorParams: msg.ExecutorParams, PvfExecTimeoutKind: msg.PvfExecTimeoutKind, - ResultCh: taskResult, } - go cv.pvfHost.Validate(validationTask) - result := <-taskResult - if result.InternalError != nil { - logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: result.InternalError, - } - } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, - } - } + taskResultChan := cv.pvfHost.Validate(validationTask) + go func() { + + result := <-taskResultChan + if result.InternalError != nil { + logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: result.InternalError, + } + } else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, + } + } + }() case PreCheck: // TODO: implement functionality to handle PreCheck, see issue #3921 @@ -193,7 +192,6 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState return } - taskResult := make(chan *pvf.ValidationTaskResult) validationTask := &pvf.ValidationTask{ PersistedValidationData: *persistedValidationData, ValidationCode: validationCode, @@ -201,11 +199,10 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState PoV: msg.Pov, ExecutorParams: msg.ExecutorParams, PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, - ResultCh: taskResult, } - go cv.pvfHost.Validate(validationTask) - result := <-taskResult + taskResultChan := cv.pvfHost.Validate(validationTask) + result := <-taskResultChan if result.InternalError != nil { logger.Errorf("failed to validate from chain state: %w", result.InternalError) msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 40ccc483b7..a87e933f7a 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -113,8 +113,6 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { executionError := pvf.ExecutionError pvfHost := pvf.NewValidationHost() - pvfHost.Start() - defer pvfHost.Stop() ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) @@ -293,7 +291,7 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { taskResult := make(chan *pvf.ValidationTaskResult) defer close(taskResult) - tt.validationTask.ResultCh = taskResult + //tt.validationTask.ResultCh = taskResult go pvfHost.Validate(tt.validationTask) diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index 5e9b3381c7..af54c033f2 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -2,7 +2,6 @@ package pvf import ( "fmt" - "sync" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" @@ -13,24 +12,23 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) type Host struct { - wg sync.WaitGroup stopCh chan struct{} workerPool *workerPool } -func (v *Host) Start() { - v.wg.Add(1) - logger.Debug("Starting validation host") - go func() { - defer v.wg.Done() - }() -} +//func (v *Host) Start() { +// v.wg.Add(1) +// logger.Debug("Starting validation host") +// go func() { +// defer v.wg.Done() +// }() +//} -func (v *Host) Stop() { - close(v.stopCh) - v.wg.Wait() -} +//func (v *Host) Stop() { +// close(v.stopCh) +// v.wg.Wait() +//} func NewValidationHost() *Host { return &Host{ @@ -39,60 +37,58 @@ func NewValidationHost() *Host { } } -func (v *Host) Validate(msg *ValidationTask) { - logger.Debugf("Validating worker %x", msg.WorkerID) - - validationCodeHash := msg.ValidationCode.Hash() - // basic checks - validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, - msg.PersistedValidationData.MaxPovSize, - msg.PoV, - validationCodeHash) - - if internalErr != nil { - logger.Errorf("performing basic checks: %w", internalErr) - intErr := &ValidationTaskResult{ - who: validationCodeHash, - InternalError: internalErr, +func (v *Host) Validate(msg *ValidationTask) <-chan *ValidationTaskResult { + resultCh := make(chan *ValidationTaskResult) + go func() { + defer close(resultCh) + logger.Debugf("Start Validating worker %x", msg.WorkerID) + validationCodeHash := msg.ValidationCode.Hash() + // performBasicChecks + validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, + msg.PersistedValidationData.MaxPovSize, + msg.PoV, + validationCodeHash) + + if internalErr != nil { + resultCh <- &ValidationTaskResult{ + who: validationCodeHash, + InternalError: internalErr, + } } - msg.ResultCh <- intErr - return - } - - if validationErr != nil { - valErr := &ValidationTaskResult{ - who: validationCodeHash, - Result: &ValidationResult{ - InvalidResult: validationErr, - }, + if validationErr != nil { + resultCh <- &ValidationTaskResult{ + who: validationCodeHash, + Result: &ValidationResult{InvalidResult: validationErr}, + } + } + // check if worker is in pool + workerID, err := v.poolContainsWorker(msg) + if err != nil { + resultCh <- &ValidationTaskResult{ + who: validationCodeHash, + InternalError: err, + } } - msg.ResultCh <- valErr - return - } - workerID, err := v.poolContainsWorker(msg) - if err != nil { - logger.Errorf("pool contains worker: %w", err) - intErr := &ValidationTaskResult{ - who: validationCodeHash, - InternalError: err, + // submit request + validationParams := parachainruntime.ValidationParameters{ + ParentHeadData: msg.PersistedValidationData.ParentHead, + BlockData: msg.PoV.BlockData, + RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, + RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, } - msg.ResultCh <- intErr - return - } - validationParams := parachainruntime.ValidationParameters{ - ParentHeadData: msg.PersistedValidationData.ParentHead, - BlockData: msg.PoV.BlockData, - RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, - RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, - } - workTask := &workerTask{ - work: validationParams, - maxPoVSize: msg.PersistedValidationData.MaxPovSize, - candidateReceipt: msg.CandidateReceipt, - ResultCh: msg.ResultCh, - } - v.workerPool.submitRequest(*workerID, workTask) + workTask := &workerTask{ + work: validationParams, + maxPoVSize: msg.PersistedValidationData.MaxPovSize, + candidateReceipt: msg.CandidateReceipt, + } + logger.Debugf("Working Validating worker %x", workerID) + resultWorkCh := v.workerPool.submitRequest(*workerID, workTask) + + result := <-resultWorkCh + resultCh <- result + }() + return resultCh } func (v *Host) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go index fd27f9322a..7366e969ce 100644 --- a/dot/parachain/pvf/host_test.go +++ b/dot/parachain/pvf/host_test.go @@ -22,7 +22,7 @@ func Test_validationHost_start(t *testing.T) { v := &Host{ workerPool: tt.fields.workerPool, } - v.Start() + v.Validate(&ValidationTask{}) }) } } diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index 3ace8af006..50993b0f01 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -1,23 +1,24 @@ package pvf import ( - "sync" - parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) +// TODO(ed): figure out a better name for this that describes what it does type worker struct { workerID parachaintypes.ValidationCodeHash instance *parachainruntime.Instance - queue chan *workerTask + // TODO(ed): determine if wasProcessed is stored here or in host + isProcessed map[parachaintypes.CandidateHash]struct{} + // TODO make this a buffered channel, and determine the buffer size + workerTasksChan chan *workerTask } type workerTask struct { work parachainruntime.ValidationParameters maxPoVSize uint32 candidateReceipt *parachaintypes.CandidateReceipt - ResultCh chan<- *ValidationTaskResult } func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerTask) (*worker, error) { @@ -27,104 +28,110 @@ func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerT return nil, err } return &worker{ - workerID: validationCode.Hash(), - instance: validationRuntime, - queue: queue, + workerID: validationCode.Hash(), + instance: validationRuntime, + workerTasksChan: queue, }, nil } -func (w *worker) run(wg *sync.WaitGroup) { - defer func() { - logger.Debugf("[STOPPED] worker %x", w.workerID) - wg.Done() - }() - - for task := range w.queue { - w.executeRequest(task) - } -} - -func (w *worker) executeRequest(task *workerTask) { +func (w *worker) executeRequest(task *workerTask) chan *ValidationTaskResult { logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) + resultCh := make(chan *ValidationTaskResult) + + go func() { + defer close(resultCh) + candidateHash, err := parachaintypes.GetCandidateHash(task.candidateReceipt) + if err != nil { + // TODO: handle error + logger.Errorf("getting candidate hash: %w", err) + } - validationResult, err := w.instance.ValidateBlock(task.work) - - if err != nil { - logger.Errorf("executing validate_block: %w", err) - reasonForInvalidity := ExecutionError - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, + // do isProcessed check here + if _, ok := w.isProcessed[candidateHash]; ok { + // TODO: determine what the isPreccessed check should return, and if re-trying is allowed + // get a better understanding of what the isProcessed check should be checking for + logger.Debugf("candidate %x already processed", candidateHash) } - task.ResultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, + validationResult, err := w.instance.ValidateBlock(task.work) + + if err != nil { + logger.Errorf("executing validate_block: %w", err) + reasonForInvalidity := ExecutionError + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + resultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return } - return - } - headDataHash, err := validationResult.HeadData.Hash() - if err != nil { - logger.Errorf("hashing head data: %w", err) - reasonForInvalidity := ExecutionError - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, - } - task.ResultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, + headDataHash, err := validationResult.HeadData.Hash() + if err != nil { + logger.Errorf("hashing head data: %w", err) + reasonForInvalidity := ExecutionError + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + resultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return } - return - } - if headDataHash != task.candidateReceipt.Descriptor.ParaHead { - reasonForInvalidity := ParaHeadHashMismatch - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, + if headDataHash != task.candidateReceipt.Descriptor.ParaHead { + reasonForInvalidity := ParaHeadHashMismatch + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + resultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return } - task.ResultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, + candidateCommitments := parachaintypes.CandidateCommitments{ + UpwardMessages: validationResult.UpwardMessages, + HorizontalMessages: validationResult.HorizontalMessages, + NewValidationCode: validationResult.NewValidationCode, + HeadData: validationResult.HeadData, + ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, + HrmpWatermark: validationResult.HrmpWatermark, } - return - } - candidateCommitments := parachaintypes.CandidateCommitments{ - UpwardMessages: validationResult.UpwardMessages, - HorizontalMessages: validationResult.HorizontalMessages, - NewValidationCode: validationResult.NewValidationCode, - HeadData: validationResult.HeadData, - ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, - HrmpWatermark: validationResult.HrmpWatermark, - } - // if validation produced a new set of commitments, we treat the candidate as invalid - if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { - reasonForInvalidity := CommitmentsHashMismatch - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, + // if validation produced a new set of commitments, we treat the candidate as invalid + if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { + reasonForInvalidity := CommitmentsHashMismatch + errorResult := &ValidationResult{ + InvalidResult: &reasonForInvalidity, + } + resultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: errorResult, + } + return } - task.ResultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, + pvd := parachaintypes.PersistedValidationData{ + ParentHead: task.work.ParentHeadData, + RelayParentNumber: task.work.RelayParentNumber, + RelayParentStorageRoot: task.work.RelayParentStorageRoot, + MaxPovSize: task.maxPoVSize, + } + validResult := &ValidationResult{ + ValidResult: &ValidValidationResult{ + CandidateCommitments: candidateCommitments, + PersistedValidationData: pvd, + }, } - return - } - pvd := parachaintypes.PersistedValidationData{ - ParentHead: task.work.ParentHeadData, - RelayParentNumber: task.work.RelayParentNumber, - RelayParentStorageRoot: task.work.RelayParentStorageRoot, - MaxPovSize: task.maxPoVSize, - } - validResult := &ValidationResult{ - ValidResult: &ValidValidationResult{ - CandidateCommitments: candidateCommitments, - PersistedValidationData: pvd, - }, - } - logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, validResult, err) + logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, validResult, err) - task.ResultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: validResult, - } + resultCh <- &ValidationTaskResult{ + who: w.workerID, + Result: validResult, + } + }() + return resultCh } diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 9b98ba7ef2..0e089dcaad 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -3,7 +3,6 @@ package pvf import ( "fmt" "sync" - "time" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) @@ -14,8 +13,8 @@ const ( type workerPool struct { mtx sync.RWMutex - wg sync.WaitGroup + // todo, make sure other functions work with paraID workers map[parachaintypes.ValidationCodeHash]*worker } @@ -27,7 +26,6 @@ type ValidationTask struct { ExecutorParams parachaintypes.ExecutorParams PvfExecTimeoutKind parachaintypes.PvfExecTimeoutKind ValidationCode *parachaintypes.ValidationCode - ResultCh chan<- *ValidationTaskResult } type ValidationTaskResult struct { @@ -128,55 +126,24 @@ func newValidationWorkerPool() *workerPool { } } -// stop will shutdown all the available workers goroutines -func (v *workerPool) stop() error { - v.mtx.RLock() - defer v.mtx.RUnlock() - - for _, sw := range v.workers { - close(sw.queue) - } - - allWorkersDoneCh := make(chan struct{}) - go func() { - defer close(allWorkersDoneCh) - v.wg.Wait() - }() - - timeoutTimer := time.NewTimer(30 * time.Second) - select { - case <-timeoutTimer.C: - return fmt.Errorf("timeout reached while finishing workers") - case <-allWorkersDoneCh: - if !timeoutTimer.Stop() { - <-timeoutTimer.C - } - - return nil - } -} - func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. ValidationCodeHash, error) { workerQueue := make(chan *workerTask, maxRequestsAllowed) worker, err := newWorker(validationCode, workerQueue) if err != nil { - logger.Errorf("failed to create a new worker: %w", err) - return nil, err + return nil, fmt.Errorf("failed to create a new worker: %w", err) } - v.wg.Add(1) - go worker.run(&v.wg) v.workers[worker.workerID] = worker return &worker.workerID, nil } -// submitRequest given a request, the worker pool will get the peer given the peer.ID -// parameter or if nil the very first available worker or -// to perform the request, the response will be dispatch in the resultCh. -func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, request *workerTask) { +// submitRequest given a request, the worker pool will get the worker for a given workerID +// a channel in returned that the response will be dispatch on +func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, + request *workerTask) chan *ValidationTaskResult { v.mtx.RLock() defer v.mtx.RUnlock() logger.Debugf("pool submit request workerID %x", workerID) @@ -187,15 +154,9 @@ func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, r panic("sync worker should not be nil") } logger.Debugf("sending request", workerID) - syncWorker.queue <- request - return - } - - logger.Errorf("workerID %x not found in the pool", workerID) - request.ResultCh <- &ValidationTaskResult{ - who: workerID, - InternalError: fmt.Errorf("workerID %x not found in the pool", workerID), + return syncWorker.executeRequest(request) } + return nil } func (v *workerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/pvf/worker_pool_test.go index c81621145f..e29fdb9d5f 100644 --- a/dot/parachain/pvf/worker_pool_test.go +++ b/dot/parachain/pvf/worker_pool_test.go @@ -55,7 +55,6 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { t.Parallel() workerPool := tt.setupWorkerPool(t) - defer workerPool.stop() require.ElementsMatch(t, maps.Keys(workerPool.workers), From 79ba043aa1f0ee8ed9ad8e880aa49c97b7872ad3 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 29 Aug 2024 10:46:49 -0400 Subject: [PATCH 13/30] revert run to match interface --- .../candidate_validation.go | 107 +++++++++--------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 94a385f4f2..f864ed9191 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -50,9 +50,19 @@ func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *Can } // Run starts the CandidateValidation subsystem -func (cv *CandidateValidation) Run(context.Context, <-chan any) { - cv.wg.Add(1) - go cv.processMessages(&cv.wg) +func (cv *CandidateValidation) Run(ctx context.Context, overseerToSubsystem <-chan any) { + for { + select { + case msg := <-overseerToSubsystem: + logger.Debugf("received message %v", msg) + cv.processMessage(msg) + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + logger.Errorf("ctx error: %s\n", err) + } + return + } + } } // Name returns the name of the subsystem @@ -74,62 +84,49 @@ func (*CandidateValidation) ProcessBlockFinalizedSignal(parachaintypes.BlockFina // Stop stops the CandidateValidation subsystem func (cv *CandidateValidation) Stop() { - close(cv.stopChan) - cv.wg.Wait() } -// processMessages processes messages sent to the CandidateValidation subsystem -func (cv *CandidateValidation) processMessages(wg *sync.WaitGroup) { - defer wg.Done() - for { - select { - case msg := <-cv.OverseerToSubsystem: - logger.Debugf("received message %v", msg) - switch msg := msg.(type) { - case ValidateFromChainState: - cv.validateFromChainState(msg) - - case ValidateFromExhaustive: - validationTask := &pvf.ValidationTask{ - PersistedValidationData: msg.PersistedValidationData, - ValidationCode: &msg.ValidationCode, - CandidateReceipt: &msg.CandidateReceipt, - PoV: msg.PoV, - ExecutorParams: msg.ExecutorParams, - PvfExecTimeoutKind: msg.PvfExecTimeoutKind, - } +func (cv *CandidateValidation) processMessage(msg any) { + switch msg := msg.(type) { + case ValidateFromChainState: + cv.validateFromChainState(msg) + case ValidateFromExhaustive: + validationTask := &pvf.ValidationTask{ + PersistedValidationData: msg.PersistedValidationData, + ValidationCode: &msg.ValidationCode, + CandidateReceipt: &msg.CandidateReceipt, + PoV: msg.PoV, + ExecutorParams: msg.ExecutorParams, + PvfExecTimeoutKind: msg.PvfExecTimeoutKind, + } + + taskResultChan := cv.pvfHost.Validate(validationTask) + + go func() { - taskResultChan := cv.pvfHost.Validate(validationTask) - - go func() { - - result := <-taskResultChan - if result.InternalError != nil { - logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: result.InternalError, - } - } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, - } - } - }() - case PreCheck: - // TODO: implement functionality to handle PreCheck, see issue #3921 - - case parachaintypes.ActiveLeavesUpdateSignal: - _ = cv.ProcessActiveLeavesUpdateSignal(msg) - - case parachaintypes.BlockFinalizedSignal: - _ = cv.ProcessBlockFinalizedSignal(msg) - - default: - logger.Errorf("%w: %T", parachaintypes.ErrUnknownOverseerMessage, msg) + result := <-taskResultChan + if result.InternalError != nil { + logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: result.InternalError, + } + } else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result.Result, + } } - case <-cv.stopChan: - return - } + }() + case PreCheck: + panic("TODO: implement functionality to handle PreCheck, see issue #3921") + + case parachaintypes.ActiveLeavesUpdateSignal: + _ = cv.ProcessActiveLeavesUpdateSignal(msg) + + case parachaintypes.BlockFinalizedSignal: + _ = cv.ProcessBlockFinalizedSignal(msg) + + default: + logger.Errorf("%w: %T", parachaintypes.ErrUnknownOverseerMessage, msg) } } From ce721e731e7f646f2d6f52b1836d3b41d29cc2ed Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 29 Aug 2024 12:03:47 -0400 Subject: [PATCH 14/30] remove redundant structs for simplicty, removed go routines to simplify code --- .../candidate_validation.go | 40 ++--- .../candidate_validation_test.go | 32 ++-- dot/parachain/pvf/host.go | 105 +++++------- dot/parachain/pvf/worker.go | 154 +++++++----------- dot/parachain/pvf/worker_pool.go | 24 +-- 5 files changed, 122 insertions(+), 233 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index f864ed9191..abb96453ae 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "sync" "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" @@ -27,10 +26,7 @@ var ( // CandidateValidation is a parachain subsystem that validates candidate parachain blocks type CandidateValidation struct { - wg sync.WaitGroup - stopChan chan struct{} SubsystemToOverseer chan<- any - OverseerToSubsystem <-chan any BlockState BlockState pvfHost *pvf.Host } @@ -100,22 +96,19 @@ func (cv *CandidateValidation) processMessage(msg any) { PvfExecTimeoutKind: msg.PvfExecTimeoutKind, } - taskResultChan := cv.pvfHost.Validate(validationTask) + result, err := cv.pvfHost.Validate(validationTask) - go func() { - - result := <-taskResultChan - if result.InternalError != nil { - logger.Errorf("failed to validate from exhaustive: %w", result.InternalError) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: result.InternalError, - } - } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, - } + if err != nil { + logger.Errorf("failed to validate from exhaustive: %w", err) + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Err: err, } - }() + } else { + msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + Data: *result, + } + } + case PreCheck: panic("TODO: implement functionality to handle PreCheck, see issue #3921") @@ -198,16 +191,15 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, } - taskResultChan := cv.pvfHost.Validate(validationTask) - result := <-taskResultChan - if result.InternalError != nil { - logger.Errorf("failed to validate from chain state: %w", result.InternalError) + result, err := cv.pvfHost.Validate(validationTask) + if err != nil { + logger.Errorf("failed to validate from chain state: %w", err) msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: result.InternalError, + Err: err, } } else { msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: *result.Result, + Data: *result, } } } diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index a87e933f7a..43111998c5 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -289,15 +289,11 @@ func TestCandidateValidation_validateFromExhaustive(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - taskResult := make(chan *pvf.ValidationTaskResult) - defer close(taskResult) - //tt.validationTask.ResultCh = taskResult + taskResult, err := pvfHost.Validate(tt.validationTask) - go pvfHost.Validate(tt.validationTask) - - result := <-taskResult - require.Equal(t, tt.want, result.Result) - require.Equal(t, tt.isValid, result.Result.IsValid()) + require.NoError(t, err) + require.Equal(t, tt.want, taskResult) + require.Equal(t, tt.isValid, taskResult.IsValid()) }) } } @@ -341,18 +337,15 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }) require.NoError(t, err) - toSubsystem := make(chan any) + overseerToSubsystem := make(chan any) sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) - stopChan := make(chan struct{}) candidateValidationSubsystem := CandidateValidation{ - OverseerToSubsystem: toSubsystem, - stopChan: stopChan, - pvfHost: pvf.NewValidationHost(), + pvfHost: pvf.NewValidationHost(), } defer candidateValidationSubsystem.Stop() ctx := context.Background() - go candidateValidationSubsystem.Run(ctx, toSubsystem) + go candidateValidationSubsystem.Run(ctx, overseerToSubsystem) tests := map[string]struct { msg ValidateFromExhaustive @@ -459,7 +452,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) for name, tt := range tests { t.Run(name, func(t *testing.T) { time.Sleep(100 * time.Millisecond) - toSubsystem <- tt.msg + overseerToSubsystem <- tt.msg time.Sleep(100 * time.Millisecond) result := <-sender require.Equal(t, tt.want, result) @@ -693,16 +686,13 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { } toSubsystem := make(chan any) - stopChan := make(chan struct{}) candidateValidationSubsystem := CandidateValidation{ - OverseerToSubsystem: toSubsystem, - stopChan: stopChan, - pvfHost: pvf.NewValidationHost(), - BlockState: mockBlockState, + pvfHost: pvf.NewValidationHost(), + BlockState: mockBlockState, } defer candidateValidationSubsystem.Stop() - candidateValidationSubsystem.Run(context.Background(), nil) + go candidateValidationSubsystem.Run(context.Background(), toSubsystem) tests := map[string]struct { msg ValidateFromChainState diff --git a/dot/parachain/pvf/host.go b/dot/parachain/pvf/host.go index af54c033f2..fc3b8e5c75 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/pvf/host.go @@ -12,83 +12,52 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) type Host struct { - stopCh chan struct{} - workerPool *workerPool } -//func (v *Host) Start() { -// v.wg.Add(1) -// logger.Debug("Starting validation host") -// go func() { -// defer v.wg.Done() -// }() -//} - -//func (v *Host) Stop() { -// close(v.stopCh) -// v.wg.Wait() -//} - func NewValidationHost() *Host { return &Host{ - stopCh: make(chan struct{}), workerPool: newValidationWorkerPool(), } } -func (v *Host) Validate(msg *ValidationTask) <-chan *ValidationTaskResult { - resultCh := make(chan *ValidationTaskResult) - go func() { - defer close(resultCh) - logger.Debugf("Start Validating worker %x", msg.WorkerID) - validationCodeHash := msg.ValidationCode.Hash() - // performBasicChecks - validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, - msg.PersistedValidationData.MaxPovSize, - msg.PoV, - validationCodeHash) - - if internalErr != nil { - resultCh <- &ValidationTaskResult{ - who: validationCodeHash, - InternalError: internalErr, - } - } - if validationErr != nil { - resultCh <- &ValidationTaskResult{ - who: validationCodeHash, - Result: &ValidationResult{InvalidResult: validationErr}, - } - } - // check if worker is in pool - workerID, err := v.poolContainsWorker(msg) - if err != nil { - resultCh <- &ValidationTaskResult{ - who: validationCodeHash, - InternalError: err, - } - } - - // submit request - validationParams := parachainruntime.ValidationParameters{ - ParentHeadData: msg.PersistedValidationData.ParentHead, - BlockData: msg.PoV.BlockData, - RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, - RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, - } - workTask := &workerTask{ - work: validationParams, - maxPoVSize: msg.PersistedValidationData.MaxPovSize, - candidateReceipt: msg.CandidateReceipt, - } - logger.Debugf("Working Validating worker %x", workerID) - resultWorkCh := v.workerPool.submitRequest(*workerID, workTask) - - result := <-resultWorkCh - resultCh <- result - }() - return resultCh +func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { + logger.Debugf("Start Validating worker %x", msg.WorkerID) + validationCodeHash := msg.ValidationCode.Hash() + // performBasicChecks + validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, + msg.PersistedValidationData.MaxPovSize, + msg.PoV, + validationCodeHash) + + if internalErr != nil { + return nil, internalErr + } + if validationErr != nil { + return &ValidationResult{InvalidResult: validationErr}, nil //nolint + } + // check if worker is in pool + workerID, internalErr := v.poolContainsWorker(msg) + if internalErr != nil { + return nil, internalErr + + } + + // submit request + validationParams := parachainruntime.ValidationParameters{ + ParentHeadData: msg.PersistedValidationData.ParentHead, + BlockData: msg.PoV.BlockData, + RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, + RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, + } + workTask := &workerTask{ + work: validationParams, + maxPoVSize: msg.PersistedValidationData.MaxPovSize, + candidateReceipt: msg.CandidateReceipt, + } + logger.Debugf("Working Validating worker %x", workerID) + return v.workerPool.submitRequest(*workerID, workTask) + } func (v *Host) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/pvf/worker.go index 50993b0f01..f550fadc42 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/pvf/worker.go @@ -11,8 +11,6 @@ type worker struct { instance *parachainruntime.Instance // TODO(ed): determine if wasProcessed is stored here or in host isProcessed map[parachaintypes.CandidateHash]struct{} - // TODO make this a buffered channel, and determine the buffer size - workerTasksChan chan *workerTask } type workerTask struct { @@ -21,117 +19,75 @@ type workerTask struct { candidateReceipt *parachaintypes.CandidateReceipt } -func newWorker(validationCode parachaintypes.ValidationCode, queue chan *workerTask) (*worker, error) { +func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { validationRuntime, err := parachainruntime.SetupVM(validationCode) if err != nil { return nil, err } return &worker{ - workerID: validationCode.Hash(), - instance: validationRuntime, - workerTasksChan: queue, + workerID: validationCode.Hash(), + instance: validationRuntime, }, nil } -func (w *worker) executeRequest(task *workerTask) chan *ValidationTaskResult { +func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) - resultCh := make(chan *ValidationTaskResult) - - go func() { - defer close(resultCh) - candidateHash, err := parachaintypes.GetCandidateHash(task.candidateReceipt) - if err != nil { - // TODO: handle error - logger.Errorf("getting candidate hash: %w", err) - } - - // do isProcessed check here - if _, ok := w.isProcessed[candidateHash]; ok { - // TODO: determine what the isPreccessed check should return, and if re-trying is allowed - // get a better understanding of what the isProcessed check should be checking for - logger.Debugf("candidate %x already processed", candidateHash) - } - validationResult, err := w.instance.ValidateBlock(task.work) + candidateHash, err := parachaintypes.GetCandidateHash(task.candidateReceipt) + if err != nil { + return nil, err + } - if err != nil { - logger.Errorf("executing validate_block: %w", err) - reasonForInvalidity := ExecutionError - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, - } - resultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, - } - return - } + // do isProcessed check here + if _, ok := w.isProcessed[candidateHash]; ok { + // TODO: determine what the isPreccessed check should return, and if re-trying is allowed + // get a better understanding of what the isProcessed check should be checking for + logger.Debugf("candidate %x already processed", candidateHash) + } + validationResult, err := w.instance.ValidateBlock(task.work) - headDataHash, err := validationResult.HeadData.Hash() - if err != nil { - logger.Errorf("hashing head data: %w", err) - reasonForInvalidity := ExecutionError - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, - } - resultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, - } - return - } + if err != nil { + logger.Errorf("executing validate_block: %w", err) + reasonForInvalidity := ExecutionError + return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + } - if headDataHash != task.candidateReceipt.Descriptor.ParaHead { - reasonForInvalidity := ParaHeadHashMismatch - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, - } - resultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, - } - return - } - candidateCommitments := parachaintypes.CandidateCommitments{ - UpwardMessages: validationResult.UpwardMessages, - HorizontalMessages: validationResult.HorizontalMessages, - NewValidationCode: validationResult.NewValidationCode, - HeadData: validationResult.HeadData, - ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, - HrmpWatermark: validationResult.HrmpWatermark, - } + headDataHash, err := validationResult.HeadData.Hash() + if err != nil { + logger.Errorf("hashing head data: %w", err) + reasonForInvalidity := ExecutionError + return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + } - // if validation produced a new set of commitments, we treat the candidate as invalid - if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { - reasonForInvalidity := CommitmentsHashMismatch - errorResult := &ValidationResult{ - InvalidResult: &reasonForInvalidity, - } - resultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: errorResult, - } - return - } - pvd := parachaintypes.PersistedValidationData{ - ParentHead: task.work.ParentHeadData, - RelayParentNumber: task.work.RelayParentNumber, - RelayParentStorageRoot: task.work.RelayParentStorageRoot, - MaxPovSize: task.maxPoVSize, - } - validResult := &ValidationResult{ - ValidResult: &ValidValidationResult{ - CandidateCommitments: candidateCommitments, - PersistedValidationData: pvd, - }, - } + if headDataHash != task.candidateReceipt.Descriptor.ParaHead { + reasonForInvalidity := ParaHeadHashMismatch + return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + } + candidateCommitments := parachaintypes.CandidateCommitments{ + UpwardMessages: validationResult.UpwardMessages, + HorizontalMessages: validationResult.HorizontalMessages, + NewValidationCode: validationResult.NewValidationCode, + HeadData: validationResult.HeadData, + ProcessedDownwardMessages: validationResult.ProcessedDownwardMessages, + HrmpWatermark: validationResult.HrmpWatermark, + } - logger.Debugf("[RESULT] worker %x, result: %v, error: %s", w.workerID, validResult, err) + // if validation produced a new set of commitments, we treat the candidate as invalid + if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { + reasonForInvalidity := CommitmentsHashMismatch + return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + } + pvd := parachaintypes.PersistedValidationData{ + ParentHead: task.work.ParentHeadData, + RelayParentNumber: task.work.RelayParentNumber, + RelayParentStorageRoot: task.work.RelayParentStorageRoot, + MaxPovSize: task.maxPoVSize, + } + return &ValidationResult{ + ValidResult: &ValidValidationResult{ + CandidateCommitments: candidateCommitments, + PersistedValidationData: pvd, + }, + }, nil - resultCh <- &ValidationTaskResult{ - who: w.workerID, - Result: validResult, - } - }() - return resultCh } diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/pvf/worker_pool.go index 0e089dcaad..12268646a9 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/pvf/worker_pool.go @@ -2,17 +2,11 @@ package pvf import ( "fmt" - "sync" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) -const ( - maxRequestsAllowed uint = 60 -) - type workerPool struct { - mtx sync.RWMutex // todo, make sure other functions work with paraID workers map[parachaintypes.ValidationCodeHash]*worker @@ -28,12 +22,6 @@ type ValidationTask struct { ValidationCode *parachaintypes.ValidationCode } -type ValidationTaskResult struct { - who parachaintypes.ValidationCodeHash - Result *ValidationResult - InternalError error -} - // ValidationResult represents the result coming from the candidate validation subsystem. // Validation results can be either a ValidValidationResult or InvalidValidationResult. // @@ -129,8 +117,7 @@ func newValidationWorkerPool() *workerPool { func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. ValidationCodeHash, error) { - workerQueue := make(chan *workerTask, maxRequestsAllowed) - worker, err := newWorker(validationCode, workerQueue) + worker, err := newWorker(validationCode) if err != nil { return nil, fmt.Errorf("failed to create a new worker: %w", err) } @@ -143,9 +130,7 @@ func (v *workerPool) newValidationWorker(validationCode parachaintypes.Validatio // submitRequest given a request, the worker pool will get the worker for a given workerID // a channel in returned that the response will be dispatch on func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, - request *workerTask) chan *ValidationTaskResult { - v.mtx.RLock() - defer v.mtx.RUnlock() + request *workerTask) (*ValidationResult, error) { logger.Debugf("pool submit request workerID %x", workerID) syncWorker, inMap := v.workers[workerID] @@ -156,13 +141,10 @@ func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, logger.Debugf("sending request", workerID) return syncWorker.executeRequest(request) } - return nil + return nil, fmt.Errorf("worker not found") } func (v *workerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { - v.mtx.RLock() - defer v.mtx.RUnlock() - _, inMap := v.workers[workerID] return inMap } From 48faacdc3a22e31e6829d7b4dc67196c8eda3f2d Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 29 Aug 2024 16:54:04 -0400 Subject: [PATCH 15/30] removed pvf package, simplified code removed concurrency --- .../backing/candidate_backing_test.go | 15 +- dot/parachain/backing/integration_test.go | 15 +- .../backing/per_relay_parent_state.go | 3 +- .../candidate_validation.go | 80 +-- .../candidate_validation_test.go | 398 ++--------- .../{pvf => candidate-validation}/host.go | 35 +- .../candidate-validation/host_test.go | 326 +++++++++ .../candidate-validation/messages.go | 5 +- .../mocks_instance_test.go | 650 ------------------ .../{pvf => candidate-validation}/worker.go | 2 +- .../worker_pool.go | 7 +- .../worker_pool_test.go | 2 +- dot/parachain/pvf/host_test.go | 28 - 13 files changed, 419 insertions(+), 1147 deletions(-) rename dot/parachain/{pvf => candidate-validation}/host.go (78%) create mode 100644 dot/parachain/candidate-validation/host_test.go delete mode 100644 dot/parachain/candidate-validation/mocks_instance_test.go rename dot/parachain/{pvf => candidate-validation}/worker.go (99%) rename dot/parachain/{pvf => candidate-validation}/worker_pool.go (97%) rename dot/parachain/{pvf => candidate-validation}/worker_pool_test.go (98%) delete mode 100644 dot/parachain/pvf/host_test.go diff --git a/dot/parachain/backing/candidate_backing_test.go b/dot/parachain/backing/candidate_backing_test.go index f7d01926ac..f2bbcb7ee7 100644 --- a/dot/parachain/backing/candidate_backing_test.go +++ b/dot/parachain/backing/candidate_backing_test.go @@ -11,7 +11,6 @@ import ( availabilitystore "github.com/ChainSafe/gossamer/dot/parachain/availability-store" candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" @@ -693,7 +692,7 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Err: errors.New("mock error getting validation result"), } default: @@ -729,9 +728,9 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - ci := pvf.ExecutionError - data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ + ci := candidatevalidation.ExecutionError + data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + Data: candidatevalidation.ValidationResult{ InvalidResult: &ci, }, } @@ -767,9 +766,9 @@ func TestValidateAndMakeAvailable(t *testing.T) { for data := range ch { switch data := data.(type) { case candidatevalidation.ValidateFromExhaustive: - data.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{}, + data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + Data: candidatevalidation.ValidationResult{ + ValidResult: &candidatevalidation.ValidValidationResult{}, }, } case availabilitystore.StoreAvailableData: diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index efe6a523d9..41c2f0cfc5 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -13,7 +13,6 @@ import ( candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" "github.com/ChainSafe/gossamer/dot/parachain/overseer" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto" @@ -226,9 +225,9 @@ func validResponseForValidateFromExhaustive( return false } - msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ + msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + Data: candidatevalidation.ValidationResult{ + ValidResult: &candidatevalidation.ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: headData, UpwardMessages: []parachaintypes.UpwardMessage{}, @@ -335,9 +334,9 @@ func TestSecondsValidCandidate(t *testing.T) { return false } - badReturn := pvf.BadReturn - validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ + badReturn := candidatevalidation.BadReturn + validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ + Data: candidatevalidation.ValidationResult{ InvalidResult: &badReturn, }, } @@ -732,7 +731,7 @@ func TestValidationFailDoesNotStopSubsystem(t *testing.T) { return false } - msgValidate.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Err: errors.New("some internal error"), } return true diff --git a/dot/parachain/backing/per_relay_parent_state.go b/dot/parachain/backing/per_relay_parent_state.go index 17c7c57e43..d9e90fb5a2 100644 --- a/dot/parachain/backing/per_relay_parent_state.go +++ b/dot/parachain/backing/per_relay_parent_state.go @@ -11,7 +11,6 @@ import ( availabilitystore "github.com/ChainSafe/gossamer/dot/parachain/availability-store" candidatevalidation "github.com/ChainSafe/gossamer/dot/parachain/candidate-validation" collatorprotocolmessages "github.com/ChainSafe/gossamer/dot/parachain/collator-protocol/messages" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/runtime" wazero_runtime "github.com/ChainSafe/gossamer/lib/runtime/wazero" @@ -298,7 +297,7 @@ func (rpState *perRelayParentState) validateAndMakeAvailable( return fmt.Errorf("setting pvfExecTimeoutKind: %w", err) } - chValidationResultRes := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) + chValidationResultRes := make(chan parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]) subSystemToOverseer <- candidatevalidation.ValidateFromExhaustive{ PersistedValidationData: pvd, ValidationCode: *validationCode, diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index abb96453ae..08fbe66d81 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -8,27 +8,17 @@ import ( "errors" "fmt" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/runtime" - "github.com/ChainSafe/gossamer/pkg/scale" -) - -var logger = log.NewFromGlobal(log.AddContext("pkg", "parachain-candidate-validation")) - -var ( - ErrValidationCodeMismatch = errors.New("validation code hash does not match") - ErrValidationInputOverLimit = errors.New("validation input is over the limit") ) // CandidateValidation is a parachain subsystem that validates candidate parachain blocks type CandidateValidation struct { SubsystemToOverseer chan<- any BlockState BlockState - pvfHost *pvf.Host + pvfHost *Host } type BlockState interface { @@ -39,7 +29,7 @@ type BlockState interface { func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *CandidateValidation { candidateValidation := CandidateValidation{ SubsystemToOverseer: overseerChan, - pvfHost: pvf.NewValidationHost(), + pvfHost: NewValidationHost(), BlockState: blockState, } return &candidateValidation @@ -50,7 +40,6 @@ func (cv *CandidateValidation) Run(ctx context.Context, overseerToSubsystem <-ch for { select { case msg := <-overseerToSubsystem: - logger.Debugf("received message %v", msg) cv.processMessage(msg) case <-ctx.Done(): if err := ctx.Err(); err != nil { @@ -82,12 +71,13 @@ func (*CandidateValidation) ProcessBlockFinalizedSignal(parachaintypes.BlockFina func (cv *CandidateValidation) Stop() { } +// processMessage processes messages sent to the CandidateValidation subsystem func (cv *CandidateValidation) processMessage(msg any) { switch msg := msg.(type) { case ValidateFromChainState: cv.validateFromChainState(msg) case ValidateFromExhaustive: - validationTask := &pvf.ValidationTask{ + validationTask := &ValidationTask{ PersistedValidationData: msg.PersistedValidationData, ValidationCode: &msg.ValidationCode, CandidateReceipt: &msg.CandidateReceipt, @@ -100,11 +90,11 @@ func (cv *CandidateValidation) processMessage(msg any) { if err != nil { logger.Errorf("failed to validate from exhaustive: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Err: err, } } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Data: *result, } } @@ -162,12 +152,13 @@ func getValidationData(runtimeInstance parachainruntime.RuntimeInstance, paraID return nil, nil, fmt.Errorf("getting persisted validation data: %w", mergedError) } +// validateFromChainState validates a parachain block from chain state message func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState) { runtimeInstance, err := cv.BlockState.GetRuntime(msg.CandidateReceipt.Descriptor.RelayParent) if err != nil { logger.Errorf("getting runtime instance: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: err, + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Err: fmt.Errorf("getting runtime instance: %w", err), } return } @@ -176,69 +167,30 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState msg.CandidateReceipt.Descriptor.ParaID) if err != nil { logger.Errorf("getting validation data: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Err: err, + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Err: fmt.Errorf("getting validation data: %w", err), } return } - validationTask := &pvf.ValidationTask{ + validationTask := &ValidationTask{ PersistedValidationData: *persistedValidationData, ValidationCode: validationCode, CandidateReceipt: &msg.CandidateReceipt, PoV: msg.Pov, ExecutorParams: msg.ExecutorParams, - PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + // todo: implement PvfExecTimeoutKind, so that validate can be called with a timeout see issue: #3429 + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, } result, err := cv.pvfHost.Validate(validationTask) if err != nil { - logger.Errorf("failed to validate from chain state: %w", err) - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Err: err, } } else { - msg.Ch <- parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Data: *result, } } } - -// performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. -// Returns ReasonForInvalidity and internal error if any. -func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, - pov parachaintypes.PoV, validationCodeHash parachaintypes.ValidationCodeHash) (validationError *pvf. - ReasonForInvalidity, internalError error) { - povHash, err := pov.Hash() - if err != nil { - return nil, fmt.Errorf("hashing PoV: %w", err) - } - - encodedPoV, err := scale.Marshal(pov) - if err != nil { - return nil, fmt.Errorf("encoding PoV: %w", err) - } - encodedPoVSize := uint32(len(encodedPoV)) - - if encodedPoVSize > maxPoVSize { - ci := pvf.ParamsTooLarge - return &ci, nil - } - - if povHash != candidate.PovHash { - ci := pvf.PoVHashMismatch - return &ci, nil - } - - if validationCodeHash != candidate.ValidationCodeHash { - ci := pvf.CodeHashMismatch - return &ci, nil - } - - err = candidate.CheckCollatorSignature() - if err != nil { - ci := pvf.BadSignature - return &ci, nil - } - return nil, nil -} diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 43111998c5..2383d8175e 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -7,9 +7,7 @@ import ( "context" "os" "testing" - "time" - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" @@ -19,6 +17,13 @@ import ( "go.uber.org/mock/gomock" ) +var ( + povHashMismatch = PoVHashMismatch + paramsTooLarge = ParamsTooLarge + codeHashMismatch = CodeHashMismatch + badSignature = BadSignature +) + func createTestCandidateReceiptAndValidationCode(t *testing.T) ( parachaintypes.CandidateReceipt, parachaintypes.ValidationCode) { // this wasm was achieved by building polkadot's adder test parachain @@ -92,212 +97,6 @@ type BlockDataInAdderParachain struct { Add uint64 } -func TestCandidateValidation_validateFromExhaustive(t *testing.T) { - t.Parallel() - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) - candidateReceipt2 := candidateReceipt - candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( - "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") - candidateReceiptParaHeadMismatch := candidateReceipt - candidateReceiptParaHeadMismatch.Descriptor.ParaHead = common.MustHexToHash( - "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") - candidateReceiptCommitmentsMismatch := candidateReceipt - candidateReceiptCommitmentsMismatch.CommitmentsHash = common.MustHexToHash( - "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") - - povHashMismatch := pvf.PoVHashMismatch - paramsTooLarge := pvf.ParamsTooLarge - codeHashMismatch := pvf.CodeHashMismatch - paraHedHashMismatch := pvf.ParaHeadHashMismatch - commitmentsHashMismatch := pvf.CommitmentsHashMismatch - executionError := pvf.ExecutionError - - pvfHost := pvf.NewValidationHost() - - ctrl := gomock.NewController(t) - t.Cleanup(ctrl.Finish) - - bd, err := scale.Marshal(BlockDataInAdderParachain{ - State: uint64(1), - Add: uint64(1), - }) - require.NoError(t, err) - pov := parachaintypes.PoV{ - BlockData: bd, - } - - // NOTE: adder parachain internally compares postState with bd.State in it's validate_block, - // so following is necessary. - encodedState, err := scale.Marshal(uint64(1)) - require.NoError(t, err) - postState, err := common.Keccak256(encodedState) - require.NoError(t, err) - - hd, err := scale.Marshal(HeadDataInAdderParachain{ - Number: uint64(1), - ParentHash: common.MustHexToHash("0x0102030405060708090001020304050607080900010203040506070809000102"), - PostState: postState, - }) - require.NoError(t, err) - - tests := map[string]struct { - validationTask *pvf.ValidationTask - want *pvf.ValidationResult - isValid bool - }{ - "invalid_pov_hash": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - CandidateReceipt: &candidateReceipt2, - PoV: pov, - PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, - ValidationCode: &validationCode, - }, - want: &pvf.ValidationResult{ - InvalidResult: &povHashMismatch, - }, - isValid: false, - }, - "invalid_pov_size": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(10), - }, - ValidationCode: &validationCode, - CandidateReceipt: &candidateReceipt, - PoV: pov, - }, - want: &pvf.ValidationResult{ - InvalidResult: ¶msTooLarge, - }, - }, - "code_mismatch": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - ValidationCode: ¶chaintypes.ValidationCode{1, 2, 3, 4, 5, 6, 7, 8}, - CandidateReceipt: &candidateReceipt, - PoV: pov, - }, - want: &pvf.ValidationResult{ - InvalidResult: &codeHashMismatch, - }, - isValid: false, - }, - "wasm_error_unreachable": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - MaxPovSize: uint32(2048), - }, - ValidationCode: &validationCode, - CandidateReceipt: &candidateReceipt, - PoV: pov, - }, - want: &pvf.ValidationResult{ - InvalidResult: &executionError, - }, - }, - "para_head_hash_mismatch": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - ValidationCode: &validationCode, - CandidateReceipt: &candidateReceiptParaHeadMismatch, - PoV: pov, - }, - want: &pvf.ValidationResult{ - InvalidResult: ¶HedHashMismatch, - }, - isValid: false, - }, - "commitments_hash_mismatch": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - ValidationCode: &validationCode, - CandidateReceipt: &candidateReceiptCommitmentsMismatch, - PoV: pov, - }, - want: &pvf.ValidationResult{ - InvalidResult: &commitmentsHashMismatch, - }, - isValid: false, - }, - "happy_path": { - validationTask: &pvf.ValidationTask{ - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: hd}, - RelayParentNumber: uint32(1), - RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: uint32(2048), - }, - ValidationCode: &validationCode, - CandidateReceipt: &candidateReceipt, - PoV: pov, - }, - want: &pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ - CandidateCommitments: parachaintypes.CandidateCommitments{ - UpwardMessages: nil, - HorizontalMessages: nil, - NewValidationCode: nil, - HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, - 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, - 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, - 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, - ProcessedDownwardMessages: 0, - HrmpWatermark: 1, - }, - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, - 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, - 15, 1, 168, 127, 226}}, - RelayParentNumber: 1, - RelayParentStorageRoot: common.MustHexToHash( - "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: 2048, - }, - }, - }, - isValid: true, - }, - } - for name, tt := range tests { - tt := tt - t.Run(name, func(t *testing.T) { - t.Parallel() - - taskResult, err := pvfHost.Validate(tt.validationTask) - - require.NoError(t, err) - require.Equal(t, tt.want, taskResult) - require.Equal(t, tt.isValid, taskResult.IsValid()) - }) - } -} - func TestCandidateValidation_wasm_invalid_magic_number(t *testing.T) { validationCode := parachaintypes.ValidationCode{1, 2, 3, 4, 5, 6, 7, 8} parachainRuntimeInstance, err := parachainruntime.SetupVM(validationCode) @@ -306,9 +105,7 @@ func TestCandidateValidation_wasm_invalid_magic_number(t *testing.T) { } func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) { - povHashMismatch := pvf.PoVHashMismatch - paramsTooLarge := pvf.ParamsTooLarge - codeHashMismatch := pvf.CodeHashMismatch + t.Parallel() candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) candidateReceipt2 := candidateReceipt @@ -338,18 +135,19 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) require.NoError(t, err) overseerToSubsystem := make(chan any) - sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) + sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) candidateValidationSubsystem := CandidateValidation{ - pvfHost: pvf.NewValidationHost(), + pvfHost: NewValidationHost(), } - defer candidateValidationSubsystem.Stop() + + t.Cleanup(candidateValidationSubsystem.Stop) ctx := context.Background() go candidateValidationSubsystem.Run(ctx, overseerToSubsystem) tests := map[string]struct { msg ValidateFromExhaustive - want parachaintypes.OverseerFuncRes[pvf.ValidationResult] + want parachaintypes.OverseerFuncRes[ValidationResult] }{ "invalid_pov_hash": { msg: ValidateFromExhaustive{ @@ -364,8 +162,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ + want: parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: ValidationResult{ InvalidResult: &povHashMismatch, }, Err: nil, @@ -384,8 +182,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ + want: parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: ValidationResult{ InvalidResult: ¶msTooLarge, }, }, @@ -403,8 +201,8 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ + want: parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: ValidationResult{ InvalidResult: &codeHashMismatch, }, }, @@ -422,9 +220,9 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) PoV: pov, Ch: sender, }, - want: parachaintypes.OverseerFuncRes[pvf.ValidationResult]{ - Data: pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ + want: parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: ValidationResult{ + ValidResult: &ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, @@ -450,129 +248,19 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, } for name, tt := range tests { + tt := tt t.Run(name, func(t *testing.T) { - time.Sleep(100 * time.Millisecond) + t.Parallel() overseerToSubsystem <- tt.msg - time.Sleep(100 * time.Millisecond) result := <-sender require.Equal(t, tt.want, result) }) } } -func Test_performBasicChecks(t *testing.T) { - paramsTooLarge := pvf.ParamsTooLarge - povHashMismatch := pvf.PoVHashMismatch - codeHashMismatch := pvf.CodeHashMismatch - badSignature := pvf.BadSignature - - pov := parachaintypes.PoV{ - BlockData: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - } - povHash, err := pov.Hash() - pov2 := parachaintypes.PoV{ - BlockData: []byte{1, 1, 1, 1, 1}, - } - validationCode := parachaintypes.ValidationCode{1, 2, 3} - validationCodeHash := validationCode.Hash() - - require.NoError(t, err) - collatorKeypair, err := sr25519.GenerateKeypair() - require.NoError(t, err) - collatorID, err := sr25519.NewPublicKey(collatorKeypair.Public().Encode()) - require.NoError(t, err) - - candidate := parachaintypes.CandidateDescriptor{ - Collator: collatorID.AsBytes(), - PovHash: povHash, - ValidationCodeHash: validationCodeHash, - } - candidate2 := candidate - - payload, err := candidate.CreateSignaturePayload() - require.NoError(t, err) - - signatureBytes, err := collatorKeypair.Sign(payload) - require.NoError(t, err) - - signature := [sr25519.SignatureLength]byte{} - copy(signature[:], signatureBytes) - - signature2Bytes, err := collatorKeypair.Sign([]byte{1, 2, 3, 4, 5, 6, 7, 8}) - require.NoError(t, err) - signature2 := [sr25519.SignatureLength]byte{} - copy(signature2[:], signature2Bytes) - - candidate.Signature = parachaintypes.CollatorSignature(signature) - candidate2.Signature = parachaintypes.CollatorSignature(signature2) - - type args struct { - candidate *parachaintypes.CandidateDescriptor - maxPoVSize uint32 - pov parachaintypes.PoV - validationCodeHash parachaintypes.ValidationCodeHash - } - tests := map[string]struct { - args args - expectedError *pvf.ReasonForInvalidity - }{ - "params_too_large": { - args: args{ - candidate: &candidate, - maxPoVSize: 2, - pov: pov, - }, - expectedError: ¶msTooLarge, - }, - "invalid_pov_hash": { - args: args{ - candidate: &candidate, - maxPoVSize: 1024, - pov: pov2, - }, - expectedError: &povHashMismatch, - }, - "invalid_code_hash": { - args: args{ - candidate: &candidate, - maxPoVSize: 1024, - pov: pov, - validationCodeHash: parachaintypes.ValidationCodeHash{1, 2, 3}, - }, - expectedError: &codeHashMismatch, - }, - "invalid_signature": { - args: args{ - candidate: &candidate2, - maxPoVSize: 1024, - pov: pov, - validationCodeHash: validationCodeHash, - }, - expectedError: &badSignature, - }, - "happy_path": { - args: args{ - candidate: &candidate, - maxPoVSize: 1024, - pov: pov, - validationCodeHash: validationCodeHash, - }, - }, - } - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - validationError, _ := performBasicChecks(tt.args.candidate, tt.args.maxPoVSize, tt.args.pov, - tt.args.validationCodeHash) - if tt.expectedError != nil { - require.EqualError(t, validationError, tt.expectedError.Error()) - } else { - require.Nil(t, validationError) - } - }) - } -} +func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) { + t.Parallel() -func TestCandidateValidation_validateFromChainState(t *testing.T) { candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( @@ -590,11 +278,6 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { candidateReceipt5 := candidateReceipt candidateReceipt5.Descriptor.ParaID = 5 - povHashMismatch := pvf.PoVHashMismatch - paramsTooLarge := pvf.ParamsTooLarge - codeHashMismatch := pvf.CodeHashMismatch - badSignature := pvf.BadSignature - ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) @@ -685,9 +368,10 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { BlockData: bd, } + sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) toSubsystem := make(chan any) candidateValidationSubsystem := CandidateValidation{ - pvfHost: pvf.NewValidationHost(), + pvfHost: NewValidationHost(), BlockState: mockBlockState, } defer candidateValidationSubsystem.Stop() @@ -696,15 +380,16 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { tests := map[string]struct { msg ValidateFromChainState - want *pvf.ValidationResult + want *ValidationResult expectedError error }{ "invalid_pov_hash": { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt2, Pov: pov, + Ch: sender, }, - want: &pvf.ValidationResult{ + want: &ValidationResult{ InvalidResult: &povHashMismatch, }, }, @@ -712,8 +397,9 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt3, Pov: pov, + Ch: sender, }, - want: &pvf.ValidationResult{ + want: &ValidationResult{ InvalidResult: ¶msTooLarge, }, }, @@ -721,8 +407,9 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt4, Pov: pov, + Ch: sender, }, - want: &pvf.ValidationResult{ + want: &ValidationResult{ InvalidResult: &codeHashMismatch, }, }, @@ -730,8 +417,9 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt5, Pov: pov, + Ch: sender, }, - want: &pvf.ValidationResult{ + want: &ValidationResult{ InvalidResult: &badSignature, }, }, @@ -739,9 +427,10 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt, Pov: pov, + Ch: sender, }, - want: &pvf.ValidationResult{ - ValidResult: &pvf.ValidValidationResult{ + want: &ValidationResult{ + ValidResult: &ValidValidationResult{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, @@ -768,12 +457,9 @@ func TestCandidateValidation_validateFromChainState(t *testing.T) { for name, tt := range tests { tt := tt t.Run(name, func(t *testing.T) { - sender := make(chan parachaintypes.OverseerFuncRes[pvf.ValidationResult]) - defer close(sender) - tt.msg.Ch = sender - time.Sleep(100 * time.Millisecond) + t.Parallel() + toSubsystem <- tt.msg - time.Sleep(100 * time.Millisecond) result := <-sender require.Equal(t, tt.want, &result.Data) }) diff --git a/dot/parachain/pvf/host.go b/dot/parachain/candidate-validation/host.go similarity index 78% rename from dot/parachain/pvf/host.go rename to dot/parachain/candidate-validation/host.go index fc3b8e5c75..ba0e457eff 100644 --- a/dot/parachain/pvf/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -1,4 +1,4 @@ -package pvf +package candidatevalidation import ( "fmt" @@ -22,7 +22,6 @@ func NewValidationHost() *Host { } func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { - logger.Debugf("Start Validating worker %x", msg.WorkerID) validationCodeHash := msg.ValidationCode.Hash() // performBasicChecks validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, @@ -36,11 +35,17 @@ func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { if validationErr != nil { return &ValidationResult{InvalidResult: validationErr}, nil //nolint } - // check if worker is in pool - workerID, internalErr := v.poolContainsWorker(msg) - if internalErr != nil { - return nil, internalErr - + // create worker if not in pool + if !v.workerPool.containsWorker(validationCodeHash) { + worker, err := v.workerPool.newValidationWorker(*msg.ValidationCode) + if err != nil { + return nil, err + } + + // sanity check + if worker.workerID != validationCodeHash { + return nil, fmt.Errorf("workerID does not match validationCodeHash") + } } // submit request @@ -55,21 +60,7 @@ func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { maxPoVSize: msg.PersistedValidationData.MaxPovSize, candidateReceipt: msg.CandidateReceipt, } - logger.Debugf("Working Validating worker %x", workerID) - return v.workerPool.submitRequest(*workerID, workTask) - -} - -func (v *Host) poolContainsWorker(msg *ValidationTask) (*parachaintypes.ValidationCodeHash, error) { - if msg.WorkerID != nil { - return msg.WorkerID, nil - } - validationCodeHash := msg.ValidationCode.Hash() - if v.workerPool.containsWorker(validationCodeHash) { - return &validationCodeHash, nil - } else { - return v.workerPool.newValidationWorker(*msg.ValidationCode) - } + return v.workerPool.submitRequest(validationCodeHash, workTask) } // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go new file mode 100644 index 0000000000..a42d1af213 --- /dev/null +++ b/dot/parachain/candidate-validation/host_test.go @@ -0,0 +1,326 @@ +package candidatevalidation + +import ( + "testing" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/crypto/sr25519" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/stretchr/testify/require" +) + +func TestHost_validate(t *testing.T) { + t.Parallel() + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt2 := candidateReceipt + candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + candidateReceiptParaHeadMismatch := candidateReceipt + candidateReceiptParaHeadMismatch.Descriptor.ParaHead = common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + candidateReceiptCommitmentsMismatch := candidateReceipt + candidateReceiptCommitmentsMismatch.CommitmentsHash = common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + + povHashMismatch := PoVHashMismatch + paramsTooLarge := ParamsTooLarge + codeHashMismatch := CodeHashMismatch + paraHedHashMismatch := ParaHeadHashMismatch + commitmentsHashMismatch := CommitmentsHashMismatch + executionError := ExecutionError + + pvfHost := NewValidationHost() + + bd, err := scale.Marshal(BlockDataInAdderParachain{ + State: uint64(1), + Add: uint64(1), + }) + require.NoError(t, err) + pov := parachaintypes.PoV{ + BlockData: bd, + } + + // NOTE: adder parachain internally compares postState with bd.State in it's validate_block, + // so following is necessary. + encodedState, err := scale.Marshal(uint64(1)) + require.NoError(t, err) + postState, err := common.Keccak256(encodedState) + require.NoError(t, err) + + hd, err := scale.Marshal(HeadDataInAdderParachain{ + Number: uint64(1), + ParentHash: common.MustHexToHash("0x0102030405060708090001020304050607080900010203040506070809000102"), + PostState: postState, + }) + require.NoError(t, err) + + tests := map[string]struct { + validationTask *ValidationTask + want *ValidationResult + isValid bool + }{ + "invalid_pov_hash": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + }, + CandidateReceipt: &candidateReceipt2, + PoV: pov, + PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, + ValidationCode: &validationCode, + }, + want: &ValidationResult{ + InvalidResult: &povHashMismatch, + }, + isValid: false, + }, + "invalid_pov_size": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(10), + }, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, + }, + want: &ValidationResult{ + InvalidResult: ¶msTooLarge, + }, + }, + "code_mismatch": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + }, + ValidationCode: ¶chaintypes.ValidationCode{1, 2, 3, 4, 5, 6, 7, 8}, + CandidateReceipt: &candidateReceipt, + PoV: pov, + }, + want: &ValidationResult{ + InvalidResult: &codeHashMismatch, + }, + isValid: false, + }, + "wasm_error_unreachable": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + MaxPovSize: uint32(2048), + }, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, + }, + want: &ValidationResult{ + InvalidResult: &executionError, + }, + }, + "para_head_hash_mismatch": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + }, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceiptParaHeadMismatch, + PoV: pov, + }, + want: &ValidationResult{ + InvalidResult: ¶HedHashMismatch, + }, + isValid: false, + }, + "commitments_hash_mismatch": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + }, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceiptCommitmentsMismatch, + PoV: pov, + }, + want: &ValidationResult{ + InvalidResult: &commitmentsHashMismatch, + }, + isValid: false, + }, + "happy_path": { + validationTask: &ValidationTask{ + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: hd}, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: uint32(2048), + }, + ValidationCode: &validationCode, + CandidateReceipt: &candidateReceipt, + PoV: pov, + }, + want: &ValidationResult{ + ValidResult: &ValidValidationResult{ + CandidateCommitments: parachaintypes.CandidateCommitments{ + UpwardMessages: nil, + HorizontalMessages: nil, + NewValidationCode: nil, + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + }, + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, + 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, + 15, 1, 168, 127, 226}}, + RelayParentNumber: 1, + RelayParentStorageRoot: common.MustHexToHash( + "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: 2048, + }, + }, + }, + isValid: true, + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + taskResult, err := pvfHost.Validate(tt.validationTask) + + require.NoError(t, err) + require.Equal(t, tt.want, taskResult) + require.Equal(t, tt.isValid, taskResult.IsValid()) + }) + } +} + +func TestHost_performBasicChecks(t *testing.T) { + paramsTooLarge := ParamsTooLarge + povHashMismatch := PoVHashMismatch + codeHashMismatch := CodeHashMismatch + badSignature := BadSignature + + pov := parachaintypes.PoV{ + BlockData: []byte{1, 2, 3, 4, 5, 6, 7, 8}, + } + povHash, err := pov.Hash() + pov2 := parachaintypes.PoV{ + BlockData: []byte{1, 1, 1, 1, 1}, + } + validationCode := parachaintypes.ValidationCode{1, 2, 3} + validationCodeHash := validationCode.Hash() + + require.NoError(t, err) + collatorKeypair, err := sr25519.GenerateKeypair() + require.NoError(t, err) + collatorID, err := sr25519.NewPublicKey(collatorKeypair.Public().Encode()) + require.NoError(t, err) + + candidate := parachaintypes.CandidateDescriptor{ + Collator: collatorID.AsBytes(), + PovHash: povHash, + ValidationCodeHash: validationCodeHash, + } + candidate2 := candidate + + payload, err := candidate.CreateSignaturePayload() + require.NoError(t, err) + + signatureBytes, err := collatorKeypair.Sign(payload) + require.NoError(t, err) + + signature := [sr25519.SignatureLength]byte{} + copy(signature[:], signatureBytes) + + signature2Bytes, err := collatorKeypair.Sign([]byte{1, 2, 3, 4, 5, 6, 7, 8}) + require.NoError(t, err) + signature2 := [sr25519.SignatureLength]byte{} + copy(signature2[:], signature2Bytes) + + candidate.Signature = parachaintypes.CollatorSignature(signature) + candidate2.Signature = parachaintypes.CollatorSignature(signature2) + + type args struct { + candidate *parachaintypes.CandidateDescriptor + maxPoVSize uint32 + pov parachaintypes.PoV + validationCodeHash parachaintypes.ValidationCodeHash + } + tests := map[string]struct { + args args + expectedError *ReasonForInvalidity + }{ + "params_too_large": { + args: args{ + candidate: &candidate, + maxPoVSize: 2, + pov: pov, + }, + expectedError: ¶msTooLarge, + }, + "invalid_pov_hash": { + args: args{ + candidate: &candidate, + maxPoVSize: 1024, + pov: pov2, + }, + expectedError: &povHashMismatch, + }, + "invalid_code_hash": { + args: args{ + candidate: &candidate, + maxPoVSize: 1024, + pov: pov, + validationCodeHash: parachaintypes.ValidationCodeHash{1, 2, 3}, + }, + expectedError: &codeHashMismatch, + }, + "invalid_signature": { + args: args{ + candidate: &candidate2, + maxPoVSize: 1024, + pov: pov, + validationCodeHash: validationCodeHash, + }, + expectedError: &badSignature, + }, + "happy_path": { + args: args{ + candidate: &candidate, + maxPoVSize: 1024, + pov: pov, + validationCodeHash: validationCodeHash, + }, + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + validationError, _ := performBasicChecks(tt.args.candidate, tt.args.maxPoVSize, tt.args.pov, + tt.args.validationCodeHash) + if tt.expectedError != nil { + require.EqualError(t, validationError, tt.expectedError.Error()) + } else { + require.Nil(t, validationError) + } + }) + } +} diff --git a/dot/parachain/candidate-validation/messages.go b/dot/parachain/candidate-validation/messages.go index 76f974d2aa..8ac68e2832 100644 --- a/dot/parachain/candidate-validation/messages.go +++ b/dot/parachain/candidate-validation/messages.go @@ -4,7 +4,6 @@ package candidatevalidation import ( - "github.com/ChainSafe/gossamer/dot/parachain/pvf" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/lib/common" ) @@ -15,7 +14,7 @@ type ValidateFromChainState struct { Pov parachaintypes.PoV ExecutorParams parachaintypes.ExecutorParams ExecKind parachaintypes.PvfExecTimeoutKind - Ch chan parachaintypes.OverseerFuncRes[pvf.ValidationResult] + Ch chan parachaintypes.OverseerFuncRes[ValidationResult] } // ValidateFromExhaustive performs full validation of a candidate with provided parameters, @@ -29,7 +28,7 @@ type ValidateFromExhaustive struct { PoV parachaintypes.PoV ExecutorParams parachaintypes.ExecutorParams PvfExecTimeoutKind parachaintypes.PvfExecTimeoutKind - Ch chan parachaintypes.OverseerFuncRes[pvf.ValidationResult] + Ch chan parachaintypes.OverseerFuncRes[ValidationResult] } // PreCheck try to compile the given validation code and return the result diff --git a/dot/parachain/candidate-validation/mocks_instance_test.go b/dot/parachain/candidate-validation/mocks_instance_test.go deleted file mode 100644 index 22efc588d2..0000000000 --- a/dot/parachain/candidate-validation/mocks_instance_test.go +++ /dev/null @@ -1,650 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ChainSafe/gossamer/lib/runtime (interfaces: Instance) -// -// Generated by this command: -// -// mockgen -destination=mocks_instance_test.go -package candidatevalidation github.com/ChainSafe/gossamer/lib/runtime Instance -// - -// Package candidatevalidation is a generated GoMock package. -package candidatevalidation - -import ( - reflect "reflect" - - parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" - types "github.com/ChainSafe/gossamer/dot/types" - common "github.com/ChainSafe/gossamer/lib/common" - ed25519 "github.com/ChainSafe/gossamer/lib/crypto/ed25519" - keystore "github.com/ChainSafe/gossamer/lib/keystore" - runtime "github.com/ChainSafe/gossamer/lib/runtime" - transaction "github.com/ChainSafe/gossamer/lib/transaction" - gomock "go.uber.org/mock/gomock" -) - -// MockInstance is a mock of Instance interface. -type MockInstance struct { - ctrl *gomock.Controller - recorder *MockInstanceMockRecorder -} - -// MockInstanceMockRecorder is the mock recorder for MockInstance. -type MockInstanceMockRecorder struct { - mock *MockInstance -} - -// NewMockInstance creates a new mock instance. -func NewMockInstance(ctrl *gomock.Controller) *MockInstance { - mock := &MockInstance{ctrl: ctrl} - mock.recorder = &MockInstanceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockInstance) EXPECT() *MockInstanceMockRecorder { - return m.recorder -} - -// ApplyExtrinsic mocks base method. -func (m *MockInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ApplyExtrinsic", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ApplyExtrinsic indicates an expected call of ApplyExtrinsic. -func (mr *MockInstanceMockRecorder) ApplyExtrinsic(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockInstance)(nil).ApplyExtrinsic), arg0) -} - -// BabeConfiguration mocks base method. -func (m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BabeConfiguration") - ret0, _ := ret[0].(*types.BabeConfiguration) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BabeConfiguration indicates an expected call of BabeConfiguration. -func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) -} - -// BabeGenerateKeyOwnershipProof mocks base method. -func (m *MockInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) - ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. -func (mr *MockInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) -} - -// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. -func (m *MockInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. -func (mr *MockInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) -} - -// CheckInherents mocks base method. -func (m *MockInstance) CheckInherents() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "CheckInherents") -} - -// CheckInherents indicates an expected call of CheckInherents. -func (mr *MockInstanceMockRecorder) CheckInherents() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockInstance)(nil).CheckInherents)) -} - -// DecodeSessionKeys mocks base method. -func (m *MockInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DecodeSessionKeys", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DecodeSessionKeys indicates an expected call of DecodeSessionKeys. -func (mr *MockInstanceMockRecorder) DecodeSessionKeys(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockInstance)(nil).DecodeSessionKeys), arg0) -} - -// Exec mocks base method. -func (m *MockInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Exec", arg0, arg1) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Exec indicates an expected call of Exec. -func (mr *MockInstanceMockRecorder) Exec(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockInstance)(nil).Exec), arg0, arg1) -} - -// ExecuteBlock mocks base method. -func (m *MockInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExecuteBlock", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ExecuteBlock indicates an expected call of ExecuteBlock. -func (mr *MockInstanceMockRecorder) ExecuteBlock(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockInstance)(nil).ExecuteBlock), arg0) -} - -// FinalizeBlock mocks base method. -func (m *MockInstance) FinalizeBlock() (*types.Header, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FinalizeBlock") - ret0, _ := ret[0].(*types.Header) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FinalizeBlock indicates an expected call of FinalizeBlock. -func (mr *MockInstanceMockRecorder) FinalizeBlock() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockInstance)(nil).FinalizeBlock)) -} - -// GenerateSessionKeys mocks base method. -func (m *MockInstance) GenerateSessionKeys() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "GenerateSessionKeys") -} - -// GenerateSessionKeys indicates an expected call of GenerateSessionKeys. -func (mr *MockInstanceMockRecorder) GenerateSessionKeys() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockInstance)(nil).GenerateSessionKeys)) -} - -// GetCodeHash mocks base method. -func (m *MockInstance) GetCodeHash() common.Hash { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCodeHash") - ret0, _ := ret[0].(common.Hash) - return ret0 -} - -// GetCodeHash indicates an expected call of GetCodeHash. -func (mr *MockInstanceMockRecorder) GetCodeHash() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockInstance)(nil).GetCodeHash)) -} - -// GrandpaAuthorities mocks base method. -func (m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GrandpaAuthorities") - ret0, _ := ret[0].([]types.Authority) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GrandpaAuthorities indicates an expected call of GrandpaAuthorities. -func (mr *MockInstanceMockRecorder) GrandpaAuthorities() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockInstance)(nil).GrandpaAuthorities)) -} - -// GrandpaGenerateKeyOwnershipProof mocks base method. -func (m *MockInstance) GrandpaGenerateKeyOwnershipProof(arg0 uint64, arg1 ed25519.PublicKeyBytes) (types.GrandpaOpaqueKeyOwnershipProof, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GrandpaGenerateKeyOwnershipProof", arg0, arg1) - ret0, _ := ret[0].(types.GrandpaOpaqueKeyOwnershipProof) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GrandpaGenerateKeyOwnershipProof indicates an expected call of GrandpaGenerateKeyOwnershipProof. -func (mr *MockInstanceMockRecorder) GrandpaGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).GrandpaGenerateKeyOwnershipProof), arg0, arg1) -} - -// GrandpaSubmitReportEquivocationUnsignedExtrinsic mocks base method. -func (m *MockInstance) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0 types.GrandpaEquivocationProof, arg1 types.GrandpaOpaqueKeyOwnershipProof) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// GrandpaSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of GrandpaSubmitReportEquivocationUnsignedExtrinsic. -func (mr *MockInstanceMockRecorder) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).GrandpaSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) -} - -// InherentExtrinsics mocks base method. -func (m *MockInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InherentExtrinsics", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// InherentExtrinsics indicates an expected call of InherentExtrinsics. -func (mr *MockInstanceMockRecorder) InherentExtrinsics(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockInstance)(nil).InherentExtrinsics), arg0) -} - -// InitializeBlock mocks base method. -func (m *MockInstance) InitializeBlock(arg0 *types.Header) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InitializeBlock", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// InitializeBlock indicates an expected call of InitializeBlock. -func (mr *MockInstanceMockRecorder) InitializeBlock(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockInstance)(nil).InitializeBlock), arg0) -} - -// Keystore mocks base method. -func (m *MockInstance) Keystore() *keystore.GlobalKeystore { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Keystore") - ret0, _ := ret[0].(*keystore.GlobalKeystore) - return ret0 -} - -// Keystore indicates an expected call of Keystore. -func (mr *MockInstanceMockRecorder) Keystore() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockInstance)(nil).Keystore)) -} - -// Metadata mocks base method. -func (m *MockInstance) Metadata() ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Metadata") - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Metadata indicates an expected call of Metadata. -func (mr *MockInstanceMockRecorder) Metadata() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockInstance)(nil).Metadata)) -} - -// NetworkService mocks base method. -func (m *MockInstance) NetworkService() runtime.BasicNetwork { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NetworkService") - ret0, _ := ret[0].(runtime.BasicNetwork) - return ret0 -} - -// NetworkService indicates an expected call of NetworkService. -func (mr *MockInstanceMockRecorder) NetworkService() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockInstance)(nil).NetworkService)) -} - -// NodeStorage mocks base method. -func (m *MockInstance) NodeStorage() runtime.NodeStorage { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NodeStorage") - ret0, _ := ret[0].(runtime.NodeStorage) - return ret0 -} - -// NodeStorage indicates an expected call of NodeStorage. -func (mr *MockInstanceMockRecorder) NodeStorage() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockInstance)(nil).NodeStorage)) -} - -// OffchainWorker mocks base method. -func (m *MockInstance) OffchainWorker() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OffchainWorker") -} - -// OffchainWorker indicates an expected call of OffchainWorker. -func (mr *MockInstanceMockRecorder) OffchainWorker() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockInstance)(nil).OffchainWorker)) -} - -// ParachainHostAsyncBackingParams mocks base method. -func (m *MockInstance) ParachainHostAsyncBackingParams() (*parachaintypes.AsyncBackingParams, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostAsyncBackingParams") - ret0, _ := ret[0].(*parachaintypes.AsyncBackingParams) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostAsyncBackingParams indicates an expected call of ParachainHostAsyncBackingParams. -func (mr *MockInstanceMockRecorder) ParachainHostAsyncBackingParams() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAsyncBackingParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostAsyncBackingParams)) -} - -// ParachainHostAvailabilityCores mocks base method. -func (m *MockInstance) ParachainHostAvailabilityCores() ([]parachaintypes.CoreState, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostAvailabilityCores") - ret0, _ := ret[0].([]parachaintypes.CoreState) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostAvailabilityCores indicates an expected call of ParachainHostAvailabilityCores. -func (mr *MockInstanceMockRecorder) ParachainHostAvailabilityCores() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAvailabilityCores", reflect.TypeOf((*MockInstance)(nil).ParachainHostAvailabilityCores)) -} - -// ParachainHostCandidateEvents mocks base method. -func (m *MockInstance) ParachainHostCandidateEvents() ([]parachaintypes.CandidateEvent, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostCandidateEvents") - ret0, _ := ret[0].([]parachaintypes.CandidateEvent) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostCandidateEvents indicates an expected call of ParachainHostCandidateEvents. -func (mr *MockInstanceMockRecorder) ParachainHostCandidateEvents() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidateEvents", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidateEvents)) -} - -// ParachainHostCandidatePendingAvailability mocks base method. -func (m *MockInstance) ParachainHostCandidatePendingAvailability(arg0 parachaintypes.ParaID) (*parachaintypes.CommittedCandidateReceipt, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostCandidatePendingAvailability", arg0) - ret0, _ := ret[0].(*parachaintypes.CommittedCandidateReceipt) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostCandidatePendingAvailability indicates an expected call of ParachainHostCandidatePendingAvailability. -func (mr *MockInstanceMockRecorder) ParachainHostCandidatePendingAvailability(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidatePendingAvailability", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidatePendingAvailability), arg0) -} - -// ParachainHostCheckValidationOutputs mocks base method. -func (m *MockInstance) ParachainHostCheckValidationOutputs(arg0 parachaintypes.ParaID, arg1 parachaintypes.CandidateCommitments) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostCheckValidationOutputs", arg0, arg1) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostCheckValidationOutputs indicates an expected call of ParachainHostCheckValidationOutputs. -func (mr *MockInstanceMockRecorder) ParachainHostCheckValidationOutputs(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCheckValidationOutputs", reflect.TypeOf((*MockInstance)(nil).ParachainHostCheckValidationOutputs), arg0, arg1) -} - -// ParachainHostMinimumBackingVotes mocks base method. -func (m *MockInstance) ParachainHostMinimumBackingVotes() (uint32, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostMinimumBackingVotes") - ret0, _ := ret[0].(uint32) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostMinimumBackingVotes indicates an expected call of ParachainHostMinimumBackingVotes. -func (mr *MockInstanceMockRecorder) ParachainHostMinimumBackingVotes() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostMinimumBackingVotes", reflect.TypeOf((*MockInstance)(nil).ParachainHostMinimumBackingVotes)) -} - -// ParachainHostPersistedValidationData mocks base method. -func (m *MockInstance) ParachainHostPersistedValidationData(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.PersistedValidationData, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostPersistedValidationData", arg0, arg1) - ret0, _ := ret[0].(*parachaintypes.PersistedValidationData) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostPersistedValidationData indicates an expected call of ParachainHostPersistedValidationData. -func (mr *MockInstanceMockRecorder) ParachainHostPersistedValidationData(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostPersistedValidationData", reflect.TypeOf((*MockInstance)(nil).ParachainHostPersistedValidationData), arg0, arg1) -} - -// ParachainHostSessionExecutorParams mocks base method. -func (m *MockInstance) ParachainHostSessionExecutorParams(arg0 parachaintypes.SessionIndex) (*parachaintypes.ExecutorParams, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostSessionExecutorParams", arg0) - ret0, _ := ret[0].(*parachaintypes.ExecutorParams) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostSessionExecutorParams indicates an expected call of ParachainHostSessionExecutorParams. -func (mr *MockInstanceMockRecorder) ParachainHostSessionExecutorParams(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionExecutorParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionExecutorParams), arg0) -} - -// ParachainHostSessionIndexForChild mocks base method. -func (m *MockInstance) ParachainHostSessionIndexForChild() (parachaintypes.SessionIndex, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostSessionIndexForChild") - ret0, _ := ret[0].(parachaintypes.SessionIndex) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostSessionIndexForChild indicates an expected call of ParachainHostSessionIndexForChild. -func (mr *MockInstanceMockRecorder) ParachainHostSessionIndexForChild() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionIndexForChild", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionIndexForChild)) -} - -// ParachainHostSessionInfo mocks base method. -func (m *MockInstance) ParachainHostSessionInfo(arg0 parachaintypes.SessionIndex) (*parachaintypes.SessionInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostSessionInfo", arg0) - ret0, _ := ret[0].(*parachaintypes.SessionInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostSessionInfo indicates an expected call of ParachainHostSessionInfo. -func (mr *MockInstanceMockRecorder) ParachainHostSessionInfo(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionInfo", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionInfo), arg0) -} - -// ParachainHostValidationCode mocks base method. -func (m *MockInstance) ParachainHostValidationCode(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.ValidationCode, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostValidationCode", arg0, arg1) - ret0, _ := ret[0].(*parachaintypes.ValidationCode) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostValidationCode indicates an expected call of ParachainHostValidationCode. -func (mr *MockInstanceMockRecorder) ParachainHostValidationCode(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCode", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCode), arg0, arg1) -} - -// ParachainHostValidationCodeByHash mocks base method. -func (m *MockInstance) ParachainHostValidationCodeByHash(arg0 common.Hash) (*parachaintypes.ValidationCode, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostValidationCodeByHash", arg0) - ret0, _ := ret[0].(*parachaintypes.ValidationCode) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostValidationCodeByHash indicates an expected call of ParachainHostValidationCodeByHash. -func (mr *MockInstanceMockRecorder) ParachainHostValidationCodeByHash(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCodeByHash", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCodeByHash), arg0) -} - -// ParachainHostValidatorGroups mocks base method. -func (m *MockInstance) ParachainHostValidatorGroups() (*parachaintypes.ValidatorGroups, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostValidatorGroups") - ret0, _ := ret[0].(*parachaintypes.ValidatorGroups) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostValidatorGroups indicates an expected call of ParachainHostValidatorGroups. -func (mr *MockInstanceMockRecorder) ParachainHostValidatorGroups() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidatorGroups", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidatorGroups)) -} - -// ParachainHostValidators mocks base method. -func (m *MockInstance) ParachainHostValidators() ([]parachaintypes.ValidatorID, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParachainHostValidators") - ret0, _ := ret[0].([]parachaintypes.ValidatorID) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParachainHostValidators indicates an expected call of ParachainHostValidators. -func (mr *MockInstanceMockRecorder) ParachainHostValidators() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidators", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidators)) -} - -// PaymentQueryInfo mocks base method. -func (m *MockInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PaymentQueryInfo", arg0) - ret0, _ := ret[0].(*types.RuntimeDispatchInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PaymentQueryInfo indicates an expected call of PaymentQueryInfo. -func (mr *MockInstanceMockRecorder) PaymentQueryInfo(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockInstance)(nil).PaymentQueryInfo), arg0) -} - -// RandomSeed mocks base method. -func (m *MockInstance) RandomSeed() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "RandomSeed") -} - -// RandomSeed indicates an expected call of RandomSeed. -func (mr *MockInstanceMockRecorder) RandomSeed() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockInstance)(nil).RandomSeed)) -} - -// SetContextStorage mocks base method. -func (m *MockInstance) SetContextStorage(arg0 runtime.Storage) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetContextStorage", arg0) -} - -// SetContextStorage indicates an expected call of SetContextStorage. -func (mr *MockInstanceMockRecorder) SetContextStorage(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockInstance)(nil).SetContextStorage), arg0) -} - -// Stop mocks base method. -func (m *MockInstance) Stop() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Stop") -} - -// Stop indicates an expected call of Stop. -func (mr *MockInstanceMockRecorder) Stop() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockInstance)(nil).Stop)) -} - -// ValidateTransaction mocks base method. -func (m *MockInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateTransaction", arg0) - ret0, _ := ret[0].(*transaction.Validity) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ValidateTransaction indicates an expected call of ValidateTransaction. -func (mr *MockInstanceMockRecorder) ValidateTransaction(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockInstance)(nil).ValidateTransaction), arg0) -} - -// Validator mocks base method. -func (m *MockInstance) Validator() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Validator") - ret0, _ := ret[0].(bool) - return ret0 -} - -// Validator indicates an expected call of Validator. -func (mr *MockInstanceMockRecorder) Validator() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockInstance)(nil).Validator)) -} - -// Version mocks base method. -func (m *MockInstance) Version() (runtime.Version, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Version") - ret0, _ := ret[0].(runtime.Version) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Version indicates an expected call of Version. -func (mr *MockInstanceMockRecorder) Version() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockInstance)(nil).Version)) -} diff --git a/dot/parachain/pvf/worker.go b/dot/parachain/candidate-validation/worker.go similarity index 99% rename from dot/parachain/pvf/worker.go rename to dot/parachain/candidate-validation/worker.go index f550fadc42..50d738903a 100644 --- a/dot/parachain/pvf/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -1,4 +1,4 @@ -package pvf +package candidatevalidation import ( parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" diff --git a/dot/parachain/pvf/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go similarity index 97% rename from dot/parachain/pvf/worker_pool.go rename to dot/parachain/candidate-validation/worker_pool.go index 12268646a9..ba18addbd7 100644 --- a/dot/parachain/pvf/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -1,4 +1,4 @@ -package pvf +package candidatevalidation import ( "fmt" @@ -114,8 +114,7 @@ func newValidationWorkerPool() *workerPool { } } -func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*parachaintypes. - ValidationCodeHash, error) { +func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { worker, err := newWorker(validationCode) if err != nil { @@ -124,7 +123,7 @@ func (v *workerPool) newValidationWorker(validationCode parachaintypes.Validatio v.workers[worker.workerID] = worker - return &worker.workerID, nil + return worker, nil } // submitRequest given a request, the worker pool will get the worker for a given workerID diff --git a/dot/parachain/pvf/worker_pool_test.go b/dot/parachain/candidate-validation/worker_pool_test.go similarity index 98% rename from dot/parachain/pvf/worker_pool_test.go rename to dot/parachain/candidate-validation/worker_pool_test.go index e29fdb9d5f..bb6cbad635 100644 --- a/dot/parachain/pvf/worker_pool_test.go +++ b/dot/parachain/candidate-validation/worker_pool_test.go @@ -1,4 +1,4 @@ -package pvf +package candidatevalidation import ( "os" diff --git a/dot/parachain/pvf/host_test.go b/dot/parachain/pvf/host_test.go deleted file mode 100644 index 7366e969ce..0000000000 --- a/dot/parachain/pvf/host_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package pvf - -import ( - "testing" -) - -func Test_validationHost_start(t *testing.T) { - type fields struct { - workerPool *workerPool - } - tests := map[string]struct { - name string - fields fields - }{ - "test": { - name: "test", - }, - } - for tname, tt := range tests { - tt := tt - t.Run(tname, func(t *testing.T) { - v := &Host{ - workerPool: tt.fields.workerPool, - } - v.Validate(&ValidationTask{}) - }) - } -} From 391c6b4b8d7f16d1749a15203c80788db0c09c6b Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 29 Aug 2024 16:56:37 -0400 Subject: [PATCH 16/30] added missing mock file --- .../mocks_instance_test.go | 650 ++++++++++++++++++ 1 file changed, 650 insertions(+) create mode 100644 dot/parachain/candidate-validation/mocks_instance_test.go diff --git a/dot/parachain/candidate-validation/mocks_instance_test.go b/dot/parachain/candidate-validation/mocks_instance_test.go new file mode 100644 index 0000000000..22efc588d2 --- /dev/null +++ b/dot/parachain/candidate-validation/mocks_instance_test.go @@ -0,0 +1,650 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/lib/runtime (interfaces: Instance) +// +// Generated by this command: +// +// mockgen -destination=mocks_instance_test.go -package candidatevalidation github.com/ChainSafe/gossamer/lib/runtime Instance +// + +// Package candidatevalidation is a generated GoMock package. +package candidatevalidation + +import ( + reflect "reflect" + + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + types "github.com/ChainSafe/gossamer/dot/types" + common "github.com/ChainSafe/gossamer/lib/common" + ed25519 "github.com/ChainSafe/gossamer/lib/crypto/ed25519" + keystore "github.com/ChainSafe/gossamer/lib/keystore" + runtime "github.com/ChainSafe/gossamer/lib/runtime" + transaction "github.com/ChainSafe/gossamer/lib/transaction" + gomock "go.uber.org/mock/gomock" +) + +// MockInstance is a mock of Instance interface. +type MockInstance struct { + ctrl *gomock.Controller + recorder *MockInstanceMockRecorder +} + +// MockInstanceMockRecorder is the mock recorder for MockInstance. +type MockInstanceMockRecorder struct { + mock *MockInstance +} + +// NewMockInstance creates a new mock instance. +func NewMockInstance(ctrl *gomock.Controller) *MockInstance { + mock := &MockInstance{ctrl: ctrl} + mock.recorder = &MockInstanceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockInstance) EXPECT() *MockInstanceMockRecorder { + return m.recorder +} + +// ApplyExtrinsic mocks base method. +func (m *MockInstance) ApplyExtrinsic(arg0 types.Extrinsic) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyExtrinsic", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ApplyExtrinsic indicates an expected call of ApplyExtrinsic. +func (mr *MockInstanceMockRecorder) ApplyExtrinsic(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyExtrinsic", reflect.TypeOf((*MockInstance)(nil).ApplyExtrinsic), arg0) +} + +// BabeConfiguration mocks base method. +func (m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeConfiguration") + ret0, _ := ret[0].(*types.BabeConfiguration) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeConfiguration indicates an expected call of BabeConfiguration. +func (mr *MockInstanceMockRecorder) BabeConfiguration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeConfiguration", reflect.TypeOf((*MockInstance)(nil).BabeConfiguration)) +} + +// BabeGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) BabeGenerateKeyOwnershipProof(arg0 uint64, arg1 [32]byte) (types.OpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.OpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BabeGenerateKeyOwnershipProof indicates an expected call of BabeGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) BabeGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).BabeGenerateKeyOwnershipProof), arg0, arg1) +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0 types.BabeEquivocationProof, arg1 types.OpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BabeSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BabeSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of BabeSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) BabeSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BabeSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).BabeSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + +// CheckInherents mocks base method. +func (m *MockInstance) CheckInherents() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "CheckInherents") +} + +// CheckInherents indicates an expected call of CheckInherents. +func (mr *MockInstanceMockRecorder) CheckInherents() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckInherents", reflect.TypeOf((*MockInstance)(nil).CheckInherents)) +} + +// DecodeSessionKeys mocks base method. +func (m *MockInstance) DecodeSessionKeys(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecodeSessionKeys", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DecodeSessionKeys indicates an expected call of DecodeSessionKeys. +func (mr *MockInstanceMockRecorder) DecodeSessionKeys(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSessionKeys", reflect.TypeOf((*MockInstance)(nil).DecodeSessionKeys), arg0) +} + +// Exec mocks base method. +func (m *MockInstance) Exec(arg0 string, arg1 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exec", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exec indicates an expected call of Exec. +func (mr *MockInstanceMockRecorder) Exec(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockInstance)(nil).Exec), arg0, arg1) +} + +// ExecuteBlock mocks base method. +func (m *MockInstance) ExecuteBlock(arg0 *types.Block) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteBlock", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteBlock indicates an expected call of ExecuteBlock. +func (mr *MockInstanceMockRecorder) ExecuteBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteBlock", reflect.TypeOf((*MockInstance)(nil).ExecuteBlock), arg0) +} + +// FinalizeBlock mocks base method. +func (m *MockInstance) FinalizeBlock() (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FinalizeBlock") + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FinalizeBlock indicates an expected call of FinalizeBlock. +func (mr *MockInstanceMockRecorder) FinalizeBlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockInstance)(nil).FinalizeBlock)) +} + +// GenerateSessionKeys mocks base method. +func (m *MockInstance) GenerateSessionKeys() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GenerateSessionKeys") +} + +// GenerateSessionKeys indicates an expected call of GenerateSessionKeys. +func (mr *MockInstanceMockRecorder) GenerateSessionKeys() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateSessionKeys", reflect.TypeOf((*MockInstance)(nil).GenerateSessionKeys)) +} + +// GetCodeHash mocks base method. +func (m *MockInstance) GetCodeHash() common.Hash { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCodeHash") + ret0, _ := ret[0].(common.Hash) + return ret0 +} + +// GetCodeHash indicates an expected call of GetCodeHash. +func (mr *MockInstanceMockRecorder) GetCodeHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCodeHash", reflect.TypeOf((*MockInstance)(nil).GetCodeHash)) +} + +// GrandpaAuthorities mocks base method. +func (m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaAuthorities") + ret0, _ := ret[0].([]types.Authority) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GrandpaAuthorities indicates an expected call of GrandpaAuthorities. +func (mr *MockInstanceMockRecorder) GrandpaAuthorities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaAuthorities", reflect.TypeOf((*MockInstance)(nil).GrandpaAuthorities)) +} + +// GrandpaGenerateKeyOwnershipProof mocks base method. +func (m *MockInstance) GrandpaGenerateKeyOwnershipProof(arg0 uint64, arg1 ed25519.PublicKeyBytes) (types.GrandpaOpaqueKeyOwnershipProof, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaGenerateKeyOwnershipProof", arg0, arg1) + ret0, _ := ret[0].(types.GrandpaOpaqueKeyOwnershipProof) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GrandpaGenerateKeyOwnershipProof indicates an expected call of GrandpaGenerateKeyOwnershipProof. +func (mr *MockInstanceMockRecorder) GrandpaGenerateKeyOwnershipProof(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaGenerateKeyOwnershipProof", reflect.TypeOf((*MockInstance)(nil).GrandpaGenerateKeyOwnershipProof), arg0, arg1) +} + +// GrandpaSubmitReportEquivocationUnsignedExtrinsic mocks base method. +func (m *MockInstance) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0 types.GrandpaEquivocationProof, arg1 types.GrandpaOpaqueKeyOwnershipProof) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// GrandpaSubmitReportEquivocationUnsignedExtrinsic indicates an expected call of GrandpaSubmitReportEquivocationUnsignedExtrinsic. +func (mr *MockInstanceMockRecorder) GrandpaSubmitReportEquivocationUnsignedExtrinsic(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrandpaSubmitReportEquivocationUnsignedExtrinsic", reflect.TypeOf((*MockInstance)(nil).GrandpaSubmitReportEquivocationUnsignedExtrinsic), arg0, arg1) +} + +// InherentExtrinsics mocks base method. +func (m *MockInstance) InherentExtrinsics(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InherentExtrinsics", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InherentExtrinsics indicates an expected call of InherentExtrinsics. +func (mr *MockInstanceMockRecorder) InherentExtrinsics(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InherentExtrinsics", reflect.TypeOf((*MockInstance)(nil).InherentExtrinsics), arg0) +} + +// InitializeBlock mocks base method. +func (m *MockInstance) InitializeBlock(arg0 *types.Header) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InitializeBlock", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// InitializeBlock indicates an expected call of InitializeBlock. +func (mr *MockInstanceMockRecorder) InitializeBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitializeBlock", reflect.TypeOf((*MockInstance)(nil).InitializeBlock), arg0) +} + +// Keystore mocks base method. +func (m *MockInstance) Keystore() *keystore.GlobalKeystore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Keystore") + ret0, _ := ret[0].(*keystore.GlobalKeystore) + return ret0 +} + +// Keystore indicates an expected call of Keystore. +func (mr *MockInstanceMockRecorder) Keystore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keystore", reflect.TypeOf((*MockInstance)(nil).Keystore)) +} + +// Metadata mocks base method. +func (m *MockInstance) Metadata() ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Metadata") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Metadata indicates an expected call of Metadata. +func (mr *MockInstanceMockRecorder) Metadata() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockInstance)(nil).Metadata)) +} + +// NetworkService mocks base method. +func (m *MockInstance) NetworkService() runtime.BasicNetwork { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkService") + ret0, _ := ret[0].(runtime.BasicNetwork) + return ret0 +} + +// NetworkService indicates an expected call of NetworkService. +func (mr *MockInstanceMockRecorder) NetworkService() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkService", reflect.TypeOf((*MockInstance)(nil).NetworkService)) +} + +// NodeStorage mocks base method. +func (m *MockInstance) NodeStorage() runtime.NodeStorage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NodeStorage") + ret0, _ := ret[0].(runtime.NodeStorage) + return ret0 +} + +// NodeStorage indicates an expected call of NodeStorage. +func (mr *MockInstanceMockRecorder) NodeStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStorage", reflect.TypeOf((*MockInstance)(nil).NodeStorage)) +} + +// OffchainWorker mocks base method. +func (m *MockInstance) OffchainWorker() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OffchainWorker") +} + +// OffchainWorker indicates an expected call of OffchainWorker. +func (mr *MockInstanceMockRecorder) OffchainWorker() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OffchainWorker", reflect.TypeOf((*MockInstance)(nil).OffchainWorker)) +} + +// ParachainHostAsyncBackingParams mocks base method. +func (m *MockInstance) ParachainHostAsyncBackingParams() (*parachaintypes.AsyncBackingParams, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostAsyncBackingParams") + ret0, _ := ret[0].(*parachaintypes.AsyncBackingParams) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostAsyncBackingParams indicates an expected call of ParachainHostAsyncBackingParams. +func (mr *MockInstanceMockRecorder) ParachainHostAsyncBackingParams() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAsyncBackingParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostAsyncBackingParams)) +} + +// ParachainHostAvailabilityCores mocks base method. +func (m *MockInstance) ParachainHostAvailabilityCores() ([]parachaintypes.CoreState, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostAvailabilityCores") + ret0, _ := ret[0].([]parachaintypes.CoreState) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostAvailabilityCores indicates an expected call of ParachainHostAvailabilityCores. +func (mr *MockInstanceMockRecorder) ParachainHostAvailabilityCores() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostAvailabilityCores", reflect.TypeOf((*MockInstance)(nil).ParachainHostAvailabilityCores)) +} + +// ParachainHostCandidateEvents mocks base method. +func (m *MockInstance) ParachainHostCandidateEvents() ([]parachaintypes.CandidateEvent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCandidateEvents") + ret0, _ := ret[0].([]parachaintypes.CandidateEvent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCandidateEvents indicates an expected call of ParachainHostCandidateEvents. +func (mr *MockInstanceMockRecorder) ParachainHostCandidateEvents() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidateEvents", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidateEvents)) +} + +// ParachainHostCandidatePendingAvailability mocks base method. +func (m *MockInstance) ParachainHostCandidatePendingAvailability(arg0 parachaintypes.ParaID) (*parachaintypes.CommittedCandidateReceipt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCandidatePendingAvailability", arg0) + ret0, _ := ret[0].(*parachaintypes.CommittedCandidateReceipt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCandidatePendingAvailability indicates an expected call of ParachainHostCandidatePendingAvailability. +func (mr *MockInstanceMockRecorder) ParachainHostCandidatePendingAvailability(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCandidatePendingAvailability", reflect.TypeOf((*MockInstance)(nil).ParachainHostCandidatePendingAvailability), arg0) +} + +// ParachainHostCheckValidationOutputs mocks base method. +func (m *MockInstance) ParachainHostCheckValidationOutputs(arg0 parachaintypes.ParaID, arg1 parachaintypes.CandidateCommitments) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostCheckValidationOutputs", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostCheckValidationOutputs indicates an expected call of ParachainHostCheckValidationOutputs. +func (mr *MockInstanceMockRecorder) ParachainHostCheckValidationOutputs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostCheckValidationOutputs", reflect.TypeOf((*MockInstance)(nil).ParachainHostCheckValidationOutputs), arg0, arg1) +} + +// ParachainHostMinimumBackingVotes mocks base method. +func (m *MockInstance) ParachainHostMinimumBackingVotes() (uint32, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostMinimumBackingVotes") + ret0, _ := ret[0].(uint32) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostMinimumBackingVotes indicates an expected call of ParachainHostMinimumBackingVotes. +func (mr *MockInstanceMockRecorder) ParachainHostMinimumBackingVotes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostMinimumBackingVotes", reflect.TypeOf((*MockInstance)(nil).ParachainHostMinimumBackingVotes)) +} + +// ParachainHostPersistedValidationData mocks base method. +func (m *MockInstance) ParachainHostPersistedValidationData(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.PersistedValidationData, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostPersistedValidationData", arg0, arg1) + ret0, _ := ret[0].(*parachaintypes.PersistedValidationData) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostPersistedValidationData indicates an expected call of ParachainHostPersistedValidationData. +func (mr *MockInstanceMockRecorder) ParachainHostPersistedValidationData(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostPersistedValidationData", reflect.TypeOf((*MockInstance)(nil).ParachainHostPersistedValidationData), arg0, arg1) +} + +// ParachainHostSessionExecutorParams mocks base method. +func (m *MockInstance) ParachainHostSessionExecutorParams(arg0 parachaintypes.SessionIndex) (*parachaintypes.ExecutorParams, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionExecutorParams", arg0) + ret0, _ := ret[0].(*parachaintypes.ExecutorParams) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionExecutorParams indicates an expected call of ParachainHostSessionExecutorParams. +func (mr *MockInstanceMockRecorder) ParachainHostSessionExecutorParams(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionExecutorParams", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionExecutorParams), arg0) +} + +// ParachainHostSessionIndexForChild mocks base method. +func (m *MockInstance) ParachainHostSessionIndexForChild() (parachaintypes.SessionIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionIndexForChild") + ret0, _ := ret[0].(parachaintypes.SessionIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionIndexForChild indicates an expected call of ParachainHostSessionIndexForChild. +func (mr *MockInstanceMockRecorder) ParachainHostSessionIndexForChild() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionIndexForChild", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionIndexForChild)) +} + +// ParachainHostSessionInfo mocks base method. +func (m *MockInstance) ParachainHostSessionInfo(arg0 parachaintypes.SessionIndex) (*parachaintypes.SessionInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostSessionInfo", arg0) + ret0, _ := ret[0].(*parachaintypes.SessionInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostSessionInfo indicates an expected call of ParachainHostSessionInfo. +func (mr *MockInstanceMockRecorder) ParachainHostSessionInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostSessionInfo", reflect.TypeOf((*MockInstance)(nil).ParachainHostSessionInfo), arg0) +} + +// ParachainHostValidationCode mocks base method. +func (m *MockInstance) ParachainHostValidationCode(arg0 uint32, arg1 parachaintypes.OccupiedCoreAssumption) (*parachaintypes.ValidationCode, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidationCode", arg0, arg1) + ret0, _ := ret[0].(*parachaintypes.ValidationCode) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidationCode indicates an expected call of ParachainHostValidationCode. +func (mr *MockInstanceMockRecorder) ParachainHostValidationCode(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCode", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCode), arg0, arg1) +} + +// ParachainHostValidationCodeByHash mocks base method. +func (m *MockInstance) ParachainHostValidationCodeByHash(arg0 common.Hash) (*parachaintypes.ValidationCode, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidationCodeByHash", arg0) + ret0, _ := ret[0].(*parachaintypes.ValidationCode) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidationCodeByHash indicates an expected call of ParachainHostValidationCodeByHash. +func (mr *MockInstanceMockRecorder) ParachainHostValidationCodeByHash(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidationCodeByHash", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidationCodeByHash), arg0) +} + +// ParachainHostValidatorGroups mocks base method. +func (m *MockInstance) ParachainHostValidatorGroups() (*parachaintypes.ValidatorGroups, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidatorGroups") + ret0, _ := ret[0].(*parachaintypes.ValidatorGroups) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidatorGroups indicates an expected call of ParachainHostValidatorGroups. +func (mr *MockInstanceMockRecorder) ParachainHostValidatorGroups() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidatorGroups", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidatorGroups)) +} + +// ParachainHostValidators mocks base method. +func (m *MockInstance) ParachainHostValidators() ([]parachaintypes.ValidatorID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParachainHostValidators") + ret0, _ := ret[0].([]parachaintypes.ValidatorID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParachainHostValidators indicates an expected call of ParachainHostValidators. +func (mr *MockInstanceMockRecorder) ParachainHostValidators() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParachainHostValidators", reflect.TypeOf((*MockInstance)(nil).ParachainHostValidators)) +} + +// PaymentQueryInfo mocks base method. +func (m *MockInstance) PaymentQueryInfo(arg0 []byte) (*types.RuntimeDispatchInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PaymentQueryInfo", arg0) + ret0, _ := ret[0].(*types.RuntimeDispatchInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PaymentQueryInfo indicates an expected call of PaymentQueryInfo. +func (mr *MockInstanceMockRecorder) PaymentQueryInfo(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaymentQueryInfo", reflect.TypeOf((*MockInstance)(nil).PaymentQueryInfo), arg0) +} + +// RandomSeed mocks base method. +func (m *MockInstance) RandomSeed() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RandomSeed") +} + +// RandomSeed indicates an expected call of RandomSeed. +func (mr *MockInstanceMockRecorder) RandomSeed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RandomSeed", reflect.TypeOf((*MockInstance)(nil).RandomSeed)) +} + +// SetContextStorage mocks base method. +func (m *MockInstance) SetContextStorage(arg0 runtime.Storage) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetContextStorage", arg0) +} + +// SetContextStorage indicates an expected call of SetContextStorage. +func (mr *MockInstanceMockRecorder) SetContextStorage(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContextStorage", reflect.TypeOf((*MockInstance)(nil).SetContextStorage), arg0) +} + +// Stop mocks base method. +func (m *MockInstance) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockInstanceMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockInstance)(nil).Stop)) +} + +// ValidateTransaction mocks base method. +func (m *MockInstance) ValidateTransaction(arg0 types.Extrinsic) (*transaction.Validity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateTransaction", arg0) + ret0, _ := ret[0].(*transaction.Validity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateTransaction indicates an expected call of ValidateTransaction. +func (mr *MockInstanceMockRecorder) ValidateTransaction(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateTransaction", reflect.TypeOf((*MockInstance)(nil).ValidateTransaction), arg0) +} + +// Validator mocks base method. +func (m *MockInstance) Validator() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validator") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Validator indicates an expected call of Validator. +func (mr *MockInstanceMockRecorder) Validator() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockInstance)(nil).Validator)) +} + +// Version mocks base method. +func (m *MockInstance) Version() (runtime.Version, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Version") + ret0, _ := ret[0].(runtime.Version) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Version indicates an expected call of Version. +func (mr *MockInstanceMockRecorder) Version() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockInstance)(nil).Version)) +} From 7988888f6ddbc7d17f4377d325defcd1129d338e Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 29 Aug 2024 17:12:43 -0400 Subject: [PATCH 17/30] address deep source comments --- dot/parachain/candidate-validation/candidate_validation.go | 2 +- .../candidate-validation/candidate_validation_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 08fbe66d81..15f9a51f6e 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -68,7 +68,7 @@ func (*CandidateValidation) ProcessBlockFinalizedSignal(parachaintypes.BlockFina } // Stop stops the CandidateValidation subsystem -func (cv *CandidateValidation) Stop() { +func (*CandidateValidation) Stop() { } // processMessage processes messages sent to the CandidateValidation subsystem diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 2383d8175e..5186f6deb4 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -281,8 +281,8 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) - //NOTE: adder parachain internally compares postState with bd.State in it's validate_block, - //so following is necessary. + // NOTE: adder parachain internally compares postState with bd.State in it's validate_block, + // so following is necessary. encodedState, err := scale.Marshal(uint64(1)) require.NoError(t, err) postState, err := common.Keccak256(encodedState) From 5820e3f8d7ca019c81a2e032b76466494e3dea0d Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 3 Sep 2024 18:50:59 -0400 Subject: [PATCH 18/30] address PR comments --- .../backing/candidate_backing_test.go | 2 +- dot/parachain/backing/integration_test.go | 2 +- .../candidate_validation_test.go | 4 +- dot/parachain/candidate-validation/host.go | 26 +--------- .../candidate-validation/host_test.go | 2 +- dot/parachain/candidate-validation/worker.go | 26 +++++----- .../candidate-validation/worker_pool.go | 51 ++++++++++++------- .../candidate-validation/worker_pool_test.go | 4 +- 8 files changed, 54 insertions(+), 63 deletions(-) diff --git a/dot/parachain/backing/candidate_backing_test.go b/dot/parachain/backing/candidate_backing_test.go index f2bbcb7ee7..4aa1c454b8 100644 --- a/dot/parachain/backing/candidate_backing_test.go +++ b/dot/parachain/backing/candidate_backing_test.go @@ -768,7 +768,7 @@ func TestValidateAndMakeAvailable(t *testing.T) { case candidatevalidation.ValidateFromExhaustive: data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{}, + ValidResult: &candidatevalidation.Valid{}, }, } case availabilitystore.StoreAvailableData: diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index 41c2f0cfc5..52e84a71dd 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -227,7 +227,7 @@ func validResponseForValidateFromExhaustive( msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.ValidValidationResult{ + ValidResult: &candidatevalidation.Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: headData, UpwardMessages: []parachaintypes.UpwardMessage{}, diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 5186f6deb4..cee8513d71 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -222,7 +222,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, want: parachaintypes.OverseerFuncRes[ValidationResult]{ Data: ValidationResult{ - ValidResult: &ValidValidationResult{ + ValidResult: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, @@ -430,7 +430,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Ch: sender, }, want: &ValidationResult{ - ValidResult: &ValidValidationResult{ + ValidResult: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, diff --git a/dot/parachain/candidate-validation/host.go b/dot/parachain/candidate-validation/host.go index ba0e457eff..47f9b438aa 100644 --- a/dot/parachain/candidate-validation/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -3,7 +3,6 @@ package candidatevalidation import ( "fmt" - parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/pkg/scale" @@ -35,32 +34,9 @@ func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { if validationErr != nil { return &ValidationResult{InvalidResult: validationErr}, nil //nolint } - // create worker if not in pool - if !v.workerPool.containsWorker(validationCodeHash) { - worker, err := v.workerPool.newValidationWorker(*msg.ValidationCode) - if err != nil { - return nil, err - } - - // sanity check - if worker.workerID != validationCodeHash { - return nil, fmt.Errorf("workerID does not match validationCodeHash") - } - } // submit request - validationParams := parachainruntime.ValidationParameters{ - ParentHeadData: msg.PersistedValidationData.ParentHead, - BlockData: msg.PoV.BlockData, - RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, - RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, - } - workTask := &workerTask{ - work: validationParams, - maxPoVSize: msg.PersistedValidationData.MaxPovSize, - candidateReceipt: msg.CandidateReceipt, - } - return v.workerPool.submitRequest(validationCodeHash, workTask) + return v.workerPool.submitRequest(msg) } // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index a42d1af213..5d6d6fff2c 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -171,7 +171,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - ValidResult: &ValidValidationResult{ + ValidResult: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ UpwardMessages: nil, HorizontalMessages: nil, diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index 50d738903a..5c5c4c1b14 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -7,10 +7,9 @@ import ( // TODO(ed): figure out a better name for this that describes what it does type worker struct { - workerID parachaintypes.ValidationCodeHash - instance *parachainruntime.Instance - // TODO(ed): determine if wasProcessed is stored here or in host - isProcessed map[parachaintypes.CandidateHash]struct{} + workerID parachaintypes.ValidationCodeHash + instance *parachainruntime.Instance + isProcessed map[parachaintypes.CandidateHash]*ValidationResult } type workerTask struct { @@ -26,8 +25,9 @@ func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { return nil, err } return &worker{ - workerID: validationCode.Hash(), - instance: validationRuntime, + workerID: validationCode.Hash(), + instance: validationRuntime, + isProcessed: make(map[parachaintypes.CandidateHash]*ValidationResult), }, nil } @@ -39,10 +39,9 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { } // do isProcessed check here - if _, ok := w.isProcessed[candidateHash]; ok { - // TODO: determine what the isPreccessed check should return, and if re-trying is allowed - // get a better understanding of what the isProcessed check should be checking for + if processed, ok := w.isProcessed[candidateHash]; ok { logger.Debugf("candidate %x already processed", candidateHash) + return processed, nil } validationResult, err := w.instance.ValidateBlock(task.work) @@ -83,11 +82,12 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { RelayParentStorageRoot: task.work.RelayParentStorageRoot, MaxPovSize: task.maxPoVSize, } - return &ValidationResult{ - ValidResult: &ValidValidationResult{ + result := &ValidationResult{ + ValidResult: &Valid{ CandidateCommitments: candidateCommitments, PersistedValidationData: pvd, }, - }, nil - + } + w.isProcessed[candidateHash] = result + return result, nil } diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index ba18addbd7..8524dc9ff7 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -3,6 +3,7 @@ package candidatevalidation import ( "fmt" + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) @@ -23,15 +24,15 @@ type ValidationTask struct { } // ValidationResult represents the result coming from the candidate validation subsystem. -// Validation results can be either a ValidValidationResult or InvalidValidationResult. +// Validation results can be either a Valid or InvalidValidationResult. // // If the result is invalid, // store the reason for invalidity in the InvalidResult field of ValidationResult. // // If the result is valid, -// set the values of the ValidResult field of ValidValidationResult. +// set the values of the ValidResult field of Valid. type ValidationResult struct { - ValidResult *ValidValidationResult + ValidResult *Valid InvalidResult *ReasonForInvalidity } @@ -39,7 +40,7 @@ func (vr ValidationResult) IsValid() bool { return vr.ValidResult != nil } -type ValidValidationResult struct { +type Valid struct { CandidateCommitments parachaintypes.CandidateCommitments PersistedValidationData parachaintypes.PersistedValidationData } @@ -114,33 +115,47 @@ func newValidationWorkerPool() *workerPool { } } -func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { +func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) error { worker, err := newWorker(validationCode) if err != nil { - return nil, fmt.Errorf("failed to create a new worker: %w", err) + return fmt.Errorf("failed to create a new worker: %w", err) } v.workers[worker.workerID] = worker - return worker, nil + return nil } // submitRequest given a request, the worker pool will get the worker for a given workerID // a channel in returned that the response will be dispatch on -func (v *workerPool) submitRequest(workerID parachaintypes.ValidationCodeHash, - request *workerTask) (*ValidationResult, error) { - logger.Debugf("pool submit request workerID %x", workerID) - - syncWorker, inMap := v.workers[workerID] - if inMap { - if syncWorker == nil { - panic("sync worker should not be nil") +func (v *workerPool) submitRequest(msg *ValidationTask) (*ValidationResult, error) { + validationCodeHash := msg.ValidationCode.Hash() + + // create worker if not in pool + if !v.containsWorker(validationCodeHash) { + err := v.newValidationWorker(*msg.ValidationCode) + if err != nil { + return nil, err } - logger.Debugf("sending request", workerID) - return syncWorker.executeRequest(request) } - return nil, fmt.Errorf("worker not found") + syncWorker := v.workers[validationCodeHash] + + logger.Debugf("sending request", validationCodeHash) + + validationParams := parachainruntime.ValidationParameters{ + ParentHeadData: msg.PersistedValidationData.ParentHead, + BlockData: msg.PoV.BlockData, + RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, + RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, + } + workTask := &workerTask{ + work: validationParams, + maxPoVSize: msg.PersistedValidationData.MaxPovSize, + candidateReceipt: msg.CandidateReceipt, + } + return syncWorker.executeRequest(workTask) + } func (v *workerPool) containsWorker(workerID parachaintypes.ValidationCodeHash) bool { diff --git a/dot/parachain/candidate-validation/worker_pool_test.go b/dot/parachain/candidate-validation/worker_pool_test.go index bb6cbad635..bf76e51c69 100644 --- a/dot/parachain/candidate-validation/worker_pool_test.go +++ b/dot/parachain/candidate-validation/worker_pool_test.go @@ -30,7 +30,7 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { "add_one_invalid_worker": { setupWorkerPool: func(t *testing.T) *workerPool { pool := newValidationWorkerPool() - _, err := pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) + err := pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) require.Error(t, err) return pool }, @@ -39,7 +39,7 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { "add_one_valid_worker": { setupWorkerPool: func(t *testing.T) *workerPool { pool := newValidationWorkerPool() - _, err := pool.newValidationWorker(testValidationCode) + err := pool.newValidationWorker(testValidationCode) require.NoError(t, err) return pool }, From 3e5ac2809d9e581675fbf1dc0e59e964bb9fedf9 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 4 Sep 2024 11:00:18 -0400 Subject: [PATCH 19/30] make private functions/structs private --- .../candidate-validation/candidate_validation.go | 8 ++++---- .../candidate-validation/candidate_validation_test.go | 4 ++-- dot/parachain/candidate-validation/host.go | 8 ++++---- dot/parachain/candidate-validation/host_test.go | 4 ++-- dot/parachain/candidate-validation/worker.go | 1 - dot/parachain/candidate-validation/worker_pool.go | 5 +++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 15f9a51f6e..ff53d3be02 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -18,7 +18,7 @@ import ( type CandidateValidation struct { SubsystemToOverseer chan<- any BlockState BlockState - pvfHost *Host + pvfHost *host } type BlockState interface { @@ -29,7 +29,7 @@ type BlockState interface { func NewCandidateValidation(overseerChan chan<- any, blockState BlockState) *CandidateValidation { candidateValidation := CandidateValidation{ SubsystemToOverseer: overseerChan, - pvfHost: NewValidationHost(), + pvfHost: newValidationHost(), BlockState: blockState, } return &candidateValidation @@ -86,7 +86,7 @@ func (cv *CandidateValidation) processMessage(msg any) { PvfExecTimeoutKind: msg.PvfExecTimeoutKind, } - result, err := cv.pvfHost.Validate(validationTask) + result, err := cv.pvfHost.validate(validationTask) if err != nil { logger.Errorf("failed to validate from exhaustive: %w", err) @@ -183,7 +183,7 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, } - result, err := cv.pvfHost.Validate(validationTask) + result, err := cv.pvfHost.validate(validationTask) if err != nil { msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Err: err, diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index cee8513d71..8ddd514a8d 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -137,7 +137,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) overseerToSubsystem := make(chan any) sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) candidateValidationSubsystem := CandidateValidation{ - pvfHost: NewValidationHost(), + pvfHost: newValidationHost(), } t.Cleanup(candidateValidationSubsystem.Stop) @@ -371,7 +371,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) toSubsystem := make(chan any) candidateValidationSubsystem := CandidateValidation{ - pvfHost: NewValidationHost(), + pvfHost: newValidationHost(), BlockState: mockBlockState, } defer candidateValidationSubsystem.Stop() diff --git a/dot/parachain/candidate-validation/host.go b/dot/parachain/candidate-validation/host.go index 47f9b438aa..62d71a584c 100644 --- a/dot/parachain/candidate-validation/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -10,17 +10,17 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) -type Host struct { +type host struct { workerPool *workerPool } -func NewValidationHost() *Host { - return &Host{ +func newValidationHost() *host { + return &host{ workerPool: newValidationWorkerPool(), } } -func (v *Host) Validate(msg *ValidationTask) (*ValidationResult, error) { +func (v *host) validate(msg *ValidationTask) (*ValidationResult, error) { validationCodeHash := msg.ValidationCode.Hash() // performBasicChecks validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index 5d6d6fff2c..35a00971c1 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -30,7 +30,7 @@ func TestHost_validate(t *testing.T) { commitmentsHashMismatch := CommitmentsHashMismatch executionError := ExecutionError - pvfHost := NewValidationHost() + pvfHost := newValidationHost() bd, err := scale.Marshal(BlockDataInAdderParachain{ State: uint64(1), @@ -204,7 +204,7 @@ func TestHost_validate(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - taskResult, err := pvfHost.Validate(tt.validationTask) + taskResult, err := pvfHost.validate(tt.validationTask) require.NoError(t, err) require.Equal(t, tt.want, taskResult) diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index 5c5c4c1b14..a4db27355d 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -44,7 +44,6 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { return processed, nil } validationResult, err := w.instance.ValidateBlock(task.work) - if err != nil { logger.Errorf("executing validate_block: %w", err) reasonForInvalidity := ExecutionError diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index 8524dc9ff7..15561a4fc3 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -127,8 +127,9 @@ func (v *workerPool) newValidationWorker(validationCode parachaintypes.Validatio return nil } -// submitRequest given a request, the worker pool will get the worker for a given workerID -// a channel in returned that the response will be dispatch on +// submitRequest given a request, the worker pool will get the worker for a given task and submit the request +// to the worker. The worker will execute the request and return the result. If the worker does not exist, a new worker +// will be created and the request will be submitted to the worker. func (v *workerPool) submitRequest(msg *ValidationTask) (*ValidationResult, error) { validationCodeHash := msg.ValidationCode.Hash() From 3e6f0259faca2349c168899fb1270770638a469e Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 5 Sep 2024 17:36:54 -0400 Subject: [PATCH 20/30] implement function timeout --- dot/parachain/candidate-validation/worker.go | 55 +++++++++++++++++-- .../candidate-validation/worker_pool.go | 4 +- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index a4db27355d..10d0c05596 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -1,11 +1,12 @@ package candidatevalidation import ( + "time" + parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) -// TODO(ed): figure out a better name for this that describes what it does type worker struct { workerID parachaintypes.ValidationCodeHash instance *parachainruntime.Instance @@ -16,6 +17,7 @@ type workerTask struct { work parachainruntime.ValidationParameters maxPoVSize uint32 candidateReceipt *parachaintypes.CandidateReceipt + timeoutKind parachaintypes.PvfExecTimeoutKind } func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { @@ -31,6 +33,26 @@ func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { }, nil } +type resultWithError struct { + result *parachainruntime.ValidationResult + err error +} + +func determineTimeout(timeoutKind parachaintypes.PvfExecTimeoutKind) time.Duration { + value, err := timeoutKind.Value() + if err != nil { + return 2 * time.Second + } + switch value.(type) { + case parachaintypes.Backing: + return 2 * time.Second + case parachaintypes.Approval: + return 12 * time.Second + default: + return 2 * time.Second + } +} + func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) candidateHash, err := parachaintypes.GetCandidateHash(task.candidateReceipt) @@ -43,10 +65,33 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { logger.Debugf("candidate %x already processed", candidateHash) return processed, nil } - validationResult, err := w.instance.ValidateBlock(task.work) - if err != nil { - logger.Errorf("executing validate_block: %w", err) - reasonForInvalidity := ExecutionError + + var validationResult *parachainruntime.ValidationResult + validationResultCh := make(chan (*resultWithError)) + timeoutDuration := determineTimeout(task.timeoutKind) + + go func() { + result, err := w.instance.ValidateBlock(task.work) + if err != nil { + validationResultCh <- &resultWithError{result: nil, err: err} + } + validationResultCh <- &resultWithError{ + result: result, + } + }() + + select { + case validationResultWErr := <-validationResultCh: + if validationResultWErr.err != nil { + logger.Errorf("executing validate_block: %w", err) + reasonForInvalidity := ExecutionError + return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil //nolint + } + validationResult = validationResultWErr.result + + case <-time.After(timeoutDuration): + logger.Errorf("validation timed out") + reasonForInvalidity := Timeout return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil } diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index 15561a4fc3..895184ca60 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -8,8 +8,6 @@ import ( ) type workerPool struct { - - // todo, make sure other functions work with paraID workers map[parachaintypes.ValidationCodeHash]*worker } @@ -150,10 +148,12 @@ func (v *workerPool) submitRequest(msg *ValidationTask) (*ValidationResult, erro RelayParentNumber: msg.PersistedValidationData.RelayParentNumber, RelayParentStorageRoot: msg.PersistedValidationData.RelayParentStorageRoot, } + workTask := &workerTask{ work: validationParams, maxPoVSize: msg.PersistedValidationData.MaxPovSize, candidateReceipt: msg.CandidateReceipt, + timeoutKind: msg.PvfExecTimeoutKind, } return syncWorker.executeRequest(workTask) From 020fb6f9d364572dd836dd304336e53d0bafa142 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 6 Sep 2024 09:19:02 -0400 Subject: [PATCH 21/30] refactor submitRequest to executeRequest --- dot/parachain/candidate-validation/host.go | 2 +- dot/parachain/candidate-validation/worker_pool.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dot/parachain/candidate-validation/host.go b/dot/parachain/candidate-validation/host.go index 62d71a584c..8c6c1f523a 100644 --- a/dot/parachain/candidate-validation/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -36,7 +36,7 @@ func (v *host) validate(msg *ValidationTask) (*ValidationResult, error) { } // submit request - return v.workerPool.submitRequest(msg) + return v.workerPool.executeRequest(msg) } // performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index 15561a4fc3..a970aef47a 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -127,10 +127,10 @@ func (v *workerPool) newValidationWorker(validationCode parachaintypes.Validatio return nil } -// submitRequest given a request, the worker pool will get the worker for a given task and submit the request +// executeRequest given a request, the worker pool will get the worker for a given task and submit the request // to the worker. The worker will execute the request and return the result. If the worker does not exist, a new worker // will be created and the request will be submitted to the worker. -func (v *workerPool) submitRequest(msg *ValidationTask) (*ValidationResult, error) { +func (v *workerPool) executeRequest(msg *ValidationTask) (*ValidationResult, error) { validationCodeHash := msg.ValidationCode.Hash() // create worker if not in pool From cdc35143d46001ad3aad7fc9651aa450da7051a4 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 6 Sep 2024 16:50:15 -0400 Subject: [PATCH 22/30] add test for candidate-validation timeout --- .../mocks_generate_test.go | 1 + .../mocks_validation_instance_test.go | 55 +++++++ dot/parachain/candidate-validation/worker.go | 6 +- .../candidate-validation/worker_test.go | 140 ++++++++++++++++++ dot/parachain/runtime/instance.go | 5 + 5 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 dot/parachain/candidate-validation/mocks_validation_instance_test.go create mode 100644 dot/parachain/candidate-validation/worker_test.go diff --git a/dot/parachain/candidate-validation/mocks_generate_test.go b/dot/parachain/candidate-validation/mocks_generate_test.go index 4cab5225ad..c8f6f93b07 100644 --- a/dot/parachain/candidate-validation/mocks_generate_test.go +++ b/dot/parachain/candidate-validation/mocks_generate_test.go @@ -6,3 +6,4 @@ package candidatevalidation //go:generate mockgen -destination=mocks_test.go -package=$GOPACKAGE . PoVRequestor //go:generate mockgen -destination=mocks_blockstate_test.go -package=$GOPACKAGE . BlockState //go:generate mockgen -destination=mocks_instance_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/lib/runtime Instance +//go:generate mockgen -destination=mocks_validation_instance_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/dot/parachain/runtime ValidatorInstance diff --git a/dot/parachain/candidate-validation/mocks_validation_instance_test.go b/dot/parachain/candidate-validation/mocks_validation_instance_test.go new file mode 100644 index 0000000000..519357cfe7 --- /dev/null +++ b/dot/parachain/candidate-validation/mocks_validation_instance_test.go @@ -0,0 +1,55 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/dot/parachain/runtime (interfaces: ValidatorInstance) +// +// Generated by this command: +// +// mockgen -destination=mocks_validation_instance_test.go -package candidatevalidation github.com/ChainSafe/gossamer/dot/parachain/runtime ValidatorInstance +// + +// Package candidatevalidation is a generated GoMock package. +package candidatevalidation + +import ( + reflect "reflect" + + parachain "github.com/ChainSafe/gossamer/dot/parachain/runtime" + gomock "go.uber.org/mock/gomock" +) + +// MockValidatorInstance is a mock of ValidatorInstance interface. +type MockValidatorInstance struct { + ctrl *gomock.Controller + recorder *MockValidatorInstanceMockRecorder +} + +// MockValidatorInstanceMockRecorder is the mock recorder for MockValidatorInstance. +type MockValidatorInstanceMockRecorder struct { + mock *MockValidatorInstance +} + +// NewMockValidatorInstance creates a new mock instance. +func NewMockValidatorInstance(ctrl *gomock.Controller) *MockValidatorInstance { + mock := &MockValidatorInstance{ctrl: ctrl} + mock.recorder = &MockValidatorInstanceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockValidatorInstance) EXPECT() *MockValidatorInstanceMockRecorder { + return m.recorder +} + +// ValidateBlock mocks base method. +func (m *MockValidatorInstance) ValidateBlock(arg0 parachain.ValidationParameters) (*parachain.ValidationResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateBlock", arg0) + ret0, _ := ret[0].(*parachain.ValidationResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateBlock indicates an expected call of ValidateBlock. +func (mr *MockValidatorInstanceMockRecorder) ValidateBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateBlock", reflect.TypeOf((*MockValidatorInstance)(nil).ValidateBlock), arg0) +} diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index 10d0c05596..abd345ce65 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -1,6 +1,7 @@ package candidatevalidation import ( + "fmt" "time" parachainruntime "github.com/ChainSafe/gossamer/dot/parachain/runtime" @@ -9,7 +10,7 @@ import ( type worker struct { workerID parachaintypes.ValidationCodeHash - instance *parachainruntime.Instance + instance parachainruntime.ValidatorInstance isProcessed map[parachaintypes.CandidateHash]*ValidationResult } @@ -54,6 +55,9 @@ func determineTimeout(timeoutKind parachaintypes.PvfExecTimeoutKind) time.Durati } func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { + if task == nil { + return nil, fmt.Errorf("task is nil") + } logger.Debugf("[EXECUTING] worker %x task %v", w.workerID, task.work) candidateHash, err := parachaintypes.GetCandidateHash(task.candidateReceipt) if err != nil { diff --git a/dot/parachain/candidate-validation/worker_test.go b/dot/parachain/candidate-validation/worker_test.go new file mode 100644 index 0000000000..636cea0bf7 --- /dev/null +++ b/dot/parachain/candidate-validation/worker_test.go @@ -0,0 +1,140 @@ +package candidatevalidation + +import ( + "testing" + "time" + + parachain "github.com/ChainSafe/gossamer/dot/parachain/runtime" + parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func Test_worker_executeRequest(t *testing.T) { + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + + validationRuntime, err := parachain.SetupVM(validationCode) + require.NoError(t, err) + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + + mockValidationInstance := NewMockValidatorInstance(ctrl) + mockValidationInstance.EXPECT().ValidateBlock(gomock.Any()).DoAndReturn(func(params parachain. + ValidationParameters) (*parachain.ValidationResult, error) { + time.Sleep(3 * time.Second) // sleep to simulate long execution time + return ¶chain.ValidationResult{}, nil + }) + + candidateReceiptCommitmentsMismatch := candidateReceipt + candidateReceiptCommitmentsMismatch.CommitmentsHash = common.MustHexToHash( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + + // NOTE: adder parachain internally compares postState with bd.State in it's validate_block, + // so following is necessary. + encodedState, err := scale.Marshal(uint64(1)) + require.NoError(t, err) + postState, err := common.Keccak256(encodedState) + require.NoError(t, err) + + hd, err := scale.Marshal(HeadDataInAdderParachain{ + Number: uint64(1), + ParentHash: common.MustHexToHash("0x0102030405060708090001020304050607080900010203040506070809000102"), + PostState: postState, + }) + require.NoError(t, err) + + blockData, err := scale.Marshal(BlockDataInAdderParachain{ + State: uint64(1), + Add: uint64(1), + }) + require.NoError(t, err) + + commitmentsHashMismatch := CommitmentsHashMismatch + timeout := Timeout + + tests := map[string]struct { + instance parachain.ValidatorInstance + task *workerTask + want *ValidationResult + }{ + "commitments_hash_mismatch": { + instance: validationRuntime, + task: &workerTask{ + work: parachain.ValidationParameters{ + ParentHeadData: parachaintypes.HeadData{Data: hd}, + BlockData: blockData, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + }, + maxPoVSize: uint32(2048), + candidateReceipt: &candidateReceiptCommitmentsMismatch, + }, + want: &ValidationResult{ + InvalidResult: &commitmentsHashMismatch, + }, + }, + "execution_timeout": { + instance: mockValidationInstance, + task: &workerTask{ + candidateReceipt: &candidateReceipt, + }, + want: &ValidationResult{ + InvalidResult: &timeout, + }, + }, + "happy_path": { + instance: validationRuntime, + task: &workerTask{ + work: parachain.ValidationParameters{ + ParentHeadData: parachaintypes.HeadData{Data: hd}, + BlockData: blockData, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + }, + maxPoVSize: uint32(2048), + candidateReceipt: &candidateReceipt, + timeoutKind: parachaintypes.PvfExecTimeoutKind{}, + }, + want: &ValidationResult{ + ValidResult: &Valid{ + CandidateCommitments: parachaintypes.CandidateCommitments{ + UpwardMessages: nil, + HorizontalMessages: nil, + NewValidationCode: nil, + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + }, + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, + 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, + 15, 1, 168, 127, 226}}, + RelayParentNumber: 1, + RelayParentStorageRoot: common.MustHexToHash( + "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: 2048, + }, + }, + }, + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + w := &worker{ + instance: tt.instance, + isProcessed: make(map[parachaintypes.CandidateHash]*ValidationResult), + } + got, err := w.executeRequest(tt.task) + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/dot/parachain/runtime/instance.go b/dot/parachain/runtime/instance.go index 41b01bfff5..57dca6606b 100644 --- a/dot/parachain/runtime/instance.go +++ b/dot/parachain/runtime/instance.go @@ -89,6 +89,11 @@ func (in *Instance) ValidateBlock(params ValidationParameters) ( return &validationResult, nil } +// ValidatorInstance +type ValidatorInstance interface { + ValidateBlock(params ValidationParameters) (*ValidationResult, error) +} + // RuntimeInstance for runtime methods type RuntimeInstance interface { ParachainHostPersistedValidationData(parachaidID uint32, assumption parachaintypes.OccupiedCoreAssumption, From 31b83f166ec2e6dafda1db53a42d55535a275983 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 10 Sep 2024 19:05:46 -0400 Subject: [PATCH 23/30] handle validation errors InvalidOutputs and BadParent --- .../candidate_validation.go | 37 +++++++++- .../candidate_validation_test.go | 73 +++++++++++++++---- .../candidate-validation/host_test.go | 2 +- .../candidate-validation/worker_test.go | 2 +- 4 files changed, 98 insertions(+), 16 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index ff53d3be02..945b31d51f 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -165,6 +165,7 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState persistedValidationData, validationCode, err := getValidationData(runtimeInstance, msg.CandidateReceipt.Descriptor.ParaID) + if err != nil { logger.Errorf("getting validation data: %w", err) msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ @@ -173,6 +174,16 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState return } + if persistedValidationData == nil { + badParent := BadParent + reason := ValidationResult{ + InvalidResult: &badParent, + } + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: reason, + } + return + } validationTask := &ValidationTask{ PersistedValidationData: *persistedValidationData, ValidationCode: validationCode, @@ -188,9 +199,33 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Err: err, } - } else { + return + } + if !result.IsValid() { msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Data: *result, } + return + } + valid, err := runtimeInstance.ParachainHostCheckValidationOutputs(parachaintypes.ParaID(msg.CandidateReceipt. + Descriptor.ParaID), result.ValidResult.CandidateCommitments) + if err != nil { + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Err: fmt.Errorf("check validation outputs: Bad request: %w", err), + } + return + } + if !valid { + invalidOutput := InvalidOutputs + reason := &ValidationResult{ + InvalidResult: &invalidOutput, + } + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: *reason, + } + return + } + msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ + Data: *result, } } diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 8ddd514a8d..e94b322dec 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -22,9 +22,11 @@ var ( paramsTooLarge = ParamsTooLarge codeHashMismatch = CodeHashMismatch badSignature = BadSignature + invalidOutputs = InvalidOutputs + badParent = BadParent ) -func createTestCandidateReceiptAndValidationCode(t *testing.T) ( +func createTestCandidateReceiptAndValidationCodeWParaId(t *testing.T, id uint32) ( parachaintypes.CandidateReceipt, parachaintypes.ValidationCode) { // this wasm was achieved by building polkadot's adder test parachain runtimeFilePath := "./testdata/test_parachain_adder.wasm" @@ -38,7 +40,7 @@ func createTestCandidateReceiptAndValidationCode(t *testing.T) ( collatorKeypair, err := sr25519.GenerateKeypair() require.NoError(t, err) - descriptor := makeValidCandidateDescriptor(t, 1000, + descriptor := makeValidCandidateDescriptor(t, id, common.MustHexToHash("0xded542bacb3ca6c033a57676f94ae7c8f36834511deb44e3164256fd3b1c0de0"), common.MustHexToHash("0x690d8f252ef66ab0f969c3f518f90012b849aa5ac94e1752c5e5ae5a8996de37"), common.MustHexToHash("0xb608991ffc48dd405fd4b10e92eaebe2b5a2eedf44d0c3efb8997fdee8bebed9"), @@ -107,7 +109,7 @@ func TestCandidateValidation_wasm_invalid_magic_number(t *testing.T) { func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) { t.Parallel() - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCodeWParaId(t, 1000) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") @@ -261,7 +263,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) { t.Parallel() - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCodeWParaId(t, 1000) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") @@ -278,6 +280,11 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) candidateReceipt5 := candidateReceipt candidateReceipt5.Descriptor.ParaID = 5 + candidateReceipt6, _ := createTestCandidateReceiptAndValidationCodeWParaId(t, 6) + + candidateReceipt7 := candidateReceipt + candidateReceipt7.Descriptor.ParaID = 7 + ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) @@ -318,6 +325,16 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) mockInstance.EXPECT(). ParachainHostValidationCode(uint32(1000), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). Return(&validationCode, nil) + validCandidateCommitments := parachaintypes.CandidateCommitments{ + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + } + mockInstance.EXPECT().ParachainHostCheckValidationOutputs(parachaintypes.ParaID(1000), + validCandidateCommitments).Return(true, nil) mockInstance.EXPECT(). ParachainHostPersistedValidationData( @@ -355,9 +372,26 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) ParachainHostValidationCode(uint32(5), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). Return(&validationCode, nil) + mockInstance.EXPECT(). + ParachainHostPersistedValidationData(uint32(6), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&expectedPersistedValidationData, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(6), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + mockInstance.EXPECT().ParachainHostCheckValidationOutputs(parachaintypes.ParaID(6), + validCandidateCommitments).Return(false, nil) + + mockInstance.EXPECT(). + ParachainHostPersistedValidationData(uint32(7), gomock.AssignableToTypeOf(parachaintypes. + OccupiedCoreAssumption{})). + Return(nil, nil) + mockInstance.EXPECT(). + ParachainHostValidationCode(uint32(7), gomock.AssignableToTypeOf(parachaintypes.OccupiedCoreAssumption{})). + Return(&validationCode, nil) + mockBlockState := NewMockBlockState(ctrl) mockBlockState.EXPECT().GetRuntime(common.MustHexToHash( - "0xded542bacb3ca6c033a57676f94ae7c8f36834511deb44e3164256fd3b1c0de0")).Return(mockInstance, nil).Times(5) + "0xded542bacb3ca6c033a57676f94ae7c8f36834511deb44e3164256fd3b1c0de0")).Return(mockInstance, nil).Times(7) bd, err := scale.Marshal(BlockDataInAdderParachain{ State: uint64(1), @@ -423,6 +457,26 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) InvalidResult: &badSignature, }, }, + "invalid_outputs": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt6, + Pov: pov, + Ch: sender, + }, + want: &ValidationResult{ + InvalidResult: &invalidOutputs, + }, + }, + "bad_parent": { + msg: ValidateFromChainState{ + CandidateReceipt: candidateReceipt7, + Pov: pov, + Ch: sender, + }, + want: &ValidationResult{ + InvalidResult: &badParent, + }, + }, "happy_path": { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt, @@ -431,14 +485,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) }, want: &ValidationResult{ ValidResult: &Valid{ - CandidateCommitments: parachaintypes.CandidateCommitments{ - HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, - 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, - 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, - 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, - ProcessedDownwardMessages: 0, - HrmpWatermark: 1, - }, + CandidateCommitments: validCandidateCommitments, PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index 35a00971c1..ac30870c8e 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -12,7 +12,7 @@ import ( func TestHost_validate(t *testing.T) { t.Parallel() - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCodeWParaId(t, 1000) candidateReceipt2 := candidateReceipt candidateReceipt2.Descriptor.PovHash = common.MustHexToHash( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") diff --git a/dot/parachain/candidate-validation/worker_test.go b/dot/parachain/candidate-validation/worker_test.go index 636cea0bf7..ad1c8e6ddc 100644 --- a/dot/parachain/candidate-validation/worker_test.go +++ b/dot/parachain/candidate-validation/worker_test.go @@ -13,7 +13,7 @@ import ( ) func Test_worker_executeRequest(t *testing.T) { - candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCode(t) + candidateReceipt, validationCode := createTestCandidateReceiptAndValidationCodeWParaId(t, 1000) validationRuntime, err := parachain.SetupVM(validationCode) require.NoError(t, err) From c96f6e8a2378c5a3b15f75861dea9ba4dfb2c843 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 11 Sep 2024 08:46:43 -0400 Subject: [PATCH 24/30] add addition validation timeout tests --- .../candidate_validation.go | 2 - .../candidate-validation/worker_test.go | 85 ++++++++++++------- 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 945b31d51f..44882c5aa1 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -190,8 +190,6 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState CandidateReceipt: &msg.CandidateReceipt, PoV: msg.Pov, ExecutorParams: msg.ExecutorParams, - // todo: implement PvfExecTimeoutKind, so that validate can be called with a timeout see issue: #3429 - PvfExecTimeoutKind: parachaintypes.PvfExecTimeoutKind{}, } result, err := cv.pvfHost.validate(validationTask) diff --git a/dot/parachain/candidate-validation/worker_test.go b/dot/parachain/candidate-validation/worker_test.go index ad1c8e6ddc..e265f82c85 100644 --- a/dot/parachain/candidate-validation/worker_test.go +++ b/dot/parachain/candidate-validation/worker_test.go @@ -21,12 +21,43 @@ func Test_worker_executeRequest(t *testing.T) { ctrl := gomock.NewController(t) t.Cleanup(ctrl.Finish) + expectedValidationResult := &ValidationResult{ + ValidResult: &Valid{ + CandidateCommitments: parachaintypes.CandidateCommitments{ + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + }, + PersistedValidationData: parachaintypes.PersistedValidationData{ + ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, + 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, + 15, 1, 168, 127, 226}}, + RelayParentNumber: 1, + RelayParentStorageRoot: common.MustHexToHash( + "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + MaxPovSize: 2048, + }, + }, + } + mockValidationInstance := NewMockValidatorInstance(ctrl) - mockValidationInstance.EXPECT().ValidateBlock(gomock.Any()).DoAndReturn(func(params parachain. + mockValidationInstance.EXPECT().ValidateBlock(gomock.Any()).DoAndReturn(func(parachain. ValidationParameters) (*parachain.ValidationResult, error) { - time.Sleep(3 * time.Second) // sleep to simulate long execution time - return ¶chain.ValidationResult{}, nil - }) + time.Sleep(3 * time.Second) // sleep to simulate execution time + return ¶chain.ValidationResult{ + HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, + 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, + 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, + 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, + ProcessedDownwardMessages: 0, + HrmpWatermark: 1, + }, nil + }).Times(2) candidateReceiptCommitmentsMismatch := candidateReceipt candidateReceiptCommitmentsMismatch.CommitmentsHash = common.MustHexToHash( @@ -52,6 +83,10 @@ func Test_worker_executeRequest(t *testing.T) { }) require.NoError(t, err) + timeoutKind := parachaintypes.NewPvfExecTimeoutKind() + err = timeoutKind.SetValue(parachaintypes.Approval{}) + require.NoError(t, err) + commitmentsHashMismatch := CommitmentsHashMismatch timeout := Timeout @@ -85,6 +120,21 @@ func Test_worker_executeRequest(t *testing.T) { InvalidResult: &timeout, }, }, + "long_timeout_ok": { + instance: mockValidationInstance, + task: &workerTask{ + work: parachain.ValidationParameters{ + ParentHeadData: parachaintypes.HeadData{Data: hd}, + BlockData: blockData, + RelayParentNumber: uint32(1), + RelayParentStorageRoot: common.MustHexToHash("0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), + }, + candidateReceipt: &candidateReceipt, + timeoutKind: timeoutKind, + maxPoVSize: 2048, + }, + want: expectedValidationResult, + }, "happy_path": { instance: validationRuntime, task: &workerTask{ @@ -98,32 +148,7 @@ func Test_worker_executeRequest(t *testing.T) { candidateReceipt: &candidateReceipt, timeoutKind: parachaintypes.PvfExecTimeoutKind{}, }, - want: &ValidationResult{ - ValidResult: &Valid{ - CandidateCommitments: parachaintypes.CandidateCommitments{ - UpwardMessages: nil, - HorizontalMessages: nil, - NewValidationCode: nil, - HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, - 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, - 164, 169, 22, 46, 144, 39, 103, 92, 31, 78, 66, 72, 252, 64, 24, 194, 129, 162, 128, 1, 77, 147, - 200, 229, 189, 242, 111, 198, 236, 139, 16, 143, 19, 245, 113, 233, 138, 210}}, - ProcessedDownwardMessages: 0, - HrmpWatermark: 1, - }, - PersistedValidationData: parachaintypes.PersistedValidationData{ - ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0, 1, 2, 48, 246, 146, 178, 86, 226, 64, 9, - 188, 179, 77, 14, 232, 77, 167, 60, 41, 138, 250, 204, 9, 36, 224, 17, 5, 226, 235, - 15, 1, 168, 127, 226}}, - RelayParentNumber: 1, - RelayParentStorageRoot: common.MustHexToHash( - "0x50c969706800c0e9c3c4565dc2babb25e4a73d1db0dee1bcf7745535a32e7ca1"), - MaxPovSize: 2048, - }, - }, - }, + want: expectedValidationResult, }, } for name, tt := range tests { From b8bbeb22371e80faf7af052e42c70b4eafce22fa Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 11 Sep 2024 11:44:10 -0400 Subject: [PATCH 25/30] address PR comments --- .../candidate-validation/candidate_validation.go | 2 +- .../candidate-validation/candidate_validation_test.go | 9 +++------ dot/parachain/candidate-validation/host.go | 1 + dot/parachain/candidate-validation/host_test.go | 6 +++++- dot/parachain/candidate-validation/worker.go | 1 - dot/parachain/candidate-validation/worker_pool.go | 2 -- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index ff53d3be02..9f61d336eb 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -18,7 +18,7 @@ import ( type CandidateValidation struct { SubsystemToOverseer chan<- any BlockState BlockState - pvfHost *host + pvfHost *host // pvfHost is the host for the parachain validation function } type BlockState interface { diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 8ddd514a8d..d1cfa93115 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -368,7 +368,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) BlockData: bd, } - sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) toSubsystem := make(chan any) candidateValidationSubsystem := CandidateValidation{ pvfHost: newValidationHost(), @@ -387,7 +386,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt2, Pov: pov, - Ch: sender, }, want: &ValidationResult{ InvalidResult: &povHashMismatch, @@ -397,7 +395,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt3, Pov: pov, - Ch: sender, }, want: &ValidationResult{ InvalidResult: ¶msTooLarge, @@ -407,7 +404,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt4, Pov: pov, - Ch: sender, }, want: &ValidationResult{ InvalidResult: &codeHashMismatch, @@ -417,7 +413,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt5, Pov: pov, - Ch: sender, }, want: &ValidationResult{ InvalidResult: &badSignature, @@ -427,7 +422,6 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt, Pov: pov, - Ch: sender, }, want: &ValidationResult{ ValidResult: &Valid{ @@ -459,6 +453,9 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) t.Run(name, func(t *testing.T) { t.Parallel() + sender := make(chan parachaintypes.OverseerFuncRes[ValidationResult]) + tt.msg.Ch = sender + toSubsystem <- tt.msg result := <-sender require.Equal(t, tt.want, &result.Data) diff --git a/dot/parachain/candidate-validation/host.go b/dot/parachain/candidate-validation/host.go index 8c6c1f523a..7b0e832273 100644 --- a/dot/parachain/candidate-validation/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -10,6 +10,7 @@ import ( var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) +// host is the struct that holds the workerPool which is responsible for executing the validation tasks type host struct { workerPool *workerPool } diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index 35a00971c1..e48f45c460 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -214,6 +214,7 @@ func TestHost_validate(t *testing.T) { } func TestHost_performBasicChecks(t *testing.T) { + t.Parallel() paramsTooLarge := ParamsTooLarge povHashMismatch := PoVHashMismatch codeHashMismatch := CodeHashMismatch @@ -313,9 +314,12 @@ func TestHost_performBasicChecks(t *testing.T) { }, } for name, tt := range tests { + tt := tt t.Run(name, func(t *testing.T) { - validationError, _ := performBasicChecks(tt.args.candidate, tt.args.maxPoVSize, tt.args.pov, + t.Parallel() + validationError, internalError := performBasicChecks(tt.args.candidate, tt.args.maxPoVSize, tt.args.pov, tt.args.validationCodeHash) + require.NoError(t, internalError) if tt.expectedError != nil { require.EqualError(t, validationError, tt.expectedError.Error()) } else { diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index a4db27355d..5f45e8e55c 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -5,7 +5,6 @@ import ( parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) -// TODO(ed): figure out a better name for this that describes what it does type worker struct { workerID parachaintypes.ValidationCodeHash instance *parachainruntime.Instance diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index a970aef47a..2bff748fbd 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -8,8 +8,6 @@ import ( ) type workerPool struct { - - // todo, make sure other functions work with paraID workers map[parachaintypes.ValidationCodeHash]*worker } From 25d95bdcb959fb92d944c452a6f344bcf9ca87f7 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 13 Sep 2024 15:08:25 -0400 Subject: [PATCH 26/30] address PR comments, rename variables and functions --- .../backing/candidate_backing_test.go | 4 +-- dot/parachain/backing/integration_test.go | 4 +-- .../backing/per_relay_parent_state.go | 8 ++--- .../candidate_validation_test.go | 18 +++++----- dot/parachain/candidate-validation/host.go | 12 +++---- .../candidate-validation/host_test.go | 16 ++++----- dot/parachain/candidate-validation/worker.go | 19 ++++++----- .../candidate-validation/worker_pool.go | 33 ++++++++++--------- .../candidate-validation/worker_pool_test.go | 8 ++--- dot/parachain/runtime/instance.go | 5 +++ 10 files changed, 67 insertions(+), 60 deletions(-) diff --git a/dot/parachain/backing/candidate_backing_test.go b/dot/parachain/backing/candidate_backing_test.go index 4aa1c454b8..eb2c29da12 100644 --- a/dot/parachain/backing/candidate_backing_test.go +++ b/dot/parachain/backing/candidate_backing_test.go @@ -731,7 +731,7 @@ func TestValidateAndMakeAvailable(t *testing.T) { ci := candidatevalidation.ExecutionError data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - InvalidResult: &ci, + Invalid: &ci, }, } default: @@ -768,7 +768,7 @@ func TestValidateAndMakeAvailable(t *testing.T) { case candidatevalidation.ValidateFromExhaustive: data.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.Valid{}, + Valid: &candidatevalidation.Valid{}, }, } case availabilitystore.StoreAvailableData: diff --git a/dot/parachain/backing/integration_test.go b/dot/parachain/backing/integration_test.go index 52e84a71dd..53f3415554 100644 --- a/dot/parachain/backing/integration_test.go +++ b/dot/parachain/backing/integration_test.go @@ -227,7 +227,7 @@ func validResponseForValidateFromExhaustive( msgValidate.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - ValidResult: &candidatevalidation.Valid{ + Valid: &candidatevalidation.Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: headData, UpwardMessages: []parachaintypes.UpwardMessage{}, @@ -337,7 +337,7 @@ func TestSecondsValidCandidate(t *testing.T) { badReturn := candidatevalidation.BadReturn validateFromExhaustive.Ch <- parachaintypes.OverseerFuncRes[candidatevalidation.ValidationResult]{ Data: candidatevalidation.ValidationResult{ - InvalidResult: &badReturn, + Invalid: &badReturn, }, } return true diff --git a/dot/parachain/backing/per_relay_parent_state.go b/dot/parachain/backing/per_relay_parent_state.go index d9e90fb5a2..4c4b2861af 100644 --- a/dot/parachain/backing/per_relay_parent_state.go +++ b/dot/parachain/backing/per_relay_parent_state.go @@ -340,8 +340,8 @@ func (rpState *perRelayParentState) validateAndMakeAvailable( bgValidationResult = backgroundValidationResult{ outputs: &backgroundValidationOutputs{ candidateReceipt: candidateReceipt, - candidateCommitments: validationResultRes.Data.ValidResult.CandidateCommitments, - persistedValidationData: validationResultRes.Data.ValidResult.PersistedValidationData, + candidateCommitments: validationResultRes.Data.Valid.CandidateCommitments, + persistedValidationData: validationResultRes.Data.Valid.PersistedValidationData, }, candidate: nil, err: nil, @@ -358,11 +358,11 @@ func (rpState *perRelayParentState) validateAndMakeAvailable( } } else { // Invalid - logger.Error(validationResultRes.Data.InvalidResult.Error()) + logger.Error(validationResultRes.Data.Invalid.Error()) bgValidationResult = backgroundValidationResult{ outputs: nil, candidate: &candidateReceipt, - err: fmt.Errorf(validationResultRes.Data.InvalidResult.Error()), + err: fmt.Errorf(validationResultRes.Data.Invalid.Error()), } } diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index d1cfa93115..9e2050ddcc 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -164,7 +164,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, want: parachaintypes.OverseerFuncRes[ValidationResult]{ Data: ValidationResult{ - InvalidResult: &povHashMismatch, + Invalid: &povHashMismatch, }, Err: nil, }, @@ -184,7 +184,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, want: parachaintypes.OverseerFuncRes[ValidationResult]{ Data: ValidationResult{ - InvalidResult: ¶msTooLarge, + Invalid: ¶msTooLarge, }, }, }, @@ -203,7 +203,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, want: parachaintypes.OverseerFuncRes[ValidationResult]{ Data: ValidationResult{ - InvalidResult: &codeHashMismatch, + Invalid: &codeHashMismatch, }, }, }, @@ -222,7 +222,7 @@ func TestCandidateValidation_processMessageValidateFromExhaustive(t *testing.T) }, want: parachaintypes.OverseerFuncRes[ValidationResult]{ Data: ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, @@ -388,7 +388,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - InvalidResult: &povHashMismatch, + Invalid: &povHashMismatch, }, }, "invalid_pov_size": { @@ -397,7 +397,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - InvalidResult: ¶msTooLarge, + Invalid: ¶msTooLarge, }, }, "code_mismatch": { @@ -406,7 +406,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - InvalidResult: &codeHashMismatch, + Invalid: &codeHashMismatch, }, }, "bad_signature": { @@ -415,7 +415,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - InvalidResult: &badSignature, + Invalid: &badSignature, }, }, "happy_path": { @@ -424,7 +424,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, diff --git a/dot/parachain/candidate-validation/host.go b/dot/parachain/candidate-validation/host.go index 7b0e832273..8b192d82e4 100644 --- a/dot/parachain/candidate-validation/host.go +++ b/dot/parachain/candidate-validation/host.go @@ -8,7 +8,7 @@ import ( "github.com/ChainSafe/gossamer/pkg/scale" ) -var logger = log.NewFromGlobal(log.AddContext("pkg", "pvf"), log.SetLevel(log.Debug)) +var logger = log.NewFromGlobal(log.AddContext("pkg", "candidatevalidation"), log.SetLevel(log.Debug)) // host is the struct that holds the workerPool which is responsible for executing the validation tasks type host struct { @@ -17,13 +17,12 @@ type host struct { func newValidationHost() *host { return &host{ - workerPool: newValidationWorkerPool(), + workerPool: newWorkerPool(), } } func (v *host) validate(msg *ValidationTask) (*ValidationResult, error) { validationCodeHash := msg.ValidationCode.Hash() - // performBasicChecks validationErr, internalErr := performBasicChecks(&msg.CandidateReceipt.Descriptor, msg.PersistedValidationData.MaxPovSize, msg.PoV, @@ -33,15 +32,15 @@ func (v *host) validate(msg *ValidationTask) (*ValidationResult, error) { return nil, internalErr } if validationErr != nil { - return &ValidationResult{InvalidResult: validationErr}, nil //nolint + return &ValidationResult{Invalid: validationErr}, nil //nolint } // submit request return v.workerPool.executeRequest(msg) } -// performBasicChecks Does basic checks of a candidate. Provide the encoded PoV-block. -// Returns ReasonForInvalidity and internal error if any. +// performBasicChecks does basic checks of a candidate. Provided the encoded PoV-block it returns ReasonForInvalidity +// and internal error if any. func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSize uint32, pov parachaintypes.PoV, validationCodeHash parachaintypes.ValidationCodeHash) ( validationError *ReasonForInvalidity, internalError error) { @@ -76,5 +75,6 @@ func performBasicChecks(candidate *parachaintypes.CandidateDescriptor, maxPoVSiz ci := BadSignature return &ci, nil } + return nil, nil } diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index e48f45c460..5491dfd4b4 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -74,7 +74,7 @@ func TestHost_validate(t *testing.T) { ValidationCode: &validationCode, }, want: &ValidationResult{ - InvalidResult: &povHashMismatch, + Invalid: &povHashMismatch, }, isValid: false, }, @@ -91,7 +91,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - InvalidResult: ¶msTooLarge, + Invalid: ¶msTooLarge, }, }, "code_mismatch": { @@ -107,7 +107,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - InvalidResult: &codeHashMismatch, + Invalid: &codeHashMismatch, }, isValid: false, }, @@ -121,7 +121,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - InvalidResult: &executionError, + Invalid: &executionError, }, }, "para_head_hash_mismatch": { @@ -137,7 +137,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - InvalidResult: ¶HedHashMismatch, + Invalid: ¶HedHashMismatch, }, isValid: false, }, @@ -154,7 +154,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - InvalidResult: &commitmentsHashMismatch, + Invalid: &commitmentsHashMismatch, }, isValid: false, }, @@ -171,7 +171,7 @@ func TestHost_validate(t *testing.T) { PoV: pov, }, want: &ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ UpwardMessages: nil, HorizontalMessages: nil, @@ -323,7 +323,7 @@ func TestHost_performBasicChecks(t *testing.T) { if tt.expectedError != nil { require.EqualError(t, validationError, tt.expectedError.Error()) } else { - require.Nil(t, validationError) + require.NoError(t, validationError) } }) } diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index 5f45e8e55c..4a38bdb9a5 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -5,9 +5,10 @@ import ( parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" ) +// worker is the thing that can execute a validation request type worker struct { workerID parachaintypes.ValidationCodeHash - instance *parachainruntime.Instance + instance parachainruntime.ValidatorInstance isProcessed map[parachaintypes.CandidateHash]*ValidationResult } @@ -18,14 +19,15 @@ type workerTask struct { } func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { - validationRuntime, err := parachainruntime.SetupVM(validationCode) + parachainRuntime, err := parachainruntime.SetupVM(validationCode) if err != nil { return nil, err } + return &worker{ workerID: validationCode.Hash(), - instance: validationRuntime, + instance: parachainRuntime, isProcessed: make(map[parachaintypes.CandidateHash]*ValidationResult), }, nil } @@ -37,7 +39,6 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { return nil, err } - // do isProcessed check here if processed, ok := w.isProcessed[candidateHash]; ok { logger.Debugf("candidate %x already processed", candidateHash) return processed, nil @@ -46,19 +47,19 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { if err != nil { logger.Errorf("executing validate_block: %w", err) reasonForInvalidity := ExecutionError - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + return &ValidationResult{Invalid: &reasonForInvalidity}, nil } headDataHash, err := validationResult.HeadData.Hash() if err != nil { logger.Errorf("hashing head data: %w", err) reasonForInvalidity := ExecutionError - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + return &ValidationResult{Invalid: &reasonForInvalidity}, nil } if headDataHash != task.candidateReceipt.Descriptor.ParaHead { reasonForInvalidity := ParaHeadHashMismatch - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + return &ValidationResult{Invalid: &reasonForInvalidity}, nil } candidateCommitments := parachaintypes.CandidateCommitments{ UpwardMessages: validationResult.UpwardMessages, @@ -72,7 +73,7 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { // if validation produced a new set of commitments, we treat the candidate as invalid if task.candidateReceipt.CommitmentsHash != candidateCommitments.Hash() { reasonForInvalidity := CommitmentsHashMismatch - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + return &ValidationResult{Invalid: &reasonForInvalidity}, nil } pvd := parachaintypes.PersistedValidationData{ ParentHead: task.work.ParentHeadData, @@ -81,7 +82,7 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { MaxPovSize: task.maxPoVSize, } result := &ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: candidateCommitments, PersistedValidationData: pvd, }, diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index 2bff748fbd..46f8dad514 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -22,20 +22,18 @@ type ValidationTask struct { } // ValidationResult represents the result coming from the candidate validation subsystem. -// Validation results can be either a Valid or InvalidValidationResult. +// Validation results can be either valid or invalid. // -// If the result is invalid, -// store the reason for invalidity in the InvalidResult field of ValidationResult. +// If the result is invalid, store the reason for invalidity. // -// If the result is valid, -// set the values of the ValidResult field of Valid. +// If the result is valid, store persisted validation data and candidate commitments. type ValidationResult struct { - ValidResult *Valid - InvalidResult *ReasonForInvalidity + Valid *Valid + Invalid *ReasonForInvalidity } func (vr ValidationResult) IsValid() bool { - return vr.ValidResult != nil + return vr.Valid != nil } type Valid struct { @@ -107,20 +105,23 @@ func (ci ReasonForInvalidity) Error() string { } } -func newValidationWorkerPool() *workerPool { +func newWorkerPool() *workerPool { return &workerPool{ workers: make(map[parachaintypes.ValidationCodeHash]*worker), } } -func (v *workerPool) newValidationWorker(validationCode parachaintypes.ValidationCode) error { +func (v *workerPool) addNewWorker(validationCode parachaintypes.ValidationCode) error { + workerID := validationCode.Hash() + if !v.containsWorker(workerID) { + worker, err := newWorker(validationCode) + if err != nil { + return fmt.Errorf("failed to create a new worker: %w", err) + } - worker, err := newWorker(validationCode) - if err != nil { - return fmt.Errorf("failed to create a new worker: %w", err) - } + v.workers[workerID] = worker - v.workers[worker.workerID] = worker + } return nil } @@ -133,7 +134,7 @@ func (v *workerPool) executeRequest(msg *ValidationTask) (*ValidationResult, err // create worker if not in pool if !v.containsWorker(validationCodeHash) { - err := v.newValidationWorker(*msg.ValidationCode) + err := v.addNewWorker(*msg.ValidationCode) if err != nil { return nil, err } diff --git a/dot/parachain/candidate-validation/worker_pool_test.go b/dot/parachain/candidate-validation/worker_pool_test.go index bf76e51c69..edf30412c3 100644 --- a/dot/parachain/candidate-validation/worker_pool_test.go +++ b/dot/parachain/candidate-validation/worker_pool_test.go @@ -29,8 +29,8 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { }{ "add_one_invalid_worker": { setupWorkerPool: func(t *testing.T) *workerPool { - pool := newValidationWorkerPool() - err := pool.newValidationWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) + pool := newWorkerPool() + err := pool.addNewWorker(parachaintypes.ValidationCode{1, 2, 3, 4}) require.Error(t, err) return pool }, @@ -38,8 +38,8 @@ func TestValidationWorkerPool_newValidationWorker(t *testing.T) { }, "add_one_valid_worker": { setupWorkerPool: func(t *testing.T) *workerPool { - pool := newValidationWorkerPool() - err := pool.newValidationWorker(testValidationCode) + pool := newWorkerPool() + err := pool.addNewWorker(testValidationCode) require.NoError(t, err) return pool }, diff --git a/dot/parachain/runtime/instance.go b/dot/parachain/runtime/instance.go index 41b01bfff5..acc3829e76 100644 --- a/dot/parachain/runtime/instance.go +++ b/dot/parachain/runtime/instance.go @@ -89,6 +89,11 @@ func (in *Instance) ValidateBlock(params ValidationParameters) ( return &validationResult, nil } +// ValidatorInstance for candidate validation methods +type ValidatorInstance interface { + ValidateBlock(params ValidationParameters) (*ValidationResult, error) +} + // RuntimeInstance for runtime methods type RuntimeInstance interface { ParachainHostPersistedValidationData(parachaidID uint32, assumption parachaintypes.OccupiedCoreAssumption, From 667747965c725e07c55bfddb7fb03625eb539c4b Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 13 Sep 2024 15:32:00 -0400 Subject: [PATCH 27/30] fix test --- dot/parachain/candidate-validation/host_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index 5491dfd4b4..2ad8bdaf1a 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -1,6 +1,7 @@ package candidatevalidation import ( + "fmt" "testing" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" @@ -323,7 +324,8 @@ func TestHost_performBasicChecks(t *testing.T) { if tt.expectedError != nil { require.EqualError(t, validationError, tt.expectedError.Error()) } else { - require.NoError(t, validationError) + fmt.Printf("validationError: %v\n", validationError) + require.Nil(t, validationError) } }) } From 942963228aa02721860c7ddf05e70966beeb8e8e Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 13 Sep 2024 16:56:39 -0400 Subject: [PATCH 28/30] remove printf from debugging --- dot/parachain/candidate-validation/host_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/dot/parachain/candidate-validation/host_test.go b/dot/parachain/candidate-validation/host_test.go index 2ad8bdaf1a..588f2526a4 100644 --- a/dot/parachain/candidate-validation/host_test.go +++ b/dot/parachain/candidate-validation/host_test.go @@ -1,7 +1,6 @@ package candidatevalidation import ( - "fmt" "testing" parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types" @@ -324,7 +323,6 @@ func TestHost_performBasicChecks(t *testing.T) { if tt.expectedError != nil { require.EqualError(t, validationError, tt.expectedError.Error()) } else { - fmt.Printf("validationError: %v\n", validationError) require.Nil(t, validationError) } }) From f869cba622c9e86a305687a03a42dfe59e644503 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 17 Sep 2024 10:39:48 -0400 Subject: [PATCH 29/30] address PR comments --- dot/parachain/candidate-validation/candidate_validation.go | 1 - dot/parachain/candidate-validation/worker.go | 1 - dot/parachain/candidate-validation/worker_pool.go | 4 ++-- dot/parachain/runtime/instance.go | 1 + 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 9f61d336eb..ef6674d979 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -87,7 +87,6 @@ func (cv *CandidateValidation) processMessage(msg any) { } result, err := cv.pvfHost.validate(validationTask) - if err != nil { logger.Errorf("failed to validate from exhaustive: %w", err) msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index 4a38bdb9a5..6781316594 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -20,7 +20,6 @@ type workerTask struct { func newWorker(validationCode parachaintypes.ValidationCode) (*worker, error) { parachainRuntime, err := parachainruntime.SetupVM(validationCode) - if err != nil { return nil, err } diff --git a/dot/parachain/candidate-validation/worker_pool.go b/dot/parachain/candidate-validation/worker_pool.go index 46f8dad514..828f37afac 100644 --- a/dot/parachain/candidate-validation/worker_pool.go +++ b/dot/parachain/candidate-validation/worker_pool.go @@ -139,7 +139,7 @@ func (v *workerPool) executeRequest(msg *ValidationTask) (*ValidationResult, err return nil, err } } - syncWorker := v.workers[validationCodeHash] + worker := v.workers[validationCodeHash] logger.Debugf("sending request", validationCodeHash) @@ -154,7 +154,7 @@ func (v *workerPool) executeRequest(msg *ValidationTask) (*ValidationResult, err maxPoVSize: msg.PersistedValidationData.MaxPovSize, candidateReceipt: msg.CandidateReceipt, } - return syncWorker.executeRequest(workTask) + return worker.executeRequest(workTask) } diff --git a/dot/parachain/runtime/instance.go b/dot/parachain/runtime/instance.go index acc3829e76..35bedf5b62 100644 --- a/dot/parachain/runtime/instance.go +++ b/dot/parachain/runtime/instance.go @@ -91,6 +91,7 @@ func (in *Instance) ValidateBlock(params ValidationParameters) ( // ValidatorInstance for candidate validation methods type ValidatorInstance interface { + // ValidateBlock validates a block by calling parachain runtime's validate_block call and returns the result. ValidateBlock(params ValidationParameters) (*ValidationResult, error) } From f1b7164f4cc0e21ce327c2febe5688a9eadf1d2d Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 18 Sep 2024 13:36:48 -0400 Subject: [PATCH 30/30] fix merge conflicts --- .../candidate-validation/candidate_validation.go | 6 +++--- .../candidate-validation/candidate_validation_test.go | 8 +++----- dot/parachain/candidate-validation/worker.go | 4 ++-- dot/parachain/candidate-validation/worker_test.go | 6 +++--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/dot/parachain/candidate-validation/candidate_validation.go b/dot/parachain/candidate-validation/candidate_validation.go index 3270ccef55..37dba1a6d9 100644 --- a/dot/parachain/candidate-validation/candidate_validation.go +++ b/dot/parachain/candidate-validation/candidate_validation.go @@ -176,7 +176,7 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState if persistedValidationData == nil { badParent := BadParent reason := ValidationResult{ - InvalidResult: &badParent, + Invalid: &badParent, } msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Data: reason, @@ -205,7 +205,7 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState return } valid, err := runtimeInstance.ParachainHostCheckValidationOutputs(parachaintypes.ParaID(msg.CandidateReceipt. - Descriptor.ParaID), result.ValidResult.CandidateCommitments) + Descriptor.ParaID), result.Valid.CandidateCommitments) if err != nil { msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Err: fmt.Errorf("check validation outputs: Bad request: %w", err), @@ -215,7 +215,7 @@ func (cv *CandidateValidation) validateFromChainState(msg ValidateFromChainState if !valid { invalidOutput := InvalidOutputs reason := &ValidationResult{ - InvalidResult: &invalidOutput, + Invalid: &invalidOutput, } msg.Ch <- parachaintypes.OverseerFuncRes[ValidationResult]{ Data: *reason, diff --git a/dot/parachain/candidate-validation/candidate_validation_test.go b/dot/parachain/candidate-validation/candidate_validation_test.go index 25074c2e74..6e01272998 100644 --- a/dot/parachain/candidate-validation/candidate_validation_test.go +++ b/dot/parachain/candidate-validation/candidate_validation_test.go @@ -456,20 +456,18 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt6, Pov: pov, - Ch: sender, }, want: &ValidationResult{ - InvalidResult: &invalidOutputs, + Invalid: &invalidOutputs, }, }, "bad_parent": { msg: ValidateFromChainState{ CandidateReceipt: candidateReceipt7, Pov: pov, - Ch: sender, }, want: &ValidationResult{ - InvalidResult: &badParent, + Invalid: &badParent, }, }, "happy_path": { @@ -478,7 +476,7 @@ func TestCandidateValidation_processMessageValidateFromChainState(t *testing.T) Pov: pov, }, want: &ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: validCandidateCommitments, PersistedValidationData: parachaintypes.PersistedValidationData{ ParentHead: parachaintypes.HeadData{Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, diff --git a/dot/parachain/candidate-validation/worker.go b/dot/parachain/candidate-validation/worker.go index a27c9269ab..1689c0ece0 100644 --- a/dot/parachain/candidate-validation/worker.go +++ b/dot/parachain/candidate-validation/worker.go @@ -89,14 +89,14 @@ func (w *worker) executeRequest(task *workerTask) (*ValidationResult, error) { if validationResultWErr.err != nil { logger.Errorf("executing validate_block: %w", err) reasonForInvalidity := ExecutionError - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil //nolint + return &ValidationResult{Invalid: &reasonForInvalidity}, nil //nolint } validationResult = validationResultWErr.result case <-time.After(timeoutDuration): logger.Errorf("validation timed out") reasonForInvalidity := Timeout - return &ValidationResult{InvalidResult: &reasonForInvalidity}, nil + return &ValidationResult{Invalid: &reasonForInvalidity}, nil } headDataHash, err := validationResult.HeadData.Hash() diff --git a/dot/parachain/candidate-validation/worker_test.go b/dot/parachain/candidate-validation/worker_test.go index e265f82c85..f4c8c0eead 100644 --- a/dot/parachain/candidate-validation/worker_test.go +++ b/dot/parachain/candidate-validation/worker_test.go @@ -22,7 +22,7 @@ func Test_worker_executeRequest(t *testing.T) { t.Cleanup(ctrl.Finish) expectedValidationResult := &ValidationResult{ - ValidResult: &Valid{ + Valid: &Valid{ CandidateCommitments: parachaintypes.CandidateCommitments{ HeadData: parachaintypes.HeadData{Data: []byte{2, 0, 0, 0, 0, 0, 0, 0, 123, 207, 206, 8, 219, 227, 136, 82, 236, 169, 14, 100, 45, 100, 31, 177, 154, 160, 220, 245, 59, 106, 76, 168, 122, 109, @@ -108,7 +108,7 @@ func Test_worker_executeRequest(t *testing.T) { candidateReceipt: &candidateReceiptCommitmentsMismatch, }, want: &ValidationResult{ - InvalidResult: &commitmentsHashMismatch, + Invalid: &commitmentsHashMismatch, }, }, "execution_timeout": { @@ -117,7 +117,7 @@ func Test_worker_executeRequest(t *testing.T) { candidateReceipt: &candidateReceipt, }, want: &ValidationResult{ - InvalidResult: &timeout, + Invalid: &timeout, }, }, "long_timeout_ok": {