Skip to content
Open
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
144 changes: 144 additions & 0 deletions core/services/ocr2/plugins/vault/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import (
"crypto/rand"
"encoding/hex"
"fmt"
"strings"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/libocr/commontypes"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
Expand Down Expand Up @@ -1895,6 +1898,74 @@
assert.Empty(t, resp.GetError())
}

func makeEncryptedShares(t *testing.T, ciphertext *tdh2easy.Ciphertext, privateShare *tdh2easy.PrivateShare, keys []string) []*vaultcommon.EncryptedShares {
t.Helper()
share, err := tdh2easy.Decrypt(ciphertext, privateShare)
require.NoError(t, err)
shareBytes, err := share.Marshal()
require.NoError(t, err)

result := make([]*vaultcommon.EncryptedShares, len(keys))
for i, pk := range keys {
pkBytes, err := hex.DecodeString(pk)
require.NoError(t, err)
pubKey := [32]byte(pkBytes)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkBytes is a []byte from hex.DecodeString, and pubKey := [32]byte(pkBytes) is not a valid conversion (won't compile). Build a [32]byte by copying into a fixed array (and ideally assert len(pkBytes)==32) before calling box.SealAnonymous.

Suggested change
pubKey := [32]byte(pkBytes)
require.Len(t, pkBytes, 32)
var pubKey [32]byte
copy(pubKey[:], pkBytes)

Copilot uses AI. Check for mistakes.
encrypted, err := box.SealAnonymous(nil, shareBytes, &pubKey, rand.Reader)
require.NoError(t, err)
result[i] = &vaultcommon.EncryptedShares{
EncryptionKey: pk,
Shares: []string{hex.EncodeToString(encrypted)},
}
}
return result
}

func makeGetSecretsObservations(
t *testing.T,
numRequests int,
owner string,
namespace string,
encryptionKeys []string,
encryptedValue string,
ciphertext *tdh2easy.Ciphertext,
privateShare *tdh2easy.PrivateShare,
) []byte {
t.Helper()
var obs []observation
for i := range numRequests {
maxKey := fmt.Sprintf("%s%d", strings.Repeat("c", defaultMaxIdentifierKeyLengthBytes-1), i)

id := &vaultcommon.SecretIdentifier{
Owner: owner,
Namespace: namespace,
Key: maxKey,
}
req := &vaultcommon.GetSecretsRequest{
Requests: []*vaultcommon.SecretRequest{
{
Id: id,
EncryptionKeys: encryptionKeys,
},
},
}
resp := &vaultcommon.GetSecretsResponse{
Responses: []*vaultcommon.SecretResponse{
{
Id: id,
Result: &vaultcommon.SecretResponse_Data{
Data: &vaultcommon.SecretData{
EncryptedValue: encryptedValue,
EncryptedDecryptionKeyShares: makeEncryptedShares(t, ciphertext, privateShare, encryptionKeys),
},
},
},
},
}
obs = append(obs, observation{id, req, resp})
}
return marshalObservations(t, obs...)
}

type observation struct {
id *vaultcommon.SecretIdentifier
req proto.Message
Expand Down Expand Up @@ -1947,7 +2018,7 @@
CreateSecretsResponse: tr,
}
case *vaultcommon.UpdateSecretsResponse:
o.Response = &vaultcommon.Observation_UpdateSecretsResponse{

Check failure on line 2021 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierKeyLengthBytes

Check failure on line 2021 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierKeyLengthBytes

Check failure on line 2021 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierKeyLengthBytes
UpdateSecretsResponse: tr,
}
case *vaultcommon.DeleteSecretsResponse:
Expand Down Expand Up @@ -2397,6 +2468,79 @@
assert.Equal(t, 1, observed.FilterMessage("sufficient observations for sha").Len())
}

func TestPlugin_StateTransition_GetSecretsRequest_ResponseSizeWithinLimit(t *testing.T) {
lggr := logger.TestLogger(t)
store := requests.NewStore[*vaulttypes.Request]()
_, pk, shares, err := tdh2easy.GenerateKeys(4, 10)
require.NoError(t, err)

numObservers := 10
r := &ReportingPlugin{
lggr: lggr,
onchainCfg: ocr3types.ReportingPluginConfig{
N: 10,
F: 3,
},
store: store,
cfg: makeReportingPluginConfig(
t,
10,
pk,
shares[0],
100,
defaultMaxCiphertextLengthBytes,
defaultMaxIdentifierOwnerLengthBytes,
defaultMaxIdentifierNamespaceLengthBytes,
defaultMaxIdentifierKeyLengthBytes,
false,
),
}

maxOwner := strings.Repeat("a", defaultMaxIdentifierOwnerLengthBytes)
maxNamespace := strings.Repeat("b", defaultMaxIdentifierNamespaceLengthBytes)

numEncryptionKeys := 10
encryptionKeys := make([]string, numEncryptionKeys)
for i := range numEncryptionKeys {
pubK, _, err := box.GenerateKey(rand.Reader)
require.NoError(t, err)
encryptionKeys[i] = hex.EncodeToString(pubK[:])
}

plaintext := make([]byte, 1)
_, err = rand.Read(plaintext)
require.NoError(t, err)
var label [32]byte
copy(label[:], maxOwner[:32])
ciphertext, err := tdh2easy.EncryptWithLabel(pk, plaintext, label)
require.NoError(t, err)
ciphertextBytes, err := ciphertext.Marshal()
require.NoError(t, err)
require.LessOrEqual(t, len(ciphertextBytes), defaultMaxCiphertextLengthBytes)
encryptedValue := hex.EncodeToString(ciphertextBytes)

// Create 10 observations from different observers, each with a distinct decryption share.
aos := make([]types.AttributedObservation, numObservers)
for i := range numObservers {
aos[i] = types.AttributedObservation{
Observer: commontypes.OracleID(i),
Observation: types.Observation(makeGetSecretsObservations(t, 10, maxOwner, maxNamespace, encryptionKeys, encryptedValue, ciphertext, shares[i])),
}
}

kvStore := &kv{m: make(map[string]response)}
reportPrecursor, err := r.StateTransition(
t.Context(),
1,
types.AttributedQuery{},
aos, kvStore, nil)
require.NoError(t, err)

maxResponseSize := 512 * 1024
assert.LessOrEqual(t, len(reportPrecursor), maxResponseSize,
"StateTransition response size %d exceeds 512KB limit", len(reportPrecursor))
}

func TestPlugin_StateTransition_GetSecretsRequest_CombinesShares(t *testing.T) {
lggr, observed := logger.TestLoggerObserved(t, zapcore.DebugLevel)
store := requests.NewStore[*vaulttypes.Request]()
Expand Down Expand Up @@ -2424,16 +2568,16 @@
}

seqNr := uint64(1)
kv := &kv{

Check failure on line 2571 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxCiphertextLengthBytes

Check failure on line 2571 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxCiphertextLengthBytes
m: make(map[string]response),

Check failure on line 2572 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierOwnerLengthBytes

Check failure on line 2572 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierOwnerLengthBytes
}

Check failure on line 2573 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierNamespaceLengthBytes

Check failure on line 2573 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierNamespaceLengthBytes

Check failure on line 2574 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierKeyLengthBytes

Check failure on line 2574 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierKeyLengthBytes
id := &vaultcommon.SecretIdentifier{

Check failure on line 2575 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

too many arguments in call to makeReportingPluginConfig

Check failure on line 2575 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

too many arguments in call to makeReportingPluginConfig
Owner: "owner",
Namespace: "main",
Key: "secret",
}

Check failure on line 2579 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierOwnerLengthBytes

Check failure on line 2579 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierOwnerLengthBytes
req := &vaultcommon.GetSecretsRequest{

Check failure on line 2580 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxIdentifierNamespaceLengthBytes

Check failure on line 2580 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxIdentifierNamespaceLengthBytes
Requests: []*vaultcommon.SecretRequest{
{
Id: id,
Expand All @@ -2452,7 +2596,7 @@
EncryptionKey: "my-encryption-key",
Shares: []string{"encrypted-share-1"},
},
},

Check failure on line 2599 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

undefined: defaultMaxCiphertextLengthBytes

Check failure on line 2599 in core/services/ocr2/plugins/vault/plugin_test.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

undefined: defaultMaxCiphertextLengthBytes
},
},
},
Expand Down
Loading