Skip to content

Commit 559f5be

Browse files
authored
fix(leios): prototype2026-w30 compatibility (#1910)
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
1 parent 74292d4 commit 559f5be

4 files changed

Lines changed: 385 additions & 7 deletions

File tree

ledger/common/certs.go

Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,64 @@ type (
399399
VrfKeyHash = Blake2b256
400400
)
401401

402+
const (
403+
LeiosBlsPublicKeySize = 96
404+
LeiosBlsPossessionProofSize = 48
405+
)
406+
407+
// LeiosKey is the BLS12-381 verification key and proof of possession
408+
// optionally registered with a Dijkstra-era stake pool. The prototype accepts
409+
// this data but does not use it for committee voting yet.
410+
type LeiosKey struct {
411+
cbor.StructAsArray
412+
PublicKey []byte `json:"publicKey"`
413+
PossessionProof []byte `json:"possessionProof"`
414+
}
415+
416+
func (k LeiosKey) validate() error {
417+
if len(k.PublicKey) != LeiosBlsPublicKeySize {
418+
return fmt.Errorf(
419+
"invalid Leios BLS public key length: expected %d, got %d",
420+
LeiosBlsPublicKeySize,
421+
len(k.PublicKey),
422+
)
423+
}
424+
if len(k.PossessionProof) != LeiosBlsPossessionProofSize {
425+
return fmt.Errorf(
426+
"invalid Leios BLS possession proof length: expected %d, got %d",
427+
LeiosBlsPossessionProofSize,
428+
len(k.PossessionProof),
429+
)
430+
}
431+
return nil
432+
}
433+
434+
func (k *LeiosKey) UnmarshalCBOR(data []byte) error {
435+
type tmpLeiosKey LeiosKey
436+
var tmp tmpLeiosKey
437+
if _, err := cbor.Decode(data, &tmp); err != nil {
438+
return err
439+
}
440+
if err := LeiosKey(tmp).validate(); err != nil {
441+
return err
442+
}
443+
*k = LeiosKey(tmp)
444+
return nil
445+
}
446+
447+
func (k *LeiosKey) UnmarshalJSON(data []byte) error {
448+
type tmpLeiosKey LeiosKey
449+
var tmp tmpLeiosKey
450+
if err := json.Unmarshal(data, &tmp); err != nil {
451+
return err
452+
}
453+
if err := LeiosKey(tmp).validate(); err != nil {
454+
return err
455+
}
456+
*k = LeiosKey(tmp)
457+
return nil
458+
}
459+
402460
type PoolMetadata struct {
403461
cbor.StructAsArray
404462
Url string
@@ -499,6 +557,7 @@ type PoolRegistrationCertificate struct {
499557
CertType uint `json:"certType,omitempty"`
500558
Operator PoolKeyHash `json:"operator"`
501559
VrfKeyHash VrfKeyHash `json:"vrfKeyHash"`
560+
LeiosKey *LeiosKey `json:"leiosKey,omitempty"`
502561
Pledge uint64 `json:"pledge"`
503562
Cost uint64 `json:"cost"`
504563
Margin GenesisRat `json:"margin"`
@@ -512,6 +571,7 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
512571
type tempPool struct {
513572
Operator string `json:"operator"`
514573
VrfKeyHash string `json:"vrfKeyHash"`
574+
LeiosKey *LeiosKey `json:"leiosKey,omitempty"`
515575
Pledge uint64 `json:"pledge"`
516576
Cost uint64 `json:"cost"`
517577
Margin json.RawMessage `json:"margin"`
@@ -564,6 +624,7 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
564624

565625
p.Pledge = tmp.Pledge
566626
p.Cost = tmp.Cost
627+
p.LeiosKey = tmp.LeiosKey
567628
p.Relays = make([]PoolRelay, len(tmp.Relays))
568629
for i, relay := range tmp.Relays {
569630
p.Relays[i] = PoolRelay{
@@ -650,16 +711,117 @@ func (p *PoolRegistrationCertificate) UnmarshalJSON(data []byte) error {
650711
func (c PoolRegistrationCertificate) isCertificate() {}
651712

652713
func (c *PoolRegistrationCertificate) UnmarshalCBOR(cborData []byte) error {
653-
type tPoolRegistrationCertificate PoolRegistrationCertificate
654-
var tmp tPoolRegistrationCertificate
655-
if _, err := cbor.Decode(cborData, &tmp); err != nil {
714+
type legacyPoolRegistrationCertificate struct {
715+
cbor.StructAsArray
716+
CertType uint
717+
Operator PoolKeyHash
718+
VrfKeyHash VrfKeyHash
719+
Pledge uint64
720+
Cost uint64
721+
Margin GenesisRat
722+
RewardAccount AddrKeyHash
723+
PoolOwners []AddrKeyHash
724+
Relays []PoolRelay
725+
PoolMetadata *PoolMetadata
726+
}
727+
type leiosPoolRegistrationCertificate struct {
728+
cbor.StructAsArray
729+
CertType uint
730+
Operator PoolKeyHash
731+
VrfKeyHash VrfKeyHash
732+
LeiosKey *LeiosKey
733+
Pledge uint64
734+
Cost uint64
735+
Margin GenesisRat
736+
RewardAccount AddrKeyHash
737+
PoolOwners []AddrKeyHash
738+
Relays []PoolRelay
739+
PoolMetadata *PoolMetadata
740+
}
741+
742+
var fields []cbor.RawMessage
743+
if _, err := cbor.Decode(cborData, &fields); err != nil {
656744
return err
657745
}
658-
*c = PoolRegistrationCertificate(tmp)
746+
switch len(fields) {
747+
case 10:
748+
var tmp legacyPoolRegistrationCertificate
749+
if _, err := cbor.Decode(cborData, &tmp); err != nil {
750+
return err
751+
}
752+
c.CertType = tmp.CertType
753+
c.Operator = tmp.Operator
754+
c.VrfKeyHash = tmp.VrfKeyHash
755+
c.LeiosKey = nil
756+
c.Pledge = tmp.Pledge
757+
c.Cost = tmp.Cost
758+
c.Margin = tmp.Margin
759+
c.RewardAccount = tmp.RewardAccount
760+
c.PoolOwners = tmp.PoolOwners
761+
c.Relays = tmp.Relays
762+
c.PoolMetadata = tmp.PoolMetadata
763+
case 11:
764+
var tmp leiosPoolRegistrationCertificate
765+
if _, err := cbor.Decode(cborData, &tmp); err != nil {
766+
return err
767+
}
768+
c.CertType = tmp.CertType
769+
c.Operator = tmp.Operator
770+
c.VrfKeyHash = tmp.VrfKeyHash
771+
c.LeiosKey = tmp.LeiosKey
772+
c.Pledge = tmp.Pledge
773+
c.Cost = tmp.Cost
774+
c.Margin = tmp.Margin
775+
c.RewardAccount = tmp.RewardAccount
776+
c.PoolOwners = tmp.PoolOwners
777+
c.Relays = tmp.Relays
778+
c.PoolMetadata = tmp.PoolMetadata
779+
default:
780+
return fmt.Errorf(
781+
"invalid pool registration certificate: expected 10 or 11 fields, got %d",
782+
len(fields),
783+
)
784+
}
659785
c.SetCbor(cborData)
660786
return nil
661787
}
662788

789+
// NOTE: UnmarshalCBOR caches the original CBOR bytes, and MarshalCBOR returns
790+
// those bytes for both 10- and 11-field variants. Call SetCbor(nil) before
791+
// marshaling mutated fields.
792+
func (c PoolRegistrationCertificate) MarshalCBOR() ([]byte, error) {
793+
if cborData := c.Cbor(); cborData != nil {
794+
return cborData, nil
795+
}
796+
if c.LeiosKey == nil {
797+
return cbor.Encode([]any{
798+
c.CertType,
799+
c.Operator,
800+
c.VrfKeyHash,
801+
c.Pledge,
802+
c.Cost,
803+
c.Margin,
804+
c.RewardAccount,
805+
c.PoolOwners,
806+
c.Relays,
807+
c.PoolMetadata,
808+
})
809+
}
810+
return cbor.Encode([]any{
811+
c.CertType,
812+
c.Operator,
813+
c.VrfKeyHash,
814+
c.LeiosKey,
815+
c.Pledge,
816+
c.Cost,
817+
c.Margin,
818+
c.RewardAccount,
819+
c.PoolOwners,
820+
c.Relays,
821+
c.PoolMetadata,
822+
})
823+
}
824+
663825
func (c *PoolRegistrationCertificate) Utxorpc() (*utxorpc.Certificate, error) {
664826
tmpPoolOwners := make([][]byte, len(c.PoolOwners))
665827
for i, owner := range c.PoolOwners {

0 commit comments

Comments
 (0)