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
45 changes: 42 additions & 3 deletions ledger/alonzo/alonzo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package alonzo
import (
"encoding/json"
"fmt"
"iter"
"math/big"
"slices"

"github.com/blinklabs-io/gouroboros/cbor"
"github.com/blinklabs-io/gouroboros/ledger/common"
Expand Down Expand Up @@ -453,6 +455,40 @@ type AlonzoRedeemer struct {

type AlonzoRedeemers []AlonzoRedeemer

func (r AlonzoRedeemers) Iter() iter.Seq2[common.RedeemerKey, common.RedeemerValue] {
return func(yield func(common.RedeemerKey, common.RedeemerValue) bool) {
// Sort redeemers
sorted := make([]AlonzoRedeemer, len(r))
copy(sorted, r)
slices.SortFunc(
sorted,
func(a, b AlonzoRedeemer) int {
if a.Tag < b.Tag || (a.Tag == b.Tag && a.Index < b.Index) {
return -1
}
if a.Tag > b.Tag || (a.Tag == b.Tag && a.Index > b.Index) {
return 1
}
return 0
},
)
// Yield keys
for _, redeemer := range sorted {
tmpKey := common.RedeemerKey{
Tag: redeemer.Tag,
Index: redeemer.Index,
}
tmpVal := common.RedeemerValue{
Data: redeemer.Data,
ExUnits: redeemer.ExUnits,
}
if !yield(tmpKey, tmpVal) {
return
}
}
}
}

func (r AlonzoRedeemers) Indexes(tag common.RedeemerTag) []uint {
ret := []uint{}
for _, redeemer := range r {
Expand All @@ -466,13 +502,16 @@ func (r AlonzoRedeemers) Indexes(tag common.RedeemerTag) []uint {
func (r AlonzoRedeemers) Value(
index uint,
tag common.RedeemerTag,
) (cbor.LazyValue, common.ExUnits) {
) common.RedeemerValue {
for _, redeemer := range r {
if redeemer.Tag == tag && uint(redeemer.Index) == index {
return redeemer.Data, redeemer.ExUnits
return common.RedeemerValue{
Data: redeemer.Data,
ExUnits: redeemer.ExUnits,
}
}
}
return cbor.LazyValue{}, common.ExUnits{}
return common.RedeemerValue{}
}

type AlonzoTransactionWitnessSet struct {
Expand Down
81 changes: 81 additions & 0 deletions ledger/alonzo/alonzo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,84 @@ func TestAlonzoTransactionOutputToPlutusDataCoinAssets(t *testing.T) {
t.Fatalf("did not get expected PlutusData\n got: %#v\n wanted: %#v", tmpData, expectedData)
}
}

func TestAlonzoRedeemersIter(t *testing.T) {
testRedeemers := AlonzoRedeemers{
{
Tag: common.RedeemerTagMint,
Index: 2,
ExUnits: common.ExUnits{
Memory: 1111,
Steps: 2222,
},
},
{
Tag: common.RedeemerTagMint,
Index: 0,
ExUnits: common.ExUnits{
Memory: 1111,
Steps: 0,
},
},
{
Tag: common.RedeemerTagSpend,
Index: 4,
ExUnits: common.ExUnits{
Memory: 0,
Steps: 4444,
},
},
}
expectedOrder := []struct {
Key common.RedeemerKey
Value common.RedeemerValue
}{
{
Key: common.RedeemerKey{
Tag: common.RedeemerTagSpend,
Index: 4,
},
Value: common.RedeemerValue{
ExUnits: common.ExUnits{
Memory: 0,
Steps: 4444,
},
},
},
{
Key: common.RedeemerKey{
Tag: common.RedeemerTagMint,
Index: 0,
},
Value: common.RedeemerValue{
ExUnits: common.ExUnits{
Memory: 1111,
Steps: 0,
},
},
},
{
Key: common.RedeemerKey{
Tag: common.RedeemerTagMint,
Index: 2,
},
Value: common.RedeemerValue{
ExUnits: common.ExUnits{
Memory: 1111,
Steps: 2222,
},
},
},
}
iterIdx := 0
for key, val := range testRedeemers.Iter() {
expected := expectedOrder[iterIdx]
if !reflect.DeepEqual(key, expected.Key) {
t.Fatalf("did not get expected key: got %#v, wanted %#v", key, expected.Key)
}
if !reflect.DeepEqual(val, expected.Value) {
t.Fatalf("did not get expected value: got %#v, wanted %#v", val, expected.Value)
}
iterIdx++
}
}
42 changes: 42 additions & 0 deletions ledger/common/redeemer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 (
"github.com/blinklabs-io/gouroboros/cbor"
)

type RedeemerTag uint8

const (
RedeemerTagSpend RedeemerTag = 0
RedeemerTagMint RedeemerTag = 1
RedeemerTagCert RedeemerTag = 2
RedeemerTagReward RedeemerTag = 3
RedeemerTagVoting RedeemerTag = 4
RedeemerTagProposing RedeemerTag = 5
)

type RedeemerKey struct {
cbor.StructAsArray
Tag RedeemerTag
Index uint32
}

type RedeemerValue struct {
cbor.StructAsArray
Data cbor.LazyValue
ExUnits ExUnits
}
5 changes: 4 additions & 1 deletion ledger/common/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package common

import (
"iter"

"github.com/blinklabs-io/gouroboros/cbor"
"github.com/blinklabs-io/plutigo/data"
utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
Expand Down Expand Up @@ -90,7 +92,8 @@ type TransactionWitnessSet interface {

type TransactionWitnessRedeemers interface {
Indexes(RedeemerTag) []uint
Value(uint, RedeemerTag) (cbor.LazyValue, ExUnits)
Value(uint, RedeemerTag) RedeemerValue
Iter() iter.Seq2[RedeemerKey, RedeemerValue]
}

type Utxo struct {
Expand Down
11 changes: 0 additions & 11 deletions ledger/common/witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,6 @@ import (
"github.com/blinklabs-io/gouroboros/cbor"
)

type RedeemerTag uint8

const (
RedeemerTagSpend RedeemerTag = 0
RedeemerTagMint RedeemerTag = 1
RedeemerTagCert RedeemerTag = 2
RedeemerTagReward RedeemerTag = 3
RedeemerTagVoting RedeemerTag = 4
RedeemerTagProposing RedeemerTag = 5
)

type VkeyWitness struct {
cbor.StructAsArray
Vkey []byte
Expand Down
51 changes: 34 additions & 17 deletions ledger/conway/conway.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ package conway
import (
"errors"
"fmt"
"iter"
"maps"
"slices"

"github.com/blinklabs-io/gouroboros/cbor"
"github.com/blinklabs-io/gouroboros/ledger/alonzo"
Expand Down Expand Up @@ -154,20 +157,8 @@ func (h *ConwayBlockHeader) Era() common.Era {
return EraConway
}

type ConwayRedeemerKey struct {
cbor.StructAsArray
Tag common.RedeemerTag
Index uint32
}

type ConwayRedeemerValue struct {
cbor.StructAsArray
Data cbor.LazyValue
ExUnits common.ExUnits
}

type ConwayRedeemers struct {
Redeemers map[ConwayRedeemerKey]ConwayRedeemerValue
Redeemers map[common.RedeemerKey]common.RedeemerValue
legacyRedeemers alonzo.AlonzoRedeemers
legacy bool
}
Expand All @@ -190,6 +181,32 @@ func (r *ConwayRedeemers) MarshalCBOR() ([]byte, error) {
return cbor.Encode(r.Redeemers)
}

func (r ConwayRedeemers) Iter() iter.Seq2[common.RedeemerKey, common.RedeemerValue] {
return func(yield func(common.RedeemerKey, common.RedeemerValue) bool) {
// Sort redeemers
sorted := slices.Collect(maps.Keys(r.Redeemers))
slices.SortFunc(
sorted,
func(a, b common.RedeemerKey) int {
if a.Tag < b.Tag || (a.Tag == b.Tag && a.Index < b.Index) {
return -1
}
if a.Tag > b.Tag || (a.Tag == b.Tag && a.Index > b.Index) {
return 1
}
return 0
},
)
// Yield keys
for _, redeemerKey := range sorted {
tmpVal := r.Redeemers[redeemerKey]
if !yield(redeemerKey, tmpVal) {
return
}
}
}
}

func (r ConwayRedeemers) Indexes(tag common.RedeemerTag) []uint {
if r.legacy {
return r.legacyRedeemers.Indexes(tag)
Expand All @@ -206,18 +223,18 @@ func (r ConwayRedeemers) Indexes(tag common.RedeemerTag) []uint {
func (r ConwayRedeemers) Value(
index uint,
tag common.RedeemerTag,
) (cbor.LazyValue, common.ExUnits) {
) common.RedeemerValue {
if r.legacy {
return r.legacyRedeemers.Value(index, tag)
}
redeemer, ok := r.Redeemers[ConwayRedeemerKey{
redeemerVal, ok := r.Redeemers[common.RedeemerKey{
Tag: tag,
Index: uint32(index), // #nosec G115
}]
if ok {
return redeemer.Data, redeemer.ExUnits
return redeemerVal
}
return cbor.LazyValue{}, common.ExUnits{}
return common.RedeemerValue{}
}

type ConwayTransactionWitnessSet struct {
Expand Down
Loading