From 1d2d5b3d5a537f2452e72808ea31ee43714550ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 22 Oct 2024 11:37:10 -0700 Subject: [PATCH 1/5] add built-in CCF contract with encode function --- cmd/cmd.go | 12 ++++ common/computationkind.go | 2 + runtime/environment.go | 16 ++++++ stdlib/builtin.go | 2 + stdlib/ccf.cdc | 7 +++ stdlib/ccf.gen.go | 82 +++++++++++++++++++++++++++ stdlib/ccf.go | 113 ++++++++++++++++++++++++++++++++++++++ tests/ccf_test.go | 106 +++++++++++++++++++++++++++++++++++ values.go | 13 +++++ 9 files changed, 353 insertions(+) create mode 100644 stdlib/ccf.cdc create mode 100644 stdlib/ccf.gen.go create mode 100644 stdlib/ccf.go create mode 100644 tests/ccf_test.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 0172a68db5..057518313f 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -26,6 +26,7 @@ import ( "strings" "time" + "github.com/onflow/cadence" "github.com/onflow/cadence/activations" "github.com/onflow/cadence/ast" "github.com/onflow/cadence/common" @@ -433,6 +434,17 @@ func (h *StandardLibraryHandler) IsContractBeingAdded(common.AddressLocation) bo return false } +func (h *StandardLibraryHandler) ExportValue( + _ interpreter.Value, + _ *interpreter.Interpreter, + _ interpreter.LocationRange, +) ( + cadence.Value, + error, +) { + return nil, goerrors.New("exporting values is not supported in this environment") +} + func formatLocationRange(locationRange interpreter.LocationRange) string { var builder strings.Builder if locationRange.Location != nil { diff --git a/common/computationkind.go b/common/computationkind.go index 3ec0e44698..4ab4ebb312 100644 --- a/common/computationkind.go +++ b/common/computationkind.go @@ -142,4 +142,6 @@ const ( // RLP ComputationKindSTDLIBRLPDecodeString ComputationKindSTDLIBRLPDecodeList + // CCF + ComputationKindSTDLIBCCFEncode ) diff --git a/runtime/environment.go b/runtime/environment.go index 9aff5b329d..38ccb10285 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -146,6 +146,7 @@ var _ stdlib.BLSPoPVerifier = &interpreterEnvironment{} var _ stdlib.BLSPublicKeyAggregator = &interpreterEnvironment{} var _ stdlib.BLSSignatureAggregator = &interpreterEnvironment{} var _ stdlib.Hasher = &interpreterEnvironment{} +var _ stdlib.Exporter = &interpreterEnvironment{} var _ ArgumentDecoder = &interpreterEnvironment{} var _ common.MemoryGauge = &interpreterEnvironment{} @@ -1426,3 +1427,18 @@ func (e *interpreterEnvironment) newValidateAccountCapabilitiesPublishHandler() return ok, err } } + +func (e *interpreterEnvironment) ExportValue( + value interpreter.Value, + interpreter *interpreter.Interpreter, + locationRange interpreter.LocationRange, +) ( + cadence.Value, + error, +) { + return ExportValue( + value, + interpreter, + locationRange, + ) +} diff --git a/stdlib/builtin.go b/stdlib/builtin.go index 1a6d4e65c0..4195a2474c 100644 --- a/stdlib/builtin.go +++ b/stdlib/builtin.go @@ -36,6 +36,7 @@ type StandardLibraryHandler interface { BLSPublicKeyAggregator BLSSignatureAggregator Hasher + Exporter } func DefaultStandardLibraryValues(handler StandardLibraryHandler) []StandardLibraryValue { @@ -54,6 +55,7 @@ func DefaultStandardLibraryValues(handler StandardLibraryHandler) []StandardLibr NewPublicKeyConstructor(handler), NewBLSContract(nil, handler), NewHashAlgorithmConstructor(handler), + NewCCFContract(nil, handler), } } diff --git a/stdlib/ccf.cdc b/stdlib/ccf.cdc new file mode 100644 index 0000000000..9e0a4b6bfc --- /dev/null +++ b/stdlib/ccf.cdc @@ -0,0 +1,7 @@ +access(all) +contract CCF { + /// Encodes an encodable value to CCF. + /// Returns nil if the value cannot be encoded. + access(all) + view fun encode(_ input: &Any): [UInt8]? +} diff --git a/stdlib/ccf.gen.go b/stdlib/ccf.gen.go new file mode 100644 index 0000000000..a2e00bff85 --- /dev/null +++ b/stdlib/ccf.gen.go @@ -0,0 +1,82 @@ +// Code generated from ccf.cdc. DO NOT EDIT. +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Flow Foundation + * + * 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 stdlib + +import ( + "github.com/onflow/cadence/ast" + "github.com/onflow/cadence/common" + "github.com/onflow/cadence/sema" +) + +const CCFTypeEncodeFunctionName = "encode" + +var CCFTypeEncodeFunctionType = &sema.FunctionType{ + Purity: sema.FunctionPurityView, + Parameters: []sema.Parameter{ + { + Label: sema.ArgumentLabelNotRequired, + Identifier: "input", + TypeAnnotation: sema.NewTypeAnnotation(&sema.ReferenceType{ + Type: sema.AnyType, + Authorization: sema.UnauthorizedAccess, + }), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + &sema.OptionalType{ + Type: &sema.VariableSizedType{ + Type: sema.UInt8Type, + }, + }, + ), +} + +const CCFTypeEncodeFunctionDocString = ` +Encodes an encodable value to CCF. +Returns nil if the value cannot be encoded. +` + +const CCFTypeName = "CCF" + +var CCFType = func() *sema.CompositeType { + var t = &sema.CompositeType{ + Identifier: CCFTypeName, + Kind: common.CompositeKindContract, + ImportableBuiltin: false, + HasComputedMembers: true, + } + + return t +}() + +func init() { + var members = []*sema.Member{ + sema.NewUnmeteredFunctionMember( + CCFType, + sema.PrimitiveAccess(ast.AccessAll), + CCFTypeEncodeFunctionName, + CCFTypeEncodeFunctionType, + CCFTypeEncodeFunctionDocString, + ), + } + + CCFType.Members = sema.MembersAsMap(members) + CCFType.Fields = sema.MembersFieldNames(members) +} diff --git a/stdlib/ccf.go b/stdlib/ccf.go new file mode 100644 index 0000000000..cd58b4115c --- /dev/null +++ b/stdlib/ccf.go @@ -0,0 +1,113 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Flow Foundation + * + * 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 stdlib + +//go:generate go run ../sema/gen -p stdlib ccf.cdc ccf.gen.go + +import ( + "github.com/onflow/cadence" + "github.com/onflow/cadence/common" + "github.com/onflow/cadence/encoding/ccf" + "github.com/onflow/cadence/errors" + "github.com/onflow/cadence/interpreter" +) + +type Exporter interface { + ExportValue( + value interpreter.Value, + interpreter *interpreter.Interpreter, + locationRange interpreter.LocationRange, + ) ( + cadence.Value, + error, + ) +} + +type CCFContractHandler interface { + Exporter +} + +// newCCFEncodeFunction creates a new host function that encodes a value using the CCF encoding format. +func newCCFEncodeFunction( + gauge common.MemoryGauge, + handler CCFContractHandler, +) *interpreter.HostFunctionValue { + return interpreter.NewStaticHostFunctionValue( + gauge, + CCFTypeEncodeFunctionType, + func(invocation interpreter.Invocation) interpreter.Value { + inter := invocation.Interpreter + locationRange := invocation.LocationRange + + referenceValue, ok := invocation.Arguments[0].(interpreter.ReferenceValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + referencedValue := referenceValue.ReferencedValue(inter, locationRange, true) + if referencedValue == nil { + return interpreter.Nil + } + + exportedValue, err := handler.ExportValue(*referencedValue, inter, locationRange) + if err != nil { + return interpreter.Nil + } + + encoded, err := ccf.Encode(exportedValue) + if err != nil { + return interpreter.Nil + } + + res := interpreter.ByteSliceToByteArrayValue(inter, encoded) + + return interpreter.NewSomeValueNonCopying(inter, res) + }, + ) +} + +var CCFTypeStaticType = interpreter.ConvertSemaToStaticType(nil, CCFType) + +func NewCCFContract( + gauge common.MemoryGauge, + handler CCFContractHandler, +) StandardLibraryValue { + + ccfContractFields := map[string]interpreter.Value{ + CCFTypeEncodeFunctionName: newCCFEncodeFunction(gauge, handler), + } + + var ccfContractValue = interpreter.NewSimpleCompositeValue( + gauge, + CCFType.ID(), + CCFTypeStaticType, + nil, + ccfContractFields, + nil, + nil, + nil, + ) + + return StandardLibraryValue{ + Name: CCFTypeName, + Type: CCFType, + Value: ccfContractValue, + Kind: common.DeclarationKindContract, + } +} diff --git a/tests/ccf_test.go b/tests/ccf_test.go new file mode 100644 index 0000000000..96ef31e647 --- /dev/null +++ b/tests/ccf_test.go @@ -0,0 +1,106 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Flow Foundation + * + * 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 tests + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/onflow/cadence" + "github.com/onflow/cadence/common" + . "github.com/onflow/cadence/runtime" + . "github.com/onflow/cadence/tests/runtime_utils" +) + +func TestRuntimeCCFEncodeStruct(t *testing.T) { + + t.Parallel() + + type testCase struct { + name string + value string + output []byte + } + + tests := []testCase{ + { + name: "String", + value: `"test"`, + output: []byte{0xd8, 0x82, 0x82, 0xd8, 0x89, 0x1, 0x64, 0x74, 0x65, 0x73, 0x74}, + }, + { + name: "Bool", + value: `true`, + output: []byte{0xd8, 0x82, 0x82, 0xd8, 0x89, 0x0, 0xf5}, + }, + { + name: "function", + value: `fun (): Int { return 1 }`, + output: []byte{0xd8, 0x82, 0x82, 0xd8, 0x89, 0x18, 0x33, 0x84, 0x80, 0x80, 0xd8, 0xb9, 0x4, 0x0}, + }, + } + + test := func(test testCase) { + t.Run(test.name, func(t *testing.T) { + + t.Parallel() + + runtime := NewTestInterpreterRuntime() + + runtimeInterface := &TestRuntimeInterface{ + Storage: NewTestLedger(nil, nil), + } + + script := []byte(fmt.Sprintf( + ` + access(all) fun main(): [UInt8]? { + let value = %s + return CCF.encode(&value as &AnyStruct) + } + `, + test.value, + )) + + result, err := runtime.ExecuteScript( + Script{ + Source: script, + }, + Context{ + Interface: runtimeInterface, + Location: common.ScriptLocation{}, + }, + ) + require.NoError(t, err) + + assert.Equal(t, + cadence.NewOptional( + cadence.ByteSliceToByteArray(test.output), + ), + result, + ) + }) + } + + for _, testCase := range tests { + test(testCase) + } +} diff --git a/values.go b/values.go index d3799c0a88..e12d6a27fb 100644 --- a/values.go +++ b/values.go @@ -1436,6 +1436,19 @@ func (v Array) String() string { return format.Array(values) } +var ByteArrayType = NewVariableSizedArrayType(PrimitiveType(interpreter.PrimitiveStaticTypeUInt8)) + +// ByteSliceToByteArray converts a byte slice to a Cadence byte array of type [UInt8]. +func ByteSliceToByteArray(b []byte) Array { + values := make([]Value, len(b)) + + for i, v := range b { + values[i] = UInt8(v) + } + + return NewArray(values).WithType(ByteArrayType) +} + // Dictionary type Dictionary struct { From 1dec9bcbf5befe375a5aaf8fd2757660b88bb1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 9 Oct 2025 13:40:16 -0700 Subject: [PATCH 2/5] avoid import of runtime in ccf --- encoding/ccf/decode_type.go | 2 +- encoding/ccf/encode.go | 2 +- encoding/ccf/encode_type.go | 2 +- encoding/ccf/simpletype.go | 8 ++++---- encoding/ccf/simpletype_test.go | 7 ++++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/encoding/ccf/decode_type.go b/encoding/ccf/decode_type.go index 3fa743c6f9..a6521cdee0 100644 --- a/encoding/ccf/decode_type.go +++ b/encoding/ccf/decode_type.go @@ -113,7 +113,7 @@ func (d *Decoder) decodeSimpleTypeID() (cadence.Type, error) { return nil, err } - ty := typeBySimpleTypeID(SimpleType(simpleTypeID)) + ty := TypeBySimpleTypeID(SimpleType(simpleTypeID)) if ty == nil { return nil, fmt.Errorf("unsupported encoded simple type ID %d", simpleTypeID) } diff --git a/encoding/ccf/encode.go b/encoding/ccf/encode.go index 47e87a328e..18e75119d2 100644 --- a/encoding/ccf/encode.go +++ b/encoding/ccf/encode.go @@ -1429,7 +1429,7 @@ func (e *Encoder) encodeTypeValue(typ cadence.Type, visited ccfTypeIDByCadenceTy visited[cadenceTypeID] = ccfTypeID(len(visited)) } - simpleTypeID, ok := simpleTypeIDByType(typ) + simpleTypeID, ok := SimpleTypeIDByType(typ) if ok { return e.encodeSimpleTypeValue(simpleTypeID) } diff --git a/encoding/ccf/encode_type.go b/encoding/ccf/encode_type.go index 509a6b4dd2..0ca29d7fe2 100644 --- a/encoding/ccf/encode_type.go +++ b/encoding/ccf/encode_type.go @@ -46,7 +46,7 @@ type encodeTypeFn func(typ cadence.Type, tids ccfTypeIDByCadenceType) error // All exported Cadence types need to be supported by this function, // including abstract and interface types. func (e *Encoder) encodeInlineType(typ cadence.Type, tids ccfTypeIDByCadenceType) error { - simpleTypeID, ok := simpleTypeIDByType(typ) + simpleTypeID, ok := SimpleTypeIDByType(typ) if ok { return e.encodeSimpleType(simpleTypeID) } diff --git a/encoding/ccf/simpletype.go b/encoding/ccf/simpletype.go index 48bbba6d84..aace7d000d 100644 --- a/encoding/ccf/simpletype.go +++ b/encoding/ccf/simpletype.go @@ -35,7 +35,7 @@ import ( // When new simple cadence.Type is added, // - ADD new ID to the end of existing IDs, // - ADD new simple cadence.Type and its ID -// to simpleTypeIDByType *and* typeBySimpleTypeID +// to SimpleTypeIDByType *and* TypeBySimpleTypeID type SimpleType uint64 @@ -156,7 +156,7 @@ const ( // Cadence simple type IDs SimpleType_Count ) -// NOTE: cadence.FunctionType isn't included in simpleTypeIDByType +// NOTE: cadence.FunctionType isn't included in SimpleTypeIDByType // because this function is used by both inline-type and type-value. // cadence.FunctionType needs to be handled differently when this // function is used by inline-type and type-value. @@ -278,7 +278,7 @@ func initSimpleTypeIDBiMap() (m *bimap.BiMap[cadence.PrimitiveType, SimpleType]) var simpleTypeIDBiMap *bimap.BiMap[cadence.PrimitiveType, SimpleType] = initSimpleTypeIDBiMap() -func simpleTypeIDByType(typ cadence.Type) (SimpleType, bool) { +func SimpleTypeIDByType(typ cadence.Type) (SimpleType, bool) { switch typ := typ.(type) { case cadence.BytesType: return SimpleTypeBytes, true @@ -289,7 +289,7 @@ func simpleTypeIDByType(typ cadence.Type) (SimpleType, bool) { return 0, false } -func typeBySimpleTypeID(simpleTypeID SimpleType) cadence.Type { +func TypeBySimpleTypeID(simpleTypeID SimpleType) cadence.Type { if simpleTypeID == SimpleTypeBytes { return cadence.TheBytesType } diff --git a/encoding/ccf/simpletype_test.go b/encoding/ccf/simpletype_test.go index 528df7d2c7..5435961171 100644 --- a/encoding/ccf/simpletype_test.go +++ b/encoding/ccf/simpletype_test.go @@ -16,7 +16,7 @@ * limitations under the License. */ -package ccf +package ccf_test import ( "testing" @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/onflow/cadence" + "github.com/onflow/cadence/encoding/ccf" "github.com/onflow/cadence/interpreter" "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/sema" @@ -43,10 +44,10 @@ func TestTypeConversion(t *testing.T) { cadenceType := runtime.ExportType(semaType, map[sema.TypeID]cadence.Type{}) - simpleTypeID, ok := simpleTypeIDByType(cadenceType) + simpleTypeID, ok := ccf.SimpleTypeIDByType(cadenceType) require.True(t, ok) - ty2 := typeBySimpleTypeID(simpleTypeID) + ty2 := ccf.TypeBySimpleTypeID(simpleTypeID) require.Equal(t, cadence.PrimitiveType(ty), ty2) }) } From 97489690f4508f2f2bc5d3d946e4f60940ada07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 9 Oct 2025 13:40:22 -0700 Subject: [PATCH 3/5] clean up --- runtime/environment.go | 2 +- runtime/vm_environment.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/environment.go b/runtime/environment.go index f8bf98fb05..c64e01ef21 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -578,7 +578,7 @@ func (e *InterpreterEnvironment) ProgramLog(message string) error { return e.Interface.ProgramLog(message) } -func (e *InterpreterEnvironment) ExportValue( +func (*InterpreterEnvironment) ExportValue( value interpreter.Value, context interpreter.ValueExportContext, ) ( diff --git a/runtime/vm_environment.go b/runtime/vm_environment.go index cb8a1d0e03..63162abb0c 100644 --- a/runtime/vm_environment.go +++ b/runtime/vm_environment.go @@ -82,6 +82,7 @@ var _ stdlib.BLSPoPVerifier = &vmEnvironment{} var _ stdlib.BLSPublicKeyAggregator = &vmEnvironment{} var _ stdlib.BLSSignatureAggregator = &vmEnvironment{} var _ stdlib.Hasher = &vmEnvironment{} +var _ stdlib.Exporter = &vmEnvironment{} var _ ArgumentDecoder = &vmEnvironment{} func newVMEnvironment(config Config) *vmEnvironment { @@ -641,7 +642,7 @@ func (e *vmEnvironment) vmBuiltinGlobals( return } -func (e *vmEnvironment) ExportValue( +func (*vmEnvironment) ExportValue( value interpreter.Value, context interpreter.ValueExportContext, ) (cadence.Value, error) { From d39728b1c1c5033b3040bcf22af2d8af505115e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 9 Oct 2025 14:08:37 -0700 Subject: [PATCH 4/5] add support for VM --- runtime/ccf_test.go | 1 + stdlib/builtin.go | 7 ++++ stdlib/ccf.go | 85 ++++++++++++++++++++++++++++----------------- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/runtime/ccf_test.go b/runtime/ccf_test.go index 3c32762ea2..7d6387fceb 100644 --- a/runtime/ccf_test.go +++ b/runtime/ccf_test.go @@ -87,6 +87,7 @@ func TestRuntimeCCFEncodeStruct(t *testing.T) { Context{ Interface: runtimeInterface, Location: common.ScriptLocation{}, + UseVM: *compile, }, ) require.NoError(t, err) diff --git a/stdlib/builtin.go b/stdlib/builtin.go index 30a71e9ebe..9f92e20e2c 100644 --- a/stdlib/builtin.go +++ b/stdlib/builtin.go @@ -51,6 +51,11 @@ var DefaultStandardLibraryTypes = []StandardLibraryType{ Name: RLPTypeName, Kind: common.DeclarationKindContract, }, + { + Type: CCFType, + Name: CCFTypeName, + Kind: common.DeclarationKindContract, + }, } func InterpreterDefaultStandardLibraryValues(handler StandardLibraryHandler) []StandardLibraryValue { @@ -141,6 +146,8 @@ func VMFunctions(handler StandardLibraryHandler) []VMFunction { NewVMBLSAggregatePublicKeysFunction(handler), NewVMBLSAggregateSignaturesFunction(handler), + NewVMCCFEncodeFunction(handler), + NewVMHashAlgorithmHashFunction(handler), NewVMHashAlgorithmHashWithTagFunction(handler), diff --git a/stdlib/ccf.go b/stdlib/ccf.go index 6dcc4a02c7..60d391a090 100644 --- a/stdlib/ccf.go +++ b/stdlib/ccf.go @@ -22,6 +22,7 @@ package stdlib import ( "github.com/onflow/cadence" + "github.com/onflow/cadence/bbq/vm" "github.com/onflow/cadence/common" "github.com/onflow/cadence/encoding/ccf" "github.com/onflow/cadence/errors" @@ -42,44 +43,64 @@ type CCFContractHandler interface { Exporter } -// newCCFEncodeFunction creates a new host function that encodes a value using the CCF encoding format. -func newCCFEncodeFunction( +func NativeCCFEncodeFunction(handler CCFContractHandler) interpreter.NativeFunction { + return func( + context interpreter.NativeFunctionContext, + _ interpreter.TypeArgumentsIterator, + _ interpreter.Value, + args []interpreter.Value, + ) interpreter.Value { + + referenceValue, ok := args[0].(interpreter.ReferenceValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + referencedValue := referenceValue.ReferencedValue(context, true) + if referencedValue == nil { + return interpreter.Nil + } + + exportedValue, err := handler.ExportValue(*referencedValue, context) + if err != nil { + return interpreter.Nil + } + + encoded, err := ccf.Encode(exportedValue) + if err != nil { + return interpreter.Nil + } + + res := interpreter.ByteSliceToByteArrayValue(context, encoded) + + return interpreter.NewSomeValueNonCopying(context, res) + } +} + +func newInterpreterCCFEncodeFunction( gauge common.MemoryGauge, handler CCFContractHandler, ) *interpreter.HostFunctionValue { - return interpreter.NewStaticHostFunctionValue( + // TODO: Should create a bound-host function here, but interpreter is not available at this point. + // However, this is not a problem for now, since underlying contract doesn't get moved. + return interpreter.NewStaticHostFunctionValueFromNativeFunction( gauge, - CCFTypeEncodeFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - inter := invocation.InvocationContext - - referenceValue, ok := invocation.Arguments[0].(interpreter.ReferenceValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - referencedValue := referenceValue.ReferencedValue(inter, true) - if referencedValue == nil { - return interpreter.Nil - } - - exportedValue, err := handler.ExportValue(*referencedValue, inter) - if err != nil { - return interpreter.Nil - } - - encoded, err := ccf.Encode(exportedValue) - if err != nil { - return interpreter.Nil - } - - res := interpreter.ByteSliceToByteArrayValue(inter, encoded) - - return interpreter.NewSomeValueNonCopying(inter, res) - }, + BLSTypeAggregatePublicKeysFunctionType, + NativeCCFEncodeFunction(handler), ) } +func NewVMCCFEncodeFunction(handler CCFContractHandler) VMFunction { + return VMFunction{ + BaseType: CCFType, + FunctionValue: vm.NewNativeFunctionValue( + CCFTypeEncodeFunctionName, + CCFTypeEncodeFunctionType, + NativeCCFEncodeFunction(handler), + ), + } +} + var CCFTypeStaticType = interpreter.ConvertSemaToStaticType(nil, CCFType) func NewCCFContract( @@ -88,7 +109,7 @@ func NewCCFContract( ) StandardLibraryValue { ccfContractFields := map[string]interpreter.Value{ - CCFTypeEncodeFunctionName: newCCFEncodeFunction(gauge, handler), + CCFTypeEncodeFunctionName: newInterpreterCCFEncodeFunction(gauge, handler), } var ccfContractValue = interpreter.NewSimpleCompositeValue( From 6c99e116241ad8af236d6f8e9a2d7be494da0f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 9 Oct 2025 14:10:36 -0700 Subject: [PATCH 5/5] regenerate --- common/computationkind_string.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/computationkind_string.go b/common/computationkind_string.go index 302fdd11bb..b2487fc7db 100644 --- a/common/computationkind_string.go +++ b/common/computationkind_string.go @@ -27,6 +27,7 @@ func _() { _ = x[ComputationKindSTDLIBRevertibleRandom-1102] _ = x[ComputationKindSTDLIBRLPDecodeString-1108] _ = x[ComputationKindSTDLIBRLPDecodeList-1109] + _ = x[ComputationKindSTDLIBCCFEncode-1110] } const ( @@ -37,7 +38,7 @@ const ( _ComputationKind_name_4 = "CreateDictionaryValueTransferDictionaryValueDestroyDictionaryValue" _ComputationKind_name_5 = "EncodeValue" _ComputationKind_name_6 = "STDLIBPanicSTDLIBAssertSTDLIBRevertibleRandom" - _ComputationKind_name_7 = "STDLIBRLPDecodeStringSTDLIBRLPDecodeList" + _ComputationKind_name_7 = "STDLIBRLPDecodeStringSTDLIBRLPDecodeListSTDLIBCCFEncode" ) var ( @@ -46,7 +47,7 @@ var ( _ComputationKind_index_3 = [...]uint8{0, 16, 34, 51} _ComputationKind_index_4 = [...]uint8{0, 21, 44, 66} _ComputationKind_index_6 = [...]uint8{0, 11, 23, 45} - _ComputationKind_index_7 = [...]uint8{0, 21, 40} + _ComputationKind_index_7 = [...]uint8{0, 21, 40, 55} ) func (i ComputationKind) String() string { @@ -70,7 +71,7 @@ func (i ComputationKind) String() string { case 1100 <= i && i <= 1102: i -= 1100 return _ComputationKind_name_6[_ComputationKind_index_6[i]:_ComputationKind_index_6[i+1]] - case 1108 <= i && i <= 1109: + case 1108 <= i && i <= 1110: i -= 1108 return _ComputationKind_name_7[_ComputationKind_index_7[i]:_ComputationKind_index_7[i+1]] default: