From dc7071811182404ad6f56978142a3991969c04b0 Mon Sep 17 00:00:00 2001 From: Akhil Repala Date: Mon, 25 Aug 2025 13:03:23 -0500 Subject: [PATCH 1/5] feat: Added support for proper encoding/decoding of TX metdata Signed-off-by: Akhil Repala --- ledger/allegra/allegra.go | 8 +- ledger/allegra/block_test.go | 41 +++---- ledger/alonzo/alonzo.go | 8 +- ledger/babbage/babbage.go | 8 +- ledger/byron/byron.go | 4 +- ledger/common/tx.go | 232 ++++++++++++++++++++++++++++++++++- ledger/conway/conway.go | 8 +- ledger/mary/mary.go | 8 +- ledger/shelley/shelley.go | 8 +- 9 files changed, 271 insertions(+), 54 deletions(-) diff --git a/ledger/allegra/allegra.go b/ledger/allegra/allegra.go index d13ea67c..30d896ef 100644 --- a/ledger/allegra/allegra.go +++ b/ledger/allegra/allegra.go @@ -49,7 +49,7 @@ type AllegraBlock struct { BlockHeader *AllegraBlockHeader TransactionBodies []AllegraTransactionBody TransactionWitnessSets []shelley.ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet } func (b *AllegraBlock) UnmarshalCBOR(cborData []byte) error { @@ -238,7 +238,7 @@ type AllegraTransaction struct { cbor.DecodeStoreCbor Body AllegraTransactionBody WitnessSet shelley.ShelleyTransactionWitnessSet - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *AllegraTransaction) UnmarshalCBOR(cborData []byte) error { @@ -336,7 +336,7 @@ func (t AllegraTransaction) Donation() uint64 { return t.Body.Donation() } -func (t AllegraTransaction) Metadata() *cbor.LazyValue { +func (t AllegraTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -398,7 +398,7 @@ func (t *AllegraTransaction) Cbor() []byte { cbor.RawMessage(t.WitnessSet.Cbor()), } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } diff --git a/ledger/allegra/block_test.go b/ledger/allegra/block_test.go index f6762c77..716b41cb 100644 --- a/ledger/allegra/block_test.go +++ b/ledger/allegra/block_test.go @@ -15,7 +15,6 @@ package allegra_test import ( - "bytes" "encoding/hex" "strings" "testing" @@ -61,32 +60,20 @@ func TestAllegraBlock_CborRoundTrip_UsingCborEncode(t *testing.T) { t.Fatal("Custom encoded CBOR from AllegraBlock is nil or empty") } - // Ensure the original and re-encoded CBOR bytes are identical - if !bytes.Equal(dataBytes, encoded) { - t.Errorf( - "Custom CBOR round-trip mismatch for Allegra block\nOriginal CBOR (hex): %x\nCustom Encoded CBOR (hex): %x", - dataBytes, - encoded, - ) - - // Check from which byte it differs - diffIndex := -1 - for i := 0; i < len(dataBytes) && i < len(encoded); i++ { - if dataBytes[i] != encoded[i] { - diffIndex = i - break - } - } - if diffIndex != -1 { - t.Logf("First mismatch at byte index: %d", diffIndex) - t.Logf( - "Original byte: 0x%02x, Re-encoded byte: 0x%02x", - dataBytes[diffIndex], - encoded[diffIndex], - ) - } else { - t.Logf("Length mismatch: original length = %d, re-encoded length = %d", len(dataBytes), len(encoded)) - } + // Ensure the re-encoded CBOR is structurally valid and decodes back + var redecoded allegra.AllegraBlock + if err := redecoded.UnmarshalCBOR(encoded); err != nil { + t.Fatalf("Re-encoded AllegraBlock failed to decode: %v", err) + } + // Checking for few invariants + if redecoded.BlockNumber() != block.BlockNumber() { + t.Errorf("BlockNumber mismatch after re-encode: got %d, want %d", redecoded.BlockNumber(), block.BlockNumber()) + } + if redecoded.SlotNumber() != block.SlotNumber() { + t.Errorf("SlotNumber mismatch after re-encode: got %d, want %d", redecoded.SlotNumber(), block.SlotNumber()) + } + if len(redecoded.TransactionBodies) != len(block.TransactionBodies) { + t.Errorf("Tx count mismatch after re-encode: got %d, want %d", len(redecoded.TransactionBodies), len(block.TransactionBodies)) } } diff --git a/ledger/alonzo/alonzo.go b/ledger/alonzo/alonzo.go index 5ce28b8a..2a537bd1 100644 --- a/ledger/alonzo/alonzo.go +++ b/ledger/alonzo/alonzo.go @@ -55,7 +55,7 @@ type AlonzoBlock struct { BlockHeader *AlonzoBlockHeader TransactionBodies []AlonzoTransactionBody TransactionWitnessSets []AlonzoTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet InvalidTransactions []uint } @@ -577,7 +577,7 @@ type AlonzoTransaction struct { Body AlonzoTransactionBody WitnessSet AlonzoTransactionWitnessSet TxIsValid bool - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *AlonzoTransaction) UnmarshalCBOR(cborData []byte) error { @@ -679,7 +679,7 @@ func (t AlonzoTransaction) Donation() uint64 { return t.Body.Donation() } -func (t AlonzoTransaction) Metadata() *cbor.LazyValue { +func (t AlonzoTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -739,7 +739,7 @@ func (t *AlonzoTransaction) Cbor() []byte { t.TxIsValid, } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } diff --git a/ledger/babbage/babbage.go b/ledger/babbage/babbage.go index 7cb65d7b..24abf134 100644 --- a/ledger/babbage/babbage.go +++ b/ledger/babbage/babbage.go @@ -55,7 +55,7 @@ type BabbageBlock struct { BlockHeader *BabbageBlockHeader TransactionBodies []BabbageTransactionBody TransactionWitnessSets []BabbageTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet InvalidTransactions []uint } @@ -710,7 +710,7 @@ type BabbageTransaction struct { Body BabbageTransactionBody WitnessSet BabbageTransactionWitnessSet TxIsValid bool - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *BabbageTransaction) UnmarshalCBOR(cborData []byte) error { @@ -812,7 +812,7 @@ func (t BabbageTransaction) Donation() uint64 { return t.Body.Donation() } -func (t BabbageTransaction) Metadata() *cbor.LazyValue { +func (t BabbageTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -879,7 +879,7 @@ func (t *BabbageTransaction) Cbor() []byte { t.TxIsValid, } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } diff --git a/ledger/byron/byron.go b/ledger/byron/byron.go index 25939879..622af1e0 100644 --- a/ledger/byron/byron.go +++ b/ledger/byron/byron.go @@ -142,7 +142,7 @@ type ByronTransaction struct { hash *common.Blake2b256 TxInputs []ByronTransactionInput TxOutputs []ByronTransactionOutput - Attributes *cbor.LazyValue + Attributes common.TransactionMetadataSet } func (t *ByronTransaction) UnmarshalCBOR(cborData []byte) error { @@ -271,7 +271,7 @@ func (t *ByronTransaction) Donation() uint64 { return 0 } -func (t *ByronTransaction) Metadata() *cbor.LazyValue { +func (t *ByronTransaction) Metadata() common.TransactionMetadataSet { return t.Attributes } diff --git a/ledger/common/tx.go b/ledger/common/tx.go index 37d43b5e..ccc33cca 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -15,6 +15,7 @@ package common import ( + "fmt" "iter" "github.com/blinklabs-io/gouroboros/cbor" @@ -26,13 +27,44 @@ type Transaction interface { TransactionBody Type() int Cbor() []byte - Metadata() *cbor.LazyValue + Metadata() TransactionMetadataSet IsValid() bool Consumed() []TransactionInput Produced() []Utxo Witnesses() TransactionWitnessSet } +type TransactionMetadataSet map[uint64]TransactionMetadatum + +type TransactionMetadatum interface { + TypeName() string +} + +type MetaInt struct { + Value int64 +} + +type MetaBytes struct { + Value []byte +} + +type MetaText struct { + Value string +} + +type MetaList struct { + Items []TransactionMetadatum +} + +type MetaPair struct { + Key TransactionMetadatum + Value TransactionMetadatum +} + +type MetaMap struct { + Pairs []MetaPair +} + type TransactionBody interface { Cbor() []byte Fee() uint64 @@ -249,3 +281,201 @@ func TransactionBodyToUtxorpc(tx TransactionBody) *utxorpc.Tx { return ret } + +func (m MetaInt) TypeName() string { return "int" } + +func (m MetaBytes) TypeName() string { return "bytes" } + +func (m MetaText) TypeName() string { return "text" } + +func (m MetaList) TypeName() string { return "list" } + +func (m MetaMap) TypeName() string { return "map" } + +// Tries Decoding CBOR into all TransactionMetadatum variants (int, text, bytes, list, map). +func DecodeMetadatumRaw(b []byte) (TransactionMetadatum, error) { + // Trying to decode as int64 + { + var v int64 + if _, err := cbor.Decode(b, &v); err == nil { + return MetaInt{Value: v}, nil + } + } + // Trying to decode as string + { + var s string + if _, err := cbor.Decode(b, &s); err == nil { + return MetaText{Value: s}, nil + } + } + // Trying to decode as []bytes + { + var bs []byte + if _, err := cbor.Decode(b, &bs); err == nil { + return MetaBytes{Value: bs}, nil + } + } + // Trying to decode as cbor.RawMessage first then recursively decode each value + { + var arr []cbor.RawMessage + if _, err := cbor.Decode(b, &arr); err == nil { + items := make([]TransactionMetadatum, 0, len(arr)) + for _, it := range arr { + md, err := DecodeMetadatumRaw(it) + if err != nil { + return nil, fmt.Errorf("decode list item: %w", err) + } + items = append(items, md) + } + return MetaList{Items: items}, nil + } + } + // Trying to decode as map[uint64]cbor.RawMessage first. + // Next trying to decode key as MetaInt and value as MetaMap + { + var m map[uint64]cbor.RawMessage + if _, err := cbor.Decode(b, &m); err == nil && len(m) > 0 { + pairs := make([]MetaPair, 0, len(m)) + for k, rv := range m { + val, err := DecodeMetadatumRaw(rv) + if err != nil { + return nil, fmt.Errorf("decode map(uint) value: %w", err) + } + pairs = append(pairs, MetaPair{ + Key: MetaInt{Value: int64(k)}, + Value: val, + }) + } + return MetaMap{Pairs: pairs}, nil + } + } + // Trying to decode as map[string]cbor.RawMessage first. + // Next trying to decode key as MetaText and value as MetaMap + { + var m map[string]cbor.RawMessage + if _, err := cbor.Decode(b, &m); err == nil && len(m) > 0 { + pairs := make([]MetaPair, 0, len(m)) + for k, rv := range m { + val, err := DecodeMetadatumRaw(rv) + if err != nil { + return nil, fmt.Errorf("decode map(text) value: %w", err) + } + pairs = append(pairs, MetaPair{ + Key: MetaText{Value: k}, + Value: val, + }) + } + return MetaMap{Pairs: pairs}, nil + } + } + + return nil, fmt.Errorf("unsupported metadatum shape") +} + +// Decodes the transaction metadata set. +func (s *TransactionMetadataSet) UnmarshalCBOR(cborData []byte) error { + // Trying to decode as map[uint64]cbor.RawMessage. + // Calling DecodeMetadatumRaw for each entry call to get the typed value. + { + var tmp map[uint64]cbor.RawMessage + if _, err := cbor.Decode(cborData, &tmp); err == nil { + out := make(TransactionMetadataSet, len(tmp)) + for k, v := range tmp { + md, err := DecodeMetadatumRaw(v) + if err != nil { + return fmt.Errorf("decode metadata value for index %d: %w", k, err) + } + out[k] = md + } + *s = out + return nil + } + } + // Trying to decode as []cbor.RawMessage. + // Each element in array is decoded by calling DecodeMetadatumRaw + { + var arr []cbor.RawMessage + if _, err := cbor.Decode(cborData, &arr); err == nil { + out := make(TransactionMetadataSet) + for i, raw := range arr { + var probe any + // Skipping null values as well after decoding to cbor.RawMessage + if _, err := cbor.Decode(raw, &probe); err == nil { + continue + } + md, err := DecodeMetadatumRaw(raw) + if err != nil { + return fmt.Errorf("decode metadata list item %d: %w", i, err) + } + out[uint64(i)] = md + } + *s = out + return nil + } + } + return fmt.Errorf("unsupported TransactionMetadataSet encoding") +} + +// Encodes the transaction metadata set as a CBOR map +func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { + if s == nil { + return cbor.Encode(&map[uint64]any{}) + } + contiguous := true + var maxKey uint64 + for k := range s { + if k > maxKey { + maxKey = k + } + } + expectedCount := int(maxKey + 1) + if len(s) != expectedCount { + contiguous = false + } else { + for i := 0; i < expectedCount; i++ { + if _, ok := s[uint64(i)]; !ok { + contiguous = false + break + } + } + } + if contiguous { + arr := make([]any, expectedCount) + for i := 0; i < expectedCount; i++ { + arr[i] = metadatumToInterface(s[uint64(i)]) + } + return cbor.Encode(&arr) + } + // Otherwise Encode as a map. + tmpMap := make(map[uint64]any, len(s)) + for k, v := range s { + tmpMap[k] = metadatumToInterface(v) + } + return cbor.Encode(&tmpMap) +} + +// converting typed metadatum back into regular go values where the CBOR library can encode +func metadatumToInterface(m TransactionMetadatum) any { + switch t := m.(type) { + case MetaInt: + return t.Value + case MetaBytes: + return []byte(t.Value) + case MetaText: + return t.Value + case MetaList: + out := make([]any, 0, len(t.Items)) + for _, it := range t.Items { + out = append(out, metadatumToInterface(it)) + } + return out + case MetaMap: + mm := make(map[any]any, len(t.Pairs)) + for _, p := range t.Pairs { + mm[metadatumToInterface(p.Key)] = metadatumToInterface(p.Value) + } + return mm + default: + return nil + } +} diff --git a/ledger/conway/conway.go b/ledger/conway/conway.go index 0feb953f..fd10d921 100644 --- a/ledger/conway/conway.go +++ b/ledger/conway/conway.go @@ -55,7 +55,7 @@ type ConwayBlock struct { BlockHeader *ConwayBlockHeader TransactionBodies []ConwayTransactionBody TransactionWitnessSets []ConwayTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet InvalidTransactions []uint } @@ -513,7 +513,7 @@ type ConwayTransaction struct { Body ConwayTransactionBody WitnessSet ConwayTransactionWitnessSet TxIsValid bool - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *ConwayTransaction) UnmarshalCBOR(cborData []byte) error { @@ -615,7 +615,7 @@ func (t ConwayTransaction) Donation() uint64 { return t.Body.Donation() } -func (t ConwayTransaction) Metadata() *cbor.LazyValue { +func (t ConwayTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -682,7 +682,7 @@ func (t *ConwayTransaction) Cbor() []byte { t.TxIsValid, } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } diff --git a/ledger/mary/mary.go b/ledger/mary/mary.go index 6562d3be..5789d8bc 100644 --- a/ledger/mary/mary.go +++ b/ledger/mary/mary.go @@ -51,7 +51,7 @@ type MaryBlock struct { BlockHeader *MaryBlockHeader TransactionBodies []MaryTransactionBody TransactionWitnessSets []shelley.ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet } func (b *MaryBlock) UnmarshalCBOR(cborData []byte) error { @@ -245,7 +245,7 @@ type MaryTransaction struct { cbor.DecodeStoreCbor Body MaryTransactionBody WitnessSet shelley.ShelleyTransactionWitnessSet - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *MaryTransaction) UnmarshalCBOR(cborData []byte) error { @@ -347,7 +347,7 @@ func (t MaryTransaction) Donation() uint64 { return t.Body.Donation() } -func (t MaryTransaction) Metadata() *cbor.LazyValue { +func (t MaryTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -397,7 +397,7 @@ func (t *MaryTransaction) Cbor() []byte { cbor.RawMessage(t.WitnessSet.Cbor()), } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } diff --git a/ledger/shelley/shelley.go b/ledger/shelley/shelley.go index 3b37bf19..54f9db57 100644 --- a/ledger/shelley/shelley.go +++ b/ledger/shelley/shelley.go @@ -53,7 +53,7 @@ type ShelleyBlock struct { BlockHeader *ShelleyBlockHeader TransactionBodies []ShelleyTransactionBody TransactionWitnessSets []ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]*cbor.LazyValue + TransactionMetadataSet map[uint]common.TransactionMetadataSet } func (b *ShelleyBlock) UnmarshalCBOR(cborData []byte) error { @@ -504,7 +504,7 @@ type ShelleyTransaction struct { cbor.DecodeStoreCbor Body ShelleyTransactionBody WitnessSet ShelleyTransactionWitnessSet - TxMetadata *cbor.LazyValue + TxMetadata common.TransactionMetadataSet } func (t *ShelleyTransaction) UnmarshalCBOR(cborData []byte) error { @@ -602,7 +602,7 @@ func (t ShelleyTransaction) Donation() uint64 { return t.Body.Donation() } -func (t ShelleyTransaction) Metadata() *cbor.LazyValue { +func (t ShelleyTransaction) Metadata() common.TransactionMetadataSet { return t.TxMetadata } @@ -661,7 +661,7 @@ func (t *ShelleyTransaction) Cbor() []byte { cbor.RawMessage(t.WitnessSet.Cbor()), } if t.TxMetadata != nil { - tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor())) + tmpObj = append(tmpObj, t.TxMetadata) } else { tmpObj = append(tmpObj, nil) } From 83da7cab38c0d66ab4572200e87c81f7dae3862c Mon Sep 17 00:00:00 2001 From: Akhil Repala Date: Mon, 25 Aug 2025 13:34:41 -0500 Subject: [PATCH 2/5] feat: Fixed all golangci-lint errors Signed-off-by: Akhil Repala --- ledger/common/tx.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ledger/common/tx.go b/ledger/common/tx.go index ccc33cca..4fb21464 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -15,8 +15,10 @@ package common import ( + "errors" "fmt" "iter" + "math" "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/plutigo/data" @@ -341,6 +343,9 @@ func DecodeMetadatumRaw(b []byte) (TransactionMetadatum, error) { if err != nil { return nil, fmt.Errorf("decode map(uint) value: %w", err) } + if k > math.MaxInt64 { + return nil, fmt.Errorf("metadata label %d exceeds int64", k) + } pairs = append(pairs, MetaPair{ Key: MetaInt{Value: int64(k)}, Value: val, @@ -369,7 +374,7 @@ func DecodeMetadatumRaw(b []byte) (TransactionMetadatum, error) { } } - return nil, fmt.Errorf("unsupported metadatum shape") + return nil, errors.New("unsupported metadatum shape") } // Decodes the transaction metadata set. @@ -400,20 +405,20 @@ func (s *TransactionMetadataSet) UnmarshalCBOR(cborData []byte) error { for i, raw := range arr { var probe any // Skipping null values as well after decoding to cbor.RawMessage - if _, err := cbor.Decode(raw, &probe); err == nil { + if _, err := cbor.Decode(raw, &probe); err == nil && probe == nil { continue } md, err := DecodeMetadatumRaw(raw) if err != nil { return fmt.Errorf("decode metadata list item %d: %w", i, err) } - out[uint64(i)] = md + out[uint64(i)] = md // #nosec G115 — i is 0..len(arr)-1 } *s = out return nil } } - return fmt.Errorf("unsupported TransactionMetadataSet encoding") + return errors.New("unsupported TransactionMetadataSet encoding") } // Encodes the transaction metadata set as a CBOR map @@ -428,6 +433,9 @@ func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { maxKey = k } } + if maxKey > uint64(math.MaxInt-1) { + return nil, errors.New("metadata set too large to encode as array") + } expectedCount := int(maxKey + 1) if len(s) != expectedCount { contiguous = false From 9a6473e9421033db2f66f86c22d36765da8b2470 Mon Sep 17 00:00:00 2001 From: Akhil Repala Date: Mon, 25 Aug 2025 13:42:23 -0500 Subject: [PATCH 3/5] feat: Added fix for uint64 errors in MarshalCbor function Signed-off-by: Akhil Repala --- ledger/common/tx.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ledger/common/tx.go b/ledger/common/tx.go index 4fb21464..47490ae3 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -433,15 +433,17 @@ func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { maxKey = k } } - if maxKey > uint64(math.MaxInt-1) { + // expectedCount64 is the length the array + expectedCount64 := maxKey + 1 + if expectedCount64 > uint64(math.MaxInt) { return nil, errors.New("metadata set too large to encode as array") } - expectedCount := int(maxKey + 1) + expectedCount := int(expectedCount64) // #nosec G115 — bounded by check above if len(s) != expectedCount { contiguous = false } else { - for i := 0; i < expectedCount; i++ { - if _, ok := s[uint64(i)]; !ok { + for i := uint64(0); i < expectedCount64; i++ { + if _, ok := s[i]; !ok { contiguous = false break } @@ -449,8 +451,8 @@ func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { } if contiguous { arr := make([]any, expectedCount) - for i := 0; i < expectedCount; i++ { - arr[i] = metadatumToInterface(s[uint64(i)]) + for i := uint64(0); i < expectedCount64; i++ { + arr[i] = metadatumToInterface(s[i]) } return cbor.Encode(&arr) } From f511c6e3a3128f4bd4b575c4be1e0afb40b0371b Mon Sep 17 00:00:00 2001 From: Akhil Repala Date: Mon, 25 Aug 2025 13:45:02 -0500 Subject: [PATCH 4/5] feat: Added nosec G115 Signed-off-by: Akhil Repala --- ledger/common/tx.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ledger/common/tx.go b/ledger/common/tx.go index 47490ae3..9dc66f14 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -412,7 +412,7 @@ func (s *TransactionMetadataSet) UnmarshalCBOR(cborData []byte) error { if err != nil { return fmt.Errorf("decode metadata list item %d: %w", i, err) } - out[uint64(i)] = md // #nosec G115 — i is 0..len(arr)-1 + out[uint64(i)] = md // #nosec G115 } *s = out return nil @@ -438,7 +438,7 @@ func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { if expectedCount64 > uint64(math.MaxInt) { return nil, errors.New("metadata set too large to encode as array") } - expectedCount := int(expectedCount64) // #nosec G115 — bounded by check above + expectedCount := int(expectedCount64) // #nosec G115 if len(s) != expectedCount { contiguous = false } else { From 8194f2a735d00db95120bf3e14832820325732d5 Mon Sep 17 00:00:00 2001 From: Akhil Repala Date: Fri, 7 Nov 2025 00:59:06 -0600 Subject: [PATCH 5/5] feat(ledger):Addressed all the comments and made corresponding changes Signed-off-by: Akhil Repala --- ledger/allegra/allegra.go | 6 +- ledger/alonzo/alonzo.go | 6 +- ledger/babbage/babbage.go | 6 +- ledger/byron/byron.go | 4 +- ledger/common/metadata.go | 310 +++++++++++++++++++++++++++++++++ ledger/common/metadata_test.go | 32 ++++ ledger/common/tx.go | 242 +------------------------ ledger/conway/conway.go | 6 +- ledger/mary/mary.go | 6 +- ledger/shelley/shelley.go | 6 +- 10 files changed, 363 insertions(+), 261 deletions(-) create mode 100644 ledger/common/metadata.go create mode 100644 ledger/common/metadata_test.go diff --git a/ledger/allegra/allegra.go b/ledger/allegra/allegra.go index df02d47e..e7696424 100644 --- a/ledger/allegra/allegra.go +++ b/ledger/allegra/allegra.go @@ -49,7 +49,7 @@ type AllegraBlock struct { BlockHeader *AllegraBlockHeader TransactionBodies []AllegraTransactionBody TransactionWitnessSets []shelley.ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet } func (b *AllegraBlock) UnmarshalCBOR(cborData []byte) error { @@ -239,7 +239,7 @@ type AllegraTransaction struct { hash *common.Blake2b256 Body AllegraTransactionBody WitnessSet shelley.ShelleyTransactionWitnessSet - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *AllegraTransaction) UnmarshalCBOR(cborData []byte) error { @@ -349,7 +349,7 @@ func (t AllegraTransaction) Donation() uint64 { return t.Body.Donation() } -func (t AllegraTransaction) Metadata() common.TransactionMetadataSet { +func (t AllegraTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata } diff --git a/ledger/alonzo/alonzo.go b/ledger/alonzo/alonzo.go index 0330f868..7dc0be73 100644 --- a/ledger/alonzo/alonzo.go +++ b/ledger/alonzo/alonzo.go @@ -55,7 +55,7 @@ type AlonzoBlock struct { BlockHeader *AlonzoBlockHeader TransactionBodies []AlonzoTransactionBody TransactionWitnessSets []AlonzoTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet InvalidTransactions []uint } @@ -591,7 +591,7 @@ type AlonzoTransaction struct { Body AlonzoTransactionBody WitnessSet AlonzoTransactionWitnessSet TxIsValid bool - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *AlonzoTransaction) UnmarshalCBOR(cborData []byte) error { @@ -705,7 +705,7 @@ func (t AlonzoTransaction) Donation() uint64 { return t.Body.Donation() } -func (t AlonzoTransaction) Metadata() common.TransactionMetadataSet { +func (t AlonzoTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata } diff --git a/ledger/babbage/babbage.go b/ledger/babbage/babbage.go index 18d4d9c6..e29df83d 100644 --- a/ledger/babbage/babbage.go +++ b/ledger/babbage/babbage.go @@ -55,7 +55,7 @@ type BabbageBlock struct { BlockHeader *BabbageBlockHeader TransactionBodies []BabbageTransactionBody TransactionWitnessSets []BabbageTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet InvalidTransactions []uint } @@ -733,7 +733,7 @@ type BabbageTransaction struct { Body BabbageTransactionBody WitnessSet BabbageTransactionWitnessSet TxIsValid bool - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *BabbageTransaction) UnmarshalCBOR(cborData []byte) error { @@ -847,7 +847,7 @@ func (t BabbageTransaction) Donation() uint64 { return t.Body.Donation() } -func (t BabbageTransaction) Metadata() common.TransactionMetadataSet { +func (t BabbageTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata } diff --git a/ledger/byron/byron.go b/ledger/byron/byron.go index 965cf8d8..e41ba718 100644 --- a/ledger/byron/byron.go +++ b/ledger/byron/byron.go @@ -142,7 +142,7 @@ type ByronTransaction struct { hash *common.Blake2b256 TxInputs []ByronTransactionInput TxOutputs []ByronTransactionOutput - Attributes common.TransactionMetadataSet + Attributes common.TransactionMetadatum } func (t *ByronTransaction) UnmarshalCBOR(cborData []byte) error { @@ -275,7 +275,7 @@ func (t *ByronTransaction) Donation() uint64 { return 0 } -func (t *ByronTransaction) Metadata() common.TransactionMetadataSet { +func (t *ByronTransaction) Metadata() common.TransactionMetadatum { return t.Attributes } diff --git a/ledger/common/metadata.go b/ledger/common/metadata.go new file mode 100644 index 00000000..8fff9a0e --- /dev/null +++ b/ledger/common/metadata.go @@ -0,0 +1,310 @@ +// Copyright 2025 Blink Labs Software +// +// 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 common + +import ( + "errors" + "fmt" + "math" + + "github.com/blinklabs-io/gouroboros/cbor" +) + +const ( + cborTypeMask byte = 0xe0 + + cborTypeUnsigned byte = 0x00 + cborTypeNegative byte = 0x20 + cborTypeByteString byte = 0x40 + cborTypeTextString byte = 0x60 + cborTypeArray byte = 0x80 + cborTypeMap byte = 0xA0 + cborTypeTag byte = 0xC0 + cborTypeFloatSim byte = 0xE0 +) + +type TransactionMetadataSet map[uint]TransactionMetadatum + +type TransactionMetadatum interface { + isTransactionMetadatum() + TypeName() string +} + +type MetaInt struct{ Value int64 } +type MetaBytes struct{ Value []byte } +type MetaText struct{ Value string } +type MetaList struct { + Items []TransactionMetadatum +} +type MetaPair struct { + Key TransactionMetadatum + Value TransactionMetadatum +} +type MetaMap struct { + Pairs []MetaPair +} + +func (MetaInt) isTransactionMetadatum() {} +func (MetaBytes) isTransactionMetadatum() {} +func (MetaText) isTransactionMetadatum() {} +func (MetaList) isTransactionMetadatum() {} +func (MetaMap) isTransactionMetadatum() {} + +func (m MetaInt) TypeName() string { return "int" } +func (m MetaBytes) TypeName() string { return "bytes" } +func (m MetaText) TypeName() string { return "text" } +func (m MetaList) TypeName() string { return "list" } +func (m MetaMap) TypeName() string { return "map" } + +func DecodeMetadatumRaw(b []byte) (TransactionMetadatum, error) { + if len(b) == 0 { + return nil, errors.New("empty cbor") + } + switch b[0] & cborTypeMask { + case cborTypeUnsigned, cborTypeNegative: + var n int64 + if _, err := cbor.Decode(b, &n); err != nil { + return nil, err + } + return MetaInt{Value: n}, nil + + case cborTypeTextString: + var s string + if _, err := cbor.Decode(b, &s); err != nil { + return nil, err + } + return MetaText{Value: s}, nil + + case cborTypeByteString: + var bs []byte + if _, err := cbor.Decode(b, &bs); err != nil { + return nil, err + } + return MetaBytes{Value: bs}, nil + + case cborTypeArray: + var rawItems []cbor.RawMessage + if _, err := cbor.Decode(b, &rawItems); err != nil { + return nil, err + } + items := make([]TransactionMetadatum, 0, len(rawItems)) + for _, r := range rawItems { + md, err := DecodeMetadatumRaw(r) + if err != nil { + return nil, err + } + items = append(items, md) + } + return MetaList{Items: items}, nil + + case cborTypeMap: + if md, ok, err := decodeMapUint(b); ok || err != nil { + return md, err + } + if md, ok, err := decodeMapText(b); ok || err != nil { + return md, err + } + if md, ok, err := decodeMapBytes(b); ok || err != nil { + return md, err + } + return nil, errors.New("unsupported map key type in metadatum") + + case cborTypeTag, cborTypeFloatSim: + var x any + if _, err := cbor.Decode(b, &x); err != nil { + return nil, err + } + return MetaText{Value: fmt.Sprintf("%v", x)}, nil + + default: + return nil, errors.New("unknown CBOR major type") + } +} + +func decodeMapUint(b []byte) (TransactionMetadatum, bool, error) { + var m map[uint]cbor.RawMessage + if _, err := cbor.Decode(b, &m); err != nil { + return nil, false, nil // not this shape + } + pairs := make([]MetaPair, 0, len(m)) + for k, rv := range m { + val, err := DecodeMetadatumRaw(rv) + if err != nil { + return nil, true, fmt.Errorf("decode map(uint) value: %w", err) + } + if k > math.MaxInt64 { + return nil, true, fmt.Errorf("metadata label %d exceeds int64", k) + } + pairs = append(pairs, MetaPair{Key: MetaInt{Value: int64(k)}, Value: val}) + } + return MetaMap{Pairs: pairs}, true, nil +} + +func decodeMapText(b []byte) (TransactionMetadatum, bool, error) { + var m map[string]cbor.RawMessage + if _, err := cbor.Decode(b, &m); err != nil { + return nil, false, nil // not this shape + } + pairs := make([]MetaPair, 0, len(m)) + for k, rv := range m { + val, err := DecodeMetadatumRaw(rv) + if err != nil { + return nil, true, fmt.Errorf("decode map(text) value: %w", err) + } + pairs = append(pairs, MetaPair{Key: MetaText{Value: k}, Value: val}) + } + return MetaMap{Pairs: pairs}, true, nil +} + +func decodeMapBytes(b []byte) (TransactionMetadatum, bool, error) { + var m map[cbor.ByteString]cbor.RawMessage + if _, err := cbor.Decode(b, &m); err != nil { + return nil, false, nil + } + pairs := make([]MetaPair, 0, len(m)) + for k, rv := range m { + val, err := DecodeMetadatumRaw(rv) + if err != nil { + return nil, true, fmt.Errorf("decode map(bytes) value: %w", err) + } + + bs := k.Bytes() + pairs = append(pairs, MetaPair{ + Key: MetaBytes{Value: append([]byte(nil), bs...)}, + Value: val, + }) + } + return MetaMap{Pairs: pairs}, true, nil +} + +func (s *TransactionMetadataSet) UnmarshalCBOR(cborData []byte) error { + + // Map form: map[uint]cbor.RawMessage + { + var tmp map[uint]cbor.RawMessage + if _, err := cbor.Decode(cborData, &tmp); err == nil { + out := make(TransactionMetadataSet, len(tmp)) + for k, v := range tmp { + md, err := DecodeMetadatumRaw(v) + if err != nil { + return fmt.Errorf("decode metadata value for index %d: %w", k, err) + } + out[k] = md + } + *s = out + return nil + } + } + // Array form: []cbor.RawMessage (nulls are skipped) + { + var arr []cbor.RawMessage + if _, err := cbor.Decode(cborData, &arr); err == nil { + out := make(TransactionMetadataSet) + for i, raw := range arr { + var probe any + if _, err := cbor.Decode(raw, &probe); err == nil && probe == nil { + continue // skip nulls + } + md, err := DecodeMetadatumRaw(raw) + if err != nil { + return fmt.Errorf("decode metadata list item %d: %w", i, err) + } + out[uint(i)] = md // #nosec G115 + } + *s = out + return nil + } + } + return errors.New("unsupported TransactionMetadataSet encoding") +} + +func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { + if s == nil { + return cbor.Encode(&map[uint]any{}) + } + tmpMap := make(map[uint]any, len(s)) + for k, v := range s { + tmpMap[k] = metadatumToInterface(v) + } + return cbor.Encode(&tmpMap) +} + +func metadatumToInterface(m TransactionMetadatum) any { + switch t := m.(type) { + case MetaInt: + return t.Value + case MetaBytes: + return t.Value + case MetaText: + return t.Value + case MetaList: + out := make([]any, 0, len(t.Items)) + for _, it := range t.Items { + out = append(out, metadatumToInterface(it)) + } + return out + case MetaMap: + allText := true + for _, p := range t.Pairs { + if _, ok := p.Key.(MetaText); !ok { + allText = false + break + } + } + if allText { + mm := make(map[string]any, len(t.Pairs)) + for _, p := range t.Pairs { + mm[p.Key.(MetaText).Value] = metadatumToInterface(p.Value) + } + return mm + } + // Try all-int keys + allInt := true + for _, p := range t.Pairs { + if _, ok := p.Key.(MetaInt); !ok { + allInt = false + break + } + } + if allInt { + mm := make(map[int64]any, len(t.Pairs)) + for _, p := range t.Pairs { + mm[p.Key.(MetaInt).Value] = metadatumToInterface(p.Value) + } + return mm + } + + allBytes := true + for _, p := range t.Pairs { + if _, ok := p.Key.(MetaBytes); !ok { + allBytes = false + break + } + } + if allBytes { + mm := make(map[cbor.ByteString]any, len(t.Pairs)) + for _, p := range t.Pairs { + bs := p.Key.(MetaBytes).Value + key := cbor.NewByteString(bs) + mm[key] = metadatumToInterface(p.Value) + } + return mm + } + return nil + + default: + return nil + } +} diff --git a/ledger/common/metadata_test.go b/ledger/common/metadata_test.go new file mode 100644 index 00000000..c7d33e5e --- /dev/null +++ b/ledger/common/metadata_test.go @@ -0,0 +1,32 @@ +package common + +import ( + "encoding/hex" + "testing" + + "github.com/blinklabs-io/gouroboros/cbor" +) + +var allegraBlockHex = "a219ef64a301582095b1d64fbf76f17b1920a34d14fbca1f5ab499ea59eac37a8117d5e6b2e09605025820f3157c8eda34976620ad12e0979b2d3135a784c5d6a185878987143053c17d1c035839012c152eaa9e68dd7123a3054190dc987a24e50f1ab389c44a0c7a4089beb4d4d62d8f0dce5d745df4a670998aa20f54703b2bdc7a00b7d3d219ef65a1015840897063bdeab54d2e0586529909f20b42447bfaccdfb9988d2558896baf82a37f43c2fa4ae4240f5761e3dccf9523d7305d728f21dee4491e02373de6b14f7e07" + +func Test_Metadata_RoundTrip_AllegraSample(t *testing.T) { + + raw, err := hex.DecodeString(allegraBlockHex) + if err != nil { + t.Fatalf("bad hex: %v", err) + } + + var set TransactionMetadataSet + if _, err := cbor.Decode(raw, &set); err != nil { + t.Fatalf("decode: %v", err) + } + + enc, err := set.MarshalCBOR() + if err != nil { + t.Fatalf("encode: %v", err) + } + + if hex.EncodeToString(enc) != allegraBlockHex { + t.Fatalf("mismatch:\n got: %s\nwant: %s", hex.EncodeToString(enc), allegraBlockHex) + } +} diff --git a/ledger/common/tx.go b/ledger/common/tx.go index d8577e99..b14051a2 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -15,10 +15,7 @@ package common import ( - "errors" - "fmt" "iter" - "math" "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/plutigo/data" @@ -31,44 +28,13 @@ type Transaction interface { Cbor() []byte Hash() Blake2b256 LeiosHash() Blake2b256 - Metadata() TransactionMetadataSet + Metadata() TransactionMetadatum IsValid() bool Consumed() []TransactionInput Produced() []Utxo Witnesses() TransactionWitnessSet } -type TransactionMetadataSet map[uint64]TransactionMetadatum - -type TransactionMetadatum interface { - TypeName() string -} - -type MetaInt struct { - Value int64 -} - -type MetaBytes struct { - Value []byte -} - -type MetaText struct { - Value string -} - -type MetaList struct { - Items []TransactionMetadatum -} - -type MetaPair struct { - Key TransactionMetadatum - Value TransactionMetadatum -} - -type MetaMap struct { - Pairs []MetaPair -} - type TransactionBody interface { Cbor() []byte Fee() uint64 @@ -294,209 +260,3 @@ func TransactionBodyToUtxorpc(tx TransactionBody) (*utxorpc.Tx, error) { return ret, nil } - -func (m MetaInt) TypeName() string { return "int" } - -func (m MetaBytes) TypeName() string { return "bytes" } - -func (m MetaText) TypeName() string { return "text" } - -func (m MetaList) TypeName() string { return "list" } - -func (m MetaMap) TypeName() string { return "map" } - -// Tries Decoding CBOR into all TransactionMetadatum variants (int, text, bytes, list, map). -func DecodeMetadatumRaw(b []byte) (TransactionMetadatum, error) { - // Trying to decode as int64 - { - var v int64 - if _, err := cbor.Decode(b, &v); err == nil { - return MetaInt{Value: v}, nil - } - } - // Trying to decode as string - { - var s string - if _, err := cbor.Decode(b, &s); err == nil { - return MetaText{Value: s}, nil - } - } - // Trying to decode as []bytes - { - var bs []byte - if _, err := cbor.Decode(b, &bs); err == nil { - return MetaBytes{Value: bs}, nil - } - } - // Trying to decode as cbor.RawMessage first then recursively decode each value - { - var arr []cbor.RawMessage - if _, err := cbor.Decode(b, &arr); err == nil { - items := make([]TransactionMetadatum, 0, len(arr)) - for _, it := range arr { - md, err := DecodeMetadatumRaw(it) - if err != nil { - return nil, fmt.Errorf("decode list item: %w", err) - } - items = append(items, md) - } - return MetaList{Items: items}, nil - } - } - // Trying to decode as map[uint64]cbor.RawMessage first. - // Next trying to decode key as MetaInt and value as MetaMap - { - var m map[uint64]cbor.RawMessage - if _, err := cbor.Decode(b, &m); err == nil && len(m) > 0 { - pairs := make([]MetaPair, 0, len(m)) - for k, rv := range m { - val, err := DecodeMetadatumRaw(rv) - if err != nil { - return nil, fmt.Errorf("decode map(uint) value: %w", err) - } - if k > math.MaxInt64 { - return nil, fmt.Errorf("metadata label %d exceeds int64", k) - } - pairs = append(pairs, MetaPair{ - Key: MetaInt{Value: int64(k)}, - Value: val, - }) - } - return MetaMap{Pairs: pairs}, nil - } - } - // Trying to decode as map[string]cbor.RawMessage first. - // Next trying to decode key as MetaText and value as MetaMap - { - var m map[string]cbor.RawMessage - if _, err := cbor.Decode(b, &m); err == nil && len(m) > 0 { - pairs := make([]MetaPair, 0, len(m)) - for k, rv := range m { - val, err := DecodeMetadatumRaw(rv) - if err != nil { - return nil, fmt.Errorf("decode map(text) value: %w", err) - } - pairs = append(pairs, MetaPair{ - Key: MetaText{Value: k}, - Value: val, - }) - } - return MetaMap{Pairs: pairs}, nil - } - } - - return nil, errors.New("unsupported metadatum shape") -} - -// Decodes the transaction metadata set. -func (s *TransactionMetadataSet) UnmarshalCBOR(cborData []byte) error { - // Trying to decode as map[uint64]cbor.RawMessage. - // Calling DecodeMetadatumRaw for each entry call to get the typed value. - { - var tmp map[uint64]cbor.RawMessage - if _, err := cbor.Decode(cborData, &tmp); err == nil { - out := make(TransactionMetadataSet, len(tmp)) - for k, v := range tmp { - md, err := DecodeMetadatumRaw(v) - if err != nil { - return fmt.Errorf("decode metadata value for index %d: %w", k, err) - } - out[k] = md - } - *s = out - return nil - } - } - // Trying to decode as []cbor.RawMessage. - // Each element in array is decoded by calling DecodeMetadatumRaw - { - var arr []cbor.RawMessage - if _, err := cbor.Decode(cborData, &arr); err == nil { - out := make(TransactionMetadataSet) - for i, raw := range arr { - var probe any - // Skipping null values as well after decoding to cbor.RawMessage - if _, err := cbor.Decode(raw, &probe); err == nil && probe == nil { - continue - } - md, err := DecodeMetadatumRaw(raw) - if err != nil { - return fmt.Errorf("decode metadata list item %d: %w", i, err) - } - out[uint64(i)] = md // #nosec G115 - } - *s = out - return nil - } - } - return errors.New("unsupported TransactionMetadataSet encoding") -} - -// Encodes the transaction metadata set as a CBOR map -func (s TransactionMetadataSet) MarshalCBOR() ([]byte, error) { - if s == nil { - return cbor.Encode(&map[uint64]any{}) - } - contiguous := true - var maxKey uint64 - for k := range s { - if k > maxKey { - maxKey = k - } - } - // expectedCount64 is the length the array - expectedCount64 := maxKey + 1 - if expectedCount64 > uint64(math.MaxInt) { - return nil, errors.New("metadata set too large to encode as array") - } - expectedCount := int(expectedCount64) // #nosec G115 - if len(s) != expectedCount { - contiguous = false - } else { - for i := uint64(0); i < expectedCount64; i++ { - if _, ok := s[i]; !ok { - contiguous = false - break - } - } - } - if contiguous { - arr := make([]any, expectedCount) - for i := uint64(0); i < expectedCount64; i++ { - arr[i] = metadatumToInterface(s[i]) - } - return cbor.Encode(&arr) - } - // Otherwise Encode as a map. - tmpMap := make(map[uint64]any, len(s)) - for k, v := range s { - tmpMap[k] = metadatumToInterface(v) - } - return cbor.Encode(&tmpMap) -} - -// converting typed metadatum back into regular go values where the CBOR library can encode -func metadatumToInterface(m TransactionMetadatum) any { - switch t := m.(type) { - case MetaInt: - return t.Value - case MetaBytes: - return []byte(t.Value) - case MetaText: - return t.Value - case MetaList: - out := make([]any, 0, len(t.Items)) - for _, it := range t.Items { - out = append(out, metadatumToInterface(it)) - } - return out - case MetaMap: - mm := make(map[any]any, len(t.Pairs)) - for _, p := range t.Pairs { - mm[metadatumToInterface(p.Key)] = metadatumToInterface(p.Value) - } - return mm - default: - return nil - } -} diff --git a/ledger/conway/conway.go b/ledger/conway/conway.go index c396cca4..1b4ec15b 100644 --- a/ledger/conway/conway.go +++ b/ledger/conway/conway.go @@ -55,7 +55,7 @@ type ConwayBlock struct { BlockHeader *ConwayBlockHeader TransactionBodies []ConwayTransactionBody TransactionWitnessSets []ConwayTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet InvalidTransactions []uint } @@ -518,7 +518,7 @@ type ConwayTransaction struct { Body ConwayTransactionBody WitnessSet ConwayTransactionWitnessSet TxIsValid bool - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *ConwayTransaction) UnmarshalCBOR(cborData []byte) error { @@ -632,7 +632,7 @@ func (t ConwayTransaction) Donation() uint64 { return t.Body.Donation() } -func (t ConwayTransaction) Metadata() common.TransactionMetadataSet { +func (t ConwayTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata } diff --git a/ledger/mary/mary.go b/ledger/mary/mary.go index 883b8a5c..0eab182a 100644 --- a/ledger/mary/mary.go +++ b/ledger/mary/mary.go @@ -52,7 +52,7 @@ type MaryBlock struct { BlockHeader *MaryBlockHeader TransactionBodies []MaryTransactionBody TransactionWitnessSets []shelley.ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet } func (b *MaryBlock) UnmarshalCBOR(cborData []byte) error { @@ -247,7 +247,7 @@ type MaryTransaction struct { hash *common.Blake2b256 Body MaryTransactionBody WitnessSet shelley.ShelleyTransactionWitnessSet - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *MaryTransaction) UnmarshalCBOR(cborData []byte) error { @@ -361,7 +361,7 @@ func (t MaryTransaction) Donation() uint64 { return t.Body.Donation() } -func (t MaryTransaction) Metadata() common.TransactionMetadataSet { +func (t MaryTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata } diff --git a/ledger/shelley/shelley.go b/ledger/shelley/shelley.go index d72d9324..8c419631 100644 --- a/ledger/shelley/shelley.go +++ b/ledger/shelley/shelley.go @@ -53,7 +53,7 @@ type ShelleyBlock struct { BlockHeader *ShelleyBlockHeader TransactionBodies []ShelleyTransactionBody TransactionWitnessSets []ShelleyTransactionWitnessSet - TransactionMetadataSet map[uint]common.TransactionMetadataSet + TransactionMetadataSet common.TransactionMetadataSet } func (b *ShelleyBlock) UnmarshalCBOR(cborData []byte) error { @@ -540,7 +540,7 @@ type ShelleyTransaction struct { hash *common.Blake2b256 Body ShelleyTransactionBody WitnessSet ShelleyTransactionWitnessSet - TxMetadata common.TransactionMetadataSet + TxMetadata common.TransactionMetadatum } func (t *ShelleyTransaction) UnmarshalCBOR(cborData []byte) error { @@ -650,7 +650,7 @@ func (t ShelleyTransaction) Donation() uint64 { return t.Body.Donation() } -func (t ShelleyTransaction) Metadata() common.TransactionMetadataSet { +func (t ShelleyTransaction) Metadata() common.TransactionMetadatum { return t.TxMetadata }