Skip to content

Commit 5e32349

Browse files
author
Jenita
committed
feat: changes to support cost models while updating Alonzon protocols
Signed-off-by: Jenita <[email protected]>
1 parent c1adc83 commit 5e32349

File tree

3 files changed

+435
-359
lines changed

3 files changed

+435
-359
lines changed

ledger/alonzo/pparams.go

Lines changed: 167 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,39 @@
1515
package alonzo
1616

1717
import (
18+
//"encoding/json"
19+
"fmt"
1820
"math"
1921
"sort"
2022

23+
//"strconv"
24+
"strings"
25+
2126
"github.com/blinklabs-io/gouroboros/cbor"
2227
"github.com/blinklabs-io/gouroboros/ledger/common"
2328
"github.com/blinklabs-io/gouroboros/ledger/mary"
2429
cardano "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
2530
)
2631

32+
type PlutusVersion string
33+
34+
const (
35+
PlutusV1 PlutusVersion = "PlutusV1"
36+
PlutusV2 PlutusVersion = "PlutusV2"
37+
PlutusV3 PlutusVersion = "PlutusV3"
38+
)
39+
40+
type CostModel struct {
41+
Version PlutusVersion
42+
Parameters map[string]int64
43+
Order []string
44+
}
45+
2746
type AlonzoProtocolParameters struct {
2847
mary.MaryProtocolParameters
2948
MinPoolCost uint64
3049
AdaPerUtxoByte uint64
31-
CostModels map[uint][]int64
50+
CostModels map[PlutusVersion]*CostModel
3251
ExecutionCosts common.ExUnitPrice
3352
MaxTxExUnits common.ExUnits
3453
MaxBlockExUnits common.ExUnits
@@ -50,7 +69,7 @@ func (p *AlonzoProtocolParameters) Update(
5069
p.AdaPerUtxoByte = *paramUpdate.AdaPerUtxoByte
5170
}
5271
if paramUpdate.CostModels != nil {
53-
p.CostModels = paramUpdate.CostModels
72+
p.convertLegacyCostModels(paramUpdate.CostModels)
5473
}
5574
if paramUpdate.ExecutionCosts != nil {
5675
p.ExecutionCosts = *paramUpdate.ExecutionCosts
@@ -72,10 +91,12 @@ func (p *AlonzoProtocolParameters) Update(
7291
}
7392
}
7493

75-
func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) {
94+
func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) error {
7695
if genesis == nil {
77-
return
96+
return nil
7897
}
98+
99+
// Common parameter updates
79100
p.AdaPerUtxoByte = genesis.LovelacePerUtxoWord / 8
80101
p.MaxValueSize = genesis.MaxValueSize
81102
p.CollateralPercentage = genesis.CollateralPercentage
@@ -88,47 +109,117 @@ func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) {
88109
Memory: uint64(genesis.MaxBlockExUnits.Mem),
89110
Steps: uint64(genesis.MaxBlockExUnits.Steps),
90111
}
91-
if genesis.ExecutionPrices.Mem != nil &&
92-
genesis.ExecutionPrices.Steps != nil {
112+
113+
if genesis.ExecutionPrices.Mem != nil && genesis.ExecutionPrices.Steps != nil {
93114
p.ExecutionCosts = common.ExUnitPrice{
94115
MemPrice: &cbor.Rat{Rat: genesis.ExecutionPrices.Mem.Rat},
95116
StepPrice: &cbor.Rat{Rat: genesis.ExecutionPrices.Steps.Rat},
96117
}
97118
}
98119

99-
// Process cost models
100120
if genesis.CostModels != nil {
101-
p.CostModels = make(map[uint][]int64)
121+
p.CostModels = make(map[PlutusVersion]*CostModel)
122+
102123
for lang, model := range genesis.CostModels {
103-
var langKey uint
104-
switch lang {
105-
case "plutus:v1":
106-
langKey = 0
107-
case "plutus:v2":
108-
langKey = 1
109-
default:
110-
// Skip unknown language
124+
version, ok := toPlutusVersion(lang)
125+
if !ok {
111126
continue
112127
}
113128

114-
// Get sorted keys to determine indexes
115-
keys := make([]string, 0, len(model))
116-
for k := range model {
117-
keys = append(keys, k)
129+
params := make(map[string]int64)
130+
order := make([]string, 0, len(model))
131+
132+
// Since model is now map[string]int, we don't need type assertions
133+
for name, val := range model {
134+
params[name] = int64(val) // Convert int to int64
135+
order = append(order, name)
118136
}
119-
sort.Strings(keys)
120137

121-
// Create slice with values in alphabetical order
122-
costs := make([]int64, len(keys))
123-
for i, key := range keys {
124-
costs[i] = int64(model[key])
138+
// Sort keys alphabetically (maintains consistency with original behavior)
139+
sort.Strings(order)
140+
141+
p.CostModels[version] = &CostModel{
142+
Version: version,
143+
Parameters: params,
144+
Order: order,
125145
}
146+
}
147+
}
148+
return nil
149+
}
150+
151+
func (p *AlonzoProtocolParameters) convertLegacyCostModels(legacyModels map[uint][]int64) {
152+
p.CostModels = make(map[PlutusVersion]*CostModel)
126153

127-
p.CostModels[langKey] = costs
154+
for langKey, values := range legacyModels {
155+
var version PlutusVersion
156+
switch langKey {
157+
case 0:
158+
version = PlutusV1
159+
case 1:
160+
version = PlutusV2
161+
case 2:
162+
version = PlutusV3
163+
default:
164+
continue
165+
}
166+
167+
params := make(map[string]int64)
168+
order := make([]string, len(values))
169+
for i, val := range values {
170+
name := fmt.Sprintf("param%d", i)
171+
params[name] = val
172+
order[i] = name
173+
}
174+
175+
p.CostModels[version] = &CostModel{
176+
Version: version,
177+
Parameters: params,
178+
Order: order,
128179
}
129180
}
130181
}
131182

183+
func toPlutusVersion(key string) (PlutusVersion, bool) {
184+
switch strings.ToLower(key) {
185+
case "plutus:v1", "plutusv1":
186+
return PlutusV1, true
187+
case "plutus:v2", "plutusv2":
188+
return PlutusV2, true
189+
case "plutus:v3", "plutusv3":
190+
return PlutusV3, true
191+
default:
192+
return "", false
193+
}
194+
}
195+
196+
func (p *AlonzoProtocolParameters) ToLegacyCostModels() map[uint][]int64 {
197+
legacyModels := make(map[uint][]int64)
198+
199+
for version, model := range p.CostModels {
200+
var langKey uint
201+
switch version {
202+
case PlutusV1:
203+
langKey = 0
204+
case PlutusV2:
205+
langKey = 1
206+
case PlutusV3:
207+
langKey = 2
208+
default:
209+
continue
210+
}
211+
212+
// Convert ordered parameters back to list format
213+
values := make([]int64, len(model.Order))
214+
for i, name := range model.Order {
215+
values[i] = model.Parameters[name]
216+
}
217+
legacyModels[langKey] = values
218+
}
219+
220+
return legacyModels
221+
}
222+
132223
type AlonzoProtocolParameterUpdate struct {
133224
mary.MaryProtocolParameterUpdate
134225
MinPoolCost *uint64 `cbor:"16,keyasint"`
@@ -147,33 +238,63 @@ func (u *AlonzoProtocolParameterUpdate) UnmarshalCBOR(data []byte) error {
147238
}
148239

149240
func (p *AlonzoProtocolParameters) Utxorpc() *cardano.PParams {
150-
// sanity check
151-
if p.A0.Num().Int64() > math.MaxInt32 ||
152-
p.A0.Denom().Int64() < 0 ||
153-
p.A0.Denom().Int64() > math.MaxUint32 {
241+
if p == nil {
154242
return nil
155243
}
156-
if p.Rho.Num().Int64() > math.MaxInt32 ||
157-
p.Rho.Denom().Int64() < 0 ||
158-
p.Rho.Denom().Int64() > math.MaxUint32 {
159-
return nil
244+
245+
// Helper function to safely check rational number bounds
246+
safeRatCheck := func(rat *cbor.Rat) bool {
247+
if rat == nil || rat.Rat == nil {
248+
return false
249+
}
250+
num := rat.Num().Int64()
251+
denom := rat.Denom().Int64()
252+
return num <= math.MaxInt32 && denom > 0 && denom <= math.MaxUint32
160253
}
161-
if p.Tau.Num().Int64() > math.MaxInt32 ||
162-
p.Tau.Denom().Int64() < 0 ||
163-
p.Tau.Denom().Int64() > math.MaxUint32 {
254+
255+
// Validate all rational numbers
256+
if !safeRatCheck(p.A0) || !safeRatCheck(p.Rho) || !safeRatCheck(p.Tau) {
164257
return nil
165258
}
166-
if p.ExecutionCosts.MemPrice.Num().Int64() > math.MaxInt32 ||
167-
p.ExecutionCosts.MemPrice.Denom().Int64() < 0 ||
168-
p.ExecutionCosts.MemPrice.Denom().Int64() > math.MaxUint32 {
259+
if p.ExecutionCosts.MemPrice == nil || p.ExecutionCosts.StepPrice == nil ||
260+
!safeRatCheck(p.ExecutionCosts.MemPrice) || !safeRatCheck(p.ExecutionCosts.StepPrice) {
169261
return nil
170262
}
171-
if p.ExecutionCosts.StepPrice.Num().Int64() > math.MaxInt32 ||
172-
p.ExecutionCosts.StepPrice.Denom().Int64() < 0 ||
173-
p.ExecutionCosts.StepPrice.Denom().Int64() > math.MaxUint32 {
174-
return nil
263+
264+
// Convert cost models with proper version handling
265+
costModels := &cardano.CostModels{}
266+
if p.CostModels != nil {
267+
// Initialize all Plutus versions to empty models first
268+
costModels.PlutusV1 = &cardano.CostModel{Values: []int64{}}
269+
costModels.PlutusV2 = &cardano.CostModel{Values: []int64{}}
270+
costModels.PlutusV3 = &cardano.CostModel{Values: []int64{}}
271+
272+
// Convert each version that exists in our parameters
273+
for version, model := range p.CostModels {
274+
var values []int64
275+
switch version {
276+
case PlutusV1:
277+
values = make([]int64, len(model.Order))
278+
for i, name := range model.Order {
279+
values[i] = model.Parameters[name]
280+
}
281+
costModels.PlutusV1.Values = values
282+
case PlutusV2:
283+
values = make([]int64, len(model.Order))
284+
for i, name := range model.Order {
285+
values[i] = model.Parameters[name]
286+
}
287+
costModels.PlutusV2.Values = values
288+
case PlutusV3:
289+
values = make([]int64, len(model.Order))
290+
for i, name := range model.Order {
291+
values[i] = model.Parameters[name]
292+
}
293+
costModels.PlutusV3.Values = values
294+
}
295+
}
175296
}
176-
// #nosec G115
297+
177298
return &cardano.PParams{
178299
CoinsPerUtxoByte: p.AdaPerUtxoByte,
179300
MaxTxSize: uint64(p.MaxTxSize),
@@ -205,9 +326,7 @@ func (p *AlonzoProtocolParameters) Utxorpc() *cardano.PParams {
205326
MaxValueSize: uint64(p.MaxValueSize),
206327
CollateralPercentage: uint64(p.CollateralPercentage),
207328
MaxCollateralInputs: uint64(p.MaxCollateralInputs),
208-
CostModels: common.ConvertToUtxorpcCardanoCostModels(
209-
p.CostModels,
210-
),
329+
CostModels: costModels,
211330
Prices: &cardano.ExPrices{
212331
Memory: &cardano.RationalNumber{
213332
Numerator: int32(p.ExecutionCosts.MemPrice.Num().Int64()),

0 commit comments

Comments
 (0)