From c3c51848263ce8e0500a5bd83d8c9c62071bcf50 Mon Sep 17 00:00:00 2001 From: Ales Verbic Date: Sat, 26 Oct 2024 21:15:49 -0400 Subject: [PATCH] feat: add Utxorpc support for cardano.PParams in Conway (#767) --- ledger/allegra/pparams.go | 10 ++++- ledger/alonzo/pparams.go | 8 +++- ledger/babbage/pparams.go | 8 +++- ledger/common/pparams.go | 26 +++++++++++ ledger/conway/pparams.go | 34 +++++++++++++++ ledger/conway/pparams_test.go | 82 +++++++++++++++++++++++++++++++++++ 6 files changed, 165 insertions(+), 3 deletions(-) diff --git a/ledger/allegra/pparams.go b/ledger/allegra/pparams.go index f25c54f3..bcfc9060 100644 --- a/ledger/allegra/pparams.go +++ b/ledger/allegra/pparams.go @@ -14,7 +14,10 @@ package allegra -import "github.com/blinklabs-io/gouroboros/ledger/shelley" +import ( + "github.com/blinklabs-io/gouroboros/ledger/shelley" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" +) type AllegraProtocolParameters struct { shelley.ShelleyProtocolParameters @@ -33,3 +36,8 @@ type AllegraProtocolParameterUpdate struct { func (u *AllegraProtocolParameterUpdate) UnmarshalCBOR(data []byte) error { return u.UnmarshalCbor(data, u) } + +func (p *AllegraProtocolParameters) Utxorpc() *cardano.PParams { + // TODO: Implement the conversion logic to cardano.PParams + return &cardano.PParams{} +} diff --git a/ledger/alonzo/pparams.go b/ledger/alonzo/pparams.go index 63525ad8..ebf07726 100644 --- a/ledger/alonzo/pparams.go +++ b/ledger/alonzo/pparams.go @@ -18,6 +18,7 @@ import ( "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger/common" "github.com/blinklabs-io/gouroboros/ledger/mary" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) type AlonzoProtocolParameters struct { @@ -95,7 +96,7 @@ type AlonzoProtocolParameterUpdate struct { mary.MaryProtocolParameterUpdate MinPoolCost *uint64 `cbor:"16,keyasint"` AdaPerUtxoByte *uint64 `cbor:"17,keyasint"` - CostModels map[uint][]int64 `cbor:"18,keyasint"` + CostModels map[uint][]int64 `cbor:"18,keyasint"` ExecutionCosts *common.ExUnitPrice `cbor:"19,keyasint"` MaxTxExUnits *common.ExUnit `cbor:"20,keyasint"` MaxBlockExUnits *common.ExUnit `cbor:"21,keyasint"` @@ -107,3 +108,8 @@ type AlonzoProtocolParameterUpdate struct { func (u *AlonzoProtocolParameterUpdate) UnmarshalCBOR(data []byte) error { return u.UnmarshalCbor(data, u) } + +func (p *AlonzoProtocolParameters) Utxorpc() *cardano.PParams { + // TODO: Implement the conversion logic to cardano.PParams + return &cardano.PParams{} +} diff --git a/ledger/babbage/pparams.go b/ledger/babbage/pparams.go index 706116d1..e30640d5 100644 --- a/ledger/babbage/pparams.go +++ b/ledger/babbage/pparams.go @@ -17,6 +17,7 @@ package babbage import ( "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger/common" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) // BabbageProtocolParameters represents the current Babbage protocol parameters as seen in local-state-query @@ -134,7 +135,7 @@ type BabbageProtocolParameterUpdate struct { ProtocolVersion *common.ProtocolParametersProtocolVersion `cbor:"14,keyasint"` MinPoolCost *uint64 `cbor:"16,keyasint"` AdaPerUtxoByte *uint64 `cbor:"17,keyasint"` - CostModels map[uint][]int64 `cbor:"18,keyasint"` + CostModels map[uint][]int64 `cbor:"18,keyasint"` ExecutionCosts *common.ExUnitPrice `cbor:"19,keyasint"` MaxTxExUnits *common.ExUnit `cbor:"20,keyasint"` MaxBlockExUnits *common.ExUnit `cbor:"21,keyasint"` @@ -148,3 +149,8 @@ func (BabbageProtocolParameterUpdate) IsProtocolParameterUpdate() {} func (u *BabbageProtocolParameterUpdate) UnmarshalCBOR(data []byte) error { return u.UnmarshalCbor(data, u) } + +func (p *BabbageProtocolParameters) Utxorpc() *cardano.PParams { + // TODO: Implement the conversion logic to cardano.PParams + return &cardano.PParams{} +} diff --git a/ledger/common/pparams.go b/ledger/common/pparams.go index 67449f7d..57fe3a65 100644 --- a/ledger/common/pparams.go +++ b/ledger/common/pparams.go @@ -16,8 +16,10 @@ package common import ( "fmt" + "log/slog" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) type ProtocolParameterUpdate interface { @@ -31,6 +33,10 @@ type ProtocolParametersProtocolVersion struct { Minor uint } +type ProtocolParametersUtxorpc interface { + Utxorpc() *cardano.PParams +} + const ( NonceType0 = 0 NonceType1 = 1 @@ -79,3 +85,23 @@ type ExUnitPrice struct { MemPrice *cbor.Rat StepPrice *cbor.Rat } + +// ConvertToUtxorpcCardanoCostModels converts a map of cost models for Plutus scripts into cardano.CostModels +// Only PlutusV(keys 1, 2, and 3) are supported. +func ConvertToUtxorpcCardanoCostModels(models map[uint][]int64) *cardano.CostModels { + costModels := &cardano.CostModels{} + for k, v := range models { + costModel := &cardano.CostModel{Values: v} + switch k { + case 1: + costModels.PlutusV1 = costModel + case 2: + costModels.PlutusV2 = costModel + case 3: + costModels.PlutusV3 = costModel + default: + slog.Warn("unsupported cost model version", "version", k) + } + } + return costModels +} diff --git a/ledger/conway/pparams.go b/ledger/conway/pparams.go index 40cd3272..29eb603f 100644 --- a/ledger/conway/pparams.go +++ b/ledger/conway/pparams.go @@ -18,6 +18,7 @@ import ( "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger/babbage" "github.com/blinklabs-io/gouroboros/ledger/common" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) type ConwayProtocolParameters struct { @@ -55,6 +56,39 @@ type ConwayProtocolParameters struct { MinFeeRefScriptCostPerByte *cbor.Rat } +func (p *ConwayProtocolParameters) Utxorpc() *cardano.PParams { + return &cardano.PParams{ + CoinsPerUtxoByte: p.AdaPerUtxoByte, + MaxTxSize: uint64(p.MaxTxSize), + MinFeeCoefficient: uint64(p.MinFeeA), + MinFeeConstant: uint64(p.MinFeeB), + MaxBlockBodySize: uint64(p.MaxBlockBodySize), + MaxBlockHeaderSize: uint64(p.MaxBlockHeaderSize), + StakeKeyDeposit: uint64(p.KeyDeposit), + PoolDeposit: uint64(p.PoolDeposit), + PoolRetirementEpochBound: uint64(p.MaxEpoch), + DesiredNumberOfPools: uint64(p.NOpt), + PoolInfluence: &cardano.RationalNumber{Numerator: int32(p.A0.Num().Int64()), Denominator: uint32(p.A0.Denom().Int64())}, + MonetaryExpansion: &cardano.RationalNumber{Numerator: int32(p.Rho.Num().Int64()), Denominator: uint32(p.Rho.Denom().Int64())}, + TreasuryExpansion: &cardano.RationalNumber{Numerator: int32(p.Tau.Num().Int64()), Denominator: uint32(p.Tau.Denom().Int64())}, + MinPoolCost: p.MinPoolCost, + ProtocolVersion: &cardano.ProtocolVersion{ + Major: uint32(p.ProtocolVersion.Major), + Minor: uint32(p.ProtocolVersion.Minor), + }, + MaxValueSize: uint64(p.MaxValueSize), + CollateralPercentage: uint64(p.CollateralPercentage), + MaxCollateralInputs: uint64(p.MaxCollateralInputs), + CostModels: common.ConvertToUtxorpcCardanoCostModels(p.CostModels), + Prices: &cardano.ExPrices{ + Memory: &cardano.RationalNumber{Numerator: int32(p.ExecutionCosts.MemPrice.Num().Int64()), Denominator: uint32(p.ExecutionCosts.MemPrice.Denom().Int64())}, + Steps: &cardano.RationalNumber{Numerator: int32(p.ExecutionCosts.StepPrice.Num().Int64()), Denominator: uint32(p.ExecutionCosts.StepPrice.Denom().Int64())}, + }, + MaxExecutionUnitsPerTransaction: &cardano.ExUnits{Memory: uint64(p.MaxTxExUnits.Mem), Steps: uint64(p.MaxTxExUnits.Steps)}, + MaxExecutionUnitsPerBlock: &cardano.ExUnits{Memory: uint64(p.MaxBlockExUnits.Mem), Steps: uint64(p.MaxBlockExUnits.Steps)}, + } +} + func (p *ConwayProtocolParameters) Update(paramUpdate *ConwayProtocolParameterUpdate) { if paramUpdate.MinFeeA != nil { p.MinFeeA = *paramUpdate.MinFeeA diff --git a/ledger/conway/pparams_test.go b/ledger/conway/pparams_test.go index 24d21db3..022b87b6 100644 --- a/ledger/conway/pparams_test.go +++ b/ledger/conway/pparams_test.go @@ -16,6 +16,7 @@ package conway_test import ( "encoding/hex" + "math/big" "reflect" "strings" "testing" @@ -23,6 +24,7 @@ import ( "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger/common" "github.com/blinklabs-io/gouroboros/ledger/conway" + "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) func TestConwayProtocolParamsUpdate(t *testing.T) { @@ -118,3 +120,83 @@ func TestConwayProtocolParamsUpdateFromGenesis(t *testing.T) { } } } +func TestUtxorpc(t *testing.T) { + // Define test cases + testDefs := []struct { + startParams conway.ConwayProtocolParameters + expectedUtxorpc *cardano.PParams + }{ + { + startParams: conway.ConwayProtocolParameters{ + AdaPerUtxoByte: 44, + MaxTxSize: 16384, + MinFeeA: 500, + MinFeeB: 2, + MaxBlockBodySize: 65536, + MaxBlockHeaderSize: 1024, + KeyDeposit: 2000, + PoolDeposit: 500000, + MaxEpoch: 2160, + NOpt: 100, + A0: &cbor.Rat{Rat: big.NewRat(1, 2)}, + Rho: &cbor.Rat{Rat: big.NewRat(3, 4)}, + Tau: &cbor.Rat{Rat: big.NewRat(5, 6)}, + MinPoolCost: 340000000, + ProtocolVersion: common.ProtocolParametersProtocolVersion{Major: 8, Minor: 0}, + MaxValueSize: 1024, + CollateralPercentage: 150, + MaxCollateralInputs: 5, + ExecutionCosts: common.ExUnitPrice{MemPrice: &cbor.Rat{Rat: big.NewRat(1, 2)}, StepPrice: &cbor.Rat{Rat: big.NewRat(2, 3)}}, + MaxTxExUnits: common.ExUnit{Mem: 1000000, Steps: 200000}, + MaxBlockExUnits: common.ExUnit{Mem: 5000000, Steps: 1000000}, + CostModels: map[uint][]int64{ + 1: {100, 200, 300}, + 2: {400, 500, 600}, + 3: {700, 800, 900}, + }, + }, + expectedUtxorpc: &cardano.PParams{ + CoinsPerUtxoByte: 44, + MaxTxSize: 16384, + MinFeeCoefficient: 500, + MinFeeConstant: 2, + MaxBlockBodySize: 65536, + MaxBlockHeaderSize: 1024, + StakeKeyDeposit: 2000, + PoolDeposit: 500000, + PoolRetirementEpochBound: 2160, + DesiredNumberOfPools: 100, + PoolInfluence: &cardano.RationalNumber{Numerator: int32(1), Denominator: uint32(2)}, + MonetaryExpansion: &cardano.RationalNumber{Numerator: int32(3), Denominator: uint32(4)}, + TreasuryExpansion: &cardano.RationalNumber{Numerator: int32(5), Denominator: uint32(6)}, + MinPoolCost: 340000000, + ProtocolVersion: &cardano.ProtocolVersion{ + Major: 8, + Minor: 0, + }, + MaxValueSize: 1024, + CollateralPercentage: 150, + MaxCollateralInputs: 5, + CostModels: &cardano.CostModels{ + PlutusV1: &cardano.CostModel{Values: []int64{100, 200, 300}}, + PlutusV2: &cardano.CostModel{Values: []int64{400, 500, 600}}, + PlutusV3: &cardano.CostModel{Values: []int64{700, 800, 900}}, + }, + Prices: &cardano.ExPrices{ + Memory: &cardano.RationalNumber{Numerator: int32(1), Denominator: uint32(2)}, + Steps: &cardano.RationalNumber{Numerator: int32(2), Denominator: uint32(3)}, + }, + MaxExecutionUnitsPerTransaction: &cardano.ExUnits{Memory: 1000000, Steps: 200000}, + MaxExecutionUnitsPerBlock: &cardano.ExUnits{Memory: 5000000, Steps: 1000000}, + }, + }, + } + + for _, testDef := range testDefs { + result := testDef.startParams.Utxorpc() + // Compare the result with the expected value + if !reflect.DeepEqual(result, testDef.expectedUtxorpc) { + t.Fatalf("Utxorpc() test failed:\nExpected: %#v\nGot: %#v", testDef.expectedUtxorpc, result) + } + } +}