Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions core/capabilities/fakes/consensus_frequency_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package fakes

import (
sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk"
valuespb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb"
)

// applyFrequencyListShape reshapes the observation value to match the output
// type expected by the consensus descriptor. The simulator runs a single node,
// so the only transformation needed is for frequency_list aggregation, which
// turns a single value T into [{value: T, count: 1}]. All other aggregation
// types have matching input and output types, so the value is returned as-is.
func applyFrequencyListShape(value *valuespb.Value, descriptor *sdkpb.ConsensusDescriptor) *valuespb.Value {
if descriptor == nil {
return value
}

switch desc := descriptor.GetDescriptor_().(type) {
case *sdkpb.ConsensusDescriptor_Aggregation:
if descriptor.GetAggregation() == sdkpb.AggregationType_AGGREGATION_TYPE_FREQUENCY_LIST {
return frequencyListSingleton(value)
}

case *sdkpb.ConsensusDescriptor_FieldsMap:

Check warning on line 24 in core/capabilities/fakes/consensus_frequency_list.go

View check run for this annotation

CL-sonarqube-production / SonarQube Code Analysis

Reduce this case clause number of lines from 22 to at most 20, for example by extracting code into methods.

[S1151] "switch case" clauses should not have too many lines See more on https://sonarqube.main.prod.cldev.sh/project/issues?id=smartcontractkit_chainlink&pullRequest=23173&issues=dbb19c82-2624-4273-99b6-76b6322f24fc&open=dbb19c82-2624-4273-99b6-76b6322f24fc
if value == nil {
return value
}
if value.GetMapValue() == nil {
return value
}
fields := value.GetMapValue().GetFields()
changed := false
newFields := make(map[string]*valuespb.Value, len(fields))
for k, v := range fields {
fieldDesc := desc.FieldsMap.GetFields()[k]
if fieldDesc != nil && fieldDesc.GetAggregation() == sdkpb.AggregationType_AGGREGATION_TYPE_FREQUENCY_LIST {
newFields[k] = frequencyListSingleton(v)
changed = true
} else {
newFields[k] = v
}
}
if changed {
return valuespb.NewMapValue(newFields)
}
}

return value
}

// frequencyListSingleton wraps a single observation value as a one-element
// frequency list: [{value: value, count: 1}].
func frequencyListSingleton(value *valuespb.Value) *valuespb.Value {
return valuespb.NewListValue([]*valuespb.Value{
valuespb.NewMapValue(map[string]*valuespb.Value{
"value": value,
"count": valuespb.NewInt64Value(1),
}),
})
}
10 changes: 7 additions & 3 deletions core/capabilities/fakes/consensus_nodag.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ func (fc *fakeConsensusNoDAG) close() error {
return nil
}

// NOTE: This fake capability currently bounces back the request payload, ignoring everything else.
// When the real NoDAG consensus OCR plugin is ready, it should be used here, similarly to how the V1 fake works.
// Simple bounces back the observation value, reshaping frequency_list fields
// to their correct output type. The simulator runs a single node, so there is
// exactly one observation: frequency_list turns a single value T into
// [{value: T, count: 1}]. All other aggregation types have matching input and
// output types, so the raw value is returned unchanged.
func (fc *fakeConsensusNoDAG) Simple(ctx context.Context, metadata capabilities.RequestMetadata, input *sdkpb.SimpleConsensusInputs) (*capabilities.ResponseAndMetadata[*valuespb.Value], caperrors.Error) {
fc.eng.Infow("Executing Fake Consensus NoDAG: Simple()", "input", input, "metadata", metadata)

Expand All @@ -74,8 +77,9 @@ func (fc *fakeConsensusNoDAG) Simple(ctx context.Context, metadata capabilities.
if obs.Value == nil {
return nil, caperrors.NewPublicUserError(errors.New("input value cannot be nil"), caperrors.InvalidArgument)
}
response := applyFrequencyListShape(obs.Value, input.Descriptors)
responseAndMetadata := capabilities.ResponseAndMetadata[*valuespb.Value]{
Response: obs.Value,
Response: response,
ResponseMetadata: capabilities.ResponseMetadata{},
}
return &responseAndMetadata, nil
Expand Down
Loading