Skip to content

Commit 44c9937

Browse files
author
Jenita
committed
feat: created genesis pools from shelly genesis
Signed-off-by: Jenita <[email protected]>
1 parent b275c23 commit 44c9937

File tree

2 files changed

+274
-7
lines changed

2 files changed

+274
-7
lines changed

ledger/shelley/genesis.go

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package shelley
1717
import (
1818
"encoding/hex"
1919
"encoding/json"
20+
"fmt"
2021
"io"
2122
"math/big"
2223
"os"
@@ -42,7 +43,40 @@ type ShelleyGenesis struct {
4243
ProtocolParameters ShelleyGenesisProtocolParams `json:"protocolParams"`
4344
GenDelegs map[string]map[string]string `json:"genDelegs"`
4445
InitialFunds map[string]uint64 `json:"initialFunds"`
45-
Staking any `json:"staking"`
46+
Staking GenesisStaking `json:"staking"`
47+
}
48+
49+
type GenesisStaking struct {
50+
Pools map[string]GenesisPool `json:"pools"`
51+
Stake map[string]string `json:"stake"`
52+
}
53+
54+
type GenesisPool struct {
55+
Cost int64 `json:"cost"`
56+
Margin float64 `json:"margin"`
57+
Metadata interface{} `json:"metadata"`
58+
Owners []string `json:"owners"`
59+
Pledge int64 `json:"pledge"`
60+
PublicKey string `json:"publicKey"`
61+
Relays []GenesisRelay `json:"relays"`
62+
RewardAccount GenesisReward `json:"rewardAccount"`
63+
Vrf string `json:"vrf"`
64+
}
65+
66+
type GenesisRelay struct {
67+
SingleHostName *SingleHostName `json:"single host name,omitempty"`
68+
}
69+
70+
type SingleHostName struct {
71+
DNSName string `json:"dnsName"`
72+
Port int `json:"port"`
73+
}
74+
75+
type GenesisReward struct {
76+
Credential struct {
77+
KeyHash string `json:"key hash"`
78+
} `json:"credential"`
79+
Network string `json:"network"`
4680
}
4781

4882
func (g ShelleyGenesis) MarshalCBOR() ([]byte, error) {
@@ -65,13 +99,52 @@ func (g ShelleyGenesis) MarshalCBOR() ([]byte, error) {
6599
cbor.NewByteString(vrfBytes),
66100
}
67101
}
68-
staking := []any{}
69-
if g.Staking == nil {
70-
staking = []any{
71-
map[any]any{},
72-
map[any]any{},
102+
103+
// Convert pools to CBOR format
104+
cborPools := make(map[cbor.ByteString]any)
105+
for poolId, pool := range g.Staking.Pools {
106+
poolIdBytes, err := hex.DecodeString(poolId)
107+
if err != nil {
108+
return nil, err
109+
}
110+
vrfBytes, err := hex.DecodeString(pool.Vrf)
111+
if err != nil {
112+
return nil, err
113+
}
114+
rewardAccountBytes, err := hex.DecodeString(pool.RewardAccount.Credential.KeyHash)
115+
if err != nil {
116+
return nil, err
117+
}
118+
cborPools[cbor.NewByteString(poolIdBytes)] = []any{
119+
pool.Cost,
120+
pool.Margin,
121+
pool.Pledge,
122+
pool.PublicKey,
123+
[]any{
124+
[]byte{0},
125+
rewardAccountBytes,
126+
},
127+
pool.Owners,
128+
pool.Relays,
129+
vrfBytes,
130+
pool.Metadata,
131+
}
132+
}
133+
134+
// Convert stake to CBOR format
135+
cborStake := make(map[cbor.ByteString]cbor.ByteString)
136+
for stakeAddr, poolId := range g.Staking.Stake {
137+
stakeAddrBytes, err := hex.DecodeString(stakeAddr)
138+
if err != nil {
139+
return nil, err
73140
}
141+
poolIdBytes, err := hex.DecodeString(poolId)
142+
if err != nil {
143+
return nil, err
144+
}
145+
cborStake[cbor.NewByteString(stakeAddrBytes)] = cbor.NewByteString(poolIdBytes)
74146
}
147+
75148
slotLengthMs := &big.Rat{}
76149
tmpData := []any{
77150
[]any{
@@ -95,7 +168,10 @@ func (g ShelleyGenesis) MarshalCBOR() ([]byte, error) {
95168
g.ProtocolParameters,
96169
genDelegs,
97170
g.InitialFunds,
98-
staking,
171+
[]any{
172+
cborPools,
173+
cborStake,
174+
},
99175
}
100176
return cbor.Encode(tmpData)
101177
}
@@ -128,6 +204,32 @@ func (g *ShelleyGenesis) GenesisUtxos() ([]common.Utxo, error) {
128204
return ret, nil
129205
}
130206

207+
// GetInitialPools returns all initial stake pools with their delegators
208+
func (g *ShelleyGenesis) GetInitialPools() (map[string]GenesisPool, map[string][]string, error) {
209+
poolStake := make(map[string][]string)
210+
for stakeAddr, poolId := range g.Staking.Stake {
211+
poolStake[poolId] = append(poolStake[poolId], stakeAddr)
212+
}
213+
return g.Staking.Pools, poolStake, nil
214+
}
215+
216+
// GetPoolById returns a specific pool by its ID along with its delegators
217+
func (g *ShelleyGenesis) GetPoolById(poolId string) (*GenesisPool, []string, error) {
218+
pool, exists := g.Staking.Pools[poolId]
219+
if !exists {
220+
return nil, nil, fmt.Errorf("pool not found")
221+
}
222+
223+
var delegators []string
224+
for stakeAddr, pId := range g.Staking.Stake {
225+
if pId == poolId {
226+
delegators = append(delegators, stakeAddr)
227+
}
228+
}
229+
230+
return &pool, delegators, nil
231+
}
232+
131233
type ShelleyGenesisProtocolParams struct {
132234
cbor.StructAsArray
133235
MinFeeA uint `json:"minFeeA"`

ledger/shelley/genesis_test.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,168 @@ func TestGenesisUtxos(t *testing.T) {
250250
)
251251
}
252252
}
253+
254+
const shelleyGenesisWithStaking = `
255+
{
256+
"activeSlotsCoeff": 0.05,
257+
"protocolParams": {
258+
"protocolVersion": {
259+
"minor": 0,
260+
"major": 2
261+
},
262+
"decentralisationParam": 1,
263+
"eMax": 18,
264+
"extraEntropy": {
265+
"tag": "NeutralNonce"
266+
},
267+
"maxTxSize": 16384,
268+
"maxBlockBodySize": 65536,
269+
"maxBlockHeaderSize": 1100,
270+
"minFeeA": 44,
271+
"minFeeB": 155381,
272+
"minUTxOValue": 1000000,
273+
"poolDeposit": 500000000,
274+
"minPoolCost": 340000000,
275+
"keyDeposit": 2000000,
276+
"nOpt": 150,
277+
"rho": 0.003,
278+
"tau": 0.20,
279+
"a0": 0.3
280+
},
281+
"genDelegs": {},
282+
"updateQuorum": 5,
283+
"networkId": "Testnet",
284+
"initialFunds": {},
285+
"maxLovelaceSupply": 45000000000000000,
286+
"networkMagic": 764824073,
287+
"epochLength": 432000,
288+
"systemStart": "2017-09-23T21:44:51Z",
289+
"slotsPerKESPeriod": 129600,
290+
"slotLength": 1,
291+
"maxKESEvolutions": 62,
292+
"securityParam": 2160,
293+
"staking": {
294+
"pools": {
295+
"0aedc455785463235311c990f68742c9043cd79af09ab31c2ba5e195": {
296+
"cost": 340000000,
297+
"margin": 0.0,
298+
"metadata": null,
299+
"owners": [],
300+
"pledge": 0,
301+
"publicKey": "0aedc455785463235311c990f68742c9043cd79af09ab31c2ba5e195",
302+
"relays": [
303+
{
304+
"single host name": {
305+
"dnsName": "p4.example",
306+
"port": 3001
307+
}
308+
}
309+
],
310+
"rewardAccount": {
311+
"credential": {
312+
"key hash": "6079cde665c2035b8d9ac8929307bdd7f20a51e678e9d4a5e39ace3a"
313+
},
314+
"network": "Testnet"
315+
},
316+
"vrf": "eb53a17fbad9b7ea0bcf1e1ea89355305600d593b426dfc3084a924d8877d47e"
317+
}
318+
},
319+
"stake": {
320+
"24632b71152f31516054075897d0d4ababc33204f8a8661136d49e36": "0aedc455785463235311c990f68742c9043cd79af09ab31c2ba5e195"
321+
}
322+
}
323+
}
324+
`
325+
326+
func TestGenesisStaking(t *testing.T) {
327+
tmpGenesis, err := shelley.NewShelleyGenesisFromReader(
328+
strings.NewReader(shelleyGenesisWithStaking),
329+
)
330+
if err != nil {
331+
t.Fatalf("unexpected error: %s", err)
332+
}
333+
334+
// Test GetInitialPools
335+
pools, delegators, err := tmpGenesis.GetInitialPools()
336+
if err != nil {
337+
t.Fatalf("unexpected error: %s", err)
338+
}
339+
340+
expectedPoolId := "0aedc455785463235311c990f68742c9043cd79af09ab31c2ba5e195"
341+
if len(pools) != 1 {
342+
t.Fatalf("expected 1 pool, got %d", len(pools))
343+
}
344+
345+
pool, exists := pools[expectedPoolId]
346+
if !exists {
347+
t.Fatalf("expected pool with ID %s not found", expectedPoolId)
348+
}
349+
350+
// Verify pool details
351+
if pool.Cost != 340000000 {
352+
t.Errorf("expected pool cost 340000000, got %d", pool.Cost)
353+
}
354+
if pool.Margin != 0.0 {
355+
t.Errorf("expected pool margin 0.0, got %f", pool.Margin)
356+
}
357+
if pool.Pledge != 0 {
358+
t.Errorf("expected pool pledge 0, got %d", pool.Pledge)
359+
}
360+
if pool.PublicKey != expectedPoolId {
361+
t.Errorf("expected pool public key %s, got %s", expectedPoolId, pool.PublicKey)
362+
}
363+
if pool.Vrf != "eb53a17fbad9b7ea0bcf1e1ea89355305600d593b426dfc3084a924d8877d47e" {
364+
t.Errorf("unexpected pool VRF key")
365+
}
366+
367+
// Verify delegators
368+
expectedStakeAddr := "24632b71152f31516054075897d0d4ababc33204f8a8661136d49e36"
369+
if len(delegators[expectedPoolId]) != 1 {
370+
t.Fatalf("expected 1 delegator for pool, got %d", len(delegators[expectedPoolId]))
371+
}
372+
if delegators[expectedPoolId][0] != expectedStakeAddr {
373+
t.Errorf("expected stake address %s, got %s", expectedStakeAddr, delegators[expectedPoolId][0])
374+
}
375+
376+
// Test GetPoolById
377+
poolById, delegatorsById, err := tmpGenesis.GetPoolById(expectedPoolId)
378+
if err != nil {
379+
t.Fatalf("unexpected error: %s", err)
380+
}
381+
382+
if poolById.PublicKey != expectedPoolId {
383+
t.Errorf("GetPoolById: expected pool public key %s, got %s", expectedPoolId, poolById.PublicKey)
384+
}
385+
386+
if len(delegatorsById) != 1 || delegatorsById[0] != expectedStakeAddr {
387+
t.Errorf("GetPoolById: unexpected delegators")
388+
}
389+
390+
// Test non-existent pool
391+
_, _, err = tmpGenesis.GetPoolById("nonexistentpoolid")
392+
if err == nil {
393+
t.Error("expected error for non-existent pool, got nil")
394+
} else if err.Error() != "pool not found" {
395+
t.Errorf("expected 'pool not found' error, got: %v", err)
396+
}
397+
}
398+
399+
func TestGenesisStakingCBOR(t *testing.T) {
400+
tmpGenesis, err := shelley.NewShelleyGenesisFromReader(
401+
strings.NewReader(shelleyGenesisWithStaking),
402+
)
403+
if err != nil {
404+
t.Fatalf("unexpected error: %s", err)
405+
}
406+
407+
// Test CBOR marshaling
408+
cborData, err := tmpGenesis.MarshalCBOR()
409+
if err != nil {
410+
t.Fatalf("unexpected error during CBOR marshaling: %s", err)
411+
}
412+
413+
if len(cborData) == 0 {
414+
t.Error("expected non-empty CBOR data, got empty")
415+
}
416+
417+
}

0 commit comments

Comments
 (0)