Skip to content

Commit 44b7e7d

Browse files
authored
refactor: decode Plutus datum as data.PlutusData (#1142)
Fixes #1137 Signed-off-by: Aurora Gaffney <[email protected]>
1 parent f00972e commit 44b7e7d

File tree

12 files changed

+195
-28
lines changed

12 files changed

+195
-28
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ toolchain go1.24.1
77
require (
88
filippo.io/edwards25519 v1.1.0
99
github.com/blinklabs-io/ouroboros-mock v0.3.8
10-
github.com/blinklabs-io/plutigo v0.0.4
10+
github.com/blinklabs-io/plutigo v0.0.5
1111
github.com/btcsuite/btcd/btcutil v1.1.6
1212
github.com/fxamacker/cbor/v2 v2.9.0
1313
github.com/jinzhu/copier v0.4.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4
33
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
44
github.com/blinklabs-io/ouroboros-mock v0.3.8 h1:+DAt2rx0ouZUxee5DBMgZq3I1+ZdxFSHG9g3tYl/FKU=
55
github.com/blinklabs-io/ouroboros-mock v0.3.8/go.mod h1:UwQIf4KqZwO13P9d90fbi3UL/X7JaJfeEbqk+bEeFQA=
6-
github.com/blinklabs-io/plutigo v0.0.4 h1:YhSt25yTqzfyUAzO0G/UihB16/lZNsvS6J7THO0f3ss=
7-
github.com/blinklabs-io/plutigo v0.0.4/go.mod h1:sXfzbcwvVS8AbyNNVnhyyIT18f88IZMqg5cwOBmiafU=
6+
github.com/blinklabs-io/plutigo v0.0.5 h1:d3q7CM4kdVGa2VRt9zZHrUkkwNwLJyuMLPP2kDrIriE=
7+
github.com/blinklabs-io/plutigo v0.0.5/go.mod h1:fXUCkc9l8lvkprHApub5HpNmakYHLNPhEuWK+49anHE=
88
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
99
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
1010
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=

ledger/alonzo/alonzo.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ func (o AlonzoTransactionOutput) DatumHash() *common.Blake2b256 {
401401
return o.OutputDatumHash
402402
}
403403

404-
func (o AlonzoTransactionOutput) Datum() *cbor.LazyValue {
404+
func (o AlonzoTransactionOutput) Datum() *common.Datum {
405405
return nil
406406
}
407407

@@ -451,7 +451,7 @@ type AlonzoRedeemer struct {
451451
cbor.StructAsArray
452452
Tag common.RedeemerTag
453453
Index uint32
454-
Data cbor.LazyValue
454+
Data common.Datum
455455
ExUnits common.ExUnits
456456
}
457457

@@ -522,7 +522,7 @@ type AlonzoTransactionWitnessSet struct {
522522
WsNativeScripts []common.NativeScript `cbor:"1,keyasint,omitempty"`
523523
BootstrapWitnesses []common.BootstrapWitness `cbor:"2,keyasint,omitempty"`
524524
WsPlutusV1Scripts [][]byte `cbor:"3,keyasint,omitempty"`
525-
WsPlutusData []cbor.Value `cbor:"4,keyasint,omitempty"`
525+
WsPlutusData []common.Datum `cbor:"4,keyasint,omitempty"`
526526
WsRedeemers AlonzoRedeemers `cbor:"5,keyasint,omitempty"`
527527
}
528528

@@ -563,7 +563,7 @@ func (w AlonzoTransactionWitnessSet) PlutusV3Scripts() [][]byte {
563563
return nil
564564
}
565565

566-
func (w AlonzoTransactionWitnessSet) PlutusData() []cbor.Value {
566+
func (w AlonzoTransactionWitnessSet) PlutusData() []common.Datum {
567567
return w.WsPlutusData
568568
}
569569

ledger/babbage/babbage.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,11 @@ const (
374374

375375
type BabbageTransactionOutputDatumOption struct {
376376
hash *common.Blake2b256
377-
data *cbor.LazyValue
377+
data *common.Datum
378378
}
379379

380-
func (d *BabbageTransactionOutputDatumOption) UnmarshalCBOR(data []byte) error {
381-
datumOptionType, err := cbor.DecodeIdFromList(data)
380+
func (d *BabbageTransactionOutputDatumOption) UnmarshalCBOR(cborData []byte) error {
381+
datumOptionType, err := cbor.DecodeIdFromList(cborData)
382382
if err != nil {
383383
return err
384384
}
@@ -389,7 +389,7 @@ func (d *BabbageTransactionOutputDatumOption) UnmarshalCBOR(data []byte) error {
389389
Type int
390390
Hash common.Blake2b256
391391
}
392-
if _, err := cbor.Decode(data, &tmpDatumHash); err != nil {
392+
if _, err := cbor.Decode(cborData, &tmpDatumHash); err != nil {
393393
return err
394394
}
395395
d.hash = &(tmpDatumHash.Hash)
@@ -399,14 +399,16 @@ func (d *BabbageTransactionOutputDatumOption) UnmarshalCBOR(data []byte) error {
399399
Type int
400400
DataCbor []byte
401401
}
402-
if _, err := cbor.Decode(data, &tmpDatumData); err != nil {
402+
if _, err := cbor.Decode(cborData, &tmpDatumData); err != nil {
403403
return err
404404
}
405-
var datumValue cbor.LazyValue
405+
var datumValue common.Datum
406406
if _, err := cbor.Decode(tmpDatumData.DataCbor, &datumValue); err != nil {
407407
return err
408408
}
409-
d.data = &(datumValue)
409+
d.data = &common.Datum{
410+
Data: datumValue.Data,
411+
}
410412
default:
411413
return fmt.Errorf("unsupported datum option type: %d", datumOptionType)
412414
}
@@ -418,7 +420,11 @@ func (d *BabbageTransactionOutputDatumOption) MarshalCBOR() ([]byte, error) {
418420
if d.hash != nil {
419421
tmpObj = []any{DatumOptionTypeHash, d.hash}
420422
} else if d.data != nil {
421-
tmpObj = []any{DatumOptionTypeData, cbor.Tag{Number: 24, Content: d.data.Cbor()}}
423+
tmpContent, err := cbor.Encode(d.data)
424+
if err != nil {
425+
return nil, err
426+
}
427+
tmpObj = []any{DatumOptionTypeData, cbor.Tag{Number: 24, Content: tmpContent}}
422428
} else {
423429
return nil, errors.New("unknown datum option type")
424430
}
@@ -471,7 +477,7 @@ func (o BabbageTransactionOutput) MarshalJSON() ([]byte, error) {
471477
Address common.Address `json:"address"`
472478
Amount uint64 `json:"amount"`
473479
Assets *common.MultiAsset[common.MultiAssetTypeOutput] `json:"assets,omitempty"`
474-
Datum *cbor.LazyValue `json:"datum,omitempty"`
480+
Datum *common.Datum `json:"datum,omitempty"`
475481
DatumHash string `json:"datumHash,omitempty"`
476482
}{
477483
Address: o.OutputAddress,
@@ -560,7 +566,7 @@ func (o BabbageTransactionOutput) DatumHash() *common.Blake2b256 {
560566
return &common.Blake2b256{}
561567
}
562568

563-
func (o BabbageTransactionOutput) Datum() *cbor.LazyValue {
569+
func (o BabbageTransactionOutput) Datum() *common.Datum {
564570
if o.DatumOption != nil {
565571
return o.DatumOption.data
566572
}
@@ -625,7 +631,7 @@ type BabbageTransactionWitnessSet struct {
625631
WsNativeScripts []common.NativeScript `cbor:"1,keyasint,omitempty"`
626632
BootstrapWitnesses []common.BootstrapWitness `cbor:"2,keyasint,omitempty"`
627633
WsPlutusV1Scripts [][]byte `cbor:"3,keyasint,omitempty"`
628-
WsPlutusData []cbor.Value `cbor:"4,keyasint,omitempty"`
634+
WsPlutusData []common.Datum `cbor:"4,keyasint,omitempty"`
629635
WsRedeemers alonzo.AlonzoRedeemers `cbor:"5,keyasint,omitempty"`
630636
WsPlutusV2Scripts [][]byte `cbor:"6,keyasint,omitempty"`
631637
}
@@ -666,7 +672,7 @@ func (w BabbageTransactionWitnessSet) PlutusV3Scripts() [][]byte {
666672
return nil
667673
}
668674

669-
func (w BabbageTransactionWitnessSet) PlutusData() []cbor.Value {
675+
func (w BabbageTransactionWitnessSet) PlutusData() []common.Datum {
670676
return w.WsPlutusData
671677
}
672678

ledger/byron/byron.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func (o ByronTransactionOutput) DatumHash() *common.Blake2b256 {
446446
return nil
447447
}
448448

449-
func (o ByronTransactionOutput) Datum() *cbor.LazyValue {
449+
func (o ByronTransactionOutput) Datum() *common.Datum {
450450
return nil
451451
}
452452

ledger/common/data.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2025 Blink Labs Software
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package common
16+
17+
import (
18+
"github.com/blinklabs-io/gouroboros/cbor"
19+
"github.com/blinklabs-io/plutigo/data"
20+
)
21+
22+
type DatumHash = Blake2b256
23+
24+
// Datum represents a Plutus datum
25+
type Datum struct {
26+
cbor.DecodeStoreCbor
27+
Data data.PlutusData `json:"data"`
28+
}
29+
30+
func (d *Datum) UnmarshalCBOR(cborData []byte) error {
31+
d.SetCbor(cborData)
32+
tmpData, err := data.Decode(cborData)
33+
if err != nil {
34+
return err
35+
}
36+
d.Data = tmpData
37+
return nil
38+
}
39+
40+
func (d *Datum) MarshalCBOR() ([]byte, error) {
41+
tmpCbor, err := data.Encode(d.Data)
42+
if err != nil {
43+
return nil, err
44+
}
45+
return tmpCbor, nil
46+
}
47+
48+
func (d *Datum) Hash() DatumHash {
49+
return Blake2b256Hash(d.Cbor())
50+
}

ledger/common/data_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2025 Blink Labs Software
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package common_test
16+
17+
import (
18+
"encoding/hex"
19+
"math/big"
20+
"reflect"
21+
"testing"
22+
23+
"github.com/blinklabs-io/gouroboros/cbor"
24+
"github.com/blinklabs-io/gouroboros/internal/test"
25+
"github.com/blinklabs-io/gouroboros/ledger/common"
26+
"github.com/blinklabs-io/plutigo/data"
27+
)
28+
29+
func TestDatumHash(t *testing.T) {
30+
testDatumBytes, _ := hex.DecodeString("d8799fd8799fd8799f581cb255e2283f9b495dd663b841090c42bc5a5103283fc2aef5c6cd2f5cffd8799fd8799fd8799f581c07d8b4b15e9609e76a38b25637900d60cdf13a6abce984757bbc1349ffffffffd8799f581cf5808c2c990d86da54bfc97d89cee6efa20cd8461616359478d96b4c582073e1518e92f367fd5820ac2da1d40ab24fbca1d6cb2c28121ad92f57aff8abceff1b0000000148f3f3579fd8799fd8799f4040ff1a094f78d8ffd8799fd8799f581cf13ac4d66b3ee19a6aa0f2a22298737bd907cc95121662fc971b527546535452494b45ff1af7c5c601ffffff")
31+
expectedHash := "4dfec91f63f946d7c91af0041e5d92a45531790a4a104637dd8691f46fdce842"
32+
var tmpDatum common.Datum
33+
if _, err := cbor.Decode(testDatumBytes, &tmpDatum); err != nil {
34+
t.Fatalf("unexpected error: %s", err)
35+
}
36+
datumHash := tmpDatum.Hash()
37+
if datumHash.String() != expectedHash {
38+
t.Fatalf("did not get expected datum hash: got %s, wanted %s", datumHash.String(), expectedHash)
39+
}
40+
}
41+
42+
func TestDatumDecode(t *testing.T) {
43+
testDatumBytes, _ := hex.DecodeString("d8799fd8799fd8799f581cb255e2283f9b495dd663b841090c42bc5a5103283fc2aef5c6cd2f5cffd8799fd8799fd8799f581c07d8b4b15e9609e76a38b25637900d60cdf13a6abce984757bbc1349ffffffffd8799f581cf5808c2c990d86da54bfc97d89cee6efa20cd8461616359478d96b4c582073e1518e92f367fd5820ac2da1d40ab24fbca1d6cb2c28121ad92f57aff8abceff1b0000000148f3f3579fd8799fd8799f4040ff1a094f78d8ffd8799fd8799f581cf13ac4d66b3ee19a6aa0f2a22298737bd907cc95121662fc971b527546535452494b45ff1af7c5c601ffffff")
44+
expectedDatum := common.Datum{
45+
Data: data.NewConstr(
46+
0,
47+
data.NewConstr(
48+
0,
49+
data.NewConstr(
50+
0,
51+
data.NewByteString(
52+
test.DecodeHexString("b255e2283f9b495dd663b841090c42bc5a5103283fc2aef5c6cd2f5c"),
53+
),
54+
),
55+
data.NewConstr(
56+
0,
57+
data.NewConstr(
58+
0,
59+
data.NewConstr(
60+
0,
61+
data.NewByteString(
62+
test.DecodeHexString("07d8b4b15e9609e76a38b25637900d60cdf13a6abce984757bbc1349"),
63+
),
64+
),
65+
),
66+
),
67+
),
68+
data.NewConstr(
69+
0,
70+
data.NewByteString(
71+
test.DecodeHexString("f5808c2c990d86da54bfc97d89cee6efa20cd8461616359478d96b4c"),
72+
),
73+
data.NewByteString(
74+
test.DecodeHexString("73e1518e92f367fd5820ac2da1d40ab24fbca1d6cb2c28121ad92f57aff8abce"),
75+
),
76+
),
77+
data.NewInteger(big.NewInt(5518914391)),
78+
data.NewList(
79+
data.NewConstr(
80+
0,
81+
data.NewConstr(
82+
0,
83+
data.NewByteString(nil),
84+
data.NewByteString(nil),
85+
),
86+
data.NewInteger(big.NewInt(156203224)),
87+
),
88+
data.NewConstr(
89+
0,
90+
data.NewConstr(
91+
0,
92+
data.NewByteString(
93+
test.DecodeHexString("f13ac4d66b3ee19a6aa0f2a22298737bd907cc95121662fc971b5275"),
94+
),
95+
data.NewByteString(
96+
test.DecodeHexString("535452494b45"),
97+
),
98+
),
99+
data.NewInteger(big.NewInt(4156933633)),
100+
),
101+
),
102+
),
103+
}
104+
var tmpDatum common.Datum
105+
if _, err := cbor.Decode(testDatumBytes, &tmpDatum); err != nil {
106+
t.Fatalf("unexpected error: %s", err)
107+
}
108+
if !reflect.DeepEqual(tmpDatum.Data, expectedDatum.Data) {
109+
t.Fatalf("did not get expected datum\n got: %#v\n wanted: %#v", tmpDatum.Data, expectedDatum.Data)
110+
}
111+
}

ledger/common/redeemer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ type RedeemerKey struct {
3737

3838
type RedeemerValue struct {
3939
cbor.StructAsArray
40-
Data cbor.LazyValue
40+
Data Datum
4141
ExUnits ExUnits
4242
}

ledger/common/tx.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type TransactionOutput interface {
7171
Address() Address
7272
Amount() uint64
7373
Assets() *MultiAsset[MultiAssetTypeOutput]
74-
Datum() *cbor.LazyValue
74+
Datum() *Datum
7575
DatumHash() *Blake2b256
7676
Cbor() []byte
7777
Utxorpc() (*utxorpc.TxOutput, error)
@@ -83,7 +83,7 @@ type TransactionWitnessSet interface {
8383
Vkey() []VkeyWitness
8484
NativeScripts() []NativeScript
8585
Bootstrap() []BootstrapWitness
86-
PlutusData() []cbor.Value
86+
PlutusData() []Datum
8787
PlutusV1Scripts() [][]byte
8888
PlutusV2Scripts() [][]byte
8989
PlutusV3Scripts() [][]byte

ledger/conway/conway.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ type ConwayTransactionWitnessSet struct {
243243
WsNativeScripts cbor.SetType[common.NativeScript] `cbor:"1,keyasint,omitempty,omitzero"`
244244
BootstrapWitnesses cbor.SetType[common.BootstrapWitness] `cbor:"2,keyasint,omitempty,omitzero"`
245245
WsPlutusV1Scripts cbor.SetType[[]byte] `cbor:"3,keyasint,omitempty,omitzero"`
246-
WsPlutusData cbor.SetType[cbor.Value] `cbor:"4,keyasint,omitempty,omitzero"`
246+
WsPlutusData cbor.SetType[common.Datum] `cbor:"4,keyasint,omitempty,omitzero"`
247247
WsRedeemers ConwayRedeemers `cbor:"5,keyasint,omitempty,omitzero"`
248248
WsPlutusV2Scripts cbor.SetType[[]byte] `cbor:"6,keyasint,omitempty,omitzero"`
249249
WsPlutusV3Scripts cbor.SetType[[]byte] `cbor:"7,keyasint,omitempty,omitzero"`
@@ -284,7 +284,7 @@ func (w ConwayTransactionWitnessSet) PlutusV3Scripts() [][]byte {
284284
return w.WsPlutusV3Scripts.Items()
285285
}
286286

287-
func (w ConwayTransactionWitnessSet) PlutusData() []cbor.Value {
287+
func (w ConwayTransactionWitnessSet) PlutusData() []common.Datum {
288288
return w.WsPlutusData.Items()
289289
}
290290

0 commit comments

Comments
 (0)