diff --git a/codegen/astgen/v3/common.go b/codegen/astgen/v3/common.go index ec87380..64e6114 100644 --- a/codegen/astgen/v3/common.go +++ b/codegen/astgen/v3/common.go @@ -216,6 +216,7 @@ func (c *codeGenAst) getTemplates( RawType: field.String(), IsOptional: isOptional, IsEnum: c.isEnumType(typeExtracted, pkg), + IsBytes: model.BytesFieldNames[fieldExtracted], IsBytesHex: model.BytesHexFieldNames[fieldExtracted], IsUint32: model.Uint32FieldNames[fieldExtracted], IsUint32List: model.Uint32ListFieldNames[fieldExtracted], @@ -438,6 +439,7 @@ func (c *codeGenAst) getDataTypes(pkg *daml.Package, module *daml.Module, module Type: typeExtracted, RawType: field.String(), IsOptional: isOptional, + IsBytes: model.BytesFieldNames[fieldExtracted], IsBytesHex: model.BytesHexFieldNames[fieldExtracted], IsUint32: model.Uint32FieldNames[fieldExtracted], IsUint32List: model.Uint32ListFieldNames[fieldExtracted], @@ -455,6 +457,7 @@ func (c *codeGenAst) getDataTypes(pkg *daml.Package, module *daml.Module, module Type: typeExtracted, RawType: field.String(), IsOptional: true, + IsBytes: model.BytesFieldNames[fieldExtracted], IsBytesHex: model.BytesHexFieldNames[fieldExtracted], IsUint32: model.Uint32FieldNames[fieldExtracted], IsUint32List: model.Uint32ListFieldNames[fieldExtracted], diff --git a/codegen/model/template.go b/codegen/model/template.go index bd7670e..192a6f2 100644 --- a/codegen/model/template.go +++ b/codegen/model/template.go @@ -29,6 +29,7 @@ type TmplField struct { RawType string IsOptional bool IsEnum bool + IsBytes bool // True if field should use uint8 length prefix (hex:"bytes" tag) IsBytesHex bool // True if field should use uint16 length prefix (hex:"bytes16" tag) IsUint32 bool // True if INT64 field should encode as 4-byte uint32 (hex:"uint32" tag) IsUint32List bool // True if []INT64 field should encode with 4-byte uint32 elements (hex:"[]uint32" tag) diff --git a/codegen/model/types.go b/codegen/model/types.go index 20197c6..7f3f007 100644 --- a/codegen/model/types.go +++ b/codegen/model/types.go @@ -68,6 +68,18 @@ func (t BytesHex) IsBytesHex() bool { return true } +// ** Custom Bytes Length Mapping ** + +// The Daml compiler erases type synonyms. When you define a field as BytesHex in Daml, +// the compiler expands it to its underlying type (Text) in the compiled Daml-LF output. +// By the time go-daml parses the .dalf files, all it sees is +// signerAddress: Text +// operationData: Text +// root: Text +// There's no way to distinguish which Text fields were originally BytesHex and require special encoding. +// The hardcoded maps (BytesFieldNames, BytesHexFieldNames) work around this limitation by explicitly listing +// field names that need hex encoding tags. + // BytesHexFieldNames contains field names that should use uint16 length prefix // encoding (hex:"bytes16" tag) instead of the default uint8 length prefix. // @@ -87,6 +99,21 @@ var BytesHexFieldNames = map[string]bool{ "salt": true, } +// BytesFieldNames contains field names that should use uint8 length prefix +// encoding (hex:"bytes" tag). These are fixed-size hex fields ≤255 bytes. +// +// From MCMS/CCIP contracts: +// - signerAddress: EVM signer address (20 bytes) +// - chainFamilySelector: Chain family selector (4 bytes) +// - root: Merkle root hash (32 bytes) +// - newRoot: New merkle root hash (32 bytes) +var BytesFieldNames = map[string]bool{ + "signerAddress": true, + "chainFamilySelector": true, + "root": true, + "newRoot": true, +} + // Uint32FieldNames contains field names where INT64 should encode as 4-byte uint32. // This matches the Daml MCMS/Codec.daml encoding which uses encodeUint32 for these fields. // diff --git a/codegen/source.go.tmpl b/codegen/source.go.tmpl index f5026a3..5b933dc 100644 --- a/codegen/source.go.tmpl +++ b/codegen/source.go.tmpl @@ -301,7 +301,7 @@ var _ types.ENUM = {{capitalise .Name}}("") // {{capitalise .Name}} is a {{.RawType}} type type {{capitalise .Name}} struct { {{- range $field := .Fields}} - {{capitalise $field.Name}} {{$field.Type.GoType}} `json:"{{$field.Name}}"{{if $field.IsOptional}} hex:"optional"{{else if $field.IsBytesHex}} hex:"bytes16"{{else if $field.IsUint32}} hex:"uint32"{{else if $field.IsUint32List}} hex:"[]uint32"{{end}}` + {{capitalise $field.Name}} {{$field.Type.GoType}} `json:"{{$field.Name}}"{{if $field.IsOptional}} hex:"optional"{{else if $field.IsBytes}} hex:"bytes"{{else if $field.IsBytesHex}} hex:"bytes16"{{else if $field.IsUint32}} hex:"uint32"{{else if $field.IsUint32List}} hex:"[]uint32"{{end}}` {{- end}} } @@ -359,7 +359,7 @@ func (t *{{capitalise .Name}}) UnmarshalHex(data string) error { type {{capitalise .Name}}MCMSParams struct { {{- range .Fields}} {{- if not (isCallerField .Name)}} - {{capitalise .Name}} {{.Type.GoType}} `json:"{{.Name}}"{{if .IsOptional}} hex:"optional"{{else if .IsBytesHex}} hex:"bytes16"{{else if .IsUint32}} hex:"uint32"{{else if .IsUint32List}} hex:"[]uint32"{{end}}` + {{capitalise .Name}} {{.Type.GoType}} `json:"{{.Name}}"{{if .IsOptional}} hex:"optional"{{else if .IsBytes}} hex:"bytes"{{else if .IsBytesHex}} hex:"bytes16"{{else if .IsUint32}} hex:"uint32"{{else if .IsUint32List}} hex:"[]uint32"{{end}}` {{- end}} {{- end}} }