Skip to content

Commit 54800ce

Browse files
authored
Merge pull request #400 from blinklabs-io/feat/block-tx-cbor
feat: CBOR for block transactions
2 parents 55f3575 + 99a9a5b commit 54800ce

File tree

6 files changed

+156
-14
lines changed

6 files changed

+156
-14
lines changed

cbor/cbor.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,18 @@ type StructAsArray struct {
5353

5454
type DecodeStoreCborInterface interface {
5555
Cbor() []byte
56+
SetCbor([]byte)
5657
}
5758

5859
type DecodeStoreCbor struct {
5960
cborData []byte
6061
}
6162

63+
func (d *DecodeStoreCbor) SetCbor(cborData []byte) {
64+
d.cborData = make([]byte, len(cborData))
65+
copy(d.cborData, cborData)
66+
}
67+
6268
// Cbor returns the original CBOR for the object
6369
func (d *DecodeStoreCbor) Cbor() []byte {
6470
return d.cborData
@@ -72,7 +78,6 @@ func (d *DecodeStoreCbor) UnmarshalCbor(cborData []byte, dest DecodeStoreCborInt
7278
// Store a copy of the original CBOR data
7379
// This must be done after we copy from the temp object above, or it gets wiped out
7480
// when using struct embedding and the DecodeStoreCbor struct is embedded at a deeper level
75-
d.cborData = make([]byte, len(cborData))
76-
copy(d.cborData, cborData)
81+
d.SetCbor(cborData)
7782
return nil
7883
}

ledger/allegra.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,32 @@ func (t AllegraTransaction) Metadata() *cbor.Value {
113113
return t.TxMetadata
114114
}
115115

116+
func (t *AllegraTransaction) Cbor() []byte {
117+
// Return stored CBOR if we have any
118+
cborData := t.DecodeStoreCbor.Cbor()
119+
if cborData != nil {
120+
return cborData[:]
121+
}
122+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
123+
if t.Body.Cbor() == nil {
124+
return nil
125+
}
126+
// Generate our own CBOR
127+
// This is necessary when a transaction is put together from pieces stored separately in a block
128+
tmpObj := []any{
129+
cbor.RawMessage(t.Body.Cbor()),
130+
cbor.RawMessage(t.WitnessSet.Cbor()),
131+
}
132+
if t.TxMetadata != nil {
133+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
134+
} else {
135+
tmpObj = append(tmpObj, nil)
136+
}
137+
// This should never fail, since we're only encoding a list and a bool value
138+
cborData, _ = cbor.Encode(&tmpObj)
139+
return cborData
140+
}
141+
116142
func NewAllegraBlockFromCbor(data []byte) (*AllegraBlock, error) {
117143
var allegraBlock AllegraBlock
118144
if _, err := cbor.Decode(data, &allegraBlock); err != nil {

ledger/alonzo.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,15 @@ func (b *AlonzoTransactionBody) Outputs() []TransactionOutput {
114114

115115
type AlonzoTransactionOutput struct {
116116
cbor.StructAsArray
117-
cborData []byte
117+
cbor.DecodeStoreCbor
118118
OutputAddress Address
119119
OutputAmount MaryTransactionOutputValue
120120
TxOutputDatumHash *Blake2b256
121121
}
122122

123123
func (o *AlonzoTransactionOutput) UnmarshalCBOR(cborData []byte) error {
124124
// Save original CBOR
125-
o.cborData = cborData[:]
125+
o.SetCbor(cborData)
126126
// Try to parse as Mary output first
127127
var tmpOutput MaryTransactionOutput
128128
if _, err := cbor.Decode(cborData, &tmpOutput); err == nil {
@@ -152,10 +152,6 @@ func (o AlonzoTransactionOutput) MarshalJSON() ([]byte, error) {
152152
return json.Marshal(&tmpObj)
153153
}
154154

155-
func (o *AlonzoTransactionOutput) Cbor() []byte {
156-
return o.cborData
157-
}
158-
159155
func (o AlonzoTransactionOutput) Address() Address {
160156
return o.OutputAddress
161157
}
@@ -183,6 +179,10 @@ type AlonzoTransactionWitnessSet struct {
183179
Redeemers []cbor.RawMessage `cbor:"5,keyasint,omitempty"`
184180
}
185181

182+
func (t *AlonzoTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error {
183+
return t.UnmarshalCbor(cborData, t)
184+
}
185+
186186
type AlonzoTransaction struct {
187187
cbor.StructAsArray
188188
cbor.DecodeStoreCbor
@@ -208,6 +208,33 @@ func (t AlonzoTransaction) Metadata() *cbor.Value {
208208
return t.TxMetadata
209209
}
210210

211+
func (t *AlonzoTransaction) Cbor() []byte {
212+
// Return stored CBOR if we have any
213+
cborData := t.DecodeStoreCbor.Cbor()
214+
if cborData != nil {
215+
return cborData[:]
216+
}
217+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
218+
if t.Body.Cbor() == nil {
219+
return nil
220+
}
221+
// Generate our own CBOR
222+
// This is necessary when a transaction is put together from pieces stored separately in a block
223+
tmpObj := []any{
224+
cbor.RawMessage(t.Body.Cbor()),
225+
cbor.RawMessage(t.WitnessSet.Cbor()),
226+
t.IsValid,
227+
}
228+
if t.TxMetadata != nil {
229+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
230+
} else {
231+
tmpObj = append(tmpObj, nil)
232+
}
233+
// This should never fail, since we're only encoding a list and a bool value
234+
cborData, _ = cbor.Encode(&tmpObj)
235+
return cborData
236+
}
237+
211238
func NewAlonzoBlockFromCbor(data []byte) (*AlonzoBlock, error) {
212239
var alonzoBlock AlonzoBlock
213240
if _, err := cbor.Decode(data, &alonzoBlock); err != nil {

ledger/babbage.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func (d *BabbageTransactionOutputDatumOption) MarshalCBOR() ([]byte, error) {
215215
}
216216

217217
type BabbageTransactionOutput struct {
218-
cborData []byte
218+
cbor.DecodeStoreCbor
219219
OutputAddress Address `cbor:"0,keyasint,omitempty"`
220220
OutputAmount MaryTransactionOutputValue `cbor:"1,keyasint,omitempty"`
221221
DatumOption *BabbageTransactionOutputDatumOption `cbor:"2,keyasint,omitempty"`
@@ -225,7 +225,7 @@ type BabbageTransactionOutput struct {
225225

226226
func (o *BabbageTransactionOutput) UnmarshalCBOR(cborData []byte) error {
227227
// Save original CBOR
228-
o.cborData = cborData[:]
228+
o.SetCbor(cborData)
229229
// Try to parse as legacy output first
230230
var tmpOutput AlonzoTransactionOutput
231231
if _, err := cbor.Decode(cborData, &tmpOutput); err == nil {
@@ -262,10 +262,6 @@ func (o BabbageTransactionOutput) MarshalJSON() ([]byte, error) {
262262
return json.Marshal(&tmpObj)
263263
}
264264

265-
func (o *BabbageTransactionOutput) Cbor() []byte {
266-
return o.cborData
267-
}
268-
269265
func (o BabbageTransactionOutput) Address() Address {
270266
return o.OutputAddress
271267
}
@@ -297,6 +293,10 @@ type BabbageTransactionWitnessSet struct {
297293
PlutusV2Scripts []cbor.RawMessage `cbor:"6,keyasint,omitempty"`
298294
}
299295

296+
func (t *BabbageTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error {
297+
return t.UnmarshalCbor(cborData, t)
298+
}
299+
300300
type BabbageTransaction struct {
301301
cbor.StructAsArray
302302
cbor.DecodeStoreCbor
@@ -322,6 +322,33 @@ func (t BabbageTransaction) Metadata() *cbor.Value {
322322
return t.TxMetadata
323323
}
324324

325+
func (t *BabbageTransaction) Cbor() []byte {
326+
// Return stored CBOR if we have any
327+
cborData := t.DecodeStoreCbor.Cbor()
328+
if cborData != nil {
329+
return cborData[:]
330+
}
331+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
332+
if t.Body.Cbor() == nil {
333+
return nil
334+
}
335+
// Generate our own CBOR
336+
// This is necessary when a transaction is put together from pieces stored separately in a block
337+
tmpObj := []any{
338+
cbor.RawMessage(t.Body.Cbor()),
339+
cbor.RawMessage(t.WitnessSet.Cbor()),
340+
t.IsValid,
341+
}
342+
if t.TxMetadata != nil {
343+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
344+
} else {
345+
tmpObj = append(tmpObj, nil)
346+
}
347+
// This should never fail, since we're only encoding a list and a bool value
348+
cborData, _ = cbor.Encode(&tmpObj)
349+
return cborData
350+
}
351+
325352
func NewBabbageBlockFromCbor(data []byte) (*BabbageBlock, error) {
326353
var babbageBlock BabbageBlock
327354
if _, err := cbor.Decode(data, &babbageBlock); err != nil {

ledger/mary.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ func (t MaryTransaction) Metadata() *cbor.Value {
124124
return t.TxMetadata
125125
}
126126

127+
func (t *MaryTransaction) Cbor() []byte {
128+
// Return stored CBOR if we have any
129+
cborData := t.DecodeStoreCbor.Cbor()
130+
if cborData != nil {
131+
return cborData[:]
132+
}
133+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
134+
if t.Body.Cbor() == nil {
135+
return nil
136+
}
137+
// Generate our own CBOR
138+
// This is necessary when a transaction is put together from pieces stored separately in a block
139+
tmpObj := []any{
140+
cbor.RawMessage(t.Body.Cbor()),
141+
cbor.RawMessage(t.WitnessSet.Cbor()),
142+
}
143+
if t.TxMetadata != nil {
144+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
145+
} else {
146+
tmpObj = append(tmpObj, nil)
147+
}
148+
// This should never fail, since we're only encoding a list and a bool value
149+
cborData, _ = cbor.Encode(&tmpObj)
150+
return cborData
151+
}
152+
127153
type MaryTransactionOutput struct {
128154
cbor.StructAsArray
129155
cbor.DecodeStoreCbor

ledger/shelley.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,16 @@ func (o ShelleyTransactionOutput) Datum() *cbor.LazyValue {
219219
}
220220

221221
type ShelleyTransactionWitnessSet struct {
222+
cbor.DecodeStoreCbor
222223
VkeyWitnesses []interface{} `cbor:"0,keyasint,omitempty"`
223224
MultisigScripts []interface{} `cbor:"1,keyasint,omitempty"`
224225
BootstrapWitnesses []interface{} `cbor:"2,keyasint,omitempty"`
225226
}
226227

228+
func (t *ShelleyTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error {
229+
return t.UnmarshalCbor(cborData, t)
230+
}
231+
227232
type ShelleyTransaction struct {
228233
cbor.StructAsArray
229234
cbor.DecodeStoreCbor
@@ -248,6 +253,32 @@ func (t ShelleyTransaction) Metadata() *cbor.Value {
248253
return t.TxMetadata
249254
}
250255

256+
func (t *ShelleyTransaction) Cbor() []byte {
257+
// Return stored CBOR if we have any
258+
cborData := t.DecodeStoreCbor.Cbor()
259+
if cborData != nil {
260+
return cborData[:]
261+
}
262+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
263+
if t.Body.Cbor() == nil {
264+
return nil
265+
}
266+
// Generate our own CBOR
267+
// This is necessary when a transaction is put together from pieces stored separately in a block
268+
tmpObj := []any{
269+
cbor.RawMessage(t.Body.Cbor()),
270+
cbor.RawMessage(t.WitnessSet.Cbor()),
271+
}
272+
if t.TxMetadata != nil {
273+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
274+
} else {
275+
tmpObj = append(tmpObj, nil)
276+
}
277+
// This should never fail, since we're only encoding a list and a bool value
278+
cborData, _ = cbor.Encode(&tmpObj)
279+
return cborData
280+
}
281+
251282
func NewShelleyBlockFromCbor(data []byte) (*ShelleyBlock, error) {
252283
var shelleyBlock ShelleyBlock
253284
if _, err := cbor.Decode(data, &shelleyBlock); err != nil {

0 commit comments

Comments
 (0)