diff --git a/ledger/allegra/allegra.go b/ledger/allegra/allegra.go index 11224085..0596498e 100644 --- a/ledger/allegra/allegra.go +++ b/ledger/allegra/allegra.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -290,6 +290,10 @@ func (t AllegraTransaction) ProtocolParameterUpdates() (uint64, map[common.Blake return t.Body.ProtocolParameterUpdates() } +func (t AllegraTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t *AllegraTransaction) Cbor() []byte { // Return stored CBOR if we have any cborData := t.DecodeStoreCbor.Cbor() diff --git a/ledger/alonzo/alonzo.go b/ledger/alonzo/alonzo.go index 0354b1a5..62c01692 100644 --- a/ledger/alonzo/alonzo.go +++ b/ledger/alonzo/alonzo.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -303,21 +303,54 @@ func (o AlonzoTransactionOutput) Utxorpc() *utxorpc.TxOutput { type AlonzoRedeemer struct { cbor.StructAsArray - Tag uint8 + Tag common.RedeemerTag Index uint32 - Data cbor.RawMessage + Data cbor.LazyValue ExUnits common.RedeemerExUnits } +type AlonzoRedeemers []AlonzoRedeemer + +func (r AlonzoRedeemers) Indexes(tag common.RedeemerTag) []uint { + ret := []uint{} + for _, redeemer := range r { + if redeemer.Tag == tag { + ret = append(ret, uint(redeemer.Index)) + } + } + return ret +} + +func (r AlonzoRedeemers) Value(index uint, tag common.RedeemerTag) (cbor.LazyValue, common.RedeemerExUnits) { + for _, redeemer := range r { + if redeemer.Tag == tag && uint(redeemer.Index) == index { + return redeemer.Data, redeemer.ExUnits + } + } + return cbor.LazyValue{}, common.RedeemerExUnits{} +} + type AlonzoTransactionWitnessSet struct { shelley.ShelleyTransactionWitnessSet - PlutusV1Scripts [][]byte `cbor:"3,keyasint,omitempty"` - PlutusData []cbor.Value `cbor:"4,keyasint,omitempty"` - Redeemers []AlonzoRedeemer `cbor:"5,keyasint,omitempty"` + WsPlutusV1Scripts [][]byte `cbor:"3,keyasint,omitempty"` + WsPlutusData []cbor.Value `cbor:"4,keyasint,omitempty"` + WsRedeemers AlonzoRedeemers `cbor:"5,keyasint,omitempty"` +} + +func (w *AlonzoTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { + return w.UnmarshalCbor(cborData, w) +} + +func (w AlonzoTransactionWitnessSet) PlutusV1Scripts() [][]byte { + return w.WsPlutusV1Scripts } -func (t *AlonzoTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { - return t.UnmarshalCbor(cborData, t) +func (w AlonzoTransactionWitnessSet) PlutusData() []cbor.Value { + return w.WsPlutusData +} + +func (w AlonzoTransactionWitnessSet) Redeemers() common.TransactionWitnessRedeemers { + return w.WsRedeemers } type AlonzoTransaction struct { @@ -452,6 +485,10 @@ func (t AlonzoTransaction) Produced() []common.Utxo { } } +func (t AlonzoTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t *AlonzoTransaction) Cbor() []byte { // Return stored CBOR if we have any cborData := t.DecodeStoreCbor.Cbor() diff --git a/ledger/babbage/babbage.go b/ledger/babbage/babbage.go index 76a4c464..80c8968d 100644 --- a/ledger/babbage/babbage.go +++ b/ledger/babbage/babbage.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -491,11 +491,15 @@ func (o BabbageTransactionOutput) Utxorpc() *utxorpc.TxOutput { type BabbageTransactionWitnessSet struct { alonzo.AlonzoTransactionWitnessSet - PlutusV2Scripts [][]byte `cbor:"6,keyasint,omitempty"` + WsPlutusV2Scripts [][]byte `cbor:"6,keyasint,omitempty"` } -func (t *BabbageTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { - return t.UnmarshalCbor(cborData, t) +func (w *BabbageTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { + return w.UnmarshalCbor(cborData, w) +} + +func (w BabbageTransactionWitnessSet) PlutusV2Scripts() [][]byte { + return w.WsPlutusV2Scripts } type BabbageTransaction struct { @@ -637,6 +641,10 @@ func (t BabbageTransaction) Produced() []common.Utxo { } } +func (t BabbageTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t *BabbageTransaction) Cbor() []byte { // Return stored CBOR if we have any cborData := t.DecodeStoreCbor.Cbor() diff --git a/ledger/byron/byron.go b/ledger/byron/byron.go index be60a9d1..124e1479 100644 --- a/ledger/byron/byron.go +++ b/ledger/byron/byron.go @@ -288,6 +288,11 @@ func (t *ByronTransaction) Produced() []common.Utxo { return ret } +func (t ByronTransaction) Witnesses() common.TransactionWitnessSet { + // TODO: implement once we properly support decoding Byron TX witnesses (#853) + return nil +} + func (t *ByronTransaction) Utxorpc() *utxorpc.Tx { return &utxorpc.Tx{} } diff --git a/ledger/common/tx.go b/ledger/common/tx.go index 73c662aa..bcc7fae6 100644 --- a/ledger/common/tx.go +++ b/ledger/common/tx.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -28,6 +28,7 @@ type Transaction interface { IsValid() bool Consumed() []TransactionInput Produced() []Utxo + Witnesses() TransactionWitnessSet } type TransactionBody interface { @@ -73,6 +74,22 @@ type TransactionOutput interface { Utxorpc() *utxorpc.TxOutput } +type TransactionWitnessSet interface { + Vkey() []VkeyWitness + NativeScripts() []NativeScript + Bootstrap() []BootstrapWitness + PlutusData() []cbor.Value + PlutusV1Scripts() [][]byte + PlutusV2Scripts() [][]byte + PlutusV3Scripts() [][]byte + Redeemers() TransactionWitnessRedeemers +} + +type TransactionWitnessRedeemers interface { + Indexes(RedeemerTag) []uint + Value(uint, RedeemerTag) (cbor.LazyValue, RedeemerExUnits) +} + type Utxo struct { Id TransactionInput Output TransactionOutput diff --git a/ledger/common/witness.go b/ledger/common/witness.go index 4ca664ce..8fe93a7e 100644 --- a/ledger/common/witness.go +++ b/ledger/common/witness.go @@ -18,6 +18,17 @@ 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 diff --git a/ledger/conway/conway.go b/ledger/conway/conway.go index ce6eb233..a4117264 100644 --- a/ledger/conway/conway.go +++ b/ledger/conway/conway.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -149,13 +149,13 @@ func (h *ConwayBlockHeader) Era() common.Era { type ConwayRedeemerKey struct { cbor.StructAsArray - Tag uint8 + Tag common.RedeemerTag Index uint32 } type ConwayRedeemerValue struct { cbor.StructAsArray - Data cbor.RawMessage + Data cbor.LazyValue ExUnits common.RedeemerExUnits } @@ -189,14 +189,43 @@ func (r *ConwayRedeemers) UnmarshalCBOR(cborData []byte) error { return nil } +func (r ConwayRedeemers) Indexes(tag common.RedeemerTag) []uint { + ret := []uint{} + for key := range r.Redeemers { + if key.Tag == tag { + ret = append(ret, uint(key.Index)) + } + } + return ret +} + +func (r ConwayRedeemers) Value(index uint, tag common.RedeemerTag) (cbor.LazyValue, common.RedeemerExUnits) { + redeemer, ok := r.Redeemers[ConwayRedeemerKey{ + Tag: tag, + Index: uint32(index), + }] + if ok { + return redeemer.Data, redeemer.ExUnits + } + return cbor.LazyValue{}, common.RedeemerExUnits{} +} + type ConwayTransactionWitnessSet struct { babbage.BabbageTransactionWitnessSet - Redeemers ConwayRedeemers `cbor:"5,keyasint,omitempty"` - PlutusV3Scripts [][]byte `cbor:"7,keyasint,omitempty"` + WsRedeemers ConwayRedeemers `cbor:"5,keyasint,omitempty"` + WsPlutusV3Scripts [][]byte `cbor:"7,keyasint,omitempty"` +} + +func (w *ConwayTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { + return w.UnmarshalCbor(cborData, w) } -func (t *ConwayTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { - return t.UnmarshalCbor(cborData, t) +func (w ConwayTransactionWitnessSet) PlutusV3Scripts() [][]byte { + return w.WsPlutusV3Scripts +} + +func (w ConwayTransactionWitnessSet) Redeemers() common.TransactionWitnessRedeemers { + return w.WsRedeemers } type ConwayTransactionInputSet struct { @@ -401,6 +430,10 @@ func (t ConwayTransaction) Produced() []common.Utxo { } } +func (t ConwayTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t *ConwayTransaction) Cbor() []byte { // Return stored CBOR if we have any cborData := t.DecodeStoreCbor.Cbor() diff --git a/ledger/mary/mary.go b/ledger/mary/mary.go index fa0153af..6481c082 100644 --- a/ledger/mary/mary.go +++ b/ledger/mary/mary.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -298,6 +298,10 @@ func (t MaryTransaction) Produced() []common.Utxo { return ret } +func (t MaryTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t *MaryTransaction) Cbor() []byte { // Return stored CBOR if we have any cborData := t.DecodeStoreCbor.Cbor() diff --git a/ledger/shelley/shelley.go b/ledger/shelley/shelley.go index a469d07a..56bcb35a 100644 --- a/ledger/shelley/shelley.go +++ b/ledger/shelley/shelley.go @@ -1,4 +1,4 @@ -// Copyright 2024 Blink Labs Software +// 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. @@ -469,7 +469,7 @@ func (o ShelleyTransactionOutput) Utxorpc() *utxorpc.TxOutput { type ShelleyTransactionWitnessSet struct { cbor.DecodeStoreCbor VkeyWitnesses []common.VkeyWitness `cbor:"0,keyasint,omitempty"` - NativeScripts []common.NativeScript `cbor:"1,keyasint,omitempty"` + WsNativeScripts []common.NativeScript `cbor:"1,keyasint,omitempty"` BootstrapWitnesses []common.BootstrapWitness `cbor:"2,keyasint,omitempty"` } @@ -477,6 +477,43 @@ func (t *ShelleyTransactionWitnessSet) UnmarshalCBOR(cborData []byte) error { return t.UnmarshalCbor(cborData, t) } +func (w ShelleyTransactionWitnessSet) Vkey() []common.VkeyWitness { + return w.VkeyWitnesses +} + +func (w ShelleyTransactionWitnessSet) Bootstrap() []common.BootstrapWitness { + return w.BootstrapWitnesses +} + +func (w ShelleyTransactionWitnessSet) NativeScripts() []common.NativeScript { + return w.WsNativeScripts +} + +func (w ShelleyTransactionWitnessSet) PlutusData() []cbor.Value { + // No plutus data in Shelley + return nil +} + +func (w ShelleyTransactionWitnessSet) PlutusV1Scripts() [][]byte { + // No plutus v1 scripts in Shelley + return nil +} + +func (w ShelleyTransactionWitnessSet) PlutusV2Scripts() [][]byte { + // No plutus v2 scripts in Shelley + return nil +} + +func (w ShelleyTransactionWitnessSet) PlutusV3Scripts() [][]byte { + // No plutus v3 scripts in Shelley + return nil +} + +func (w ShelleyTransactionWitnessSet) Redeemers() common.TransactionWitnessRedeemers { + // No redeemers in Shelley + return nil +} + type ShelleyTransaction struct { cbor.StructAsArray cbor.DecodeStoreCbor @@ -595,6 +632,10 @@ func (t ShelleyTransaction) Produced() []common.Utxo { return ret } +func (t ShelleyTransaction) Witnesses() common.TransactionWitnessSet { + return t.WitnessSet +} + func (t ShelleyTransaction) Utxorpc() *utxorpc.Tx { return t.Body.Utxorpc() }