Skip to content

Commit 2a5b082

Browse files
author
Jenita
committed
feat: created genesis pools from shelly genesis
Signed-off-by: Jenita <[email protected]>
1 parent 23c86c1 commit 2a5b082

File tree

3 files changed

+76
-44
lines changed

3 files changed

+76
-44
lines changed

ledger/common/certs.go

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"encoding/json"
2020
"errors"
2121
"fmt"
22-
"math/big"
2322
"net"
2423

2524
"github.com/blinklabs-io/gouroboros/cbor"
@@ -383,7 +382,7 @@ type PoolRegistrationCertificate struct {
383382
VrfKeyHash VrfKeyHash `json:"vrfKeyHash"`
384383
Pledge uint64 `json:"pledge"`
385384
Cost uint64 `json:"cost"`
386-
Margin cbor.Rat `json:"margin"`
385+
Margin GenesisRat `json:"margin"`
387386
RewardAccount AddrKeyHash `json:"rewardAccount"`
388387
PoolOwners []AddrKeyHash `json:"poolOwners"`
389388
Relays []PoolRelay `json:"relays"`
@@ -406,7 +405,6 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
406405
Ipv6 *net.IP `json:"ipv6,omitempty"`
407406
Hostname *string `json:"hostname,omitempty"`
408407
} `json:"relays"`
409-
410408
PoolMetadata *PoolMetadata `json:"poolMetadata,omitempty"`
411409
}
412410

@@ -432,35 +430,18 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
432430

433431
// Handle margin field
434432
if len(tmp.Margin) > 0 {
435-
var marginValue interface{}
436-
if err := json.Unmarshal(tmp.Margin, &marginValue); err != nil {
433+
if err := p.Margin.UnmarshalJSON(tmp.Margin); err != nil {
437434
return fmt.Errorf("failed to unmarshal margin: %w", err)
438435
}
439-
440-
switch v := marginValue.(type) {
441-
case float64:
442-
p.Margin.Rat = new(big.Rat).SetFloat64(v)
443-
case []interface{}:
444-
if len(v) == 2 {
445-
if num, ok := v[0].(float64); ok {
446-
if den, ok := v[1].(float64); ok && den != 0 {
447-
p.Margin.Rat = new(big.Rat).SetFrac64(int64(num), int64(den))
448-
}
449-
}
450-
}
451-
}
452436
}
453437

454438
// Handle reward account
455439
if len(tmp.RewardAccount) > 0 {
456-
type credential struct {
457-
KeyHash string `json:"key hash"`
458-
}
459-
type rewardAccount struct {
460-
Credential credential `json:"credential"`
440+
var ra struct {
441+
Credential struct {
442+
KeyHash string `json:"key hash"`
443+
} `json:"credential"`
461444
}
462-
463-
var ra rewardAccount
464445
if err := json.Unmarshal(tmp.RewardAccount, &ra); err != nil {
465446
return fmt.Errorf("failed to unmarshal reward account: %w", err)
466447
}
@@ -470,30 +451,29 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
470451
if err != nil {
471452
return fmt.Errorf("failed to decode reward account key hash: %w", err)
472453
}
473-
if len(hashBytes) != 28 {
474-
return fmt.Errorf("invalid key hash length: expected 28, got %d", len(hashBytes))
454+
if len(hashBytes) != AddressHashSize {
455+
return fmt.Errorf("invalid key hash length: expected %d, got %d", AddressHashSize, len(hashBytes))
475456
}
476-
var hash Blake2b224
477-
copy(hash[:], hashBytes)
478-
p.RewardAccount = AddrKeyHash(hash)
457+
p.RewardAccount = AddrKeyHash(NewBlake2b224(hashBytes))
479458
}
480459
}
481460

482-
// Convert string fields to binary types
461+
// Convert operator key
483462
if tmp.Operator != "" {
484463
opBytes, err := hex.DecodeString(tmp.Operator)
485464
if err != nil {
486465
return fmt.Errorf("invalid operator key: %w", err)
487466
}
488-
p.Operator = PoolKeyHash(Blake2b224(opBytes))
467+
p.Operator = PoolKeyHash(NewBlake2b224(opBytes))
489468
}
490469

470+
// Convert VRF key hash
491471
if tmp.VrfKeyHash != "" {
492472
vrfBytes, err := hex.DecodeString(tmp.VrfKeyHash)
493473
if err != nil {
494474
return fmt.Errorf("invalid VRF key hash: %w", err)
495475
}
496-
p.VrfKeyHash = VrfKeyHash(Blake2b256(vrfBytes))
476+
p.VrfKeyHash = VrfKeyHash(NewBlake2b256(vrfBytes))
497477
}
498478

499479
// Convert pool owners
@@ -504,7 +484,7 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
504484
if err != nil {
505485
return fmt.Errorf("invalid pool owner key: %w", err)
506486
}
507-
owners[i] = AddrKeyHash(Blake2b224(ownerBytes))
487+
owners[i] = AddrKeyHash(NewBlake2b224(ownerBytes))
508488
}
509489
p.PoolOwners = owners
510490
}

ledger/shelley/genesis.go

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,49 @@ import (
2222
"math/big"
2323
"os"
2424
"reflect"
25+
"sync"
2526
"time"
2627

2728
"github.com/blinklabs-io/gouroboros/cbor"
2829
"github.com/blinklabs-io/gouroboros/ledger/common"
2930
)
3031

32+
// Network stake address headers
33+
var (
34+
stakeHeaderRegistry = map[string]struct {
35+
Base, Script byte
36+
}{
37+
"Mainnet": {0xE0, 0xE1},
38+
"Testnet": {0xF0, 0xF1},
39+
}
40+
stakeHeaderMutex sync.RWMutex
41+
)
42+
43+
// RegisterStakeHeaders allows runtime registration of network address headers
44+
func RegisterStakeHeaders(networkId string, baseHeader, scriptHeader byte) {
45+
stakeHeaderMutex.Lock()
46+
defer stakeHeaderMutex.Unlock()
47+
stakeHeaderRegistry[networkId] = struct{ Base, Script byte }{
48+
Base: baseHeader,
49+
Script: scriptHeader,
50+
}
51+
}
52+
53+
func getStakeAddressHeader(networkId string, isScript bool) (byte, error) {
54+
stakeHeaderMutex.RLock()
55+
defer stakeHeaderMutex.RUnlock()
56+
57+
headers, exists := stakeHeaderRegistry[networkId]
58+
if !exists {
59+
return 0, errors.New("network not registered in stake header registry")
60+
}
61+
62+
if isScript {
63+
return headers.Script, nil
64+
}
65+
return headers.Base, nil
66+
}
67+
3168
type ShelleyGenesis struct {
3269
cbor.StructAsArray
3370
SystemStart time.Time `json:"systemStart"`
@@ -232,7 +269,6 @@ func (g *ShelleyGenesis) GenesisUtxos() ([]common.Utxo, error) {
232269
return ret, nil
233270
}
234271

235-
// InitialPools returns all pools and their delegators from the genesis data
236272
func (g *ShelleyGenesis) InitialPools() (map[string]common.PoolRegistrationCertificate, map[string][]common.Address, error) {
237273
pools := make(map[string]common.PoolRegistrationCertificate)
238274
poolStake := make(map[string][]common.Address)
@@ -241,6 +277,11 @@ func (g *ShelleyGenesis) InitialPools() (map[string]common.PoolRegistrationCerti
241277
return pools, poolStake, nil
242278
}
243279

280+
headerByte, err := getStakeAddressHeader(g.NetworkId, true)
281+
if err != nil {
282+
return nil, nil, errors.New("failed to get stake address header")
283+
}
284+
244285
for stakeAddr, poolId := range g.Staking.Stake {
245286
if len(stakeAddr) != 56 {
246287
return nil, nil, errors.New("invalid stake address length")
@@ -251,7 +292,7 @@ func (g *ShelleyGenesis) InitialPools() (map[string]common.PoolRegistrationCerti
251292
return nil, nil, errors.New("failed to decode stake key")
252293
}
253294

254-
stakeAddrBytes := append([]byte{0xE1}, stakeKeyBytes...)
295+
stakeAddrBytes := append([]byte{headerByte}, stakeKeyBytes...)
255296
addr, err := common.NewAddressFromBytes(stakeAddrBytes)
256297
if err != nil {
257298
return nil, nil, errors.New("failed to create stake address")
@@ -286,7 +327,6 @@ func (g *ShelleyGenesis) InitialPools() (map[string]common.PoolRegistrationCerti
286327
return pools, poolStake, nil
287328
}
288329

289-
// PoolById returns a specific pool by its ID along with its delegators
290330
func (g *ShelleyGenesis) PoolById(poolId string) (*common.PoolRegistrationCertificate, []common.Address, error) {
291331
if len(poolId) != 56 {
292332
return nil, nil, errors.New("invalid pool ID length")
@@ -297,9 +337,9 @@ func (g *ShelleyGenesis) PoolById(poolId string) (*common.PoolRegistrationCertif
297337
return nil, nil, errors.New("pool not found")
298338
}
299339

300-
operatorBytes, err := hex.DecodeString(poolId)
340+
headerByte, err := getStakeAddressHeader(g.NetworkId, true)
301341
if err != nil {
302-
return nil, nil, errors.New("failed to decode pool operator key")
342+
return nil, nil, errors.New("failed to get stake address header")
303343
}
304344

305345
var delegators []common.Address
@@ -314,7 +354,7 @@ func (g *ShelleyGenesis) PoolById(poolId string) (*common.PoolRegistrationCertif
314354
return nil, nil, errors.New("failed to decode stake key")
315355
}
316356

317-
stakeAddrBytes := append([]byte{0xE1}, stakeKeyBytes...)
357+
stakeAddrBytes := append([]byte{headerByte}, stakeKeyBytes...)
318358
addr, err := common.NewAddressFromBytes(stakeAddrBytes)
319359
if err != nil {
320360
return nil, nil, errors.New("failed to create stake address")
@@ -324,6 +364,11 @@ func (g *ShelleyGenesis) PoolById(poolId string) (*common.PoolRegistrationCertif
324364
}
325365
}
326366

367+
operatorBytes, err := hex.DecodeString(poolId)
368+
if err != nil {
369+
return nil, nil, errors.New("failed to decode pool operator key")
370+
}
371+
327372
return &common.PoolRegistrationCertificate{
328373
Operator: common.Blake2b224(operatorBytes),
329374
VrfKeyHash: pool.VrfKeyHash,

ledger/shelley/genesis_test.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ import (
2727
"github.com/blinklabs-io/gouroboros/ledger/shelley"
2828
)
2929

30+
func init() {
31+
// Initialize network headers for tests
32+
shelley.RegisterStakeHeaders("Mainnet", 0xE0, 0xE1)
33+
shelley.RegisterStakeHeaders("Testnet", 0xF0, 0xF1)
34+
}
35+
3036
const shelleyGenesisConfig = `
3137
{
3238
"activeSlotsCoeff": 0.05,
@@ -256,6 +262,7 @@ func TestGenesisStaking(t *testing.T) {
256262
const testGenesis = `{
257263
"systemStart": "2017-09-23T21:44:51Z",
258264
"networkMagic": 764824073,
265+
"networkId": "Testnet",
259266
"staking": {
260267
"pools": {
261268
"0aedc455785463235311c990f68742c9043cd79af09ab31c2ba5e195": {
@@ -327,8 +334,8 @@ func TestGenesisStaking(t *testing.T) {
327334
} else {
328335
// Extract stake key from address
329336
addrBytes, _ := delegs[0].Bytes()
330-
if len(addrBytes) != 29 || addrBytes[0] != 0xE1 {
331-
t.Error("Delegator address is not in expected stake address format")
337+
if len(addrBytes) != 29 || addrBytes[0] != 0xF1 { // Testnet script stake address
338+
t.Errorf("Delegator address is not in expected stake address format: got %x", addrBytes[0])
332339
} else {
333340
stakeKey := hex.EncodeToString(addrBytes[1:])
334341
if stakeKey != expectedStakeKey {
@@ -364,8 +371,8 @@ func TestGenesisStaking(t *testing.T) {
364371
} else {
365372
// Extract stake key from address
366373
addrBytes, _ := delegators[0].Bytes()
367-
if len(addrBytes) != 29 || addrBytes[0] != 0xE1 {
368-
t.Error("Delegator address is not in expected stake address format")
374+
if len(addrBytes) != 29 || addrBytes[0] != 0xF1 { // Testnet script stake address
375+
t.Errorf("Delegator address is not in expected stake address format: got %x", addrBytes[0])
369376
} else {
370377
stakeKey := hex.EncodeToString(addrBytes[1:])
371378
if stakeKey != expectedStakeKey {

0 commit comments

Comments
 (0)