Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ledger/alonzo/alonzo.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,21 @@ func (o AlonzoTransactionOutput) Utxorpc() (*utxorpc.TxOutput, error) {
nil
}

func (o AlonzoTransactionOutput) String() string {
assets := ""
if o.OutputAmount.Assets != nil {
if as := o.OutputAmount.Assets.String(); as != "[]" {
assets = " assets=" + as
}
}
return fmt.Sprintf(
"(AlonzoTransactionOutput address=%s amount=%d%s)",
o.OutputAddress.String(),
o.OutputAmount.Amount,
assets,
)
}

type AlonzoRedeemer struct {
cbor.StructAsArray
Tag common.RedeemerTag
Expand Down
22 changes: 22 additions & 0 deletions ledger/alonzo/alonzo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package alonzo

import (
"encoding/hex"
"math/big"
"reflect"
"testing"
Expand Down Expand Up @@ -277,3 +278,24 @@ func TestAlonzoRedeemersIter(t *testing.T) {
iterIdx++
}
}

func TestAlonzoTransactionOutputString(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
ma := common.NewMultiAsset[common.MultiAssetTypeOutput](
map[common.Blake2b224]map[cbor.ByteString]uint64{
common.NewBlake2b224(make([]byte, 28)): {cbor.NewByteString([]byte("t")): 2},
},
)
out := AlonzoTransactionOutput{
OutputAddress: addr,
OutputAmount: mary.MaryTransactionOutputValue{Amount: 456, Assets: &ma},
}
s := out.String()
policyStr := common.NewBlake2b224(make([]byte, 28)).String()
assetsStr := "[" + policyStr + "." + hex.EncodeToString([]byte("t")) + "=2]"
expected := "(AlonzoTransactionOutput address=" + addrStr + " amount=456 assets=" + assetsStr + ")"
if s != expected {
t.Fatalf("unexpected string: %s", s)
}
}
15 changes: 15 additions & 0 deletions ledger/babbage/babbage.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,21 @@ func (o BabbageTransactionOutput) Utxorpc() (*utxorpc.TxOutput, error) {
nil
}

func (o BabbageTransactionOutput) String() string {
assets := ""
if o.OutputAmount.Assets != nil {
if as := o.OutputAmount.Assets.String(); as != "[]" {
assets = " assets=" + as
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should build out a list of the assets for the string output

return fmt.Sprintf(
"(BabbageTransactionOutput address=%s amount=%d%s)",
o.OutputAddress.String(),
o.OutputAmount.Amount,
assets,
)
}

type BabbageTransactionWitnessSet struct {
cbor.DecodeStoreCbor
VkeyWitnesses []common.VkeyWitness `cbor:"0,keyasint,omitempty"`
Expand Down
19 changes: 19 additions & 0 deletions ledger/babbage/babbage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2970,3 +2970,22 @@ func TestBabbageTransactionOutputToPlutusDataCoinAssets(t *testing.T) {
)
}
}

func TestBabbageTransactionOutputString(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
ma := common.NewMultiAsset[common.MultiAssetTypeOutput](
map[common.Blake2b224]map[cbor.ByteString]uint64{
common.NewBlake2b224(make([]byte, 28)): {cbor.NewByteString([]byte("x")): 2},
},
)
out := BabbageTransactionOutput{
OutputAddress: addr,
OutputAmount: mary.MaryTransactionOutputValue{Amount: 456, Assets: &ma},
}
s := out.String()
expected := "(BabbageTransactionOutput address=" + addrStr + " amount=456 assets=" + ma.String() + ")"
if s != expected {
t.Fatalf("unexpected string: %s", s)
}
}
8 changes: 8 additions & 0 deletions ledger/byron/byron.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,14 @@ func (o ByronTransactionOutput) Utxorpc() (*utxorpc.TxOutput, error) {
nil
}

func (o ByronTransactionOutput) String() string {
return fmt.Sprintf(
"(ByronTransactionOutput address=%s amount=%d)",
o.OutputAddress.String(),
o.OutputAmount,
)
}

type ByronBlockVersion struct {
cbor.StructAsArray
Major uint16
Expand Down
21 changes: 21 additions & 0 deletions ledger/byron/byron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,24 @@ func TestByronTransaction_Utxorpc_Empty(t *testing.T) {
t.Errorf("Expected fee = 0, got %d", result.Fee)
}
}

func TestByronTransactionOutputString(t *testing.T) {
addr, err := common.NewByronAddressFromParts(
0,
make([]byte, common.AddressHashSize),
common.ByronAddressAttributes{},
)
if err != nil {
t.Fatalf("address: %v", err)
}
addrStr := addr.String()
out := byron.ByronTransactionOutput{
OutputAddress: addr,
OutputAmount: 456,
}
s := out.String()
expected := "(ByronTransactionOutput address=" + addrStr + " amount=456)"
if s != expected {
t.Fatalf("unexpected string: %s", s)
}
}
39 changes: 39 additions & 0 deletions ledger/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"maps"
"math/big"
"slices"
"strings"

"github.com/blinklabs-io/gouroboros/cbor"
"github.com/blinklabs-io/plutigo/data"
Expand Down Expand Up @@ -325,6 +326,44 @@ func (m *MultiAsset[T]) normalize() map[Blake2b224]map[cbor.ByteString]T {
return ret
}

// String returns a stable, human-friendly representation of the MultiAsset.
// Output format: [<policyId>.<assetNameHex>=<amount>, ...] sorted by policyId, then asset name
func (m *MultiAsset[T]) String() string {
if m == nil {
return "[]"
}
norm := m.normalize()
if len(norm) == 0 {
return "[]"
}

policies := slices.Collect(maps.Keys(norm))
slices.SortFunc(policies, func(a, b Blake2b224) int { return bytes.Compare(a.Bytes(), b.Bytes()) })

var b strings.Builder
b.WriteByte('[')
first := true
for _, pid := range policies {
assets := norm[pid]
names := slices.Collect(maps.Keys(assets))
slices.SortFunc(names, func(a, b cbor.ByteString) int { return bytes.Compare(a.Bytes(), b.Bytes()) })

for _, name := range names {
if !first {
b.WriteString(", ")
}
first = false
b.WriteString(pid.String())
b.WriteByte('.')
b.WriteString(hex.EncodeToString(name.Bytes()))
b.WriteByte('=')
fmt.Fprintf(&b, "%d", assets[name])
}
}
b.WriteByte(']')
return b.String()
}

type AssetFingerprint struct {
policyId []byte
assetName []byte
Expand Down
1 change: 1 addition & 0 deletions ledger/common/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type TransactionOutput interface {
Utxorpc() (*utxorpc.TxOutput, error)
ScriptRef() Script
ToPlutusData() data.PlutusData
String() string
}

type TransactionWitnessSet interface {
Expand Down
3 changes: 1 addition & 2 deletions ledger/mary/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package mary

import (
"fmt"
"strings"

"github.com/blinklabs-io/gouroboros/ledger/common"
Expand All @@ -28,7 +27,7 @@ type OutputTooBigUtxoError struct {
func (e OutputTooBigUtxoError) Error() string {
tmpOutputs := make([]string, len(e.Outputs))
for idx, tmpOutput := range e.Outputs {
tmpOutputs[idx] = fmt.Sprintf("%#v", tmpOutput)
tmpOutputs[idx] = tmpOutput.String()
}
return "output value too large: " + strings.Join(tmpOutputs, ", ")
}
15 changes: 15 additions & 0 deletions ledger/mary/mary.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,21 @@ func (o MaryTransactionOutput) Utxorpc() (*utxorpc.TxOutput, error) {
err
}

func (o MaryTransactionOutput) String() string {
assets := ""
if o.OutputAmount.Assets != nil {
if as := o.OutputAmount.Assets.String(); as != "[]" {
assets = " assets=" + as
}
}
return fmt.Sprintf(
"(MaryTransactionOutput address=%s amount=%d%s)",
o.OutputAddress.String(),
o.OutputAmount.Amount,
assets,
)
}

type MaryTransactionOutputValue struct {
cbor.StructAsArray
Amount uint64
Expand Down
34 changes: 34 additions & 0 deletions ledger/mary/mary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package mary

import (
"encoding/hex"
"fmt"
"reflect"
"testing"

Expand Down Expand Up @@ -115,3 +116,36 @@ func TestMaryTransactionOutputValueEncodeDecode(t *testing.T) {
}
}
}

func TestMaryTransactionOutputString(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
ma := common.NewMultiAsset[common.MultiAssetTypeOutput](
map[common.Blake2b224]map[cbor.ByteString]uint64{
common.NewBlake2b224(make([]byte, 28)): {cbor.NewByteString([]byte("token")): 2},
},
)
out := MaryTransactionOutput{
OutputAddress: addr,
OutputAmount: MaryTransactionOutputValue{Amount: 456, Assets: &ma},
}
s := out.String()
expected := fmt.Sprintf("(MaryTransactionOutput address=%s amount=456 assets=%s)", addrStr, ma.String())
if s != expected {
t.Fatalf("unexpected string: %s", s)
}
}

func TestMaryOutputTooBigErrorFormatting(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
out := &MaryTransactionOutput{
OutputAddress: addr,
OutputAmount: MaryTransactionOutputValue{Amount: 456},
}
errStr := OutputTooBigUtxoError{Outputs: []common.TransactionOutput{out}}.Error()
expected := fmt.Sprintf("output value too large: (MaryTransactionOutput address=%s amount=456)", addrStr)
if errStr != expected {
t.Fatalf("unexpected error: %s", errStr)
}
}
4 changes: 2 additions & 2 deletions ledger/shelley/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ type OutputTooSmallUtxoError struct {
func (e OutputTooSmallUtxoError) Error() string {
tmpOutputs := make([]string, len(e.Outputs))
for idx, tmpOutput := range e.Outputs {
tmpOutputs[idx] = fmt.Sprintf("%#v", tmpOutput)
tmpOutputs[idx] = tmpOutput.String()
}
return "output too small: " + strings.Join(tmpOutputs, ", ")
}
Expand All @@ -123,7 +123,7 @@ type OutputBootAddrAttrsTooBigError struct {
func (e OutputBootAddrAttrsTooBigError) Error() string {
tmpOutputs := make([]string, len(e.Outputs))
for idx, tmpOutput := range e.Outputs {
tmpOutputs[idx] = fmt.Sprintf("%#v", tmpOutput)
tmpOutputs[idx] = tmpOutput.String()
}
return "output bootstrap address attributes too big: " + strings.Join(
tmpOutputs,
Expand Down
8 changes: 8 additions & 0 deletions ledger/shelley/shelley.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@ func (o ShelleyTransactionOutput) Utxorpc() (*utxorpc.TxOutput, error) {
}, nil
}

func (o ShelleyTransactionOutput) String() string {
return fmt.Sprintf(
"(ShelleyTransactionOutput address=%s amount=%d)",
o.OutputAddress.String(),
o.OutputAmount,
)
}

type ShelleyTransactionWitnessSet struct {
cbor.DecodeStoreCbor
VkeyWitnesses []common.VkeyWitness `cbor:"0,keyasint,omitempty"`
Expand Down
37 changes: 37 additions & 0 deletions ledger/shelley/shelley_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package shelley_test

import (
"fmt"
"testing"

"github.com/blinklabs-io/gouroboros/ledger/common"
"github.com/blinklabs-io/gouroboros/ledger/shelley"
)

func TestShelleyTransactionOutputString(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
out := shelley.ShelleyTransactionOutput{
OutputAddress: addr,
OutputAmount: 456,
}
s := out.String()
expected := fmt.Sprintf("(ShelleyTransactionOutput address=%s amount=456)", addrStr)
if s != expected {
t.Fatalf("unexpected string: %s", s)
}
}

func TestShelleyOutputTooSmallErrorFormatting(t *testing.T) {
addrStr := "addr1qytna5k2fq9ler0fuk45j7zfwv7t2zwhp777nvdjqqfr5tz8ztpwnk8zq5ngetcz5k5mckgkajnygtsra9aej2h3ek5seupmvd"
addr, _ := common.NewAddress(addrStr)
out := &shelley.ShelleyTransactionOutput{
OutputAddress: addr,
OutputAmount: 456,
}
errStr := shelley.OutputTooSmallUtxoError{Outputs: []common.TransactionOutput{out}}.Error()
expected := fmt.Sprintf("output too small: (ShelleyTransactionOutput address=%s amount=456)", addrStr)
if errStr != expected {
t.Fatalf("unexpected error: %s", errStr)
}
}
Loading