diff --git a/ledger/allegra.go b/ledger/allegra.go index 668d092b..927135c2 100644 --- a/ledger/allegra.go +++ b/ledger/allegra.go @@ -21,6 +21,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -202,7 +203,7 @@ func (t AllegraTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t AllegraTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t AllegraTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } diff --git a/ledger/alonzo.go b/ledger/alonzo.go index d86502fa..d3ed5986 100644 --- a/ledger/alonzo.go +++ b/ledger/alonzo.go @@ -22,6 +22,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -209,10 +210,10 @@ func (o *AlonzoTransactionOutput) MarshalCBOR() ([]byte, error) { func (o AlonzoTransactionOutput) MarshalJSON() ([]byte, error) { tmpObj := struct { - Address Address `json:"address"` - Amount uint64 `json:"amount"` - Assets *MultiAsset[MultiAssetTypeOutput] `json:"assets,omitempty"` - DatumHash string `json:"datumHash,omitempty"` + Address Address `json:"address"` + Amount uint64 `json:"amount"` + Assets *common.MultiAsset[common.MultiAssetTypeOutput] `json:"assets,omitempty"` + DatumHash string `json:"datumHash,omitempty"` }{ Address: o.OutputAddress, Amount: o.OutputAmount.Amount, @@ -232,7 +233,7 @@ func (o AlonzoTransactionOutput) Amount() uint64 { return o.OutputAmount.Amount } -func (o AlonzoTransactionOutput) Assets() *MultiAsset[MultiAssetTypeOutput] { +func (o AlonzoTransactionOutput) Assets() *common.MultiAsset[common.MultiAssetTypeOutput] { return o.OutputAmount.Assets } @@ -247,13 +248,15 @@ func (o AlonzoTransactionOutput) Datum() *cbor.LazyValue { func (o AlonzoTransactionOutput) Utxorpc() *utxorpc.TxOutput { var assets []*utxorpc.Multiasset if o.Assets() != nil { - for policyId, policyData := range o.Assets().data { + tmpAssets := o.Assets() + for _, policyId := range tmpAssets.Policies() { var ma = &utxorpc.Multiasset{ PolicyId: policyId.Bytes(), } - for assetName, amount := range policyData { + for _, assetName := range tmpAssets.Assets(policyId) { + amount := tmpAssets.Asset(policyId, assetName) asset := &utxorpc.Asset{ - Name: assetName.Bytes(), + Name: assetName, OutputCoin: amount, } ma.Assets = append(ma.Assets, asset) @@ -366,7 +369,7 @@ func (t AlonzoTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t AlonzoTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t AlonzoTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } diff --git a/ledger/babbage.go b/ledger/babbage.go index d712aa55..19d79b73 100644 --- a/ledger/babbage.go +++ b/ledger/babbage.go @@ -22,6 +22,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -363,11 +364,11 @@ func (o *BabbageTransactionOutput) MarshalCBOR() ([]byte, error) { func (o BabbageTransactionOutput) MarshalJSON() ([]byte, error) { tmpObj := struct { - Address Address `json:"address"` - Amount uint64 `json:"amount"` - Assets *MultiAsset[MultiAssetTypeOutput] `json:"assets,omitempty"` - Datum *cbor.LazyValue `json:"datum,omitempty"` - DatumHash string `json:"datumHash,omitempty"` + Address Address `json:"address"` + Amount uint64 `json:"amount"` + Assets *common.MultiAsset[common.MultiAssetTypeOutput] `json:"assets,omitempty"` + Datum *cbor.LazyValue `json:"datum,omitempty"` + DatumHash string `json:"datumHash,omitempty"` }{ Address: o.OutputAddress, Amount: o.OutputAmount.Amount, @@ -392,7 +393,7 @@ func (o BabbageTransactionOutput) Amount() uint64 { return o.OutputAmount.Amount } -func (o BabbageTransactionOutput) Assets() *MultiAsset[MultiAssetTypeOutput] { +func (o BabbageTransactionOutput) Assets() *common.MultiAsset[common.MultiAssetTypeOutput] { return o.OutputAmount.Assets } @@ -420,13 +421,15 @@ func (o BabbageTransactionOutput) Utxorpc() *utxorpc.TxOutput { var assets []*utxorpc.Multiasset if o.Assets() != nil { - for policyId, policyData := range o.Assets().data { + tmpAssets := o.Assets() + for _, policyId := range tmpAssets.Policies() { var ma = &utxorpc.Multiasset{ PolicyId: policyId.Bytes(), } - for assetName, amount := range policyData { + for _, assetName := range tmpAssets.Assets(policyId) { + amount := tmpAssets.Asset(policyId, assetName) asset := &utxorpc.Asset{ - Name: assetName.Bytes(), + Name: assetName, OutputCoin: amount, } ma.Assets = append(ma.Assets, asset) @@ -540,7 +543,7 @@ func (t BabbageTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t BabbageTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t BabbageTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } diff --git a/ledger/byron.go b/ledger/byron.go index 88d0c8b9..707aae9b 100644 --- a/ledger/byron.go +++ b/ledger/byron.go @@ -21,6 +21,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -216,7 +217,7 @@ func (t *ByronTransaction) RequiredSigners() []Blake2b224 { return nil } -func (t *ByronTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t *ByronTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { // No asset mints in Byron return nil } @@ -385,7 +386,7 @@ func (o ByronTransactionOutput) Amount() uint64 { return o.OutputAmount } -func (o ByronTransactionOutput) Assets() *MultiAsset[MultiAssetTypeOutput] { +func (o ByronTransactionOutput) Assets() *common.MultiAsset[common.MultiAssetTypeOutput] { return nil } diff --git a/ledger/address.go b/ledger/common/address.go similarity index 99% rename from ledger/address.go rename to ledger/common/address.go index 951201bd..a6d9439a 100644 --- a/ledger/address.go +++ b/ledger/common/address.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ledger +package common import ( "fmt" diff --git a/ledger/address_test.go b/ledger/common/address_test.go similarity index 99% rename from ledger/address_test.go rename to ledger/common/address_test.go index 7bfd64a8..99649038 100644 --- a/ledger/address_test.go +++ b/ledger/common/address_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ledger +package common import ( "testing" diff --git a/ledger/common.go b/ledger/common/common.go similarity index 94% rename from ledger/common.go rename to ledger/common/common.go index c667ca3d..ccb27b6d 100644 --- a/ledger/common.go +++ b/ledger/common/common.go @@ -1,4 +1,4 @@ -// Copyright 2023 Blink Labs Software +// Copyright 2024 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. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ledger +package common import ( "encoding/hex" @@ -82,6 +82,12 @@ type MultiAsset[T MultiAssetTypeOutput | MultiAssetTypeMint] struct { data map[Blake2b224]map[cbor.ByteString]T } +// NewMultiAsset creates a MultiAsset with the specified data +func NewMultiAsset[T MultiAssetTypeOutput | MultiAssetTypeMint](data map[Blake2b224]map[cbor.ByteString]T) MultiAsset[T] { + return MultiAsset[T]{data: data} +} + +// multiAssetJson is a convenience type for marshaling/unmarshaling MultiAsset to/from JSON type multiAssetJson[T MultiAssetTypeOutput | MultiAssetTypeMint] struct { Name string `json:"name"` NameHex string `json:"nameHex"` diff --git a/ledger/common_test.go b/ledger/common/common_test.go similarity index 87% rename from ledger/common_test.go rename to ledger/common/common_test.go index 563d0a14..3ca1ab64 100644 --- a/ledger/common_test.go +++ b/ledger/common/common_test.go @@ -1,4 +1,18 @@ -package ledger +// Copyright 2024 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 ( "encoding/hex" diff --git a/ledger/compat.go b/ledger/compat.go new file mode 100644 index 00000000..bfdc5963 --- /dev/null +++ b/ledger/compat.go @@ -0,0 +1,56 @@ +// Copyright 2024 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 ledger + +import ( + "github.com/blinklabs-io/gouroboros/ledger/common" +) + +// The below are compatability types and functions to keep existing code working +// after a refactor of the ledger package + +// Hash types +type Blake2b224 = common.Blake2b224 +type Blake2b256 = common.Blake2b256 + +func NewBlake2b224(data []byte) Blake2b224 { + return common.NewBlake2b224(data) +} + +func NewBlake2b256(data []byte) Blake2b256 { + return common.NewBlake2b256(data) +} + +// Address +type Address = common.Address +type AddrKeyHash = common.AddrKeyHash + +func NewAddress(addr string) (Address, error) { + return common.NewAddress(addr) +} + +// Other types +type IssuerVkey = common.IssuerVkey +type PoolId = common.PoolId + +func NewPoolIdFromBech32(poolId string) (PoolId, error) { + return common.NewPoolIdFromBech32(poolId) +} + +type AssetFingerprint = common.AssetFingerprint + +func NewAssetFingerprint(policyId []byte, assetName []byte) AssetFingerprint { + return common.NewAssetFingerprint(policyId, assetName) +} diff --git a/ledger/conway.go b/ledger/conway.go index 55796016..6c0f8496 100644 --- a/ledger/conway.go +++ b/ledger/conway.go @@ -21,6 +21,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -502,7 +503,7 @@ func (t ConwayTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t ConwayTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t ConwayTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } diff --git a/ledger/mary.go b/ledger/mary.go index 2e845aee..d5ae8f5a 100644 --- a/ledger/mary.go +++ b/ledger/mary.go @@ -22,6 +22,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -120,8 +121,8 @@ type MaryTransactionBody struct { ProtocolParamUpdates map[Blake2b224]MaryProtocolParameterUpdate Epoch uint64 } `cbor:"6,keyasint,omitempty"` - TxOutputs []MaryTransactionOutput `cbor:"1,keyasint,omitempty"` - TxMint *MultiAsset[MultiAssetTypeMint] `cbor:"9,keyasint,omitempty"` + TxOutputs []MaryTransactionOutput `cbor:"1,keyasint,omitempty"` + TxMint *common.MultiAsset[common.MultiAssetTypeMint] `cbor:"9,keyasint,omitempty"` } func (b *MaryTransactionBody) UnmarshalCBOR(cborData []byte) error { @@ -145,7 +146,7 @@ func (b *MaryTransactionBody) ProtocolParametersUpdate() map[Blake2b224]any { return updateMap } -func (b *MaryTransactionBody) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (b *MaryTransactionBody) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return b.TxMint } @@ -223,7 +224,7 @@ func (t MaryTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t MaryTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t MaryTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } @@ -312,9 +313,9 @@ type MaryTransactionOutput struct { func (o MaryTransactionOutput) MarshalJSON() ([]byte, error) { tmpObj := struct { - Address Address `json:"address"` - Amount uint64 `json:"amount"` - Assets *MultiAsset[MultiAssetTypeOutput] `json:"assets,omitempty"` + Address Address `json:"address"` + Amount uint64 `json:"amount"` + Assets *common.MultiAsset[common.MultiAssetTypeOutput] `json:"assets,omitempty"` }{ Address: o.OutputAddress, Amount: o.OutputAmount.Amount, @@ -331,7 +332,7 @@ func (o MaryTransactionOutput) Amount() uint64 { return o.OutputAmount.Amount } -func (o MaryTransactionOutput) Assets() *MultiAsset[MultiAssetTypeOutput] { +func (o MaryTransactionOutput) Assets() *common.MultiAsset[common.MultiAssetTypeOutput] { return o.OutputAmount.Assets } @@ -355,7 +356,7 @@ type MaryTransactionOutputValue struct { cbor.StructAsArray Amount uint64 // We use a pointer here to allow it to be nil - Assets *MultiAsset[MultiAssetTypeOutput] + Assets *common.MultiAsset[common.MultiAssetTypeOutput] } func (v *MaryTransactionOutputValue) UnmarshalCBOR(data []byte) error { diff --git a/ledger/mary_test.go b/ledger/mary_test.go index d15664a1..d337a569 100644 --- a/ledger/mary_test.go +++ b/ledger/mary_test.go @@ -21,13 +21,14 @@ import ( "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/internal/test" + "github.com/blinklabs-io/gouroboros/ledger/common" ) func createMaryTransactionOutputValueAssets( policyId []byte, assetName []byte, amount uint64, -) *MultiAsset[MultiAssetTypeOutput] { +) *common.MultiAsset[common.MultiAssetTypeOutput] { data := map[Blake2b224]map[cbor.ByteString]uint64{} policyIdKey := Blake2b224{} copy(policyIdKey[:], policyId) @@ -35,7 +36,8 @@ func createMaryTransactionOutputValueAssets( data[policyIdKey] = map[cbor.ByteString]uint64{ assetKey: amount, } - return &MultiAsset[MultiAssetTypeOutput]{data: data} + ret := common.NewMultiAsset[common.MultiAssetTypeOutput](data) + return &ret } func TestMaryTransactionOutputValueEncodeDecode(t *testing.T) { diff --git a/ledger/shelley.go b/ledger/shelley.go index fae744b0..ae656a5b 100644 --- a/ledger/shelley.go +++ b/ledger/shelley.go @@ -21,6 +21,7 @@ import ( utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) const ( @@ -266,7 +267,7 @@ func (b *ShelleyTransactionBody) RequiredSigners() []Blake2b224 { return nil } -func (b *ShelleyTransactionBody) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (b *ShelleyTransactionBody) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { // No asset minting in Shelley return nil } @@ -383,7 +384,7 @@ func (o ShelleyTransactionOutput) Amount() uint64 { return o.OutputAmount } -func (o ShelleyTransactionOutput) Assets() *MultiAsset[MultiAssetTypeOutput] { +func (o ShelleyTransactionOutput) Assets() *common.MultiAsset[common.MultiAssetTypeOutput] { return nil } @@ -477,7 +478,7 @@ func (t ShelleyTransaction) RequiredSigners() []Blake2b224 { return t.Body.RequiredSigners() } -func (t ShelleyTransaction) AssetMint() *MultiAsset[MultiAssetTypeMint] { +func (t ShelleyTransaction) AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] { return t.Body.AssetMint() } diff --git a/ledger/tx.go b/ledger/tx.go index 5f48d622..256f60b1 100644 --- a/ledger/tx.go +++ b/ledger/tx.go @@ -22,6 +22,7 @@ import ( "golang.org/x/crypto/blake2b" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/gouroboros/ledger/common" ) type Transaction interface { @@ -49,7 +50,7 @@ type TransactionBody interface { Withdrawals() map[*Address]uint64 AuxDataHash() *Blake2b256 RequiredSigners() []Blake2b224 - AssetMint() *MultiAsset[MultiAssetTypeMint] + AssetMint() *common.MultiAsset[common.MultiAssetTypeMint] ScriptDataHash() *Blake2b256 VotingProcedures() VotingProcedures ProposalProcedures() []ProposalProcedure @@ -67,7 +68,7 @@ type TransactionInput interface { type TransactionOutput interface { Address() Address Amount() uint64 - Assets() *MultiAsset[MultiAssetTypeOutput] + Assets() *common.MultiAsset[common.MultiAssetTypeOutput] Datum() *cbor.LazyValue DatumHash() *Blake2b256 Cbor() []byte diff --git a/ledger/verify_block_body.go b/ledger/verify_block_body.go index 687c1731..5771b353 100644 --- a/ledger/verify_block_body.go +++ b/ledger/verify_block_body.go @@ -21,7 +21,6 @@ package ledger import ( "bytes" "encoding/hex" - "encoding/json" "fmt" "strconv" @@ -286,26 +285,15 @@ func ExtractTokens(output TransactionOutput) ([]UTXOOutputToken, error) { TokenValue: strconv.FormatUint(output.Amount(), 10), }) if output.Assets() != nil { - assetsBytes, assetsBytesError := output.Assets().MarshalJSON() - if assetsBytesError != nil { - return nil, fmt.Errorf( - "ExtractTokens: MarshalJSON assets error, %v", - assetsBytesError.Error(), - ) - } - var assets []multiAssetJson[MultiAssetTypeOutput] - err := json.Unmarshal(assetsBytes, &assets) - if err != nil { - return nil, fmt.Errorf( - "ExtractTokens: json.Unmarshal error, %v", - err.Error(), - ) - } - for _, asset := range assets { - outputTokens = append(outputTokens, UTXOOutputToken{ - TokenAssetName: asset.PolicyId + asset.NameHex, - TokenValue: strconv.FormatUint(asset.Amount, 10), - }) + tmpAssets := output.Assets() + for _, policyId := range tmpAssets.Policies() { + for _, assetName := range tmpAssets.Assets(policyId) { + amount := tmpAssets.Asset(policyId, assetName) + outputTokens = append(outputTokens, UTXOOutputToken{ + TokenAssetName: policyId.String() + hex.EncodeToString(assetName), + TokenValue: strconv.FormatUint(amount, 10), + }) + } } } return outputTokens, nil diff --git a/networks.go b/networks.go index e1496bb0..80c0fa80 100644 --- a/networks.go +++ b/networks.go @@ -14,40 +14,38 @@ package ouroboros -import ( - "github.com/blinklabs-io/gouroboros/ledger" -) +import "github.com/blinklabs-io/gouroboros/ledger/common" // Network definitions var ( NetworkTestnet = Network{ - Id: ledger.AddressNetworkTestnet, + Id: common.AddressNetworkTestnet, Name: "testnet", NetworkMagic: 1097911063, } NetworkMainnet = Network{ - Id: ledger.AddressNetworkMainnet, + Id: common.AddressNetworkMainnet, Name: "mainnet", NetworkMagic: 764824073, PublicRootAddress: "backbone.cardano-mainnet.iohk.io", PublicRootPort: 3001, } NetworkPreprod = Network{ - Id: ledger.AddressNetworkTestnet, + Id: common.AddressNetworkTestnet, Name: "preprod", NetworkMagic: 1, PublicRootAddress: "preprod-node.world.dev.cardano.org", PublicRootPort: 30000, } NetworkPreview = Network{ - Id: ledger.AddressNetworkTestnet, + Id: common.AddressNetworkTestnet, Name: "preview", NetworkMagic: 2, PublicRootAddress: "preview-node.play.dev.cardano.org", PublicRootPort: 3001, } NetworkSancho = Network{ - Id: ledger.AddressNetworkTestnet, + Id: common.AddressNetworkTestnet, Name: "sanchonet", NetworkMagic: 4, PublicRootAddress: "sanchonet-node.play.dev.cardano.org",