Skip to content

Commit

Permalink
Add Safrole structs (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
pantrif authored Jul 30, 2024
1 parent 11856c3 commit c3dd4e3
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 5 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/eigerco/strawberry

go 1.22.5

require github.com/ChainSafe/gossamer v0.9.0
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
github.com/ChainSafe/gossamer v0.9.0 h1:Xj2oRO+5JFIpE3qkC9L8pyR1fxTPv5fTGwvvD2BnmQQ=
github.com/ChainSafe/gossamer v0.9.0/go.mod h1:V/ePNNEpATpoP8IS65suyVT05waGwQT/EtyhMhqOTKk=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
12 changes: 7 additions & 5 deletions internal/crypto/constants.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package crypto

const (
HashSize = 32
BandersnatchSize = 32
Ed25519PublicSize = 32
Ed25519PrivateSize = 64
BLSSize = 144
HashSize = 32
BandersnatchSize = 32
Ed25519PublicSize = 32
Ed25519PrivateSize = 64
BLSSize = 144
BandersnatchRingSize = 144
MetadataSize = 128
)
6 changes: 6 additions & 0 deletions internal/crypto/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ package crypto

import (
"crypto/ed25519"
"github.com/eigerco/strawberry/internal/time"
)

type Ed25519PublicKey ed25519.PublicKey
type Ed25519PrivateKey ed25519.PrivateKey
type BlsKey [BLSSize]byte
type BandersnatchKey [BandersnatchSize]byte
type MetadataKey [MetadataSize]byte
type RingCommitment [BandersnatchRingSize]byte
type EpochKeys [time.TimeslotsPerEpoch]BandersnatchKey
13 changes: 13 additions & 0 deletions internal/safrole/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package safrole

const (
// Custom error codes as defined here https://github.com/w3f/jamtestvectors/blob/master/safrole/safrole.asn#L30

BadSlot CustomErrorCode = 0 // Timeslot value must be strictly monotonic.
UnexpectedTicket CustomErrorCode = 1 // Received a ticket while in epoch's tail.
BadTicketOrder CustomErrorCode = 2 // Tickets must be sorted.
BadTicketProof CustomErrorCode = 3 // Invalid ticket ring proof.
BadTicketAttempt CustomErrorCode = 4 // Invalid ticket attempt value.
Reserved CustomErrorCode = 5 // Reserved
DuplicateTicket CustomErrorCode = 6 // Found a ticket duplicate.
)
134 changes: 134 additions & 0 deletions internal/safrole/safrole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package safrole

import (
"fmt"
"github.com/ChainSafe/gossamer/pkg/scale"
"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/time"
)

type TicketsBodies [time.TimeslotsPerEpoch]block.Ticket
type TicketsMark [time.TimeslotsPerEpoch]block.Ticket

type CustomErrorCode int

type Safrole struct {
Input Input
PreState State
Output OutputOrError
PostState State
}

type Input struct {
Slot uint32 // Current slot.
Entropy crypto.Hash // Per block entropy (originated from block entropy source VRF).
Extrinsic []block.TicketProof // Safrole extrinsic.
}

// TicketsOrKeys is enum
type TicketsOrKeys struct {
inner any
}

type TicketsOrKeysValues interface {
crypto.EpochKeys | TicketsBodies
}

func setTicketsOrKeys[Value TicketsOrKeysValues](tok *TicketsOrKeys, value Value) {
tok.inner = value
}

func (tok *TicketsOrKeys) SetValue(value any) (err error) {
switch value := value.(type) {
case crypto.EpochKeys:
setTicketsOrKeys(tok, value)
return nil
case TicketsBodies:
setTicketsOrKeys(tok, value)
return nil
default:
return fmt.Errorf("unsupported type")
}
}

func (tok TicketsOrKeys) IndexValue() (index uint, value any, err error) {
switch tok.inner.(type) {
case crypto.EpochKeys:
return 1, tok.inner, nil
case TicketsBodies:
return 2, tok.inner, nil
}
return 0, nil, scale.ErrUnsupportedVaryingDataTypeValue
}

func (tok TicketsOrKeys) Value() (value any, err error) {
_, value, err = tok.IndexValue()
return
}

func (tok TicketsOrKeys) ValueAt(index uint) (value any, err error) {
switch index {
case 1:
return crypto.EpochKeys{}, nil
case 2:
return TicketsBodies{}, nil
}
return nil, scale.ErrUnknownVaryingDataTypeValue
}

// OutputOrError is the output from Safrole protocol
type OutputOrError struct {
inner any
}

type OutputOrErrorValues interface {
OutputMarks | CustomErrorCode
}

type OutputMarks struct {
EpochMark *block.EpochMarker
TicketsMark *TicketsMark
}

func setOutputOrError[Value OutputOrErrorValues](oe *OutputOrError, value Value) {
oe.inner = value
}

func (oe *OutputOrError) SetValue(value any) (err error) {
switch value := value.(type) {
case OutputMarks:
setOutputOrError(oe, value)
return nil
case CustomErrorCode:
setOutputOrError(oe, value)
return nil
default:
return fmt.Errorf("unsupported type")
}
}

func (oe OutputOrError) IndexValue() (index uint, value any, err error) {
switch oe.inner.(type) {
case OutputMarks:
return 1, oe.inner, nil
case CustomErrorCode:
return 2, oe.inner, nil
}
return 0, nil, scale.ErrUnsupportedVaryingDataTypeValue
}

func (oe OutputOrError) Value() (value any, err error) {
_, value, err = oe.IndexValue()
return
}

func (oe OutputOrError) ValueAt(index uint) (value any, err error) {
switch index {
case 1:
return OutputMarks{}, nil
case 2:
return CustomErrorCode(0), nil
}
return nil, scale.ErrUnknownVaryingDataTypeValue
}
27 changes: 27 additions & 0 deletions internal/safrole/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package safrole

import (
"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/crypto"
)

// State relevant to Safrole protocol
type State struct {
MostRecentTimeslot uint32 // (τ) Most recent block's timeslot.
EntropyAccumulator [4]crypto.Hash // (η) Entropy accumulator and epochal randomness.
PreviousValidators ValidatorsData // (λ) Validator keys and metadata which were active in the prior epoch.
CurrentValidators ValidatorsData // (κ) Validator keys and metadata currently active.
NextValidators ValidatorsData // (γk) Validator keys for the following epoch.
FutureValidators ValidatorsData // (ι) Validator keys and metadata to be drawn from next.
TicketAccumulator []block.Ticket // (γa) Sealing-key contest ticket accumulator.
SealingKeySeries TicketsOrKeys // (γs) Sealing-key series of the current epoch.
RingCommitment crypto.RingCommitment // (γz) Bandersnatch ring commitment.
}

type ValidatorData struct {
Bandersnatch crypto.BandersnatchKey
Ed25519 crypto.Ed25519PublicKey
Bls crypto.BlsKey
Metadata crypto.MetadataKey
}
type ValidatorsData [block.NumberOfValidators]ValidatorData

0 comments on commit c3dd4e3

Please sign in to comment.