Skip to content

Commit

Permalink
Merge branch 'main' into refactor/upgrade-to-v0.5.4
Browse files Browse the repository at this point in the history
  • Loading branch information
danielvladco committed Jan 21, 2025
2 parents 6770541 + 78505ff commit 9c7da86
Show file tree
Hide file tree
Showing 25 changed files with 1,056 additions and 235 deletions.
2 changes: 2 additions & 0 deletions internal/block/ticket.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type Ticket struct {
EntryIndex uint8 // r ∈ Nn (0, 1)
}

func (t Ticket) TicketOrKeyType() {}

// TicketProof represents a proof of a valid ticket
type TicketProof struct {
EntryIndex uint8 // r ∈ Nn (0, 1)
Expand Down
8 changes: 8 additions & 0 deletions internal/crypto/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@ type Ed25519Signature [Ed25519SignatureSize]byte
type BlsKey [BLSSize]byte
type BandersnatchSeedKey [BandersnatchSize]byte
type BandersnatchPrivateKey [BandersnatchSize]byte

type BandersnatchPublicKey [BandersnatchSize]byte

func (b BandersnatchPublicKey) TicketOrKeyType() {}

type BandersnatchSignature [96]byte
type BandersnatchOutputHash [32]byte
type RingVrfSignature [VrfProofSize]byte
type MetadataKey [MetadataSize]byte
type RingCommitment [BandersnatchRingSize]byte

type EpochKeys [jamtime.TimeslotsPerEpoch]BandersnatchPublicKey

func (e EpochKeys) TicketsOrKeysType() {}

type ValidatorKey struct {
Bandersnatch BandersnatchPublicKey
Ed25519 ed25519.PublicKey
Expand Down
61 changes: 59 additions & 2 deletions internal/polkavm/host_call/accumulate_functions.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package host_call

import (
"bytes"

"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/common"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/jamtime"
. "github.com/eigerco/strawberry/internal/polkavm"
"github.com/eigerco/strawberry/internal/service"
"github.com/eigerco/strawberry/internal/state"
"github.com/eigerco/strawberry/pkg/serialization/codec/jam"
)

// Bless ΩB(ϱ, ω, μ, (x, y))
Expand Down Expand Up @@ -253,9 +256,63 @@ func Eject(gas Gas, regs Registers, mem Memory, ctxPair AccumulateContextPair, t
}
gas -= EjectCost

// TODO: implement method
d, o := regs[A0], regs[A1]

return gas, regs, mem, ctxPair, nil
// let h = μo..o+32 if Zo..o+32 ⊂ Vμ
h := make([]byte, 32)
if err := mem.Read(uint32(o), h); err != nil {
// otherwise ∇
return gas, withCode(regs, OOB), mem, ctxPair, nil
}

if block.ServiceId(d) == ctxPair.RegularCtx.ServiceId {
// d = x_s => WHO
return gas, withCode(regs, WHO), mem, ctxPair, nil
}

// if d ∈ K((x_u)_d)
serviceAccount, ok := ctxPair.RegularCtx.AccumulationState.ServiceState[block.ServiceId(d)]
if !ok {
return gas, withCode(regs, WHO), mem, ctxPair, nil
}

encodedXs, err := jam.Marshal(struct {
ServiceId block.ServiceId `jam:"length=32"`
}{ctxPair.RegularCtx.ServiceId})
if err != nil || !bytes.Equal(serviceAccount.CodeHash[:], encodedXs) {
// d_c ≠ E32(x_s) => WHO
return gas, withCode(regs, WHO), mem, ctxPair, err
}

if serviceAccount.TotalItems() != 2 {
// d_i ≠ 2 => HUH
return gas, withCode(regs, HUH), mem, ctxPair, nil
}

// l = max(81, d_o) - 81
l := max(81, len(serviceAccount.Code())) - 81

key := service.PreImageMetaKey{Hash: crypto.Hash(h), Length: service.PreimageLength(l)}
dL, ok := serviceAccount.PreimageMeta[key]
if !ok {
// (h, l) ∉ d_l => HUH
return gas, withCode(regs, HUH), mem, ctxPair, nil
}

// if d_l[h, l] = [x, y], y < t − D => OK
if len(dL) == 2 && dL[1] < timeslot-jamtime.PreimageExpulsionPeriod {
xs := ctxPair.RegularCtx.ServiceAccount()
// s'_b = ((x_u)d)[x_s]b + d_b
xs.Balance += serviceAccount.Balance

delete(ctxPair.RegularCtx.AccumulationState.ServiceState, block.ServiceId(d))
ctxPair.RegularCtx.AccumulationState.ServiceState[ctxPair.RegularCtx.ServiceId] = xs

return gas, withCode(regs, OK), mem, ctxPair, nil
}

// otherwise => HUH
return gas, withCode(regs, HUH), mem, ctxPair, nil
}

// Query ΩQ(ϱ, ω, μ, (x, y))
Expand Down
65 changes: 65 additions & 0 deletions internal/polkavm/host_call/accumulate_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,71 @@ func TestAccumulate(t *testing.T) {
}},
},
},
{
name: "eject",
fn: fnTms(Eject),
initialGas: 100,
timeslot: 200,
initialRegs: deltaRegs{
A0: 999,
},
alloc: alloc{
A1: hash2bytes(randomHash),
},
X: AccumulateContext{
ServiceId: 222,
AccumulationState: state.AccumulationState{
ServiceState: service.ServiceState{
// d = 999 (the ejected service)
999: func() service.ServiceAccount {
e32, err := jam.Marshal(struct {
ServiceId block.ServiceId `jam:"length=32"`
}{222})
require.NoError(t, err)

var codeHash crypto.Hash
copy(codeHash[:], e32)

preImgLookup := map[crypto.Hash][]byte{
codeHash: make([]byte, 81),
}

preImgMeta := map[service.PreImageMetaKey]service.PreimageHistoricalTimeslots{
{Hash: randomHash, Length: 0}: {50, 100},
}

return service.ServiceAccount{
CodeHash: codeHash,
Balance: 100, // d_b
PreimageLookup: preImgLookup,
PreimageMeta: preImgMeta,
}
}(),
// x_s
222: {
Balance: 1000,
},
},
},
},
expectedGas: 88,
expectedDeltaRegs: deltaRegs{
A0: uint64(OK),
},
// After success:
// - The ejected service 999 is removed
// - x_s(222).Balance = 1000+100=1100
expectedX: AccumulateContext{
ServiceId: 222,
AccumulationState: state.AccumulationState{
ServiceState: service.ServiceState{
222: {
Balance: 1100,
},
},
},
},
},
{
name: "solicit_out_of_gas",
fn: fnTms(Solicit),
Expand Down
45 changes: 28 additions & 17 deletions internal/safrole/safrole.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package safrole

import (
"fmt"

"github.com/eigerco/strawberry/pkg/serialization/codec/jam"

"github.com/eigerco/strawberry/internal/block"
Expand All @@ -11,48 +12,58 @@ import (

type TicketsBodies [jamtime.TimeslotsPerEpoch]block.Ticket

// TicketsOrKeys is enum
type TicketsOrKeys struct {
inner any
func (t TicketsBodies) TicketsOrKeysType() {}

// TicketAccumulator is enum/union that represents ya. It should contain either
// TicketBodies which is an array of tickets, or in the fallback case
// crypto.EpochKeys, an array of bandersnatch public keys.
type TicketAccumulator struct {
inner TicketsOrKeys
}

// TicketsOrKeys represents the union of either TicketBodies or
// crypto.EpochKeys.
type TicketsOrKeys interface {
TicketsOrKeysType()
}

type TicketsOrKeysValues interface {
crypto.EpochKeys | TicketsBodies
func (ta *TicketAccumulator) Set(value TicketsOrKeys) {
ta.inner = value
}

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

func (tok *TicketsOrKeys) SetValue(value any) error {
func (ta *TicketAccumulator) SetValue(value any) error {
switch value := value.(type) {
case crypto.EpochKeys:
setTicketsOrKeys(tok, value)
ta.inner = value
return nil
case TicketsBodies:
setTicketsOrKeys(tok, value)
ta.inner = value
return nil
default:
return fmt.Errorf(jam.ErrUnsupportedType, value)
}
}

func (tok TicketsOrKeys) IndexValue() (uint, any, error) {
switch tok.inner.(type) {
func (ta TicketAccumulator) IndexValue() (uint, any, error) {
switch ta.inner.(type) {
case crypto.EpochKeys:
return 1, tok.inner, nil
return 1, ta.inner, nil
case TicketsBodies:
return 0, tok.inner, nil
return 0, ta.inner, nil
}
return 0, nil, jam.ErrUnsupportedEnumTypeValue
}

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

func (tok TicketsOrKeys) ValueAt(index uint) (any, error) {
func (ta TicketAccumulator) ValueAt(index uint) (any, error) {
switch index {
case 1:
return crypto.EpochKeys{}, nil
Expand Down
2 changes: 1 addition & 1 deletion internal/safrole/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
type State struct {
NextValidators ValidatorsData // (γk) Validator keys for the following epoch.
TicketAccumulator []block.Ticket // (γa) Sealing-key contest ticket accumulator.
SealingKeySeries TicketsOrKeys // (γs) Sealing-key series of the current epoch.
SealingKeySeries TicketAccumulator // (γs) Sealing-key series of the current epoch.
RingCommitment crypto.RingCommitment // (γz) Bandersnatch ring commitment.
}

Expand Down
Loading

0 comments on commit 9c7da86

Please sign in to comment.