From 0f10d578ad9d85e776ad26527196517394e9b0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 Apr 2024 12:17:11 -0700 Subject: [PATCH 1/5] unexport fields to prevent access by index --- encoding/ccf/ccf_test.go | 8 +- encoding/ccf/encode.go | 40 +- encoding/ccf/service_events_test.go | 716 ++++++++++++++++----- encoding/ccf/traverse_value.go | 10 +- encoding/json/encode.go | 46 +- encoding/json/encoding_test.go | 8 +- runtime/account_test.go | 200 +++--- runtime/attachments_test.go | 13 +- runtime/contract_test.go | 78 ++- runtime/convertValues.go | 12 +- runtime/convertValues_test.go | 738 ++++++++++------------ runtime/crypto_test.go | 19 +- runtime/deployment_test.go | 18 +- runtime/interpreter/value.go | 17 +- runtime/predeclaredvalues_test.go | 22 +- runtime/program_params_validation_test.go | 61 +- runtime/resourcedictionary_test.go | 6 +- runtime/runtime_test.go | 12 +- types.go | 35 +- values.go | 104 +-- values_test.go | 31 +- 21 files changed, 1332 insertions(+), 862 deletions(-) diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index cd3b97a32d..8b060bd803 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -11698,11 +11698,9 @@ func TestExportRecursiveType(t *testing.T) { testEncode( t, - cadence.Resource{ - Fields: []cadence.Value{ - cadence.Optional{}, - }, - }.WithType(ty), + cadence.NewResource([]cadence.Value{ + cadence.Optional{}, + }).WithType(ty), []byte{ // language=json, format=json-cdc // {"type":"Resource","value":{"id":"S.test.Foo","fields":[{"name":"foo","value":{"type": "Optional","value":null}}]}} diff --git a/encoding/ccf/encode.go b/encoding/ccf/encode.go index e9d755dd3d..854ccae024 100644 --- a/encoding/ccf/encode.go +++ b/encoding/ccf/encode.go @@ -25,6 +25,7 @@ import ( goRuntime "runtime" "sort" "sync" + _ "unsafe" "github.com/fxamacker/cbor/v2" @@ -1021,46 +1022,73 @@ func (e *Encoder) encodeInclusiveRange(v *cadence.InclusiveRange, tids ccfTypeID return e.encodeValue(v.Step, staticElementType, tids) } +//go:linkname getFieldValues github.com/onflow/cadence.getFieldValues +func getFieldValues(cadence.Composite) []cadence.Value + // encodeStruct encodes cadence.Struct as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeStruct(v cadence.Struct, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.StructType, v.Fields, tids) + return e.encodeComposite( + v.StructType, + getFieldValues(v), + tids, + ) } // encodeResource encodes cadence.Resource as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeResource(v cadence.Resource, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.ResourceType, v.Fields, tids) + return e.encodeComposite( + v.ResourceType, + getFieldValues(v), + tids, + ) } // encodeEvent encodes cadence.Event as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeEvent(v cadence.Event, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.EventType, v.Fields, tids) + return e.encodeComposite( + v.EventType, + getFieldValues(v), + tids, + ) } // encodeContract encodes cadence.Contract as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeContract(v cadence.Contract, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.ContractType, v.Fields, tids) + return e.encodeComposite( + v.ContractType, + getFieldValues(v), + tids, + ) } // encodeEnum encodes cadence.Enum as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeEnum(v cadence.Enum, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.EnumType, v.Fields, tids) + return e.encodeComposite( + v.EnumType, + getFieldValues(v), + tids, + ) } // encodeAttachment encodes cadence.Attachment as // language=CDDL // composite-value = [* (field: value)] func (e *Encoder) encodeAttachment(v cadence.Attachment, tids ccfTypeIDByCadenceType) error { - return e.encodeComposite(v.AttachmentType, v.Fields, tids) + return e.encodeComposite( + v.AttachmentType, + getFieldValues(v), + tids, + ) } // encodeComposite encodes composite types as diff --git a/encoding/ccf/service_events_test.go b/encoding/ccf/service_events_test.go index b2ba61358a..e57e5671c4 100644 --- a/encoding/ccf/service_events_test.go +++ b/encoding/ccf/service_events_test.go @@ -46,195 +46,396 @@ func TestEpochSetupEvent(t *testing.T) { evt, ok := decodedValue.(cadence.Event) require.True(t, ok) - require.Equal(t, 9, len(evt.Fields)) + + fields := cadence.FieldsMappedByName(evt) + require.Len(t, fields, 9) evtType, ok := decodedValue.Type().(*cadence.EventType) require.True(t, ok) - require.Equal(t, 9, len(evtType.Fields)) + require.Len(t, evtType.Fields, 9) // field 0: counter - require.Equal(t, "counter", evtType.Fields[0].Identifier) - require.Equal(t, cadence.UInt64(1), evt.Fields[0]) + require.Equal(t, + "counter", + evtType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt64(1), + fields["counter"], + ) // field 1: nodeInfo - require.Equal(t, "nodeInfo", evtType.Fields[1].Identifier) - nodeInfos, ok := evt.Fields[1].(cadence.Array) + require.Equal(t, + "nodeInfo", + evtType.Fields[1].Identifier, + ) + nodeInfos, ok := fields["nodeInfo"].(cadence.Array) require.True(t, ok) testNodeInfos(t, nodeInfos) // field 2: firstView - require.Equal(t, "firstView", evtType.Fields[2].Identifier) - require.Equal(t, cadence.UInt64(100), evt.Fields[2]) + require.Equal(t, + "firstView", + evtType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.UInt64(100), + fields["firstView"], + ) // field 3: finalView - require.Equal(t, "finalView", evtType.Fields[3].Identifier) - require.Equal(t, cadence.UInt64(200), evt.Fields[3]) + require.Equal(t, + "finalView", + evtType.Fields[3].Identifier, + ) + require.Equal(t, + cadence.UInt64(200), + fields["finalView"], + ) // field 4: collectorClusters - require.Equal(t, "collectorClusters", evtType.Fields[4].Identifier) - epochCollectors, ok := evt.Fields[4].(cadence.Array) + require.Equal(t, + "collectorClusters", + evtType.Fields[4].Identifier, + ) + epochCollectors, ok := fields["collectorClusters"].(cadence.Array) require.True(t, ok) testEpochCollectors(t, epochCollectors) // field 5: randomSource - require.Equal(t, "randomSource", evtType.Fields[5].Identifier) - require.Equal(t, cadence.String("01020304"), evt.Fields[5]) + require.Equal(t, + "randomSource", + evtType.Fields[5].Identifier, + ) + require.Equal(t, + cadence.String("01020304"), + fields["randomSource"], + ) // field 6: DKGPhase1FinalView - require.Equal(t, "DKGPhase1FinalView", evtType.Fields[6].Identifier) - require.Equal(t, cadence.UInt64(150), evt.Fields[6]) + require.Equal(t, + "DKGPhase1FinalView", + evtType.Fields[6].Identifier, + ) + require.Equal(t, + cadence.UInt64(150), + fields["DKGPhase1FinalView"], + ) // field 7: DKGPhase2FinalView - require.Equal(t, "DKGPhase2FinalView", evtType.Fields[7].Identifier) - require.Equal(t, cadence.UInt64(160), evt.Fields[7]) + require.Equal(t, + "DKGPhase2FinalView", + evtType.Fields[7].Identifier, + ) + require.Equal(t, + cadence.UInt64(160), + fields["DKGPhase2FinalView"], + ) // field 8: DKGPhase3FinalView - require.Equal(t, "DKGPhase3FinalView", evtType.Fields[8].Identifier) - require.Equal(t, cadence.UInt64(170), evt.Fields[8]) + require.Equal(t, + "DKGPhase3FinalView", + evtType.Fields[8].Identifier, + ) + require.Equal(t, + cadence.UInt64(170), + fields["DKGPhase3FinalView"], + ) } func testNodeInfos(t *testing.T, nodeInfos cadence.Array) { - require.Equal(t, 7, len(nodeInfos.Values)) + require.Len(t, nodeInfos.Values, 7) // Test nodeInfo 0 node0, ok := nodeInfos.Values[0].(cadence.Struct) require.True(t, ok) - require.Equal(t, 14, len(node0.Fields)) + + node0Fields := cadence.FieldsMappedByName(node0) + require.Len(t, node0Fields, 14) nodeInfoType, ok := node0.Type().(*cadence.StructType) require.True(t, ok) - require.Equal(t, 14, len(nodeInfoType.Fields)) + require.Len(t, nodeInfoType.Fields, 14) // field 0: id - require.Equal(t, "id", nodeInfoType.Fields[0].Identifier) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000001"), node0.Fields[0]) + require.Equal(t, + "id", + nodeInfoType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.String("0000000000000000000000000000000000000000000000000000000000000001"), + node0Fields["id"], + ) // field 1: role - require.Equal(t, "role", nodeInfoType.Fields[1].Identifier) - require.Equal(t, cadence.UInt8(1), node0.Fields[1]) + require.Equal(t, + "role", + nodeInfoType.Fields[1].Identifier, + ) + require.Equal(t, + cadence.UInt8(1), + node0Fields["role"], + ) // field 2: networkingAddress - require.Equal(t, "networkingAddress", nodeInfoType.Fields[2].Identifier) - require.Equal(t, cadence.String("1.flow.com"), node0.Fields[2]) + require.Equal(t, + "networkingAddress", + nodeInfoType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.String("1.flow.com"), + node0Fields["networkingAddress"], + ) // field 3: networkingKey - require.Equal(t, "networkingKey", nodeInfoType.Fields[3].Identifier) - require.Equal(t, cadence.String("378dbf45d85c614feb10d8bd4f78f4b6ef8eec7d987b937e123255444657fb3da031f232a507e323df3a6f6b8f50339c51d188e80c0e7a92420945cc6ca893fc"), node0.Fields[3]) + require.Equal(t, + "networkingKey", + nodeInfoType.Fields[3].Identifier, + ) + require.Equal(t, + cadence.String("378dbf45d85c614feb10d8bd4f78f4b6ef8eec7d987b937e123255444657fb3da031f232a507e323df3a6f6b8f50339c51d188e80c0e7a92420945cc6ca893fc"), + node0Fields["networkingKey"], + ) // field 4: stakingKey - require.Equal(t, "stakingKey", nodeInfoType.Fields[4].Identifier) - require.Equal(t, cadence.String("af4aade26d76bb2ab15dcc89adcef82a51f6f04b3cb5f4555214b40ec89813c7a5f95776ea4fe449de48166d0bbc59b919b7eabebaac9614cf6f9461fac257765415f4d8ef1376a2365ec9960121888ea5383d88a140c24c29962b0a14e4e4e7"), node0.Fields[4]) + require.Equal(t, + "stakingKey", + nodeInfoType.Fields[4].Identifier, + ) + require.Equal(t, + cadence.String("af4aade26d76bb2ab15dcc89adcef82a51f6f04b3cb5f4555214b40ec89813c7a5f95776ea4fe449de48166d0bbc59b919b7eabebaac9614cf6f9461fac257765415f4d8ef1376a2365ec9960121888ea5383d88a140c24c29962b0a14e4e4e7"), + node0Fields["stakingKey"], + ) // field 5: tokensStaked - require.Equal(t, "tokensStaked", nodeInfoType.Fields[5].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node0.Fields[5]) + require.Equal(t, + "tokensStaked", + nodeInfoType.Fields[5].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node0Fields["tokensStaked"], + ) // field 6: tokensCommitted - require.Equal(t, "tokensCommitted", nodeInfoType.Fields[6].Identifier) - require.Equal(t, ufix64FromString("1350000.00000000"), node0.Fields[6]) + require.Equal(t, + "tokensCommitted", + nodeInfoType.Fields[6].Identifier, + ) + require.Equal(t, + ufix64FromString("1350000.00000000"), + node0Fields["tokensCommitted"], + ) // field 7: tokensUnstaking - require.Equal(t, "tokensUnstaking", nodeInfoType.Fields[7].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node0.Fields[7]) + require.Equal(t, + "tokensUnstaking", + nodeInfoType.Fields[7].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node0Fields["tokensUnstaking"], + ) // field 8: tokensUnstaked - require.Equal(t, "tokensUnstaked", nodeInfoType.Fields[8].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node0.Fields[8]) + require.Equal(t, + "tokensUnstaked", + nodeInfoType.Fields[8].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node0Fields["tokensUnstaked"], + ) // field 9: tokensRewarded - require.Equal(t, "tokensRewarded", nodeInfoType.Fields[9].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node0.Fields[9]) + require.Equal(t, + "tokensRewarded", + nodeInfoType.Fields[9].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node0Fields["tokensRewarded"], + ) // field 10: delegators require.Equal(t, "delegators", nodeInfoType.Fields[10].Identifier) - delegators, ok := node0.Fields[10].(cadence.Array) + delegators, ok := node0Fields["delegators"].(cadence.Array) + require.True(t, ok) - require.Equal(t, 0, len(delegators.Values)) + require.Len(t, delegators.Values, 0) // field 11: delegatorIDCounter require.Equal(t, "delegatorIDCounter", nodeInfoType.Fields[11].Identifier) - require.Equal(t, cadence.UInt32(0), node0.Fields[11]) + require.Equal(t, + cadence.UInt32(0), + node0Fields["delegatorIDCounter"], + ) // field 12: tokensRequestedToUnstake require.Equal(t, "tokensRequestedToUnstake", nodeInfoType.Fields[12].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node0.Fields[12]) + require.Equal(t, + ufix64FromString("0.00000000"), + node0Fields["tokensRequestedToUnstake"], + ) // field 13: initialWeight require.Equal(t, "initialWeight", nodeInfoType.Fields[13].Identifier) - require.Equal(t, cadence.UInt64(100), node0.Fields[13]) + require.Equal(t, + cadence.UInt64(100), + node0Fields["initialWeight"], + ) // Test nodeInfo 6 (last nodeInfo struct) node6, ok := nodeInfos.Values[6].(cadence.Struct) require.True(t, ok) - require.Equal(t, 14, len(node6.Fields)) + node6Fields := cadence.FieldsMappedByName(node6) + require.Len(t, node6Fields, 14) nodeInfoType, ok = node6.Type().(*cadence.StructType) require.True(t, ok) - require.Equal(t, 14, len(nodeInfoType.Fields)) + require.Len(t, nodeInfoType.Fields, 14) // field 0: id require.Equal(t, "id", nodeInfoType.Fields[0].Identifier) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000031"), node6.Fields[0]) + require.Equal(t, + cadence.String("0000000000000000000000000000000000000000000000000000000000000031"), + node6Fields["id"], + ) // field 1: role - require.Equal(t, "role", nodeInfoType.Fields[1].Identifier) - require.Equal(t, cadence.UInt8(4), node6.Fields[1]) + require.Equal(t, + "role", + nodeInfoType.Fields[1].Identifier, + ) + require.Equal(t, + cadence.UInt8(4), + node6Fields["role"], + ) // field 2: networkingAddress - require.Equal(t, "networkingAddress", nodeInfoType.Fields[2].Identifier) - require.Equal(t, cadence.String("31.flow.com"), node6.Fields[2]) + require.Equal(t, + "networkingAddress", + nodeInfoType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.String("31.flow.com"), + node6Fields["networkingAddress"], + ) // field 3: networkingKey - require.Equal(t, "networkingKey", nodeInfoType.Fields[3].Identifier) - require.Equal(t, cadence.String("697241208dcc9142b6f53064adc8ff1c95760c68beb2ba083c1d005d40181fd7a1b113274e0163c053a3addd47cd528ec6a1f190cf465aac87c415feaae011ae"), node6.Fields[3]) + require.Equal(t, + "networkingKey", + nodeInfoType.Fields[3].Identifier, + ) + require.Equal(t, + cadence.String("697241208dcc9142b6f53064adc8ff1c95760c68beb2ba083c1d005d40181fd7a1b113274e0163c053a3addd47cd528ec6a1f190cf465aac87c415feaae011ae"), + node6Fields["networkingKey"], + ) // field 4: stakingKey - require.Equal(t, "stakingKey", nodeInfoType.Fields[4].Identifier) - require.Equal(t, cadence.String("b1f97d0a06020eca97352e1adde72270ee713c7daf58da7e74bf72235321048b4841bdfc28227964bf18e371e266e32107d238358848bcc5d0977a0db4bda0b4c33d3874ff991e595e0f537c7b87b4ddce92038ebc7b295c9ea20a1492302aa7"), node6.Fields[4]) + require.Equal(t, + "stakingKey", + nodeInfoType.Fields[4].Identifier, + ) + require.Equal(t, + cadence.String("b1f97d0a06020eca97352e1adde72270ee713c7daf58da7e74bf72235321048b4841bdfc28227964bf18e371e266e32107d238358848bcc5d0977a0db4bda0b4c33d3874ff991e595e0f537c7b87b4ddce92038ebc7b295c9ea20a1492302aa7"), + node6Fields["stakingKey"], + ) // field 5: tokensStaked - require.Equal(t, "tokensStaked", nodeInfoType.Fields[5].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node6.Fields[5]) + require.Equal(t, + "tokensStaked", + nodeInfoType.Fields[5].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node6Fields["tokensStaked"], + ) // field 6: tokensCommitted - require.Equal(t, "tokensCommitted", nodeInfoType.Fields[6].Identifier) - require.Equal(t, ufix64FromString("1350000.00000000"), node6.Fields[6]) + require.Equal(t, + "tokensCommitted", + nodeInfoType.Fields[6].Identifier, + ) + require.Equal(t, + ufix64FromString("1350000.00000000"), + node6Fields["tokensCommitted"], + ) // field 7: tokensUnstaking - require.Equal(t, "tokensUnstaking", nodeInfoType.Fields[7].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node6.Fields[7]) + require.Equal(t, + "tokensUnstaking", + nodeInfoType.Fields[7].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node6Fields["tokensUnstaking"], + ) // field 8: tokensUnstaked - require.Equal(t, "tokensUnstaked", nodeInfoType.Fields[8].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node6.Fields[8]) + require.Equal(t, + "tokensUnstaked", + nodeInfoType.Fields[8].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node6Fields["tokensUnstaked"], + ) // field 9: tokensRewarded - require.Equal(t, "tokensRewarded", nodeInfoType.Fields[9].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node6.Fields[9]) + require.Equal(t, + "tokensRewarded", + nodeInfoType.Fields[9].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node6Fields["tokensRewarded"], + ) // field 10: delegators - require.Equal(t, "delegators", nodeInfoType.Fields[10].Identifier) - delegators, ok = node6.Fields[10].(cadence.Array) + require.Equal(t, + "delegators", + nodeInfoType.Fields[10].Identifier, + ) + delegators, ok = node6Fields["delegators"].(cadence.Array) require.True(t, ok) - require.Equal(t, 0, len(delegators.Values)) + require.Len(t, delegators.Values, 0) // field 11: delegatorIDCounter - require.Equal(t, "delegatorIDCounter", nodeInfoType.Fields[11].Identifier) - require.Equal(t, cadence.UInt32(0), node6.Fields[11]) + require.Equal(t, + "delegatorIDCounter", + nodeInfoType.Fields[11].Identifier, + ) + require.Equal(t, + cadence.UInt32(0), + node6Fields["delegatorIDCounter"], + ) // field 12: tokensRequestedToUnstake - require.Equal(t, "tokensRequestedToUnstake", nodeInfoType.Fields[12].Identifier) - require.Equal(t, ufix64FromString("0.00000000"), node6.Fields[12]) + require.Equal(t, + "tokensRequestedToUnstake", + nodeInfoType.Fields[12].Identifier, + ) + require.Equal(t, + ufix64FromString("0.00000000"), + node6Fields["tokensRequestedToUnstake"], + ) // field 13: initialWeight - require.Equal(t, "initialWeight", nodeInfoType.Fields[13].Identifier) - require.Equal(t, cadence.UInt64(100), node6.Fields[13]) + require.Equal(t, + "initialWeight", + nodeInfoType.Fields[13].Identifier, + ) + require.Equal(t, + cadence.UInt64(100), + node6Fields["initialWeight"], + ) } func testEpochCollectors(t *testing.T, collectors cadence.Array) { - require.Equal(t, 2, len(collectors.Values)) + require.Len(t, collectors.Values, 2) // collector 0 collector0, ok := collectors.Values[0].(cadence.Struct) @@ -243,42 +444,69 @@ func testEpochCollectors(t *testing.T, collectors cadence.Array) { collectorType, ok := collector0.Type().(*cadence.StructType) require.True(t, ok) + collector0Fields := cadence.FieldsMappedByName(collector0) + // field 0: index - require.Equal(t, "index", collectorType.Fields[0].Identifier) - require.Equal(t, cadence.UInt16(0), collector0.Fields[0]) + require.Equal(t, + "index", + collectorType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt16(0), + collector0Fields["index"], + ) // field 1: nodeWeights - require.Equal(t, "nodeWeights", collectorType.Fields[1].Identifier) - weights, ok := collector0.Fields[1].(cadence.Dictionary) + require.Equal(t, + "nodeWeights", + collectorType.Fields[1].Identifier, + ) + weights, ok := collector0Fields["nodeWeights"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 2, len(weights.Pairs)) + require.Len(t, weights.Pairs, 2) + require.Equal(t, cadence.KeyValuePair{ Key: cadence.String("0000000000000000000000000000000000000000000000000000000000000001"), Value: cadence.UInt64(100), }, - weights.Pairs[0]) + weights.Pairs[0], + ) require.Equal(t, cadence.KeyValuePair{ Key: cadence.String("0000000000000000000000000000000000000000000000000000000000000002"), Value: cadence.UInt64(100), - }, weights.Pairs[1]) + }, + weights.Pairs[1], + ) // field 2: totalWeight - require.Equal(t, "totalWeight", collectorType.Fields[2].Identifier) - require.Equal(t, cadence.NewUInt64(100), collector0.Fields[2]) + require.Equal(t, + "totalWeight", + collectorType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.NewUInt64(100), + collector0Fields["totalWeight"], + ) // field 3: generatedVotes - require.Equal(t, "generatedVotes", collectorType.Fields[3].Identifier) - generatedVotes, ok := collector0.Fields[3].(cadence.Dictionary) + require.Equal(t, + "generatedVotes", + collectorType.Fields[3].Identifier, + ) + generatedVotes, ok := collector0Fields["generatedVotes"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 0, len(generatedVotes.Pairs)) + require.Len(t, generatedVotes.Pairs, 0) // field 4: uniqueVoteMessageTotalWeights - require.Equal(t, "uniqueVoteMessageTotalWeights", collectorType.Fields[4].Identifier) - uniqueVoteMessageTotalWeights, ok := collector0.Fields[4].(cadence.Dictionary) + require.Equal(t, + "uniqueVoteMessageTotalWeights", + collectorType.Fields[4].Identifier, + ) + uniqueVoteMessageTotalWeights, ok := collector0Fields["uniqueVoteMessageTotalWeights"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 0, len(uniqueVoteMessageTotalWeights.Pairs)) + require.Len(t, uniqueVoteMessageTotalWeights.Pairs, 0) // collector 1 collector1, ok := collectors.Values[1].(cadence.Struct) @@ -287,42 +515,68 @@ func testEpochCollectors(t *testing.T, collectors cadence.Array) { collectorType, ok = collector1.Type().(*cadence.StructType) require.True(t, ok) + collector1Fields := cadence.FieldsMappedByName(collector1) + // field 0: index - require.Equal(t, "index", collectorType.Fields[0].Identifier) - require.Equal(t, cadence.UInt16(1), collector1.Fields[0]) + require.Equal(t, + "index", + collectorType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt16(1), + collector1Fields["index"], + ) // field 1: nodeWeights - require.Equal(t, "nodeWeights", collectorType.Fields[1].Identifier) - weights, ok = collector1.Fields[1].(cadence.Dictionary) + require.Equal(t, + "nodeWeights", + collectorType.Fields[1].Identifier, + ) + weights, ok = collector1Fields["nodeWeights"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 2, len(weights.Pairs)) + require.Len(t, weights.Pairs, 2) require.Equal(t, cadence.KeyValuePair{ Key: cadence.String("0000000000000000000000000000000000000000000000000000000000000003"), Value: cadence.UInt64(100), }, - weights.Pairs[0]) + weights.Pairs[0], + ) require.Equal(t, cadence.KeyValuePair{ Key: cadence.String("0000000000000000000000000000000000000000000000000000000000000004"), Value: cadence.UInt64(100), - }, weights.Pairs[1]) + }, + weights.Pairs[1], + ) // field 2: totalWeight - require.Equal(t, "totalWeight", collectorType.Fields[2].Identifier) - require.Equal(t, cadence.NewUInt64(0), collector1.Fields[2]) + require.Equal(t, + "totalWeight", + collectorType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.NewUInt64(0), + collector1Fields["totalWeight"], + ) // field 3: generatedVotes - require.Equal(t, "generatedVotes", collectorType.Fields[3].Identifier) - generatedVotes, ok = collector1.Fields[3].(cadence.Dictionary) + require.Equal(t, + "generatedVotes", + collectorType.Fields[3].Identifier, + ) + generatedVotes, ok = collector1Fields["generatedVotes"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 0, len(generatedVotes.Pairs)) + require.Len(t, generatedVotes.Pairs, 0) // field 4: uniqueVoteMessageTotalWeights - require.Equal(t, "uniqueVoteMessageTotalWeights", collectorType.Fields[4].Identifier) - uniqueVoteMessageTotalWeights, ok = collector1.Fields[4].(cadence.Dictionary) + require.Equal(t, + "uniqueVoteMessageTotalWeights", + collectorType.Fields[4].Identifier, + ) + uniqueVoteMessageTotalWeights, ok = collector1Fields["uniqueVoteMessageTotalWeights"].(cadence.Dictionary) require.True(t, ok) - require.Equal(t, 0, len(uniqueVoteMessageTotalWeights.Pairs)) + require.Len(t, uniqueVoteMessageTotalWeights.Pairs, 0) } func TestEpochCommitEvent(t *testing.T) { @@ -343,33 +597,52 @@ func TestEpochCommitEvent(t *testing.T) { evt, ok := decodedValue.(cadence.Event) require.True(t, ok) - require.Equal(t, 3, len(evt.Fields)) + + fields := cadence.FieldsMappedByName(evt) + require.Len(t, fields, 3) evtType, ok := decodedValue.Type().(*cadence.EventType) require.True(t, ok) - require.Equal(t, 3, len(evtType.Fields)) + require.Len(t, evtType.Fields, 3) // field 0: counter - require.Equal(t, "counter", evtType.Fields[0].Identifier) - require.Equal(t, cadence.UInt64(1), evt.Fields[0]) + require.Equal(t, + "counter", + evtType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt64(1), + fields["counter"], + ) // field 1: clusterQCs - require.Equal(t, "clusterQCs", evtType.Fields[1].Identifier) - clusterQCs, ok := evt.Fields[1].(cadence.Array) + require.Equal(t, + "clusterQCs", + evtType.Fields[1].Identifier, + ) + clusterQCs, ok := fields["clusterQCs"].(cadence.Array) require.True(t, ok) testClusterQCs(t, clusterQCs) // field 2: dkgPubKeys - require.Equal(t, "dkgPubKeys", evtType.Fields[2].Identifier) - dkgPubKeys, ok := evt.Fields[2].(cadence.Array) + require.Equal(t, + "dkgPubKeys", + evtType.Fields[2].Identifier, + ) + dkgPubKeys, ok := fields["dkgPubKeys"].(cadence.Array) require.True(t, ok) - require.Equal(t, 2, len(dkgPubKeys.Values)) - require.Equal(t, cadence.String("8c588266db5f5cda629e83f8aa04ae9413593fac19e4865d06d291c9d14fbdd9bdb86a7a12f9ef8590c79cb635e3163315d193087e9336092987150d0cd2b14ac6365f7dc93eec573752108b8c12368abb65f0652d9f644e5aed611c37926950"), dkgPubKeys.Values[0]) - require.Equal(t, cadence.String("87a339e4e5c74f089da20a33f515d8c8f4464ab53ede5a74aa2432cd1ae66d522da0c122249ee176cd747ddc83ca81090498389384201614caf51eac392c1c0a916dfdcfbbdf7363f9552b6468434add3d3f6dc91a92bbe3ee368b59b7828488"), dkgPubKeys.Values[1]) + + require.Equal(t, + []cadence.Value{ + cadence.String("8c588266db5f5cda629e83f8aa04ae9413593fac19e4865d06d291c9d14fbdd9bdb86a7a12f9ef8590c79cb635e3163315d193087e9336092987150d0cd2b14ac6365f7dc93eec573752108b8c12368abb65f0652d9f644e5aed611c37926950"), + cadence.String("87a339e4e5c74f089da20a33f515d8c8f4464ab53ede5a74aa2432cd1ae66d522da0c122249ee176cd747ddc83ca81090498389384201614caf51eac392c1c0a916dfdcfbbdf7363f9552b6468434add3d3f6dc91a92bbe3ee368b59b7828488"), + }, + dkgPubKeys.Values, + ) } func testClusterQCs(t *testing.T, clusterQCs cadence.Array) { - require.Equal(t, 2, len(clusterQCs.Values)) + require.Len(t, clusterQCs.Values, 2) // Test clusterQC0 @@ -379,29 +652,54 @@ func testClusterQCs(t *testing.T, clusterQCs cadence.Array) { clusterQCType, ok := clusterQC0.Type().(*cadence.StructType) require.True(t, ok) + clusterQC0Fields := cadence.FieldsMappedByName(clusterQC0) + // field 0: index require.Equal(t, "index", clusterQCType.Fields[0].Identifier) - require.Equal(t, cadence.UInt16(0), clusterQC0.Fields[0]) + require.Equal(t, + cadence.UInt16(0), + clusterQC0Fields["index"], + ) // field 1: voteSignatures - require.Equal(t, "voteSignatures", clusterQCType.Fields[1].Identifier) - sigs, ok := clusterQC0.Fields[1].(cadence.Array) + require.Equal(t, + "voteSignatures", + clusterQCType.Fields[1].Identifier, + ) + sigs, ok := clusterQC0Fields["voteSignatures"].(cadence.Array) require.True(t, ok) - require.Equal(t, 2, len(sigs.Values)) - require.Equal(t, cadence.String("a39cd1e1bf7e2fb0609b7388ce5215a6a4c01eef2aee86e1a007faa28a6b2a3dc876e11bb97cdb26c3846231d2d01e4d"), sigs.Values[0]) - require.Equal(t, cadence.String("91673ad9c717d396c9a0953617733c128049ac1a639653d4002ab245b121df1939430e313bcbfd06948f6a281f6bf853"), sigs.Values[1]) + require.Equal(t, + []cadence.Value{ + cadence.String("a39cd1e1bf7e2fb0609b7388ce5215a6a4c01eef2aee86e1a007faa28a6b2a3dc876e11bb97cdb26c3846231d2d01e4d"), + cadence.String("91673ad9c717d396c9a0953617733c128049ac1a639653d4002ab245b121df1939430e313bcbfd06948f6a281f6bf853"), + }, + sigs.Values, + ) // field 2: voteMessage - require.Equal(t, "voteMessage", clusterQCType.Fields[2].Identifier) - require.Equal(t, cadence.String("irrelevant_for_these_purposes"), clusterQC0.Fields[2]) + require.Equal(t, + "voteMessage", + clusterQCType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.String("irrelevant_for_these_purposes"), + clusterQC0Fields["voteMessage"], + ) // field 3: voterIDs - require.Equal(t, "voterIDs", clusterQCType.Fields[3].Identifier) - ids, ok := clusterQC0.Fields[3].(cadence.Array) + require.Equal(t, + "voterIDs", + clusterQCType.Fields[3].Identifier, + ) + ids, ok := clusterQC0Fields["voterIDs"].(cadence.Array) require.True(t, ok) - require.Equal(t, 2, len(ids.Values)) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000001"), ids.Values[0]) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000002"), ids.Values[1]) + require.Equal(t, + []cadence.Value{ + cadence.String("0000000000000000000000000000000000000000000000000000000000000001"), + cadence.String("0000000000000000000000000000000000000000000000000000000000000002"), + }, + ids.Values, + ) // Test clusterQC1 @@ -411,29 +709,57 @@ func testClusterQCs(t *testing.T, clusterQCs cadence.Array) { clusterQCType, ok = clusterQC1.Type().(*cadence.StructType) require.True(t, ok) + clusterQC1Fields := cadence.FieldsMappedByName(clusterQC1) + // field 0: index - require.Equal(t, "index", clusterQCType.Fields[0].Identifier) - require.Equal(t, cadence.UInt16(1), clusterQC1.Fields[0]) + require.Equal(t, + "index", + clusterQCType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt16(1), + clusterQC1Fields["index"], + ) // field 1: voteSignatures - require.Equal(t, "voteSignatures", clusterQCType.Fields[1].Identifier) - sigs, ok = clusterQC1.Fields[1].(cadence.Array) + require.Equal(t, + "voteSignatures", + clusterQCType.Fields[1].Identifier, + ) + sigs, ok = clusterQC1Fields["voteSignatures"].(cadence.Array) require.True(t, ok) - require.Equal(t, 2, len(sigs.Values)) - require.Equal(t, cadence.String("b2bff159971852ed63e72c37991e62c94822e52d4fdcd7bf29aaf9fb178b1c5b4ce20dd9594e029f3574cb29533b857a"), sigs.Values[0]) - require.Equal(t, cadence.String("9931562f0248c9195758da3de4fb92f24fa734cbc20c0cb80280163560e0e0348f843ac89ecbd3732e335940c1e8dccb"), sigs.Values[1]) + require.Equal(t, + []cadence.Value{ + cadence.String("b2bff159971852ed63e72c37991e62c94822e52d4fdcd7bf29aaf9fb178b1c5b4ce20dd9594e029f3574cb29533b857a"), + cadence.String("9931562f0248c9195758da3de4fb92f24fa734cbc20c0cb80280163560e0e0348f843ac89ecbd3732e335940c1e8dccb"), + }, + sigs.Values, + ) // field 2: voteMessage - require.Equal(t, "voteMessage", clusterQCType.Fields[2].Identifier) - require.Equal(t, cadence.String("irrelevant_for_these_purposes"), clusterQC1.Fields[2]) + require.Equal(t, + "voteMessage", + clusterQCType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.String("irrelevant_for_these_purposes"), + clusterQC1Fields["voteMessage"], + ) // field 3: voterIDs - require.Equal(t, "voterIDs", clusterQCType.Fields[3].Identifier) - ids, ok = clusterQC1.Fields[3].(cadence.Array) + require.Equal(t, + "voterIDs", + clusterQCType.Fields[3].Identifier, + ) + ids, ok = clusterQC1Fields["voterIDs"].(cadence.Array) require.True(t, ok) - require.Equal(t, 2, len(ids.Values)) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000003"), ids.Values[0]) - require.Equal(t, cadence.String("0000000000000000000000000000000000000000000000000000000000000004"), ids.Values[1]) + require.Equal(t, + []cadence.Value{ + cadence.String("0000000000000000000000000000000000000000000000000000000000000003"), + cadence.String("0000000000000000000000000000000000000000000000000000000000000004"), + }, + ids.Values, + ) } func TestVersionBeaconEvent(t *testing.T) { @@ -454,67 +780,115 @@ func TestVersionBeaconEvent(t *testing.T) { evt, ok := decodedValue.(cadence.Event) require.True(t, ok) - require.Equal(t, 2, len(evt.Fields)) + + fields := cadence.FieldsMappedByName(evt) + require.Len(t, fields, 2) evtType, ok := decodedValue.Type().(*cadence.EventType) require.True(t, ok) - require.Equal(t, 2, len(evtType.Fields)) + require.Len(t, evtType.Fields, 2) // field 0: versionBoundaries - require.Equal(t, "versionBoundaries", evtType.Fields[0].Identifier) - versionBoundaries, ok := evt.Fields[0].(cadence.Array) + require.Equal(t, + "versionBoundaries", + evtType.Fields[0].Identifier, + ) + versionBoundaries, ok := fields["versionBoundaries"].(cadence.Array) require.True(t, ok) testVersionBoundaries(t, versionBoundaries) // field 1: sequence - require.Equal(t, "sequence", evtType.Fields[1].Identifier) - require.Equal(t, cadence.UInt64(5), evt.Fields[1]) + require.Equal(t, + "sequence", + evtType.Fields[1].Identifier, + ) + require.Equal(t, + cadence.UInt64(5), + fields["sequence"], + ) } func testVersionBoundaries(t *testing.T, versionBoundaries cadence.Array) { - require.Equal(t, 1, len(versionBoundaries.Values)) + require.Len(t, versionBoundaries.Values, 1) boundary, ok := versionBoundaries.Values[0].(cadence.Struct) require.True(t, ok) - require.Equal(t, 2, len(boundary.Fields)) + + fields := cadence.FieldsMappedByName(boundary) + require.Len(t, fields, 2) boundaryType, ok := boundary.Type().(*cadence.StructType) require.True(t, ok) - require.Equal(t, 2, len(boundaryType.Fields)) + require.Len(t, boundaryType.Fields, 2) // field 0: blockHeight - require.Equal(t, "blockHeight", boundaryType.Fields[0].Identifier) - require.Equal(t, cadence.UInt64(44), boundary.Fields[0]) + require.Equal(t, + "blockHeight", + boundaryType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.UInt64(44), + fields["blockHeight"], + ) // field 1: version - require.Equal(t, "version", boundaryType.Fields[1].Identifier) - version, ok := boundary.Fields[1].(cadence.Struct) + require.Equal(t, + "version", + boundaryType.Fields[1].Identifier, + ) + version, ok := fields["version"].(cadence.Struct) require.True(t, ok) testSemver(t, version) } func testSemver(t *testing.T, version cadence.Struct) { - require.Equal(t, 4, len(version.Fields)) + versionFields := cadence.FieldsMappedByName(version) + + require.Len(t, versionFields, 4) semverType, ok := version.Type().(*cadence.StructType) require.True(t, ok) - require.Equal(t, 4, len(semverType.Fields)) + require.Len(t, semverType.Fields, 4) // field 0: preRelease - require.Equal(t, "preRelease", semverType.Fields[0].Identifier) - require.Equal(t, cadence.NewOptional(cadence.String("")), version.Fields[0]) + require.Equal(t, + "preRelease", + semverType.Fields[0].Identifier, + ) + require.Equal(t, + cadence.NewOptional(cadence.String("")), + versionFields["preRelease"], + ) // field 1: major - require.Equal(t, "major", semverType.Fields[1].Identifier) - require.Equal(t, cadence.UInt8(2), version.Fields[1]) + require.Equal(t, + "major", + semverType.Fields[1].Identifier, + ) + require.Equal(t, + cadence.UInt8(2), + versionFields["major"], + ) // field 2: minor - require.Equal(t, "minor", semverType.Fields[2].Identifier) - require.Equal(t, cadence.UInt8(13), version.Fields[2]) + require.Equal(t, + "minor", + semverType.Fields[2].Identifier, + ) + require.Equal(t, + cadence.UInt8(13), + versionFields["minor"], + ) // field 3: patch - require.Equal(t, "patch", semverType.Fields[3].Identifier) - require.Equal(t, cadence.UInt8(7), version.Fields[3]) + require.Equal(t, + "patch", + semverType.Fields[3].Identifier, + ) + require.Equal(t, + cadence.UInt8(7), + versionFields["patch"], + ) } func createEpochSetupEvent() cadence.Event { diff --git a/encoding/ccf/traverse_value.go b/encoding/ccf/traverse_value.go index 35e8b79f62..f9776eb816 100644 --- a/encoding/ccf/traverse_value.go +++ b/encoding/ccf/traverse_value.go @@ -97,27 +97,27 @@ func (ct *compositeTypes) traverseValue(v cadence.Value) { } case cadence.Struct: - for _, field := range v.Fields { + for _, field := range getFieldValues(v) { ct.traverseValue(field) } case cadence.Resource: - for _, field := range v.Fields { + for _, field := range getFieldValues(v) { ct.traverseValue(field) } case cadence.Event: - for _, field := range v.Fields { + for _, field := range getFieldValues(v) { ct.traverseValue(field) } case cadence.Contract: - for _, field := range v.Fields { + for _, field := range getFieldValues(v) { ct.traverseValue(field) } case cadence.Attachment: - for _, field := range v.Fields { + for _, field := range getFieldValues(v) { ct.traverseValue(field) } } diff --git a/encoding/json/encode.go b/encoding/json/encode.go index f8e9189f9f..895fe5b614 100644 --- a/encoding/json/encode.go +++ b/encoding/json/encode.go @@ -27,6 +27,7 @@ import ( goRuntime "runtime" "strconv" "strings" + _ "unsafe" "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" @@ -603,28 +604,61 @@ func prepareInclusiveRange(v *cadence.InclusiveRange) jsonValue { } } +//go:linkname getFieldValues github.com/onflow/cadence.getFieldValues +func getFieldValues(cadence.Composite) []cadence.Value + func prepareStruct(v cadence.Struct) jsonValue { - return prepareComposite(structTypeStr, v.StructType.ID(), v.StructType.Fields, v.Fields) + return prepareComposite( + structTypeStr, + v.StructType.ID(), + v.StructType.Fields, + getFieldValues(v), + ) } func prepareResource(v cadence.Resource) jsonValue { - return prepareComposite(resourceTypeStr, v.ResourceType.ID(), v.ResourceType.Fields, v.Fields) + return prepareComposite( + resourceTypeStr, + v.ResourceType.ID(), + v.ResourceType.Fields, + getFieldValues(v), + ) } func prepareEvent(v cadence.Event) jsonValue { - return prepareComposite(eventTypeStr, v.EventType.ID(), v.EventType.Fields, v.Fields) + return prepareComposite( + eventTypeStr, + v.EventType.ID(), + v.EventType.Fields, + getFieldValues(v), + ) } func prepareContract(v cadence.Contract) jsonValue { - return prepareComposite(contractTypeStr, v.ContractType.ID(), v.ContractType.Fields, v.Fields) + return prepareComposite( + contractTypeStr, + v.ContractType.ID(), + v.ContractType.Fields, + getFieldValues(v), + ) } func prepareEnum(v cadence.Enum) jsonValue { - return prepareComposite(enumTypeStr, v.EnumType.ID(), v.EnumType.Fields, v.Fields) + return prepareComposite( + enumTypeStr, + v.EnumType.ID(), + v.EnumType.Fields, + getFieldValues(v), + ) } func prepareAttachment(v cadence.Attachment) jsonValue { - return prepareComposite(attachmentTypeStr, v.AttachmentType.ID(), v.AttachmentType.Fields, v.Fields) + return prepareComposite( + attachmentTypeStr, + v.AttachmentType.ID(), + v.AttachmentType.Fields, + getFieldValues(v), + ) } func prepareComposite(kind, id string, fieldTypes []cadence.Field, fields []cadence.Value) jsonValue { diff --git a/encoding/json/encoding_test.go b/encoding/json/encoding_test.go index 57592e01b5..fb8bd50872 100644 --- a/encoding/json/encoding_test.go +++ b/encoding/json/encoding_test.go @@ -3170,11 +3170,9 @@ func TestExportRecursiveType(t *testing.T) { testEncode( t, - cadence.Resource{ - Fields: []cadence.Value{ - cadence.Optional{}, - }, - }.WithType(ty), + cadence.NewResource([]cadence.Value{ + cadence.Optional{}, + }).WithType(ty), // language=json ` { diff --git a/runtime/account_test.go b/runtime/account_test.go index 0087bd8c9e..35941285b6 100644 --- a/runtime/account_test.go +++ b/runtime/account_test.go @@ -543,42 +543,39 @@ func TestRuntimeAuthAccountKeysAdd(t *testing.T) { key1AddedEvent.Type().ID(), ) + key0AddedEventFields := cadence.FieldsMappedByName(key0AddedEvent) + key1AddedEventFields := cadence.FieldsMappedByName(key1AddedEvent) + // address assert.Equal(t, cadence.Address(accountKeyTestAddress), - key0AddedEvent.Fields[0], + key0AddedEventFields[stdlib.AccountEventAddressParameter.Identifier], ) assert.Equal(t, cadence.Address(accountKeyTestAddress), - key1AddedEvent.Fields[0], + key1AddedEventFields[stdlib.AccountEventAddressParameter.Identifier], ) // public key assert.Equal(t, - cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue(pubKey1), - - // Signature Algo - newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), - }, - }, - key0AddedEvent.Fields[1], + cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue(pubKey1), + + // Signature Algo + newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), + }).WithType(PublicKeyType), + key0AddedEventFields[stdlib.AccountEventPublicKeyParameterAsCompositeType.Identifier], ) assert.Equal(t, - cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue(pubKey2), - - // Signature Algo - newSignAlgoValue(sema.SignatureAlgorithmECDSA_secp256k1), - }, - }, - key1AddedEvent.Fields[1], + cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue(pubKey2), + + // Signature Algo + newSignAlgoValue(sema.SignatureAlgorithmECDSA_secp256k1), + }).WithType(PublicKeyType), + key1AddedEventFields[stdlib.AccountEventPublicKeyParameterAsCompositeType.Identifier], ) // key weight @@ -589,46 +586,62 @@ func TestRuntimeAuthAccountKeysAdd(t *testing.T) { assert.Equal(t, key0Weight, - key0AddedEvent.Fields[2], + key0AddedEventFields[stdlib.AccountEventKeyWeightParameter.Identifier], ) assert.Equal(t, sema.UFix64TypeName, - key0AddedEvent.Fields[2].Type().ID(), + key0AddedEventFields[stdlib.AccountEventKeyWeightParameter.Identifier].Type().ID(), ) assert.Equal(t, key1Weight, - key1AddedEvent.Fields[2], + key1AddedEventFields[stdlib.AccountEventKeyWeightParameter.Identifier], ) assert.Equal(t, sema.UFix64TypeName, - key1AddedEvent.Fields[2].Type().ID(), + key1AddedEventFields[stdlib.AccountEventKeyWeightParameter.Identifier].Type().ID(), ) // key hash algorithm + key0HashAlgo := key0AddedEventFields[stdlib.AccountEventHashAlgorithmParameter.Identifier].(cadence.Enum) + key0HashAlgoFields := cadence.FieldsMappedByName(key0HashAlgo) assert.Equal(t, cadence.UInt8(sema.HashAlgorithmSHA3_256), - key0AddedEvent.Fields[3].(cadence.Enum).Fields[0], + key0HashAlgoFields[sema.EnumRawValueFieldName], ) assert.Equal(t, sema.HashAlgorithmTypeName, - key0AddedEvent.Fields[3].Type().ID(), + key0AddedEventFields[stdlib.AccountEventHashAlgorithmParameter.Identifier].Type().ID(), ) + key1HashAlgo := key1AddedEventFields[stdlib.AccountEventHashAlgorithmParameter.Identifier].(cadence.Enum) + key1HashAlgoFields := cadence.FieldsMappedByName(key1HashAlgo) assert.Equal(t, cadence.UInt8(sema.HashAlgorithmSHA2_256), - key1AddedEvent.Fields[3].(cadence.Enum).Fields[0], + key1HashAlgoFields[sema.EnumRawValueFieldName], ) assert.Equal(t, sema.HashAlgorithmTypeName, - key1AddedEvent.Fields[3].Type().ID(), + key1AddedEventFields[stdlib.AccountEventHashAlgorithmParameter.Identifier].Type().ID(), ) // key index - assert.Equal(t, cadence.NewInt(0), key0AddedEvent.Fields[4]) - assert.Equal(t, sema.IntTypeName, key0AddedEvent.Fields[4].Type().ID()) - assert.Equal(t, cadence.NewInt(1), key1AddedEvent.Fields[4]) - assert.Equal(t, sema.IntTypeName, key1AddedEvent.Fields[4].Type().ID()) + assert.Equal(t, + cadence.NewInt(0), + key0AddedEventFields[stdlib.AccountEventKeyIndexParameter.Identifier], + ) + assert.Equal(t, + sema.IntTypeName, + key0AddedEventFields[stdlib.AccountEventKeyIndexParameter.Identifier].Type().ID(), + ) + assert.Equal(t, + cadence.NewInt(1), + key1AddedEventFields[stdlib.AccountEventKeyIndexParameter.Identifier], + ) + assert.Equal(t, + sema.IntTypeName, + key1AddedEventFields[stdlib.AccountEventKeyIndexParameter.Identifier].Type().ID(), + ) } func TestRuntimePublicAccountKeys(t *testing.T) { @@ -886,10 +899,12 @@ func TestRuntimeHashAlgorithm(t *testing.T) { require.IsType(t, cadence.Enum{}, optionalValue.Value) builtinStruct := optionalValue.Value.(cadence.Enum) - require.Len(t, builtinStruct.Fields, 1) + fields := cadence.FieldsMappedByName(builtinStruct) + + require.Len(t, fields, 1) assert.Equal(t, cadence.NewUInt8(HashAlgorithmSHA3_256.RawValue()), - builtinStruct.Fields[0], + fields[sema.EnumRawValueFieldName], ) // Check key2 @@ -899,10 +914,11 @@ func TestRuntimeHashAlgorithm(t *testing.T) { require.IsType(t, cadence.Enum{}, optionalValue.Value) builtinStruct = optionalValue.Value.(cadence.Enum) - require.Len(t, builtinStruct.Fields, 1) + fields = cadence.FieldsMappedByName(builtinStruct) + require.Len(t, fields, 1) assert.Equal(t, cadence.NewUInt8(HashAlgorithmSHA3_256.RawValue()), - builtinStruct.Fields[0], + fields[sema.EnumRawValueFieldName], ) // Check key3 @@ -958,10 +974,11 @@ func TestRuntimeSignatureAlgorithm(t *testing.T) { require.IsType(t, cadence.Enum{}, optionalValue.Value) builtinStruct := optionalValue.Value.(cadence.Enum) - require.Len(t, builtinStruct.Fields, 1) + fields := cadence.FieldsMappedByName(builtinStruct) + require.Len(t, fields, 1) assert.Equal(t, cadence.NewUInt8(SignatureAlgorithmECDSA_secp256k1.RawValue()), - builtinStruct.Fields[0], + fields[sema.EnumRawValueFieldName], ) // Check key2 @@ -971,10 +988,11 @@ func TestRuntimeSignatureAlgorithm(t *testing.T) { require.IsType(t, cadence.Enum{}, optionalValue.Value) builtinStruct = optionalValue.Value.(cadence.Enum) - require.Len(t, builtinStruct.Fields, 1) + fields = cadence.FieldsMappedByName(builtinStruct) + require.Len(t, fields, 1) assert.Equal(t, cadence.NewUInt8(SignatureAlgorithmECDSA_secp256k1.RawValue()), - builtinStruct.Fields[0], + fields[sema.EnumRawValueFieldName], ) // Check key3 @@ -1026,36 +1044,30 @@ func accountKeyExportedValue( panic(err) } - return cadence.Struct{ - StructType: AccountKeyType, - Fields: []cadence.Value{ - // Key index - cadence.NewInt(index), - - // Public Key (struct) - cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue(publicKeyBytes), - - // Signature Algo - newSignAlgoValue(signAlgo), - }, - }, + return cadence.NewStruct([]cadence.Value{ + // Key index + cadence.NewInt(index), - // Hash algo - cadence.NewEnum([]cadence.Value{ - cadence.NewUInt8(hashAlgo.RawValue()), - }).WithType(HashAlgoType), + // Public Key (struct) + cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue(publicKeyBytes), - // Weight - weightUFix64, + // Signature Algo + newSignAlgoValue(signAlgo), + }).WithType(PublicKeyType), - // IsRevoked - cadence.NewBool(isRevoked), - }, - } + // Hash algo + cadence.NewEnum([]cadence.Value{ + cadence.NewUInt8(hashAlgo.RawValue()), + }).WithType(HashAlgoType), + + // Weight + weightUFix64, + + // IsRevoked + cadence.NewBool(isRevoked), + }).WithType(AccountKeyType) } var accountKeyTestAddress = Address{42} @@ -1279,16 +1291,13 @@ func TestRuntimePublicKey(t *testing.T) { value, err := executeScript(script, runtimeInterface) require.NoError(t, err) - expected := cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue([]byte{1, 2}), + expected := cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue([]byte{1, 2}), - // Signature Algo - newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), - }, - } + // Signature Algo + newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), + }).WithType(PublicKeyType) assert.Equal(t, expected, value) }) @@ -1544,16 +1553,13 @@ func TestRuntimePublicKey(t *testing.T) { value, err := executeScript(script, runtimeInterface) require.NoError(t, err) - expected := cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue([]byte{1, 2}), + expected := cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue([]byte{1, 2}), - // Signature Algo - newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), - }, - } + // Signature Algo + newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), + }).WithType(PublicKeyType) assert.Equal(t, expected, value) }) @@ -1585,19 +1591,15 @@ func TestRuntimePublicKey(t *testing.T) { value, err := executeScript(script, runtimeInterface) require.NoError(t, err) - expected := cadence.Struct{ - StructType: PublicKeyType, - Fields: []cadence.Value{ - // Public key (bytes) - newBytesValue([]byte{1, 2}), - // Signature Algo - newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), - }, - } + expected := cadence.NewStruct([]cadence.Value{ + // Public key (bytes) + newBytesValue([]byte{1, 2}), + // Signature Algo + newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256), + }).WithType(PublicKeyType) assert.Equal(t, expected, value) }) - } func TestRuntimeAuthAccountContracts(t *testing.T) { diff --git a/runtime/attachments_test.go b/runtime/attachments_test.go index f512cbfeab..9864dcb705 100644 --- a/runtime/attachments_test.go +++ b/runtime/attachments_test.go @@ -395,9 +395,16 @@ func TestRuntimeAccountAttachedExport(t *testing.T) { require.NoError(t, err) require.IsType(t, cadence.Resource{}, v) - require.Len(t, v.(cadence.Resource).Fields, 2) - require.IsType(t, cadence.Attachment{}, v.(cadence.Resource).Fields[1]) - require.Equal(t, "A.0000000000000001.Test.A()", v.(cadence.Resource).Fields[1].String()) + fields := cadence.FieldsMappedByName(v.(cadence.Resource)) + require.Len(t, fields, 2) + + attachment := fields["$A.0000000000000001.Test.A"] + require.IsType(t, cadence.Attachment{}, attachment) + require.Equal( + t, + "A.0000000000000001.Test.A()", + attachment.String(), + ) } func TestRuntimeAccountAttachmentSaveAndBorrow(t *testing.T) { diff --git a/runtime/contract_test.go b/runtime/contract_test.go index 02a9bb7ece..0c4d5476e4 100644 --- a/runtime/contract_test.go +++ b/runtime/contract_test.go @@ -886,18 +886,41 @@ func TestRuntimeContractInterfaceEventEmission(t *testing.T) { // first two events are `AccountContractAdded` require.Len(t, actualEvents, 4) - intfEvent := actualEvents[2] + interfaceEvent := actualEvents[2] concreteEvent := actualEvents[3] - require.Equal(t, intfEvent.EventType.QualifiedIdentifier, "TestInterface.Foo") - require.Equal(t, concreteEvent.EventType.QualifiedIdentifier, "TestContract.Foo") + require.Equal( + t, + "TestInterface.Foo", + interfaceEvent.EventType.QualifiedIdentifier, + ) + require.Equal( + t, + "TestContract.Foo", + concreteEvent.EventType.QualifiedIdentifier, + ) + + interfaceFields := cadence.FieldsMappedByName(interfaceEvent) + concreteFields := cadence.FieldsMappedByName(concreteEvent) - require.Len(t, intfEvent.Fields, 1) - require.Len(t, concreteEvent.Fields, 2) + require.Len(t, interfaceFields, 1) + require.Len(t, concreteFields, 2) - require.Equal(t, intfEvent.Fields[0], cadence.NewInt(3)) - require.Equal(t, concreteEvent.Fields[0], cadence.String("")) - require.Equal(t, concreteEvent.Fields[1], cadence.NewInt(2)) + require.Equal( + t, + cadence.NewInt(3), + interfaceFields["x"], + ) + require.Equal( + t, + cadence.String(""), + concreteFields["x"], + ) + require.Equal( + t, + cadence.NewInt(2), + concreteFields["y"], + ) } func TestRuntimeContractInterfaceConditionEventEmission(t *testing.T) { @@ -1009,18 +1032,41 @@ func TestRuntimeContractInterfaceConditionEventEmission(t *testing.T) { // first two events are `AccountContractAdded` require.Len(t, actualEvents, 4) - intfEvent := actualEvents[3] + interfaceEvent := actualEvents[3] concreteEvent := actualEvents[2] - require.Equal(t, intfEvent.EventType.QualifiedIdentifier, "TestInterface.Foo") - require.Equal(t, concreteEvent.EventType.QualifiedIdentifier, "TestContract.Foo") + require.Equal( + t, + "TestInterface.Foo", + interfaceEvent.EventType.QualifiedIdentifier, + ) + require.Equal( + t, + "TestContract.Foo", + concreteEvent.EventType.QualifiedIdentifier, + ) + + interfaceFields := cadence.FieldsMappedByName(interfaceEvent) + concreteFields := cadence.FieldsMappedByName(concreteEvent) - require.Len(t, intfEvent.Fields, 1) - require.Len(t, concreteEvent.Fields, 2) + require.Len(t, interfaceFields, 1) + require.Len(t, concreteFields, 2) - require.Equal(t, intfEvent.Fields[0], cadence.NewInt(3)) - require.Equal(t, concreteEvent.Fields[0], cadence.String("")) - require.Equal(t, concreteEvent.Fields[1], cadence.NewInt(2)) + require.Equal( + t, + cadence.NewInt(3), + interfaceFields["x"], + ) + require.Equal( + t, + cadence.String(""), + concreteFields["x"], + ) + require.Equal( + t, + cadence.NewInt(2), + concreteFields["y"], + ) } func TestRuntimeContractTryUpdate(t *testing.T) { diff --git a/runtime/convertValues.go b/runtime/convertValues.go index a38773b79d..33d9e3e3dd 100644 --- a/runtime/convertValues.go +++ b/runtime/convertValues.go @@ -20,6 +20,7 @@ package runtime import ( "math/big" + _ "unsafe" "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" @@ -775,6 +776,9 @@ func ImportValue( }.importValue(value, expectedType) } +//go:linkname getFieldValues github.com/onflow/cadence.getFieldValues +func getFieldValues(cadence.Composite) []cadence.Value + func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type) (interpreter.Value, error) { switch v := value.(type) { case cadence.Void: @@ -847,7 +851,7 @@ func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type) v.StructType.Location, v.StructType.QualifiedIdentifier, v.StructType.Fields, - v.Fields, + getFieldValues(v), ) case cadence.Resource: return i.importCompositeValue( @@ -855,7 +859,7 @@ func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type) v.ResourceType.Location, v.ResourceType.QualifiedIdentifier, v.ResourceType.Fields, - v.Fields, + getFieldValues(v), ) case cadence.Event: return i.importCompositeValue( @@ -863,7 +867,7 @@ func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type) v.EventType.Location, v.EventType.QualifiedIdentifier, v.EventType.Fields, - v.Fields, + getFieldValues(v), ) case cadence.Enum: return i.importCompositeValue( @@ -871,7 +875,7 @@ func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type) v.EnumType.Location, v.EnumType.QualifiedIdentifier, v.EnumType.Fields, - v.Fields, + getFieldValues(v), ) case *cadence.InclusiveRange: return i.importInclusiveRangeValue(v, expectedType) diff --git a/runtime/convertValues_test.go b/runtime/convertValues_test.go index 4d4e2c044e..9ca8b69a20 100644 --- a/runtime/convertValues_test.go +++ b/runtime/convertValues_test.go @@ -474,62 +474,50 @@ func TestRuntimeExportValue(t *testing.T) { publicKeyType := newPublicKeyType(signatureAlgorithmType) hashAlgorithmType := newHashAlgorithmType() - return cadence.Struct{ - StructType: &cadence.StructType{ - QualifiedIdentifier: "AccountKey", - Fields: []cadence.Field{ - { - Identifier: "keyIndex", - Type: cadence.IntType, - }, - { - Identifier: "publicKey", - Type: publicKeyType, - }, - { - Identifier: "hashAlgorithm", - Type: hashAlgorithmType, - }, - { - Identifier: "weight", - Type: cadence.UFix64Type, - }, - { - Identifier: "isRevoked", - Type: cadence.BoolType, - }, + return cadence.NewStruct([]cadence.Value{ + cadence.NewInt(1), + cadence.NewStruct([]cadence.Value{ + cadence.NewArray([]cadence.Value{ + cadence.NewUInt8(1), + cadence.NewUInt8(2), + cadence.NewUInt8(3), + }).WithType(&cadence.VariableSizedArrayType{ + ElementType: cadence.UInt8Type, + }), + cadence.NewEnum([]cadence.Value{ + cadence.UInt8(2), + }).WithType(signatureAlgorithmType), + }).WithType(publicKeyType), + cadence.NewEnum([]cadence.Value{ + cadence.UInt8(1), + }).WithType(hashAlgorithmType), + cadence.UFix64(10_00000000), + cadence.Bool(false), + }).WithType(&cadence.StructType{ + QualifiedIdentifier: "AccountKey", + Fields: []cadence.Field{ + { + Identifier: "keyIndex", + Type: cadence.IntType, }, - }, - Fields: []cadence.Value{ - cadence.NewInt(1), - cadence.Struct{ - StructType: publicKeyType, - Fields: []cadence.Value{ - cadence.NewArray([]cadence.Value{ - cadence.NewUInt8(1), - cadence.NewUInt8(2), - cadence.NewUInt8(3), - }).WithType(&cadence.VariableSizedArrayType{ - ElementType: cadence.UInt8Type, - }), - cadence.Enum{ - EnumType: signatureAlgorithmType, - Fields: []cadence.Value{ - cadence.UInt8(2), - }, - }, - }, + { + Identifier: "publicKey", + Type: publicKeyType, }, - cadence.Enum{ - EnumType: hashAlgorithmType, - Fields: []cadence.Value{ - cadence.UInt8(1), - }, + { + Identifier: "hashAlgorithm", + Type: hashAlgorithmType, + }, + { + Identifier: "weight", + Type: cadence.UFix64Type, + }, + { + Identifier: "isRevoked", + Type: cadence.BoolType, }, - cadence.UFix64(10_00000000), - cadence.Bool(false), }, - } + }) }(), }, { @@ -2353,22 +2341,19 @@ func TestRuntimeEnumValue(t *testing.T) { t.Parallel() newEnumValue := func() cadence.Enum { - return cadence.Enum{ - EnumType: &cadence.EnumType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Direction", - Fields: []cadence.Field{ - { - Identifier: sema.EnumRawValueFieldName, - Type: cadence.IntType, - }, + return cadence.NewEnum([]cadence.Value{ + cadence.NewInt(3), + }).WithType(&cadence.EnumType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Direction", + Fields: []cadence.Field{ + { + Identifier: sema.EnumRawValueFieldName, + Type: cadence.IntType, }, - RawType: cadence.IntType, - }, - Fields: []cadence.Value{ - cadence.NewInt(3), }, - } + RawType: cadence.IntType, + }) } t.Run("test export", func(t *testing.T) { @@ -2723,112 +2708,109 @@ func TestRuntimeComplexStructArgumentPassing(t *testing.T) { t.Parallel() // Complex struct value - complexStructValue := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.OptionalType{ - Type: cadence.StringType, - }, - }, - { - Identifier: "b", - Type: &cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.StringType, - }, - }, - { - Identifier: "c", - Type: &cadence.VariableSizedArrayType{ - ElementType: cadence.StringType, - }, - }, - { - Identifier: "d", - Type: &cadence.ConstantSizedArrayType{ - ElementType: cadence.StringType, - Size: 2, - }, - }, - { - Identifier: "e", - Type: cadence.AddressType, - }, - { - Identifier: "f", - Type: cadence.BoolType, - }, - { - Identifier: "g", - Type: cadence.StoragePathType, - }, - { - Identifier: "h", - Type: cadence.PublicPathType, - }, - { - Identifier: "i", - Type: cadence.PrivatePathType, + structType := &cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.OptionalType{ + Type: cadence.StringType, }, - { - Identifier: "j", - Type: cadence.AnyStructType, + }, + { + Identifier: "b", + Type: &cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.StringType, }, - { - Identifier: "k", - Type: cadence.HashableStructType, + }, + { + Identifier: "c", + Type: &cadence.VariableSizedArrayType{ + ElementType: cadence.StringType, }, }, - }, - - Fields: []cadence.Value{ - cadence.NewOptional( - cadence.String("John"), - ), - cadence.NewDictionary([]cadence.KeyValuePair{ - { - Key: cadence.String("name"), - Value: cadence.String("Doe"), + { + Identifier: "d", + Type: &cadence.ConstantSizedArrayType{ + ElementType: cadence.StringType, + Size: 2, }, - }).WithType(&cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.StringType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.VariableSizedArrayType{ - ElementType: cadence.StringType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.ConstantSizedArrayType{ - ElementType: cadence.StringType, - Size: 2, - }), - cadence.NewAddress([8]byte{0, 0, 0, 0, 0, 1, 0, 2}), - cadence.NewBool(true), - cadence.Path{ - Domain: common.PathDomainStorage, - Identifier: "foo", }, - cadence.Path{ - Domain: common.PathDomainPublic, - Identifier: "foo", + { + Identifier: "e", + Type: cadence.AddressType, }, - cadence.Path{ - Domain: common.PathDomainPrivate, - Identifier: "foo", + { + Identifier: "f", + Type: cadence.BoolType, + }, + { + Identifier: "g", + Type: cadence.StoragePathType, + }, + { + Identifier: "h", + Type: cadence.PublicPathType, }, + { + Identifier: "i", + Type: cadence.PrivatePathType, + }, + { + Identifier: "j", + Type: cadence.AnyStructType, + }, + { + Identifier: "k", + Type: cadence.HashableStructType, + }, + }, + } + complexStructValue := cadence.NewStruct([]cadence.Value{ + cadence.NewOptional( + cadence.String("John"), + ), + cadence.NewDictionary([]cadence.KeyValuePair{ + { + Key: cadence.String("name"), + Value: cadence.String("Doe"), + }, + }).WithType(&cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.StringType, + }), + cadence.NewArray([]cadence.Value{ cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.VariableSizedArrayType{ + ElementType: cadence.StringType, + }), + cadence.NewArray([]cadence.Value{ cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.ConstantSizedArrayType{ + ElementType: cadence.StringType, + Size: 2, + }), + cadence.NewAddress([8]byte{0, 0, 0, 0, 0, 1, 0, 2}), + cadence.NewBool(true), + cadence.Path{ + Domain: common.PathDomainStorage, + Identifier: "foo", + }, + cadence.Path{ + Domain: common.PathDomainPublic, + Identifier: "foo", + }, + cadence.Path{ + Domain: common.PathDomainPrivate, + Identifier: "foo", }, - } + cadence.String("foo"), + cadence.String("foo"), + }).WithType(structType) script := fmt.Sprintf( ` @@ -2885,74 +2867,71 @@ func TestRuntimeComplexStructWithAnyStructFields(t *testing.T) { t.Parallel() // Complex struct value - complexStructValue := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.OptionalType{ - Type: cadence.AnyStructType, - }, - }, - { - Identifier: "b", - Type: &cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.AnyStructType, - }, - }, - { - Identifier: "c", - Type: &cadence.VariableSizedArrayType{ - ElementType: cadence.AnyStructType, - }, + structType := &cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.OptionalType{ + Type: cadence.AnyStructType, }, - { - Identifier: "d", - Type: &cadence.ConstantSizedArrayType{ - ElementType: cadence.AnyStructType, - Size: 2, - }, + }, + { + Identifier: "b", + Type: &cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.AnyStructType, }, - { - Identifier: "e", - Type: cadence.AnyStructType, + }, + { + Identifier: "c", + Type: &cadence.VariableSizedArrayType{ + ElementType: cadence.AnyStructType, }, }, - }, - - Fields: []cadence.Value{ - cadence.NewOptional(cadence.String("John")), - cadence.NewDictionary([]cadence.KeyValuePair{ - { - Key: cadence.String("name"), - Value: cadence.String("Doe"), + { + Identifier: "d", + Type: &cadence.ConstantSizedArrayType{ + ElementType: cadence.AnyStructType, + Size: 2, }, - }).WithType(&cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.AnyStructType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.VariableSizedArrayType{ - ElementType: cadence.AnyStructType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.ConstantSizedArrayType{ - ElementType: cadence.AnyStructType, - Size: 2, - }), - cadence.Path{ - Domain: common.PathDomainStorage, - Identifier: "foo", + }, + { + Identifier: "e", + Type: cadence.AnyStructType, }, }, } + complexStructValue := cadence.NewStruct([]cadence.Value{ + cadence.NewOptional(cadence.String("John")), + cadence.NewDictionary([]cadence.KeyValuePair{ + { + Key: cadence.String("name"), + Value: cadence.String("Doe"), + }, + }).WithType(&cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.AnyStructType, + }), + cadence.NewArray([]cadence.Value{ + cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.VariableSizedArrayType{ + ElementType: cadence.AnyStructType, + }), + cadence.NewArray([]cadence.Value{ + cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.ConstantSizedArrayType{ + ElementType: cadence.AnyStructType, + Size: 2, + }), + cadence.Path{ + Domain: common.PathDomainStorage, + Identifier: "foo", + }, + }).WithType(structType) script := fmt.Sprintf( ` @@ -2995,74 +2974,71 @@ func TestRuntimeComplexStructWithHashableStructFields(t *testing.T) { t.Parallel() // Complex struct value - complexStructValue := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.OptionalType{ - Type: cadence.HashableStructType, - }, - }, - { - Identifier: "b", - Type: &cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.HashableStructType, - }, - }, - { - Identifier: "c", - Type: &cadence.VariableSizedArrayType{ - ElementType: cadence.HashableStructType, - }, + structType := &cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.OptionalType{ + Type: cadence.HashableStructType, }, - { - Identifier: "d", - Type: &cadence.ConstantSizedArrayType{ - ElementType: cadence.HashableStructType, - Size: 2, - }, + }, + { + Identifier: "b", + Type: &cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.HashableStructType, }, - { - Identifier: "e", - Type: cadence.HashableStructType, + }, + { + Identifier: "c", + Type: &cadence.VariableSizedArrayType{ + ElementType: cadence.HashableStructType, }, }, - }, - - Fields: []cadence.Value{ - cadence.NewOptional(cadence.String("John")), - cadence.NewDictionary([]cadence.KeyValuePair{ - { - Key: cadence.String("name"), - Value: cadence.String("Doe"), + { + Identifier: "d", + Type: &cadence.ConstantSizedArrayType{ + ElementType: cadence.HashableStructType, + Size: 2, }, - }).WithType(&cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: cadence.HashableStructType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.VariableSizedArrayType{ - ElementType: cadence.HashableStructType, - }), - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }).WithType(&cadence.ConstantSizedArrayType{ - ElementType: cadence.HashableStructType, - Size: 2, - }), - cadence.Path{ - Domain: common.PathDomainStorage, - Identifier: "foo", + }, + { + Identifier: "e", + Type: cadence.HashableStructType, }, }, } + complexStructValue := cadence.NewStruct([]cadence.Value{ + cadence.NewOptional(cadence.String("John")), + cadence.NewDictionary([]cadence.KeyValuePair{ + { + Key: cadence.String("name"), + Value: cadence.String("Doe"), + }, + }).WithType(&cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: cadence.HashableStructType, + }), + cadence.NewArray([]cadence.Value{ + cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.VariableSizedArrayType{ + ElementType: cadence.HashableStructType, + }), + cadence.NewArray([]cadence.Value{ + cadence.String("foo"), + cadence.String("bar"), + }).WithType(&cadence.ConstantSizedArrayType{ + ElementType: cadence.HashableStructType, + Size: 2, + }), + cadence.Path{ + Domain: common.PathDomainStorage, + Identifier: "foo", + }, + }).WithType(structType) script := fmt.Sprintf( ` @@ -3119,105 +3095,90 @@ func TestRuntimeMalformedArgumentPassing(t *testing.T) { } newMalformedStruct1 := func() cadence.Struct { - return cadence.Struct{ - StructType: newMalformedStructType1(), - Fields: []cadence.Value{ - cadence.NewInt(3), - }, - } + return cadence.NewStruct([]cadence.Value{ + cadence.NewInt(3), + }).WithType(newMalformedStructType1()) } // Struct with wrong field name newMalformedStruct2 := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "nonExisting", - Type: cadence.StringType, - }, + return cadence.NewStruct([]cadence.Value{ + cadence.String("John"), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "nonExisting", + Type: cadence.StringType, }, }, - Fields: []cadence.Value{ - cadence.String("John"), - }, - } + }) } // Struct with nested malformed array value newMalformedStruct3 := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Bar", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.VariableSizedArrayType{ - ElementType: newMalformedStructType1(), - }, + return cadence.NewStruct([]cadence.Value{ + cadence.NewArray([]cadence.Value{ + newMalformedStruct1(), + }), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Bar", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.VariableSizedArrayType{ + ElementType: newMalformedStructType1(), }, }, }, - Fields: []cadence.Value{ - cadence.NewArray([]cadence.Value{ - newMalformedStruct1(), - }), - }, - } + }) } // Struct with nested malformed dictionary value newMalformedStruct4 := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Baz", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.DictionaryType{ - KeyType: cadence.StringType, - ElementType: newMalformedStructType1(), - }, - }, + return cadence.NewStruct([]cadence.Value{ + cadence.NewDictionary([]cadence.KeyValuePair{ + { + Key: cadence.String("foo"), + Value: newMalformedStruct1(), }, - }, - Fields: []cadence.Value{ - cadence.NewDictionary([]cadence.KeyValuePair{ - { - Key: cadence.String("foo"), - Value: newMalformedStruct1(), + }), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Baz", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.DictionaryType{ + KeyType: cadence.StringType, + ElementType: newMalformedStructType1(), }, - }), + }, }, - } + }) } // Struct with nested array with mismatching element type newMalformedStruct5 := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Bar", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: &cadence.VariableSizedArrayType{ - ElementType: newMalformedStructType1(), - }, + return cadence.NewStruct([]cadence.Value{ + cadence.NewArray([]cadence.Value{ + cadence.String("mismatching value"), + }), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Bar", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: &cadence.VariableSizedArrayType{ + ElementType: newMalformedStructType1(), }, }, }, - Fields: []cadence.Value{ - cadence.NewArray([]cadence.Value{ - cadence.String("mismatching value"), - }), - }, - } + }) } type argumentPassingTest struct { @@ -4949,12 +4910,9 @@ func TestRuntimeImportExportComplex(t *testing.T) { common.ZeroAddress, ) - externalCompositeValue := cadence.Struct{ - StructType: externalCompositeType, - Fields: []cadence.Value{ - externalDictionaryValue, - }, - } + externalCompositeValue := cadence.NewStruct([]cadence.Value{ + externalDictionaryValue, + }).WithType(externalCompositeType) t.Run("export", func(t *testing.T) { @@ -5025,25 +4983,21 @@ func TestRuntimeStaticTypeAvailability(t *testing.T) { } ` - structValue := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: cadence.AnyStructType, - }, + structValue := cadence.NewStruct([]cadence.Value{ + cadence.NewArray([]cadence.Value{ + cadence.String("foo"), + cadence.String("bar"), + }), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: cadence.AnyStructType, }, }, - - Fields: []cadence.Value{ - cadence.NewArray([]cadence.Value{ - cadence.String("foo"), - cadence.String("bar"), - }), - }, - } + }) _, err := executeTestScript(t, script, structValue) require.NoError(t, err) @@ -5063,27 +5017,23 @@ func TestRuntimeStaticTypeAvailability(t *testing.T) { } ` - structValue := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.ScriptLocation{}, - QualifiedIdentifier: "Foo", - Fields: []cadence.Field{ - { - Identifier: "a", - Type: cadence.AnyStructType, - }, + structValue := cadence.NewStruct([]cadence.Value{ + cadence.NewDictionary([]cadence.KeyValuePair{ + { + Key: cadence.String("foo"), + Value: cadence.String("bar"), + }, + }), + }).WithType(&cadence.StructType{ + Location: common.ScriptLocation{}, + QualifiedIdentifier: "Foo", + Fields: []cadence.Field{ + { + Identifier: "a", + Type: cadence.AnyStructType, }, }, - - Fields: []cadence.Value{ - cadence.NewDictionary([]cadence.KeyValuePair{ - { - Key: cadence.String("foo"), - Value: cadence.String("bar"), - }, - }), - }, - } + }) _, err := executeTestScript(t, script, structValue) require.NoError(t, err) diff --git a/runtime/crypto_test.go b/runtime/crypto_test.go index eb24fe59f9..c869e54239 100644 --- a/runtime/crypto_test.go +++ b/runtime/crypto_test.go @@ -276,8 +276,12 @@ func TestRuntimeHashingAlgorithmExport(t *testing.T) { require.IsType(t, cadence.Enum{}, value) enumValue := value.(cadence.Enum) - require.Len(t, enumValue.Fields, 1) - assert.Equal(t, cadence.NewUInt8(algo.RawValue()), enumValue.Fields[0]) + fields := cadence.FieldsMappedByName(enumValue) + require.Len(t, fields, 1) + assert.Equal(t, + cadence.NewUInt8(algo.RawValue()), + fields[sema.EnumRawValueFieldName], + ) } for _, algo := range sema.HashAlgorithms { @@ -317,8 +321,12 @@ func TestRuntimeSignatureAlgorithmExport(t *testing.T) { require.IsType(t, cadence.Enum{}, value) enumValue := value.(cadence.Enum) - require.Len(t, enumValue.Fields, 1) - assert.Equal(t, cadence.NewUInt8(algo.RawValue()), enumValue.Fields[0]) + fields := cadence.FieldsMappedByName(enumValue) + require.Len(t, fields, 1) + assert.Equal(t, + cadence.NewUInt8(algo.RawValue()), + fields[sema.EnumRawValueFieldName], + ) } for _, algo := range sema.SignatureAlgorithms { @@ -655,6 +663,7 @@ func TestRuntimeBLSAggregatePublicKeys(t *testing.T) { ) require.NoError(t, err) + fields := cadence.FieldsMappedByName(result.(cadence.Optional).Value.(cadence.Struct)) assert.Equal(t, cadence.NewArray([]cadence.Value{ cadence.UInt8(1), @@ -664,7 +673,7 @@ func TestRuntimeBLSAggregatePublicKeys(t *testing.T) { }).WithType(&cadence.VariableSizedArrayType{ ElementType: cadence.UInt8Type, }), - result.(cadence.Optional).Value.(cadence.Struct).Fields[0], + fields[sema.PublicKeyTypePublicKeyFieldName], ) assert.True(t, called) diff --git a/runtime/deployment_test.go b/runtime/deployment_test.go index c885f4590a..be963f97cd 100644 --- a/runtime/deployment_test.go +++ b/runtime/deployment_test.go @@ -55,24 +55,10 @@ func TestRuntimeTransactionWithContractDeployment(t *testing.T) { require.Equal(t, event.Type(), expectedEventType) - expectedEventCompositeType := expectedEventType.(*cadence.EventType) - - codeHashParameterIndex := -1 - - for i, field := range expectedEventCompositeType.Fields { - if field.Identifier != stdlib.AccountEventCodeHashParameter.Identifier { - continue - } - codeHashParameterIndex = i - } - - if codeHashParameterIndex < 0 { - t.Error("couldn't find code hash parameter in event type") - } - expectedCodeHash := sha3.Sum256(accountCode) - codeHashValue := event.Fields[codeHashParameterIndex] + fields := cadence.FieldsMappedByName(event) + codeHashValue := fields["codeHash"] inter := NewTestInterpreter(t) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index ede57acf95..11b95b2c04 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -18198,12 +18198,17 @@ func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeV v.base = base } -func attachmentMemberName(ty sema.Type) string { - return unrepresentableNamePrefix + string(ty.ID()) +func AttachmentMemberName(typeID string) string { + return unrepresentableNamePrefix + typeID } func (v *CompositeValue) getAttachmentValue(interpreter *Interpreter, locationRange LocationRange, ty sema.Type) *CompositeValue { - if attachment := v.GetMember(interpreter, locationRange, attachmentMemberName(ty)); attachment != nil { + attachment := v.GetMember( + interpreter, + locationRange, + AttachmentMemberName(string(ty.ID())), + ) + if attachment != nil { return attachment.(*CompositeValue) } return nil @@ -18384,7 +18389,8 @@ func (v *CompositeValue) SetTypeKey( attachmentType sema.Type, attachment Value, ) { - if v.SetMember(interpreter, locationRange, attachmentMemberName(attachmentType), attachment) { + memberName := AttachmentMemberName(string(attachmentType.ID())) + if v.SetMember(interpreter, locationRange, memberName, attachment) { panic(DuplicateAttachmentError{ AttachmentType: attachmentType, Value: v, @@ -18398,7 +18404,8 @@ func (v *CompositeValue) RemoveTypeKey( locationRange LocationRange, attachmentType sema.Type, ) Value { - return v.RemoveMember(interpreter, locationRange, attachmentMemberName(attachmentType)) + memberName := AttachmentMemberName(string(attachmentType.ID())) + return v.RemoveMember(interpreter, locationRange, memberName) } func (v *CompositeValue) Iterator(interpreter *Interpreter, locationRange LocationRange) ValueIterator { diff --git a/runtime/predeclaredvalues_test.go b/runtime/predeclaredvalues_test.go index 62b7633440..5fa2a24b1e 100644 --- a/runtime/predeclaredvalues_test.go +++ b/runtime/predeclaredvalues_test.go @@ -385,10 +385,13 @@ func TestRuntimePredeclaredTypes(t *testing.T) { require.NoError(t, err) require.Equal(t, - cadence.Struct{ - StructType: cadence.NewStructType(nil, xType.QualifiedIdentifier(), []cadence.Field{}, nil), - Fields: []cadence.Value{}, - }, + cadence.NewStruct([]cadence.Value{}). + WithType(cadence.NewStructType( + nil, + xType.QualifiedIdentifier(), + []cadence.Field{}, + nil, + )), result, ) }) @@ -529,10 +532,13 @@ func TestRuntimePredeclaredTypes(t *testing.T) { require.NoError(t, err) require.Equal(t, - cadence.Struct{ - StructType: cadence.NewStructType(nil, yType.QualifiedIdentifier(), []cadence.Field{}, nil), - Fields: []cadence.Value{}, - }, + cadence.NewStruct([]cadence.Value{}). + WithType(cadence.NewStructType( + nil, + yType.QualifiedIdentifier(), + []cadence.Field{}, + nil, + )), result, ) }) diff --git a/runtime/program_params_validation_test.go b/runtime/program_params_validation_test.go index f9a2b693db..9fb66a85a0 100644 --- a/runtime/program_params_validation_test.go +++ b/runtime/program_params_validation_test.go @@ -58,24 +58,20 @@ func TestRuntimeScriptParameterTypeValidation(t *testing.T) { } newFooStruct := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ + return cadence.NewStruct([]cadence.Value{}). + WithType(&cadence.StructType{ Location: common.ScriptLocation{}, QualifiedIdentifier: "Foo", Fields: []cadence.Field{}, - }, - Fields: []cadence.Value{}, - } + }) } newPublicAccountKeys := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ + return cadence.NewStruct([]cadence.Value{}). + WithType(&cadence.StructType{ QualifiedIdentifier: "Account.Keys", Fields: []cadence.Field{}, - }, - Fields: []cadence.Value{}, - } + }) } executeScript := func(t *testing.T, script string, arg cadence.Value) (err error) { @@ -669,27 +665,23 @@ func TestRuntimeTransactionParameterTypeValidation(t *testing.T) { } newFooStruct := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ + return cadence.NewStruct([]cadence.Value{}). + WithType(&cadence.StructType{ Location: common.AddressLocation{ Address: common.MustBytesToAddress([]byte{0x1}), Name: "C", }, QualifiedIdentifier: "C.Foo", Fields: []cadence.Field{}, - }, - Fields: []cadence.Value{}, - } + }) } newPublicAccountKeys := func() cadence.Struct { - return cadence.Struct{ - StructType: &cadence.StructType{ + return cadence.NewStruct([]cadence.Value{}). + WithType(&cadence.StructType{ QualifiedIdentifier: "Account.Keys", Fields: []cadence.Field{}, - }, - Fields: []cadence.Value{}, - } + }) } executeTransaction := func( @@ -1268,24 +1260,21 @@ func TestRuntimeTransactionParameterTypeValidation(t *testing.T) { cadence.NewReferenceType(cadence.UnauthorizedAccess, cadence.AccountType), ) - arg := cadence.Struct{ - StructType: &cadence.StructType{ - Location: common.AddressLocation{ - Address: address, - Name: "C", - }, - QualifiedIdentifier: "C.S", - Fields: []cadence.Field{ - { - Identifier: "cap", - Type: &cadence.CapabilityType{}, - }, - }, + arg := cadence.NewStruct([]cadence.Value{ + capability, + }).WithType(&cadence.StructType{ + Location: common.AddressLocation{ + Address: address, + Name: "C", }, - Fields: []cadence.Value{ - capability, + QualifiedIdentifier: "C.S", + Fields: []cadence.Field{ + { + Identifier: "cap", + Type: &cadence.CapabilityType{}, + }, }, - } + }) err := executeTransaction(t, script, contracts, arg) expectRuntimeError(t, err, &ArgumentNotImportableError{}) diff --git a/runtime/resourcedictionary_test.go b/runtime/resourcedictionary_test.go index ed463df2a5..238a656718 100644 --- a/runtime/resourcedictionary_test.go +++ b/runtime/resourcedictionary_test.go @@ -982,8 +982,10 @@ func TestRuntimeResourceDictionaryValues_Destruction(t *testing.T) { require.Equal(t, "flow.AccountContractAdded", events[0].EventType.ID()) require.Equal(t, "A.0000000000000001.Test.R.ResourceDestroyed", events[1].EventType.ID()) require.Equal(t, "A.0000000000000001.Test.R.ResourceDestroyed", events[2].EventType.ID()) - require.Equal(t, "1", events[2].Fields[0].String()) - require.Equal(t, "2", events[1].Fields[0].String()) + event2Fields := cadence.FieldsMappedByName(events[1]) + event3Fields := cadence.FieldsMappedByName(events[2]) + require.Equal(t, "2", event2Fields["value"].String()) + require.Equal(t, "1", event3Fields["value"].String()) } func TestRuntimeResourceDictionaryValues_Insertion(t *testing.T) { diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index e8f0bebd4e..22257dc7ee 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -9079,10 +9079,10 @@ func TestRuntimeEventEmission(t *testing.T) { assert.Equal( t, - []cadence.Value{ - cadence.NewInt(42), + map[string]cadence.Value{ + "ref": cadence.NewInt(42), }, - event.GetFieldValues(), + cadence.FieldsMappedByName(event), ) }) @@ -9138,10 +9138,10 @@ func TestRuntimeEventEmission(t *testing.T) { assert.Equal( t, - []cadence.Value{ - cadence.NewInt(42), + map[string]cadence.Value{ + "ref": cadence.NewInt(42), }, - event.GetFieldValues(), + cadence.FieldsMappedByName(event), ) }) diff --git a/types.go b/types.go index f6faabe539..2e39a6920e 100644 --- a/types.go +++ b/types.go @@ -426,13 +426,13 @@ func NewField(identifier string, typ Type) Field { } } -type HasFields interface { - GetFields() []Field - GetFieldValues() []Value -} - -func GetFieldByName(v HasFields, fieldName string) Value { - fieldValues := v.GetFieldValues() +// SearchFieldByName searches for the field with the given name in the composite type, +// and returns the value of the field, or nil if the field is not found. +// +// WARNING: This function performs a linear search, so is not efficient for accessing multiple fields. +// Prefer using FieldsMappedByName if you need to access multiple fields. +func SearchFieldByName(v Composite, fieldName string) Value { + fieldValues := v.getFieldValues() fields := v.GetFields() if fieldValues == nil || fields == nil { @@ -441,14 +441,14 @@ func GetFieldByName(v HasFields, fieldName string) Value { for i, field := range v.GetFields() { if field.Identifier == fieldName { - return v.GetFieldValues()[i] + return fieldValues[i] } } return nil } -func GetFieldsMappedByName(v HasFields) map[string]Value { - fieldValues := v.GetFieldValues() +func FieldsMappedByName(v Composite) map[string]Value { + fieldValues := v.getFieldValues() fields := v.GetFields() if fieldValues == nil || fields == nil { @@ -456,14 +456,21 @@ func GetFieldsMappedByName(v HasFields) map[string]Value { } fieldsMap := make(map[string]Value, len(fields)) - for i, field := range fields { - fieldsMap[field.Identifier] = fieldValues[i] + for i, fieldValue := range fieldValues { + var fieldName string + if i < len(fields) { + fieldName = fields[i].Identifier + } else if attachment, ok := fieldValue.(Attachment); ok { + fieldName = interpreter.AttachmentMemberName(attachment.Type().ID()) + } + fieldsMap[fieldName] = fieldValue } + return fieldsMap } // DecodeFields decodes a HasFields into a struct -func DecodeFields(hasFields HasFields, s interface{}) error { +func DecodeFields(composite Composite, s interface{}) error { v := reflect.ValueOf(s) if !v.IsValid() || v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { return fmt.Errorf("s must be a pointer to a struct") @@ -472,7 +479,7 @@ func DecodeFields(hasFields HasFields, s interface{}) error { v = v.Elem() t := v.Type() - fieldsMap := GetFieldsMappedByName(hasFields) + fieldsMap := FieldsMappedByName(composite) for i := 0; i < v.NumField(); i++ { structField := t.Field(i) diff --git a/values.go b/values.go index 01b893706e..bd82ecf7d6 100644 --- a/values.go +++ b/values.go @@ -1660,17 +1660,32 @@ func NewMeteredKeyValuePair(gauge common.MemoryGauge, key, value Value) KeyValue } } +// Composite + +type Composite interface { + Value + GetFields() []Field + getFieldValues() []Value +} + +// linked in by packages that need access to getFieldValues, +// e.g. JSON and CCF codecs +func getFieldValues(composite Composite) []Value { + return composite.getFieldValues() +} + // Struct type Struct struct { StructType *StructType - Fields []Value + fields []Value } var _ Value = Struct{} +var _ Composite = Struct{} func NewStruct(fields []Value) Struct { - return Struct{Fields: fields} + return Struct{fields: fields} } func NewMeteredStruct( @@ -1710,9 +1725,9 @@ func (v Struct) WithType(typ *StructType) Struct { } func (v Struct) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -1723,7 +1738,7 @@ func (v Struct) String() string { return formatComposite( v.StructType.ID(), v.StructType.Fields, - v.Fields, + v.fields, ) } @@ -1735,8 +1750,8 @@ func (v Struct) GetFields() []Field { return v.StructType.Fields } -func (v Struct) GetFieldValues() []Value { - return v.Fields +func (v Struct) getFieldValues() []Value { + return v.fields } func formatComposite(typeID string, fields []Field, values []Value) string { @@ -1764,13 +1779,14 @@ func formatComposite(typeID string, fields []Field, values []Value) string { type Resource struct { ResourceType *ResourceType - Fields []Value + fields []Value } var _ Value = Resource{} +var _ Composite = Resource{} func NewResource(fields []Value) Resource { - return Resource{Fields: fields} + return Resource{fields: fields} } func NewMeteredResource( @@ -1809,9 +1825,9 @@ func (v Resource) WithType(typ *ResourceType) Resource { } func (v Resource) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -1822,7 +1838,7 @@ func (v Resource) String() string { return formatComposite( v.ResourceType.ID(), v.ResourceType.Fields, - v.Fields, + v.fields, ) } @@ -1834,21 +1850,22 @@ func (v Resource) GetFields() []Field { return v.ResourceType.Fields } -func (v Resource) GetFieldValues() []Value { - return v.Fields +func (v Resource) getFieldValues() []Value { + return v.fields } // Attachment type Attachment struct { AttachmentType *AttachmentType - Fields []Value + fields []Value } var _ Value = Attachment{} +var _ Composite = Attachment{} func NewAttachment(fields []Value) Attachment { - return Attachment{Fields: fields} + return Attachment{fields: fields} } func NewMeteredAttachment( @@ -1887,9 +1904,9 @@ func (v Attachment) WithType(typ *AttachmentType) Attachment { } func (v Attachment) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -1900,7 +1917,7 @@ func (v Attachment) String() string { return formatComposite( v.AttachmentType.ID(), v.AttachmentType.Fields, - v.Fields, + v.fields, ) } @@ -1912,21 +1929,22 @@ func (v Attachment) GetFields() []Field { return v.AttachmentType.Fields } -func (v Attachment) GetFieldValues() []Value { - return v.Fields +func (v Attachment) getFieldValues() []Value { + return v.fields } // Event type Event struct { EventType *EventType - Fields []Value + fields []Value } var _ Value = Event{} +var _ Composite = Event{} func NewEvent(fields []Value) Event { - return Event{Fields: fields} + return Event{fields: fields} } func NewMeteredEvent( @@ -1965,9 +1983,9 @@ func (v Event) WithType(typ *EventType) Event { } func (v Event) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -1977,7 +1995,7 @@ func (v Event) String() string { return formatComposite( v.EventType.ID(), v.EventType.Fields, - v.Fields, + v.fields, ) } @@ -1989,21 +2007,22 @@ func (v Event) GetFields() []Field { return v.EventType.Fields } -func (v Event) GetFieldValues() []Value { - return v.Fields +func (v Event) getFieldValues() []Value { + return v.fields } // Contract type Contract struct { ContractType *ContractType - Fields []Value + fields []Value } var _ Value = Contract{} +var _ Composite = Contract{} func NewContract(fields []Value) Contract { - return Contract{Fields: fields} + return Contract{fields: fields} } func NewMeteredContract( @@ -2042,9 +2061,9 @@ func (v Contract) WithType(typ *ContractType) Contract { } func (v Contract) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -2055,7 +2074,7 @@ func (v Contract) String() string { return formatComposite( v.ContractType.ID(), v.ContractType.Fields, - v.Fields, + v.fields, ) } @@ -2067,8 +2086,8 @@ func (v Contract) GetFields() []Field { return v.ContractType.Fields } -func (v Contract) GetFieldValues() []Value { - return v.Fields +func (v Contract) getFieldValues() []Value { + return v.fields } // InclusiveRange @@ -2318,13 +2337,14 @@ func (v Capability) String() string { // Enum type Enum struct { EnumType *EnumType - Fields []Value + fields []Value } var _ Value = Enum{} +var _ Composite = Enum{} func NewEnum(fields []Value) Enum { - return Enum{Fields: fields} + return Enum{fields: fields} } func NewMeteredEnum( @@ -2363,9 +2383,9 @@ func (v Enum) WithType(typ *EnumType) Enum { } func (v Enum) ToGoValue() any { - ret := make([]any, len(v.Fields)) + ret := make([]any, len(v.fields)) - for i, field := range v.Fields { + for i, field := range v.fields { ret[i] = field.ToGoValue() } @@ -2376,7 +2396,7 @@ func (v Enum) String() string { return formatComposite( v.EnumType.ID(), v.EnumType.Fields, - v.Fields, + v.fields, ) } @@ -2388,8 +2408,8 @@ func (v Enum) GetFields() []Field { return v.EnumType.Fields } -func (v Enum) GetFieldValues() []Value { - return v.Fields +func (v Enum) getFieldValues() []Value { + return v.fields } // Function diff --git a/values_test.go b/values_test.go index 29ed541ad6..cee4e7b7b7 100644 --- a/values_test.go +++ b/values_test.go @@ -887,7 +887,7 @@ func TestValue_Type(t *testing.T) { } } -func TestValue_HasFields(t *testing.T) { +func TestComposite(t *testing.T) { t.Parallel() test := func(name string, testCase valueTestCase) { @@ -897,12 +897,12 @@ func TestValue_HasFields(t *testing.T) { switch value.(type) { case Event, Struct, Contract, Enum, Resource, Attachment: valueWithType := testCase.withType(value, testCase.exampleType) - assert.Implements(t, (*HasFields)(nil), valueWithType) - fieldedValueWithType := valueWithType.(HasFields) - assert.NotNil(t, fieldedValueWithType.GetFieldValues()) + require.Implements(t, (*Composite)(nil), valueWithType) + fieldedValueWithType := valueWithType.(Composite) + assert.NotNil(t, fieldedValueWithType.getFieldValues()) assert.NotNil(t, fieldedValueWithType.GetFields()) - fieldedValue := value.(HasFields) + fieldedValue := value.(Composite) assert.Nil(t, fieldedValue.GetFields()) } @@ -924,8 +924,8 @@ func TestEvent_GetFieldByName(t *testing.T) { String("foo"), }, ) - assert.Nil(t, GetFieldsMappedByName(simpleEvent)) - assert.Nil(t, GetFieldByName(simpleEvent, "a")) + assert.Nil(t, FieldsMappedByName(simpleEvent)) + assert.Nil(t, SearchFieldByName(simpleEvent, "a")) simpleEventWithType := simpleEvent.WithType(&EventType{ Location: utils.TestLocation, @@ -942,12 +942,15 @@ func TestEvent_GetFieldByName(t *testing.T) { }, }) - assert.Equal(t, NewInt(1), GetFieldByName(simpleEventWithType, "a").(Int)) - assert.Equal(t, String("foo"), GetFieldByName(simpleEventWithType, "b").(String)) - assert.Nil(t, GetFieldByName(simpleEventWithType, "c")) + assert.Equal(t, NewInt(1), SearchFieldByName(simpleEventWithType, "a")) + assert.Equal(t, String("foo"), SearchFieldByName(simpleEventWithType, "b")) + assert.Nil(t, SearchFieldByName(simpleEventWithType, "c")) - assert.Equal(t, map[string]Value{ - "a": NewInt(1), - "b": String("foo"), - }, GetFieldsMappedByName(simpleEventWithType)) + assert.Equal(t, + map[string]Value{ + "a": NewInt(1), + "b": String("foo"), + }, + FieldsMappedByName(simpleEventWithType), + ) } From d93686ba54340adc07150d5603169d67efc4d42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 Apr 2024 12:30:24 -0700 Subject: [PATCH 2/5] tests module got renamed --- tools/update/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/update/config.yaml b/tools/update/config.yaml index 1aa3ce72df..701ff396a6 100644 --- a/tools/update/config.yaml +++ b/tools/update/config.yaml @@ -98,7 +98,7 @@ repos: - onflow/cadence - onflow/flow-go-sdk - onflow/flow-go - - path: integration + - path: tests deps: - onflow/cadence - onflow/flow-go-sdk From 8d20e96b623df622e27dacce75d13b30638b0e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 Apr 2024 12:33:06 -0700 Subject: [PATCH 3/5] nolint --- values.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/values.go b/values.go index bd82ecf7d6..1272db12b6 100644 --- a/values.go +++ b/values.go @@ -1670,7 +1670,7 @@ type Composite interface { // linked in by packages that need access to getFieldValues, // e.g. JSON and CCF codecs -func getFieldValues(composite Composite) []Value { +func getFieldValues(composite Composite) []Value { //nolint:unused return composite.getFieldValues() } From 56d60c0110d638d92fecd9a141d38b79d15f9e76 Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:27:56 -0500 Subject: [PATCH 4/5] Bump atree version to latest --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b6a3c1abdd..a4ae46f0af 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/kr/pretty v0.3.1 github.com/leanovate/gopter v0.2.9 github.com/logrusorgru/aurora/v4 v4.0.0 - github.com/onflow/atree v0.6.1-0.20240416233652-f4568c0c03df + github.com/onflow/atree v0.6.1-0.20240429171449-cb486ceb1f9c github.com/rivo/uniseg v0.4.4 github.com/schollz/progressbar/v3 v3.13.1 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 187edf4907..761161345a 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvr github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/onflow/atree v0.6.1-0.20240416233652-f4568c0c03df h1:9dmE37nSKCV1obdPFtUgjKFH2yUHmfSkULX5h35l8yo= -github.com/onflow/atree v0.6.1-0.20240416233652-f4568c0c03df/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= +github.com/onflow/atree v0.6.1-0.20240429171449-cb486ceb1f9c h1:Ol+qFATYiS7LfwQQKBjfLJ8z6VwzZehVrYH1JI2ssUU= +github.com/onflow/atree v0.6.1-0.20240429171449-cb486ceb1f9c/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= From ef4680d6327899475d67f32f41d0b763af14f811 Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Fri, 19 Apr 2024 13:41:37 -0700 Subject: [PATCH 5/5] Add runtime check for transaction value moves --- runtime/interpreter/simplecompositevalue.go | 7 ++ runtime/runtime_test.go | 117 ++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/runtime/interpreter/simplecompositevalue.go b/runtime/interpreter/simplecompositevalue.go index 008a3741be..8e40bfd9a7 100644 --- a/runtime/interpreter/simplecompositevalue.go +++ b/runtime/interpreter/simplecompositevalue.go @@ -271,6 +271,13 @@ func (v *SimpleCompositeValue) Transfer( if remove { interpreter.RemoveReferencedSlab(storable) } + + if v.isTransaction { + panic(NonTransferableValueError{ + Value: v, + }) + } + return v } diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index e8f0bebd4e..12bc9f459d 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -10633,3 +10633,120 @@ func TestRuntimeNonPublicAccessModifierInInterface(t *testing.T) { require.Len(t, conformanceErr.MemberMismatches, 2) } + +func TestRuntimeMoveSelfVariable(t *testing.T) { + + t.Parallel() + + t.Run("contract", func(t *testing.T) { + t.Parallel() + + contract := []byte(` + access(all) contract Foo { + + access(all) fun moveSelf() { + var x = self! + } + } + `) + + runtime := NewTestInterpreterRuntimeWithConfig(Config{ + AtreeValidationEnabled: false, + }) + + address := common.MustBytesToAddress([]byte{0x1}) + + var contractCode []byte + + runtimeInterface := &TestRuntimeInterface{ + Storage: NewTestLedger(nil, nil), + OnGetSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil + }, + OnGetAccountContractCode: func(location common.AddressLocation) ([]byte, error) { + return contractCode, nil + }, + OnResolveLocation: NewSingleIdentifierLocationResolver(t), + OnUpdateAccountContractCode: func(_ common.AddressLocation, code []byte) error { + contractCode = code + return nil + }, + OnEmitEvent: func(event cadence.Event) error { + return nil + }, + } + + nextTransactionLocation := NewTransactionLocationGenerator() + + // Deploy + + deploymentTx := DeploymentTransaction("Foo", contract) + err := runtime.ExecuteTransaction( + Script{ + Source: deploymentTx, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + require.NoError(t, err) + + // Execute script + + nextScriptLocation := NewScriptLocationGenerator() + + script := []byte(fmt.Sprintf(` + import Foo from %[1]s + + access(all) fun main(): Void { + Foo.moveSelf() + }`, + address.HexWithPrefix(), + )) + + _, err = runtime.ExecuteScript( + Script{ + Source: script, + }, + Context{ + Interface: runtimeInterface, + Location: nextScriptLocation(), + }, + ) + + RequireError(t, err) + require.ErrorAs(t, err, &interpreter.NonTransferableValueError{}) + }) + + t.Run("transaction", func(t *testing.T) { + t.Parallel() + + script := []byte(` + transaction { + prepare() { + var x = true ? self : self + } + execute {} + } + `) + + runtime := NewTestInterpreterRuntime() + runtimeInterface := &TestRuntimeInterface{} + + nextTransactionLocation := NewTransactionLocationGenerator() + + err := runtime.ExecuteTransaction( + Script{ + Source: script, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + + RequireError(t, err) + require.ErrorAs(t, err, &interpreter.NonTransferableValueError{}) + }) +}