Skip to content

Commit a135321

Browse files
jkawanJenita
andauthored
feat: changes to support cost models while updating Alonzo protocols through genesis config (#984)
* feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> * feat: changes to support cost models while updating Alonzon protocols Signed-off-by: Jenita <[email protected]> --------- Signed-off-by: Jenita <[email protected]> Co-authored-by: Jenita <[email protected]>
1 parent 46fd3f7 commit a135321

File tree

4 files changed

+415
-61
lines changed

4 files changed

+415
-61
lines changed

ledger/alonzo/genesis.go

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ package alonzo
1616

1717
import (
1818
"encoding/json"
19+
"fmt"
1920
"io"
21+
"math"
2022
"math/big"
2123
"os"
24+
"strconv"
2225
)
2326

2427
type AlonzoGenesis struct {
@@ -29,7 +32,100 @@ type AlonzoGenesis struct {
2932
ExecutionPrices AlonzoGenesisExecutionPrices `json:"executionPrices"`
3033
MaxTxExUnits AlonzoGenesisExUnits `json:"maxTxExUnits"`
3134
MaxBlockExUnits AlonzoGenesisExUnits `json:"maxBlockExUnits"`
32-
CostModels map[string]map[string]int `json:"costModels"`
35+
CostModels map[string]CostModel `json:"costModels"`
36+
}
37+
38+
type CostModel map[string]int
39+
40+
// NormalizeCostModels converts all cost model keys to consistent paramX format
41+
func (g *AlonzoGenesis) NormalizeCostModels() error {
42+
if g.CostModels == nil {
43+
return nil
44+
}
45+
46+
for version, model := range g.CostModels {
47+
normalized := make(CostModel)
48+
for k, v := range model {
49+
// Check if key is already in paramX format
50+
var index int
51+
if _, err := fmt.Sscanf(k, "param%d", &index); err == nil {
52+
normalized[k] = v // Keep existing paramX keys
53+
continue
54+
}
55+
56+
// Check if key is a numeric index (from array format)
57+
if _, err := fmt.Sscanf(k, "%d", &index); err == nil {
58+
normalized[fmt.Sprintf("param%d", index)] = v
59+
continue
60+
}
61+
normalized[k] = v
62+
}
63+
g.CostModels[version] = normalized
64+
}
65+
return nil
66+
}
67+
68+
func (c *CostModel) UnmarshalJSON(data []byte) error {
69+
tmpMap := make(map[string]interface{})
70+
if err := json.Unmarshal(data, &tmpMap); err != nil {
71+
// Try to unmarshal as array first
72+
var tmpArray []interface{}
73+
if arrayErr := json.Unmarshal(data, &tmpArray); arrayErr == nil {
74+
*c = make(CostModel)
75+
for i, v := range tmpArray {
76+
num, err := toInt(v)
77+
if err != nil {
78+
return fmt.Errorf("array index %d: %w", i, err)
79+
}
80+
(*c)[strconv.Itoa(i)] = num
81+
}
82+
return nil
83+
}
84+
return err
85+
}
86+
87+
*c = make(CostModel)
88+
for k, v := range tmpMap {
89+
num, err := toInt(v)
90+
if err != nil {
91+
return fmt.Errorf("key %s: %w", k, err)
92+
}
93+
(*c)[k] = num
94+
}
95+
return nil
96+
}
97+
98+
func toInt(v interface{}) (int, error) {
99+
switch val := v.(type) {
100+
case float64:
101+
if val > float64(math.MaxInt) || val < float64(math.MinInt) {
102+
return 0, fmt.Errorf("float64 value %v overflows int", val)
103+
}
104+
return int(val), nil
105+
case int:
106+
return val, nil
107+
case json.Number:
108+
intVal, err := val.Int64()
109+
if err != nil {
110+
return 0, err
111+
}
112+
if intVal > math.MaxInt || intVal < math.MinInt {
113+
return 0, fmt.Errorf("json.Number value %v overflows int", val)
114+
}
115+
return int(intVal), nil
116+
case int64:
117+
if val > math.MaxInt || val < math.MinInt {
118+
return 0, fmt.Errorf("int64 value %v overflows int", val)
119+
}
120+
return int(val), nil
121+
case uint64:
122+
if val > math.MaxInt {
123+
return 0, fmt.Errorf("uint64 value %v overflows int", val)
124+
}
125+
return int(val), nil
126+
default:
127+
return 0, fmt.Errorf("unsupported numeric type: %T", v)
128+
}
33129
}
34130

35131
func NewAlonzoGenesisFromReader(r io.Reader) (AlonzoGenesis, error) {
@@ -39,6 +135,9 @@ func NewAlonzoGenesisFromReader(r io.Reader) (AlonzoGenesis, error) {
39135
if err := dec.Decode(&ret); err != nil {
40136
return ret, err
41137
}
138+
if err := ret.NormalizeCostModels(); err != nil {
139+
return ret, err
140+
}
42141
return ret, nil
43142
}
44143

ledger/alonzo/genesis_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ var expectedGenesisObj = alonzo.AlonzoGenesis{
243243
Mem: 50000000,
244244
Steps: 40000000000,
245245
},
246-
CostModels: map[string]map[string]int{
247-
"PlutusV1": {
246+
CostModels: map[string]alonzo.CostModel{
247+
"PlutusV1": map[string]int{
248248
"addInteger-cpu-arguments-intercept": 197209,
249249
"addInteger-cpu-arguments-slope": 0,
250250
"addInteger-memory-arguments-intercept": 1,
@@ -478,8 +478,8 @@ func TestNewAlonzoGenesisFromReader(t *testing.T) {
478478
)
479479
}
480480

481-
expectedCostModels := map[string]map[string]int{
482-
"PlutusV1": {
481+
expectedCostModels := map[string]alonzo.CostModel{
482+
"PlutusV1": map[string]int{
483483
"addInteger-cpu-arguments-intercept": 205665,
484484
"addInteger-cpu-arguments-slope": 812,
485485
},

ledger/alonzo/pparams.go

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,30 @@
1515
package alonzo
1616

1717
import (
18+
"fmt"
1819
"math"
20+
"strconv"
1921

2022
"github.com/blinklabs-io/gouroboros/cbor"
2123
"github.com/blinklabs-io/gouroboros/ledger/common"
2224
"github.com/blinklabs-io/gouroboros/ledger/mary"
2325
cardano "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
2426
)
2527

28+
// Constants for Plutus version mapping
29+
const (
30+
PlutusV1Key uint = 0
31+
PlutusV2Key uint = 1
32+
PlutusV3Key uint = 2
33+
)
34+
35+
// Expected parameter counts for validation
36+
var plutusParamCounts = map[uint]int{
37+
PlutusV1Key: 166,
38+
PlutusV2Key: 175,
39+
PlutusV3Key: 187,
40+
}
41+
2642
type AlonzoProtocolParameters struct {
2743
cbor.StructAsArray
2844
MinFeeA uint
@@ -134,10 +150,12 @@ func (p *AlonzoProtocolParameters) Update(
134150
}
135151
}
136152

137-
func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) {
153+
func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) error {
138154
if genesis == nil {
139-
return
155+
return nil
140156
}
157+
158+
// Common parameter updates
141159
p.AdaPerUtxoByte = genesis.LovelacePerUtxoWord / 8
142160
p.MaxValueSize = genesis.MaxValueSize
143161
p.CollateralPercentage = genesis.CollateralPercentage
@@ -150,16 +168,64 @@ func (p *AlonzoProtocolParameters) UpdateFromGenesis(genesis *AlonzoGenesis) {
150168
Memory: uint64(genesis.MaxBlockExUnits.Mem),
151169
Steps: uint64(genesis.MaxBlockExUnits.Steps),
152170
}
171+
153172
if genesis.ExecutionPrices.Mem != nil &&
154173
genesis.ExecutionPrices.Steps != nil {
155174
p.ExecutionCosts = common.ExUnitPrice{
156175
MemPrice: &cbor.Rat{Rat: genesis.ExecutionPrices.Mem.Rat},
157176
StepPrice: &cbor.Rat{Rat: genesis.ExecutionPrices.Steps.Rat},
158177
}
159178
}
160-
// TODO: cost models (#852)
161-
// We have 150+ string values to map to array indexes
162-
// CostModels map[string]map[string]int
179+
180+
if genesis.CostModels != nil {
181+
p.CostModels = make(map[uint][]int64)
182+
183+
for versionStr, model := range genesis.CostModels {
184+
key, ok := plutusVersionToKey(versionStr)
185+
if !ok {
186+
continue
187+
}
188+
189+
expectedCount, ok := plutusParamCounts[key]
190+
if !ok {
191+
continue
192+
}
193+
194+
values := make([]int64, expectedCount)
195+
196+
for paramName, val := range model {
197+
if index, err := strconv.Atoi(paramName); err == nil {
198+
if index >= 0 && index < expectedCount {
199+
values[index] = int64(val)
200+
}
201+
}
202+
}
203+
204+
// Verify we have all expected parameters
205+
for i, val := range values {
206+
if val == 0 {
207+
return fmt.Errorf("missing parameter at index %d for %s", i, versionStr)
208+
}
209+
}
210+
211+
p.CostModels[key] = values
212+
}
213+
}
214+
return nil
215+
}
216+
217+
// Helper to convert Plutus version string to key
218+
func plutusVersionToKey(version string) (uint, bool) {
219+
switch version {
220+
case "PlutusV1":
221+
return PlutusV1Key, true
222+
case "PlutusV2":
223+
return PlutusV2Key, true
224+
case "PlutusV3":
225+
return PlutusV3Key, true
226+
default:
227+
return 0, false
228+
}
163229
}
164230

165231
type AlonzoProtocolParameterUpdate struct {

0 commit comments

Comments
 (0)