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/8] 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 6c50a30b1385969aa5d36b7aeccc5897b8dc012f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 Apr 2024 12:27:59 -0700 Subject: [PATCH 2/8] remove Value.ToGoValue and NewValue --- helpers.go | 150 ----------------------------------- types.go | 2 +- values.go | 226 ----------------------------------------------------- 3 files changed, 1 insertion(+), 377 deletions(-) delete mode 100644 helpers.go diff --git a/helpers.go b/helpers.go deleted file mode 100644 index f7cda19545..0000000000 --- a/helpers.go +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Cadence - The resource-oriented smart contract programming language - * - * Copyright Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cadence - -import "fmt" - -// Unmetered because this function is only used by the client. -func NewValue(value any) (Value, error) { - switch v := value.(type) { - case string: - return NewString(v) - case int: - return NewInt(v), nil - case int8: - return NewInt8(v), nil - case int16: - return NewInt16(v), nil - case int32: - return NewInt32(v), nil - case int64: - return NewInt64(v), nil - case uint8: - return NewUInt8(v), nil - case uint16: - return NewUInt16(v), nil - case uint32: - return NewUInt32(v), nil - case uint64: - return NewUInt64(v), nil - case []any: - values := make([]Value, len(v)) - - for i, v := range v { - t, err := NewValue(v) - if err != nil { - return nil, err - } - - values[i] = t - } - - return NewArray(values), nil - case nil: - return NewOptional(nil), nil - } - - return nil, fmt.Errorf("value type %T cannot be converted to ABI value type", value) -} - -// MustConvertValue converts a Go value to an ABI value or panics if the value -// cannot be converted. -func MustConvertValue(value any) Value { - ret, err := NewValue(value) - if err != nil { - panic(err) - } - - return ret -} - -func CastToString(value Value) (string, error) { - casted, ok := value.(String) - if !ok { - return "", fmt.Errorf("%T is not a values.String", value) - } - - goValue := casted.ToGoValue() - - str, ok := goValue.(string) - if !ok { - return "", fmt.Errorf("%T is not a string", goValue) - } - return str, nil -} - -func CastToUInt8(value Value) (uint8, error) { - casted, ok := value.(UInt8) - if !ok { - return 0, fmt.Errorf("%T is not a values.UInt8", value) - } - - goValue := casted.ToGoValue() - - u, ok := goValue.(uint8) - if !ok { - return 0, fmt.Errorf("%T is not a uint8", value) - } - return u, nil -} - -func CastToUInt16(value Value) (uint16, error) { - casted, ok := value.(UInt16) - if !ok { - return 0, fmt.Errorf("%T is not a values.UInt16", value) - } - - goValue := casted.ToGoValue() - - u, ok := goValue.(uint16) - if !ok { - return 0, fmt.Errorf("%T is not a uint16", value) - } - return u, nil -} - -func CastToArray(value Value) ([]any, error) { - casted, ok := value.(Array) - if !ok { - return nil, fmt.Errorf("%T is not a values.Array", value) - } - - goValue := casted.ToGoValue() - - u, ok := goValue.([]any) - if !ok { - return nil, fmt.Errorf("%T is not a []any]", value) - } - return u, nil -} - -func CastToInt(value Value) (int, error) { - casted, ok := value.(Int) - if !ok { - return 0, fmt.Errorf("%T is not a values.Int", value) - } - - goValue := casted.ToGoValue() - - u, ok := goValue.(int) - if !ok { - return 0, fmt.Errorf("%T %v is not a int", value, value) - } - return u, nil -} diff --git a/types.go b/types.go index f6faabe539..df1cd61ba0 100644 --- a/types.go +++ b/types.go @@ -537,7 +537,7 @@ func decodeOptional(valueType reflect.Type, cadenceField Value) (*reflect.Value, } // if optional is nil, skip and default the field to nil - if optional.ToGoValue() == nil { + if optional.Value == nil { zeroValue := reflect.Zero(valueType) return &zeroValue, nil } diff --git a/values.go b/values.go index 01b893706e..3a6d0870cd 100644 --- a/values.go +++ b/values.go @@ -39,7 +39,6 @@ type Value interface { isValue() Type() Type MeteredType(gauge common.MemoryGauge) Type - ToGoValue() any fmt.Stringer } @@ -75,10 +74,6 @@ func (v Void) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (Void) ToGoValue() any { - return nil -} - func (Void) String() string { return format.Void } @@ -129,16 +124,6 @@ func (o Optional) MeteredType(gauge common.MemoryGauge) Type { ) } -func (o Optional) ToGoValue() any { - if o.Value == nil { - return nil - } - - value := o.Value.ToGoValue() - - return value -} - func (o Optional) String() string { if o.Value == nil { return format.Nil @@ -171,10 +156,6 @@ func (v Bool) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Bool) ToGoValue() any { - return bool(v) -} - func (v Bool) String() string { return format.Bool(bool(v)) } @@ -213,10 +194,6 @@ func (v String) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v String) ToGoValue() any { - return string(v) -} - func (v String) String() string { return format.String(string(v)) } @@ -242,10 +219,6 @@ func (v Bytes) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Bytes) ToGoValue() any { - return []byte(v) -} - func (v Bytes) String() string { return format.Bytes(v) } @@ -286,10 +259,6 @@ func (v Character) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Character) ToGoValue() any { - return string(v) -} - func (v Character) String() string { return format.String(string(v)) } @@ -332,10 +301,6 @@ func (Address) MeteredType(common.MemoryGauge) Type { return AddressType } -func (v Address) ToGoValue() any { - return [AddressLength]byte(v) -} - func (v Address) Bytes() []byte { return v[:] } @@ -388,10 +353,6 @@ func (v Int) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int) ToGoValue() any { - return v.Big() -} - func (v Int) Int() int { return int(v.Value.Int64()) } @@ -427,10 +388,6 @@ func NewMeteredInt8(memoryGauge common.MemoryGauge, v int8) Int8 { func (Int8) isValue() {} -func (v Int8) ToGoValue() any { - return int8(v) -} - func (Int8) Type() Type { return Int8Type } @@ -474,10 +431,6 @@ func (v Int16) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int16) ToGoValue() any { - return int16(v) -} - func (v Int16) ToBigEndianBytes() []byte { b := make([]byte, 2) binary.BigEndian.PutUint16(b, uint16(v)) @@ -515,10 +468,6 @@ func (v Int32) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int32) ToGoValue() any { - return int32(v) -} - func (v Int32) ToBigEndianBytes() []byte { b := make([]byte, 4) binary.BigEndian.PutUint32(b, uint32(v)) @@ -556,10 +505,6 @@ func (v Int64) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int64) ToGoValue() any { - return int64(v) -} - func (v Int64) ToBigEndianBytes() []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) @@ -618,10 +563,6 @@ func (v Int128) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int128) ToGoValue() any { - return v.Big() -} - func (v Int128) Int() int { return int(v.Value.Int64()) } @@ -686,10 +627,6 @@ func (v Int256) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Int256) ToGoValue() any { - return v.Big() -} - func (v Int256) Int() int { return int(v.Value.Int64()) } @@ -749,10 +686,6 @@ func (v UInt) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt) ToGoValue() any { - return v.Big() -} - func (v UInt) Int() int { return int(v.Value.Uint64()) } @@ -796,10 +729,6 @@ func (v UInt8) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt8) ToGoValue() any { - return uint8(v) -} - func (v UInt8) ToBigEndianBytes() []byte { return []byte{byte(v)} } @@ -835,10 +764,6 @@ func (v UInt16) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt16) ToGoValue() any { - return uint16(v) -} - func (v UInt16) ToBigEndianBytes() []byte { b := make([]byte, 2) binary.BigEndian.PutUint16(b, uint16(v)) @@ -876,10 +801,6 @@ func (v UInt32) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt32) ToGoValue() any { - return uint32(v) -} - func (v UInt32) ToBigEndianBytes() []byte { b := make([]byte, 4) binary.BigEndian.PutUint32(b, uint32(v)) @@ -917,10 +838,6 @@ func (v UInt64) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt64) ToGoValue() any { - return uint64(v) -} - func (v UInt64) ToBigEndianBytes() []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) @@ -979,10 +896,6 @@ func (v UInt128) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt128) ToGoValue() any { - return v.Big() -} - func (v UInt128) Int() int { return int(v.Value.Uint64()) } @@ -1047,10 +960,6 @@ func (v UInt256) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UInt256) ToGoValue() any { - return v.Big() -} - func (v UInt256) Int() int { return int(v.Value.Uint64()) } @@ -1094,10 +1003,6 @@ func (v Word8) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word8) ToGoValue() any { - return uint8(v) -} - func (v Word8) ToBigEndianBytes() []byte { return []byte{byte(v)} } @@ -1133,10 +1038,6 @@ func (v Word16) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word16) ToGoValue() any { - return uint16(v) -} - func (v Word16) ToBigEndianBytes() []byte { b := make([]byte, 2) binary.BigEndian.PutUint16(b, uint16(v)) @@ -1174,10 +1075,6 @@ func (v Word32) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word32) ToGoValue() any { - return uint32(v) -} - func (v Word32) ToBigEndianBytes() []byte { b := make([]byte, 4) binary.BigEndian.PutUint32(b, uint32(v)) @@ -1215,10 +1112,6 @@ func (v Word64) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word64) ToGoValue() any { - return uint64(v) -} - func (v Word64) ToBigEndianBytes() []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) @@ -1277,10 +1170,6 @@ func (v Word128) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word128) ToGoValue() any { - return v.Big() -} - func (v Word128) Int() int { return int(v.Value.Uint64()) } @@ -1345,10 +1234,6 @@ func (v Word256) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Word256) ToGoValue() any { - return v.Big() -} - func (v Word256) Int() int { return int(v.Value.Uint64()) } @@ -1418,10 +1303,6 @@ func (v Fix64) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v Fix64) ToGoValue() any { - return int64(v) -} - func (v Fix64) ToBigEndianBytes() []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) @@ -1492,10 +1373,6 @@ func (v UFix64) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (v UFix64) ToGoValue() any { - return uint64(v) -} - func (v UFix64) ToBigEndianBytes() []byte { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) @@ -1551,16 +1428,6 @@ func (v Array) WithType(arrayType ArrayType) Array { return v } -func (v Array) ToGoValue() any { - ret := make([]any, len(v.Values)) - - for i, e := range v.Values { - ret[i] = e.ToGoValue() - } - - return ret -} - func (v Array) String() string { values := make([]string, len(v.Values)) for i, value := range v.Values { @@ -1616,16 +1483,6 @@ func (v Dictionary) WithType(dictionaryType *DictionaryType) Dictionary { return v } -func (v Dictionary) ToGoValue() any { - ret := map[any]any{} - - for _, p := range v.Pairs { - ret[p.Key.ToGoValue()] = p.Value.ToGoValue() - } - - return ret -} - func (v Dictionary) String() string { pairs := make([]struct { Key string @@ -1709,16 +1566,6 @@ func (v Struct) WithType(typ *StructType) Struct { return v } -func (v Struct) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} - func (v Struct) String() string { return formatComposite( v.StructType.ID(), @@ -1808,16 +1655,6 @@ func (v Resource) WithType(typ *ResourceType) Resource { return v } -func (v Resource) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} - func (v Resource) String() string { return formatComposite( v.ResourceType.ID(), @@ -1886,16 +1723,6 @@ func (v Attachment) WithType(typ *AttachmentType) Attachment { return v } -func (v Attachment) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} - func (v Attachment) String() string { return formatComposite( v.AttachmentType.ID(), @@ -1964,15 +1791,6 @@ func (v Event) WithType(typ *EventType) Event { return v } -func (v Event) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} func (v Event) String() string { return formatComposite( v.EventType.ID(), @@ -2041,16 +1859,6 @@ func (v Contract) WithType(typ *ContractType) Contract { return v } -func (v Contract) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} - func (v Contract) String() string { return formatComposite( v.ContractType.ID(), @@ -2119,14 +1927,6 @@ func (v *InclusiveRange) WithType(typ *InclusiveRangeType) *InclusiveRange { return v } -func (v *InclusiveRange) ToGoValue() any { - return []any{ - v.Start.ToGoValue(), - v.End.ToGoValue(), - v.Step.ToGoValue(), - } -} - func (v *InclusiveRange) String() string { if v.InclusiveRangeType == nil { return "" @@ -2209,10 +2009,6 @@ func (v Path) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (Path) ToGoValue() any { - return nil -} - func (v Path) String() string { return format.Path( v.Domain.Identifier(), @@ -2249,10 +2045,6 @@ func (v TypeValue) MeteredType(common.MemoryGauge) Type { return v.Type() } -func (TypeValue) ToGoValue() any { - return nil -} - func (v TypeValue) String() string { return format.TypeValue(v.StaticType.ID()) } @@ -2303,10 +2095,6 @@ func (v Capability) MeteredType(gauge common.MemoryGauge) Type { return NewMeteredCapabilityType(gauge, v.BorrowType) } -func (Capability) ToGoValue() any { - return nil -} - func (v Capability) String() string { return format.Capability( v.BorrowType.ID(), @@ -2362,16 +2150,6 @@ func (v Enum) WithType(typ *EnumType) Enum { return v } -func (v Enum) ToGoValue() any { - ret := make([]any, len(v.Fields)) - - for i, field := range v.Fields { - ret[i] = field.ToGoValue() - } - - return ret -} - func (v Enum) String() string { return formatComposite( v.EnumType.ID(), @@ -2425,10 +2203,6 @@ func (v Function) MeteredType(common.MemoryGauge) Type { return v.FunctionType } -func (Function) ToGoValue() any { - return nil -} - func (v Function) String() string { // TODO: include function type return "fun ..." 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 3/8] 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 4/8] 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 5/8] 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 6/8] 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{}) + }) +} From 5d04cba786d2888e84de5a750694ab57a49bd5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 30 Apr 2024 10:54:40 -0700 Subject: [PATCH 7/8] add predicate function and test for atree's PersistentSlabStorage.FixLoadedBrokenReferences --- migrations/broken_dictionary.go | 47 +++++++++ migrations/migration_test.go | 99 +++++++++++++++++++ .../testdata/missing-slabs-payloads.csv | 25 +++++ runtime/tests/runtime_utils/testledger.go | 39 ++++++-- 4 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 migrations/broken_dictionary.go create mode 100644 migrations/testdata/missing-slabs-payloads.csv diff --git a/migrations/broken_dictionary.go b/migrations/broken_dictionary.go new file mode 100644 index 0000000000..a342920770 --- /dev/null +++ b/migrations/broken_dictionary.go @@ -0,0 +1,47 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package migrations + +import ( + "github.com/onflow/atree" + + "github.com/onflow/cadence/runtime/interpreter" +) + +// ShouldFixBrokenCompositeKeyedDictionary returns true if the given value is a dictionary with a composite key type. +// +// It is useful for use with atree's PersistentSlabStorage.FixLoadedBrokenReferences. +// +// NOTE: The intended use case is to enable migration programs in onflow/flow-go to fix broken references. +// As of April 2024, only 10 registers in testnet (not mainnet) were found to have broken references, +// and they seem to have resulted from a bug that was fixed 2 years ago by https://github.com/onflow/cadence/pull/1565. +func ShouldFixBrokenCompositeKeyedDictionary(atreeValue atree.Value) bool { + orderedMap, ok := atreeValue.(*atree.OrderedMap) + if !ok { + return false + } + + dictionaryStaticType, ok := orderedMap.Type().(*interpreter.DictionaryStaticType) + if !ok { + return false + } + + _, ok = dictionaryStaticType.KeyType.(*interpreter.CompositeStaticType) + return ok +} diff --git a/migrations/migration_test.go b/migrations/migration_test.go index 3895e4a8be..73818a8411 100644 --- a/migrations/migration_test.go +++ b/migrations/migration_test.go @@ -19,6 +19,10 @@ package migrations import ( + "bytes" + _ "embed" + "encoding/csv" + "encoding/hex" "errors" "fmt" "testing" @@ -2659,3 +2663,98 @@ func TestDictionaryKeyConflict(t *testing.T) { test(t, false) }) } + +//go:embed testdata/missing-slabs-payloads.csv +var missingSlabsPayloadsData []byte + +// '$' + 8 byte index +const slabKeyLength = 9 + +func isSlabStorageKey(key []byte) bool { + return len(key) == slabKeyLength && key[0] == '$' +} + +func TestFixLoadedBrokenReferences(t *testing.T) { + + t.Parallel() + + // Read CSV file with test data + + reader := csv.NewReader(bytes.NewReader(missingSlabsPayloadsData)) + + // account, key, value + reader.FieldsPerRecord = 3 + + records, err := reader.ReadAll() + require.NoError(t, err) + + // Load data into ledger. Skip header + + ledger := NewTestLedger(nil, nil) + + for _, record := range records[1:] { + account, err := hex.DecodeString(record[0]) + require.NoError(t, err) + + key, err := hex.DecodeString(record[1]) + require.NoError(t, err) + + value, err := hex.DecodeString(record[2]) + require.NoError(t, err) + + err = ledger.SetValue(account, key, value) + require.NoError(t, err) + } + + storage := runtime.NewStorage(ledger, nil) + + // Check health. + // Retrieve all slabs before migration + + err = ledger.ForEach(func(owner, key, value []byte) error { + + if !isSlabStorageKey(key) { + return nil + } + + // Convert the owner/key to a storage ID. + + var storageIndex atree.StorageIndex + copy(storageIndex[:], key[1:]) + + storageID := atree.NewStorageID(atree.Address(owner), storageIndex) + + // Retrieve the slab. + _, _, err = storage.Retrieve(storageID) + require.NoError(t, err) + + return nil + }) + require.NoError(t, err) + + address, err := common.HexToAddress("0x5d63c34d7f05e5a4") + require.NoError(t, err) + + for _, domain := range common.AllPathDomains { + _ = storage.GetStorageMap(address, domain.Identifier(), false) + } + + err = storage.CheckHealth() + require.Error(t, err) + + require.ErrorContains(t, err, "slab (0x0.49) not found: slab not found during slab iteration") + + // Fix the broken slab references + + fixedSlabs, skippedSlabIDs, err := storage.PersistentSlabStorage. + FixLoadedBrokenReferences(ShouldFixBrokenCompositeKeyedDictionary) + require.NoError(t, err) + + require.NotEmpty(t, fixedSlabs) + require.Empty(t, skippedSlabIDs) + + // Re-run health check. This time it should pass. + + err = storage.CheckHealth() + require.NoError(t, err) +} diff --git a/migrations/testdata/missing-slabs-payloads.csv b/migrations/testdata/missing-slabs-payloads.csv new file mode 100644 index 0000000000..c64aa50fa8 --- /dev/null +++ b/migrations/testdata/missing-slabs-payloads.csv @@ -0,0 +1,25 @@ +owner,key,value +5d63c34d7f05e5a4,240000000000000009,008883d88483d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7402021b6f605c4ae015732a008883005b00000000000000100727f5bf434b68c18638e048b5b7cdb49b0000000000000002826475756964d8a41a00a4a65d826762616c616e6365d8bc1b0000001748783b3a +5d63c34d7f05e5a4,612e73,0000000000000012b9000000000000002b0000000000000001 +5d63c34d7f05e5a4,24000000000000000f,00c883d8d982d8d41830d8d582d8c08248631e88ae7f1d7c20704e6f6e46756e6769626c65546f6b656e744e6f6e46756e6769626c65546f6b656e2e4e4654031bb9d0e9f36650574100c883005b00000000000000180a5d0065f54d3b70efeefcbe52b8e6bbfe71d66e8625c1019b000000000000000382d8a419bfedd8ff505d63c34d7f05e5a4000000000000001682d8a419bfecd8ff505d63c34d7f05e5a4000000000000001082d8a419c026d8ff505d63c34d7f05e5a40000000000000028 +5d63c34d7f05e5a4,240000000000000005,00c883d88483d8c08248a47a2d3a3b7e9133734469676974616c436f6e74656e744173736574781b4469676974616c436f6e74656e7441737365742e4e46544461746101041bdb477d045820e23f00c883005b000000000000002001e9dead718715827af7a9558c406fd09c308d168ef2bca4bbd2c23d2c1c98209b0000000000000004826c73657269616c4e756d626572d8a30182666974656d4964d8876e746573742d6974656d2d69642d3282686d65746164617461d8ff505d63c34d7f05e5a40000000000000006826b6974656d56657273696f6ed8a301 +5d63c34d7f05e5a4,240000000000000006,008883d8d982d8d408d8d408011bd3ad92ee82a688cf008883005b00000000000000087d4660d52656b0f19b000000000000000182d887666578496e666fd887781b4164646974696f6e616c20696e666f206561636820746f6b656e2e +5d63c34d7f05e5a4,24000000000000002a,008883d8d982d8d408d8d408001b7d63d5c2a25d9570008883005b00000000000000009b0000000000000000 +5d63c34d7f05e5a4,24000000000000000d,008883f6051bbe10d8ef134f8081008883005b00000000000000283c74aa8be0b9f0e484cd59f126f4e5908c69f0b6aca96e5f9c1af60840e775e3c06c0966bef02b939b0000000000000005826d444341436f6c6c656374696f6ed8cb82d8c882016d444341436f6c6c656374696f6ed8db82f4d8dc82d8d40581d8d682d8c08248a47a2d3a3b7e9133734469676974616c436f6e74656e74417373657478244469676974616c436f6e74656e7441737365742e436f6c6c656374696f6e5075626c6963827046616e546f705065726d697373696f6ed8cb82d8c882017046616e546f705065726d697373696f6ed8db82f4d8dc82d8d40581d8d682d8c08248a47a2d3a3b7e91337046616e546f705065726d697373696f6e781946616e546f705065726d697373696f6e2e52656365697665728270666c6f77546f6b656e42616c616e6365d8cb82d8c882016e666c6f77546f6b656e5661756c74d8db82f4d8dc82d8d582d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7481d8d682d8c082489a0766d93b6608b76d46756e6769626c65546f6b656e7546756e6769626c65546f6b656e2e42616c616e63658271666c6f77546f6b656e5265636569766572d8cb82d8c882016e666c6f77546f6b656e5661756c74d8db82f4d8dc82d8d582d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7481d8d682d8c082489a0766d93b6608b76d46756e6769626c65546f6b656e7646756e6769626c65546f6b656e2e5265636569766572827546616e546f70546f6b656e436f6c6c656374696f6ed8cb82d8c882017546616e546f70546f6b656e436f6c6c656374696f6ed8db82f4d8dc82d8d40581d8d682d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e781c46616e546f70546f6b656e2e436f6c6c656374696f6e5075626c6963 +5d63c34d7f05e5a4,7075626c6963,000000000000000d +5d63c34d7f05e5a4,240000000000000029,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e7346616e546f70546f6b656e2e4e46544461746101041bee2eefad66dc79bb00c883005b000000000000002038fc822d312df7f38ef037256b43eed596a75665ca80dfe6aec0bc45428aa9e59b0000000000000004826b6974656d56657273696f6ed8a301826c73657269616c4e756d626572d8a30182686d65746164617461d8ff505d63c34d7f05e5a4000000000000002a82666974656d4964d887781a746573742d6974656d2d69642d31363534393133393635393138 +5d63c34d7f05e5a4,73746f72616765,000000000000000c +5d63c34d7f05e5a4,24000000000000000c,00c883f6041bd6bd24f14bb87b1d00c883005b000000000000002011e0799c7eee7e48e100d7590eb37bbcfc5fbcac8f0e7c49fdc92797c5d69e9f9b0000000000000004826e666c6f77546f6b656e5661756c74d8ff505d63c34d7f05e5a40000000000000009827546616e546f70546f6b656e436f6c6c656374696f6ed8ff505d63c34d7f05e5a4000000000000000e827046616e546f705065726d697373696f6ed8ff505d63c34d7f05e5a4000000000000000a826d444341436f6c6c656374696f6ed8ff505d63c34d7f05e5a40000000000000008 +5d63c34d7f05e5a4,240000000000000028,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e6f46616e546f70546f6b656e2e4e465402041bb77700225b8d6b5200c883005b00000000000000202183e3a62217fe8a36d1395a6a775e199d29ed46c773a0acc6d7ec7f9e97bfc79b0000000000000004826464617461d8ff505d63c34d7f05e5a40000000000000029826475756964d8a41a05cb6bc982657265664964d8877819746573742d7265662d69642d3136353439313339363539313882626964d8a419c026 +5d63c34d7f05e5a4,240000000000000016,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e6f46616e546f70546f6b656e2e4e465402041bb77700225b8d6b5200c883005b00000000000000202183e3a62217fe8a36d1395a6a775e199d29ed46c773a0acc6d7ec7f9e97bfc79b0000000000000004826464617461d8ff505d63c34d7f05e5a40000000000000017826475756964d8a41a05c8448882657265664964d8877819746573742d7265662d69642d3136353436363835373330383182626964d8a419bfed +5d63c34d7f05e5a4,24000000000000000b,00c883d8d982d8d582d8c08248a47a2d3a3b7e91337046616e546f705065726d697373696f6e7546616e546f705065726d697373696f6e2e526f6c65d8ddf6011b535c9de83a38cab000c883005b00000000000000089bd8ae8dd553d9479b000000000000000182d8ff5000000000000000000000000000000031d8c983d88348a47a2d3a3b7e9133d8c882026c46616e546f704d696e746572d8db82f4d8d582d8c08248a47a2d3a3b7e91337046616e546f705065726d697373696f6e7746616e546f705065726d697373696f6e2e4d696e746572 +5d63c34d7f05e5a4,240000000000000007,00c883d8d982d8d41830d8d582d8c08248631e88ae7f1d7c20704e6f6e46756e6769626c65546f6b656e744e6f6e46756e6769626c65546f6b656e2e4e4654011b095f1b185a2800d900c883005b00000000000000085521726dbf8b37549b000000000000000182d8a4182bd8ff505d63c34d7f05e5a40000000000000004 +5d63c34d7f05e5a4,240000000000000004,00c883d88483d8c08248a47a2d3a3b7e9133734469676974616c436f6e74656e744173736574774469676974616c436f6e74656e7441737365742e4e465402041bf62e63ac21a3216600c883005b00000000000000200507c593895292f5ab364b56d50468c7d0766f8c688ebb74f8c1a4433ffbccf29b000000000000000482626964d8a4182b826464617461d8ff505d63c34d7f05e5a40000000000000005826475756964d8a41a00a5641882657265664964d8877830746573742d7265662d69642d61353662363764392d306634352d346339622d613264352d636534306439376339333230 +5d63c34d7f05e5a4,240000000000000008,00c883d88483d8c08248a47a2d3a3b7e9133734469676974616c436f6e74656e744173736574781e4469676974616c436f6e74656e7441737365742e436f6c6c656374696f6e02021bf7f58ec9906ea65700c883005b0000000000000010e5df9d08d0a2430ce91971a214b62eaa9b0000000000000002826475756964d8a41a00a4a66682696f776e65644e465473d8ff505d63c34d7f05e5a40000000000000007 +5d63c34d7f05e5a4,240000000000000017,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e7346616e546f70546f6b656e2e4e46544461746101041bee2eefad66dc79bb00c883005b000000000000002038fc822d312df7f38ef037256b43eed596a75665ca80dfe6aec0bc45428aa9e59b0000000000000004826b6974656d56657273696f6ed8a301826c73657269616c4e756d626572d8a30182686d65746164617461d8ff505d63c34d7f05e5a4000000000000001882666974656d4964d887781a746573742d6974656d2d69642d31363534363638353733303831 +5d63c34d7f05e5a4,240000000000000018,008883d8d982d8d408d8d408001b7d63d5c2a25d9570008883005b00000000000000009b0000000000000000 +5d63c34d7f05e5a4,240000000000000010,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e6f46616e546f70546f6b656e2e4e465402041bb77700225b8d6b5200c883005b00000000000000202183e3a62217fe8a36d1395a6a775e199d29ed46c773a0acc6d7ec7f9e97bfc79b0000000000000004826464617461d8ff505d63c34d7f05e5a40000000000000011826475756964d8a41a05c838bf82657265664964d8877819746573742d7265662d69642d3136353436363539323439343382626964d8a419bfec +5d63c34d7f05e5a4,240000000000000011,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e7346616e546f70546f6b656e2e4e46544461746101041bee2eefad66dc79bb00c883005b000000000000002038fc822d312df7f38ef037256b43eed596a75665ca80dfe6aec0bc45428aa9e59b0000000000000004826b6974656d56657273696f6ed8a301826c73657269616c4e756d626572d8a30182686d65746164617461d8ff505d63c34d7f05e5a4000000000000001282666974656d4964d887781a746573742d6974656d2d69642d31363534363635393234393433 +5d63c34d7f05e5a4,24000000000000000a,00c883d88483d8c08248a47a2d3a3b7e91337046616e546f705065726d697373696f6e7746616e546f705065726d697373696f6e2e486f6c64657202031bb9d0e9f36650574100c883005b000000000000001820d6c23f2e85e694b0070dbc21a9822de5725916c4a005e99b0000000000000003826475756964d8a41a00d858bc8265726f6c6573d8ff505d63c34d7f05e5a4000000000000000b8269726563697069656e74d883485d63c34d7f05e5a4 +5d63c34d7f05e5a4,240000000000000012,008883d8d982d8d408d8d408001b7d63d5c2a25d9570008883005b00000000000000009b0000000000000000 +5d63c34d7f05e5a4,24000000000000000e,00c883d88483d8c08248a47a2d3a3b7e91336b46616e546f70546f6b656e7646616e546f70546f6b656e2e436f6c6c656374696f6e02021b85d7c70d054429ef00c883005b000000000000001012dab75ddc75f021eec8d5b5338fb70a9b000000000000000282696f776e65644e465473d8ff505d63c34d7f05e5a4000000000000000f826475756964d8a41a05c83883 diff --git a/runtime/tests/runtime_utils/testledger.go b/runtime/tests/runtime_utils/testledger.go index 082936a253..86b1e9bff7 100644 --- a/runtime/tests/runtime_utils/testledger.go +++ b/runtime/tests/runtime_utils/testledger.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "sort" "strconv" "strings" @@ -54,6 +55,34 @@ func (s TestLedger) AllocateStorageIndex(owner []byte) (atree.StorageIndex, erro return s.OnAllocateStorageIndex(owner) } +const testLedgerKeySeparator = "|" + +func (s TestLedger) ForEach(f func(owner, key, value []byte) error) error { + + var keys []string + for key := range s.StoredValues { //nolint:maprange + keys = append(keys, key) + } + sort.Strings(keys) + + for _, key := range keys { //nolint:maprange + value := s.StoredValues[key] + + keyParts := strings.Split(key, testLedgerKeySeparator) + owner := []byte(keyParts[0]) + key := []byte(keyParts[1]) + + if err := f(owner, key, value); err != nil { + return err + } + } + return nil +} + +func TestStorageKey(owner, key string) string { + return strings.Join([]string{owner, key}, testLedgerKeySeparator) +} + func (s TestLedger) Dump() { // Only used for testing/debugging purposes for key, data := range s.StoredValues { //nolint:maprange @@ -68,10 +97,6 @@ func NewTestLedger( onWrite func(owner, key, value []byte), ) TestLedger { - storageKey := func(owner, key string) string { - return strings.Join([]string{owner, key}, "|") - } - storedValues := map[string][]byte{} storageIndices := map[string]uint64{} @@ -79,18 +104,18 @@ func NewTestLedger( return TestLedger{ StoredValues: storedValues, OnValueExists: func(owner, key []byte) (bool, error) { - value := storedValues[storageKey(string(owner), string(key))] + value := storedValues[TestStorageKey(string(owner), string(key))] return len(value) > 0, nil }, OnGetValue: func(owner, key []byte) (value []byte, err error) { - value = storedValues[storageKey(string(owner), string(key))] + value = storedValues[TestStorageKey(string(owner), string(key))] if onRead != nil { onRead(owner, key, value) } return value, nil }, OnSetValue: func(owner, key, value []byte) (err error) { - storedValues[storageKey(string(owner), string(key))] = value + storedValues[TestStorageKey(string(owner), string(key))] = value if onWrite != nil { onWrite(owner, key, value) } From 111954535fbeb469a511cfbabc0ae4ba4092cbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 30 Apr 2024 12:01:09 -0700 Subject: [PATCH 8/8] go mod tidy --- tools/storage-explorer/go.mod | 2 +- tools/storage-explorer/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/storage-explorer/go.mod b/tools/storage-explorer/go.mod index ad18459d6e..2efa24054d 100644 --- a/tools/storage-explorer/go.mod +++ b/tools/storage-explorer/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/gorilla/mux v1.8.1 - github.com/onflow/atree v0.6.1-0.20240416233652-f4568c0c03df + github.com/onflow/atree v0.6.1-0.20240429171449-cb486ceb1f9c github.com/onflow/cadence v1.0.0-M8 github.com/onflow/flow-go v0.34.0-crescendo-preview.5.0.20240229164931-a67398875618 github.com/rs/zerolog v1.32.0 diff --git a/tools/storage-explorer/go.sum b/tools/storage-explorer/go.sum index e5acacaab2..bbc50d39f5 100644 --- a/tools/storage-explorer/go.sum +++ b/tools/storage-explorer/go.sum @@ -1775,8 +1775,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= -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/onflow/flow-core-contracts/lib/go/contracts v0.15.2-0.20240227190927-0e6ce7e3222b h1:oXHQft30sElpK7G3xWB5tEizI2G+S4p64iVh0LtX4E0=