Skip to content

Commit d7b0083

Browse files
committed
fix(ledger): use raw bytes for metadata
Signed-off-by: Chris Gianelloni <[email protected]>
1 parent ac6eddd commit d7b0083

File tree

9 files changed

+583
-175
lines changed

9 files changed

+583
-175
lines changed

ledger/allegra/allegra.go

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ func (b *AllegraBlock) UnmarshalCBOR(cborData []byte) error {
6161
}
6262
*b = AllegraBlock(tmp)
6363
b.SetCbor(cborData)
64+
65+
// Extract and store CBOR for each component
66+
if err := common.ExtractTransactionCbor(cborData, &b.TransactionBodies, &b.TransactionWitnessSets); err != nil {
67+
return err
68+
}
6469
return nil
6570
}
6671

@@ -104,13 +109,14 @@ func (b *AllegraBlock) Transactions() []common.Transaction {
104109
ret := make([]common.Transaction, len(b.TransactionBodies))
105110
// #nosec G115
106111
for idx := range b.TransactionBodies {
107-
// Note: Ignoring the presence flag; if distinguishing "missing" vs "present but empty/failed decode" is needed, plumb the second return value through
108-
txMetadata, _ := b.TransactionMetadataSet.GetMetadata(uint(idx))
109-
ret[idx] = &AllegraTransaction{
112+
tx := &AllegraTransaction{
110113
Body: b.TransactionBodies[idx],
111114
WitnessSet: b.TransactionWitnessSets[idx],
112-
TxMetadata: txMetadata,
113115
}
116+
if metadata, ok := b.TransactionMetadataSet.GetMetadata(uint(idx)); ok {
117+
tx.TxMetadata = metadata
118+
}
119+
ret[idx] = tx
114120
}
115121
return ret
116122
}
@@ -250,12 +256,35 @@ type AllegraTransaction struct {
250256
}
251257

252258
func (t *AllegraTransaction) UnmarshalCBOR(cborData []byte) error {
253-
type tAllegraTransaction AllegraTransaction
254-
var tmp tAllegraTransaction
255-
if _, err := cbor.Decode(cborData, &tmp); err != nil {
259+
// Decode as raw array to capture metadata bytes
260+
var txArray []cbor.RawMessage
261+
if _, err := cbor.Decode(cborData, &txArray); err != nil {
256262
return err
257263
}
258-
*t = AllegraTransaction(tmp)
264+
if len(txArray) < 2 {
265+
return fmt.Errorf(
266+
"invalid transaction: expected at least 2 components, got %d",
267+
len(txArray),
268+
)
269+
}
270+
// Decode body and witness set
271+
if _, err := cbor.Decode(txArray[0], &t.Body); err != nil {
272+
return fmt.Errorf("failed to decode transaction body: %w", err)
273+
}
274+
if _, err := cbor.Decode(txArray[1], &t.WitnessSet); err != nil {
275+
return fmt.Errorf("failed to decode transaction witness set: %w", err)
276+
}
277+
// Handle metadata (component 3) - preserve raw bytes
278+
if len(txArray) > 2 && len(txArray[2]) > 0 {
279+
metadata, err := common.DecodeAuxiliaryDataToMetadata(txArray[2])
280+
if err == nil && metadata != nil {
281+
// Ensure the metadata has the raw auxiliary data bytes stored
282+
if setCbor, ok := interface{}(metadata).(interface{ SetCbor([]byte) }); ok {
283+
setCbor.SetCbor([]byte(txArray[2]))
284+
}
285+
t.TxMetadata = metadata
286+
}
287+
}
259288
t.SetCbor(cborData)
260289
return nil
261290
}
@@ -356,7 +385,7 @@ func (t AllegraTransaction) Donation() uint64 {
356385
return t.Body.Donation()
357386
}
358387

359-
func (t AllegraTransaction) Metadata() common.TransactionMetadatum {
388+
func (t *AllegraTransaction) Metadata() common.TransactionMetadatum {
360389
return t.TxMetadata
361390
}
362391

@@ -401,6 +430,25 @@ func (t AllegraTransaction) Utxorpc() (*utxorpc.Tx, error) {
401430
return tx, nil
402431
}
403432

433+
func (t *AllegraTransaction) MarshalCBOR() ([]byte, error) {
434+
// If we have stored CBOR (from decode), return it to preserve metadata bytes
435+
cborData := t.DecodeStoreCbor.Cbor()
436+
if cborData != nil {
437+
return cborData, nil
438+
}
439+
// Otherwise, construct and encode
440+
tmpObj := []any{
441+
t.Body,
442+
t.WitnessSet,
443+
}
444+
if t.TxMetadata != nil {
445+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
446+
} else {
447+
tmpObj = append(tmpObj, nil)
448+
}
449+
return cbor.Encode(tmpObj)
450+
}
451+
404452
func (t *AllegraTransaction) Cbor() []byte {
405453
// Return stored CBOR if we have any
406454
cborData := t.DecodeStoreCbor.Cbor()
@@ -411,19 +459,8 @@ func (t *AllegraTransaction) Cbor() []byte {
411459
if t.Body.Cbor() == nil {
412460
return nil
413461
}
414-
// Generate our own CBOR
415-
// This is necessary when a transaction is put together from pieces stored separately in a block
416-
tmpObj := []any{
417-
cbor.RawMessage(t.Body.Cbor()),
418-
cbor.RawMessage(t.WitnessSet.Cbor()),
419-
}
420-
if t.TxMetadata != nil {
421-
tmpObj = append(tmpObj, t.TxMetadata)
422-
} else {
423-
tmpObj = append(tmpObj, nil)
424-
}
425-
// This should never fail, since we're only encoding a list and a bool value
426-
cborData, err := cbor.Encode(&tmpObj)
462+
// Delegate to MarshalCBOR which handles encoding
463+
cborData, err := cbor.Encode(t)
427464
if err != nil {
428465
panic("CBOR encoding that should never fail has failed: " + err.Error())
429466
}

ledger/alonzo/alonzo.go

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ func (b *AlonzoBlock) UnmarshalCBOR(cborData []byte) error {
6868
}
6969
*b = AlonzoBlock(tmp)
7070
b.SetCbor(cborData)
71+
72+
// Extract and store CBOR for each component
73+
if err := common.ExtractTransactionCbor(cborData, &b.TransactionBodies, &b.TransactionWitnessSets); err != nil {
74+
return err
75+
}
7176
return nil
7277
}
7378

@@ -156,14 +161,15 @@ func (b *AlonzoBlock) Transactions() []common.Transaction {
156161
ret := make([]common.Transaction, len(b.TransactionBodies))
157162
// #nosec G115
158163
for idx := range b.TransactionBodies {
159-
// Note: Ignoring the presence flag; if distinguishing "missing" vs "present but empty/failed decode" is needed, plumb the second return value through
160-
txMetadata, _ := b.TransactionMetadataSet.GetMetadata(uint(idx))
161-
ret[idx] = &AlonzoTransaction{
164+
tx := &AlonzoTransaction{
162165
Body: b.TransactionBodies[idx],
163166
WitnessSet: b.TransactionWitnessSets[idx],
164-
TxMetadata: txMetadata,
165167
TxIsValid: !invalidTxMap[uint(idx)],
166168
}
169+
if metadata, ok := b.TransactionMetadataSet.GetMetadata(uint(idx)); ok {
170+
tx.TxMetadata = metadata
171+
}
172+
ret[idx] = tx
167173
}
168174
return ret
169175
}
@@ -646,16 +652,55 @@ type AlonzoTransaction struct {
646652
}
647653

648654
func (t *AlonzoTransaction) UnmarshalCBOR(cborData []byte) error {
649-
type tAlonzoTransaction AlonzoTransaction
650-
var tmp tAlonzoTransaction
651-
if _, err := cbor.Decode(cborData, &tmp); err != nil {
655+
// Decode as raw array to preserve metadata bytes
656+
var txArray []cbor.RawMessage
657+
if _, err := cbor.Decode(cborData, &txArray); err != nil {
652658
return err
653659
}
654-
*t = AlonzoTransaction(tmp)
660+
661+
// Ensure we have at least 3 components
662+
if len(txArray) < 3 {
663+
return fmt.Errorf(
664+
"invalid transaction: expected at least 3 components, got %d",
665+
len(txArray),
666+
)
667+
}
668+
669+
// Decode body
670+
if _, err := cbor.Decode([]byte(txArray[0]), &t.Body); err != nil {
671+
return fmt.Errorf("failed to decode transaction body: %w", err)
672+
}
673+
674+
// Decode witness set
675+
if _, err := cbor.Decode([]byte(txArray[1]), &t.WitnessSet); err != nil {
676+
return fmt.Errorf("failed to decode transaction witness set: %w", err)
677+
}
678+
679+
// Decode TxIsValid flag
680+
if _, err := cbor.Decode([]byte(txArray[2]), &t.TxIsValid); err != nil {
681+
return fmt.Errorf("failed to decode TxIsValid: %w", err)
682+
}
683+
684+
// Handle metadata (component 4) - preserve raw bytes
685+
if len(txArray) > 3 && len(txArray[3]) > 0 {
686+
metadata, err := common.DecodeAuxiliaryDataToMetadata(txArray[3])
687+
if err == nil && metadata != nil {
688+
// Ensure the metadata has the raw auxiliary data bytes stored
689+
if setCbor, ok := interface{}(metadata).(interface{ SetCbor([]byte) }); ok {
690+
setCbor.SetCbor([]byte(txArray[3]))
691+
}
692+
t.TxMetadata = metadata
693+
}
694+
}
695+
655696
t.SetCbor(cborData)
656697
return nil
657698
}
658699

700+
func (t *AlonzoTransaction) Metadata() common.TransactionMetadatum {
701+
return t.TxMetadata
702+
}
703+
659704
func (AlonzoTransaction) Type() int {
660705
return TxTypeAlonzo
661706
}
@@ -756,10 +801,6 @@ func (t AlonzoTransaction) Donation() uint64 {
756801
return t.Body.Donation()
757802
}
758803

759-
func (t AlonzoTransaction) Metadata() common.TransactionMetadatum {
760-
return t.TxMetadata
761-
}
762-
763804
func (t AlonzoTransaction) IsValid() bool {
764805
return t.TxIsValid
765806
}
@@ -798,30 +839,38 @@ func (t AlonzoTransaction) Witnesses() common.TransactionWitnessSet {
798839
return t.WitnessSet
799840
}
800841

801-
func (t *AlonzoTransaction) Cbor() []byte {
802-
// Return stored CBOR if we have any
842+
func (t *AlonzoTransaction) MarshalCBOR() ([]byte, error) {
843+
// If we have stored CBOR (from decode), return it to preserve metadata bytes
803844
cborData := t.DecodeStoreCbor.Cbor()
804845
if len(cborData) > 0 {
805-
return cborData[:]
846+
return cborData, nil
806847
}
807-
// Return immediately if the body CBOR is also empty, which implies an empty TX object
808-
if t.Body.Cbor() == nil {
809-
return nil
810-
}
811-
// Generate our own CBOR
812-
// This is necessary when a transaction is put together from pieces stored separately in a block
848+
// Otherwise, construct and encode
813849
tmpObj := []any{
814-
cbor.RawMessage(t.Body.Cbor()),
815-
cbor.RawMessage(t.WitnessSet.Cbor()),
850+
t.Body,
851+
t.WitnessSet,
816852
t.TxIsValid,
817853
}
818854
if t.TxMetadata != nil {
819-
tmpObj = append(tmpObj, t.TxMetadata)
855+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
820856
} else {
821857
tmpObj = append(tmpObj, nil)
822858
}
823-
// This should never fail, since we're only encoding a list and a bool value
824-
cborData, err := cbor.Encode(&tmpObj)
859+
return cbor.Encode(tmpObj)
860+
}
861+
862+
func (t *AlonzoTransaction) Cbor() []byte {
863+
// Return stored CBOR if we have any
864+
cborData := t.DecodeStoreCbor.Cbor()
865+
if len(cborData) > 0 {
866+
return cborData[:]
867+
}
868+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
869+
if t.Body.Cbor() == nil {
870+
return nil
871+
}
872+
// Delegate to MarshalCBOR which handles encoding
873+
cborData, err := cbor.Encode(t)
825874
if err != nil {
826875
panic("CBOR encoding that should never fail has failed: " + err.Error())
827876
}

0 commit comments

Comments
 (0)