Skip to content

Commit cf1cc45

Browse files
[CLD-569]:fix(operations): handle marshalable edge case (#344)
This bug was discovered in this [support ticket](https://chainlink-core.slack.com/archives/C08QF1BEW4T/p1756395130562909) after some investigations Since all the fields in AddressRef is public and each field is either public or implement Marshaler and Unmarshaler , operations api should be able to serialise it. There is a bug where operations API fails to serialize it if both marshalJSON and unmarshalJSON are different receiver types eg ``` func (s LabelSet) MarshalJSON() ([]byte, error) { ... } func (s *LabelSet) UnmarshalJSON(data []byte) error { ... } ``` Note MarshalJSON is a value receiver and UnmarshalJSON is a pointer receiver, then even though LabelSet is serializable but operations api validation fails it. JIRA: https://smartcontract-it.atlassian.net/browse/CLD-569
1 parent ba11ea0 commit cf1cc45

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

.changeset/quick-bats-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
fix(operations): handle missing case causing Operations APi unable to serialize certain Marshalable struct

operations/validation.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,17 @@ func isValueSerializable(lggr logger.Logger, v reflect.Value) bool {
3232
}
3333

3434
// Check if type implements json.Marshaler and json.Unmarshaler
35-
t := v.Type()
35+
fieldTypeRef := v.Type()
36+
ptrFieldTypeRef := reflect.PointerTo(fieldTypeRef)
37+
3638
marshalType := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
3739
unmarshalType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
3840

41+
implementsMarshaler := fieldTypeRef.Implements(marshalType) || ptrFieldTypeRef.Implements(marshalType)
42+
implementsUnmarshaler := fieldTypeRef.Implements(unmarshalType) || ptrFieldTypeRef.Implements(unmarshalType)
43+
3944
// If it implements both interfaces, assume it's serializable
40-
if t.Implements(marshalType) && t.Implements(unmarshalType) {
45+
if implementsMarshaler && implementsUnmarshaler {
4146
return true
4247
}
4348

operations/validation_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
mcmslib "github.com/smartcontractkit/mcms"
1313
"github.com/smartcontractkit/mcms/types"
1414
"github.com/stretchr/testify/require"
15+
16+
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
1517
)
1618

1719
func Test_IsSerializable(t *testing.T) {
@@ -78,9 +80,9 @@ func Test_IsSerializable(t *testing.T) {
7880
want: true,
7981
},
8082
{
81-
name: "should fail to serialise value customMarshaler - does not implements MarshalJSON & UnmarshalJSON",
83+
name: "should serialise value customMarshaler - also implements MarshalJSON & UnmarshalJSON",
8284
v: customMarshaler{data: "test"},
83-
want: false,
85+
want: true,
8486
},
8587
{
8688
name: "should serialise nested struct",
@@ -144,6 +146,11 @@ func Test_IsSerializable(t *testing.T) {
144146
v: createMCMSTimelockProposal(t),
145147
want: true,
146148
},
149+
{
150+
name: "should serialize Datastore AddressRef",
151+
v: datastore.AddressRef{},
152+
want: true,
153+
},
147154
}
148155

149156
for _, tt := range tests {

0 commit comments

Comments
 (0)