Skip to content

Commit

Permalink
feat: refine invocation
Browse files Browse the repository at this point in the history
  • Loading branch information
danielvladco committed Jan 6, 2025
1 parent 14c9618 commit a43ec12
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
121 changes: 121 additions & 0 deletions internal/refine/refine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package refine

import (
"errors"

"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/polkavm"
"github.com/eigerco/strawberry/internal/polkavm/host_call"
"github.com/eigerco/strawberry/internal/polkavm/interpreter"
"github.com/eigerco/strawberry/internal/state"
"github.com/eigerco/strawberry/internal/work"
"github.com/eigerco/strawberry/pkg/serialization/codec/jam"
)

const (
RefineCost = 10
)

var (
ErrBad = errors.New("service’s code was not available for lookup") // BAD
ErrBig = errors.New("code beyond the maximum size allowed") // BIG
)

type Refine struct {
state state.State
}

// InvokePVM ΨR(H, NG, NS , H, Y, X, H, Y, ⟦G⟧, ⟦Y⟧, N) → (Y ∪ J, ⟦Y⟧)
func (r *Refine) InvokePVM(
serviceCodePredictionHash crypto.Hash, gas uint64, serviceIndex block.ServiceId,
workPackageHash crypto.Hash, workPayload []byte, refinementContext block.RefinementContext,
authorizerHash crypto.Hash, authorizerHashOutput []byte, importedSegments []polkavm.Segment,
extrinsicDataBlobs [][]byte, exportOffset uint64,
) ([]byte, []polkavm.Segment, error) {
// let a = E(s, y, p, c, a, ↕o, ↕[↕x | x <− x])
args, err := jam.Marshal(struct {
ServiceIndex block.ServiceId
WorkPayload []byte
WorkPackageHash crypto.Hash
RefinementContext block.RefinementContext
AuthorizerHash crypto.Hash
AuthorizerHashOutput []byte
ExtrinsicDataBlobs [][]byte
}{
ServiceIndex: serviceIndex,
WorkPayload: workPayload,
WorkPackageHash: workPackageHash,
RefinementContext: refinementContext,
AuthorizerHash: authorizerHash,
AuthorizerHashOutput: authorizerHashOutput,
ExtrinsicDataBlobs: extrinsicDataBlobs, // we assume the extrinsic data is a ordered sequence
})
if err != nil {
return nil, nil, err
}

// if s ∉ K(δ) ∨ Λ(δ[s], ct, c) = ∅ then (BAD, [])
service, ok := r.state.Services[serviceIndex]
if !ok {
return nil, nil, ErrBad
}
code := service.LookupPreimage(refinementContext.LookupAnchor.Timeslot, serviceCodePredictionHash)
if code == nil {
return nil, nil, ErrBad
}

// if |Λ(δ[s], ct, c)| > W_C then (BIG, [])
if len(code) > work.MaxSizeServiceCode {
return nil, nil, ErrBig
}

// F ∈ Ω⟨(D⟨N → M⟩, ⟦Y⟧)⟩∶ (n, ϱ, ω, μ, (m, e))
hostCall := func(hostCall uint32, gasCounter polkavm.Gas, regs polkavm.Registers, mem polkavm.Memory, ctxPair polkavm.RefineContextPair) (polkavm.Gas, polkavm.Registers, polkavm.Memory, polkavm.RefineContextPair, error) {
switch hostCall {
case host_call.HistoricalLookupID:
gasCounter, regs, mem, ctxPair, err = host_call.HistoricalLookup(gasCounter, regs, mem, ctxPair, serviceIndex, r.state.Services, refinementContext.LookupAnchor.Timeslot)
case host_call.ImportID:
gasCounter, regs, mem, ctxPair, err = host_call.Import(gasCounter, regs, mem, ctxPair, importedSegments)
case host_call.ExportID:
gasCounter, regs, mem, ctxPair, err = host_call.Export(gasCounter, regs, mem, ctxPair, exportOffset)
case host_call.GasID:
gasCounter, regs, err = host_call.GasRemaining(gasCounter, regs)
case host_call.MachineID:
gasCounter, regs, mem, ctxPair, err = host_call.Machine(gasCounter, regs, mem, ctxPair)
case host_call.PeekID:
gasCounter, regs, mem, ctxPair, err = host_call.Peek(gasCounter, regs, mem, ctxPair)
case host_call.ZeroID:
gasCounter, regs, mem, ctxPair, err = host_call.Zero(gasCounter, regs, mem, ctxPair)
case host_call.PokeID:
gasCounter, regs, mem, ctxPair, err = host_call.Poke(gasCounter, regs, mem, ctxPair)
case host_call.VoidID:
gasCounter, regs, mem, ctxPair, err = host_call.Void(gasCounter, regs, mem, ctxPair)
case host_call.InvokeID:
gasCounter, regs, mem, ctxPair, err = host_call.Invoke(gasCounter, regs, mem, ctxPair)
case host_call.ExpungeID:
gasCounter, regs, mem, ctxPair, err = host_call.Expunge(gasCounter, regs, mem, ctxPair)
default:
regs[polkavm.A0] = uint64(host_call.WHAT)
gasCounter -= RefineCost

}
return gasCounter, regs, mem, ctxPair, nil
}

// (g, r, (m, e)) = ΨM(Λ(δ[s], ct, c), 0, g, a, F, (∅, []))∶
_, result, ctxPair, err := interpreter.InvokeWholeProgram(code, 0, gas, args, hostCall, polkavm.RefineContextPair{
IntegratedPVMMap: make(map[uint64]polkavm.IntegratedPVM),
Segments: []polkavm.Segment{},
})

// if r ∈ {∞, ☇} then (r, [])
if err != nil {
panicErr := &polkavm.ErrPanic{}
if errors.Is(err, polkavm.ErrOutOfGas) || errors.As(err, &panicErr) {
return nil, nil, err
}
}

return result, ctxPair.Segments, err
}
1 change: 1 addition & 0 deletions internal/work/constants.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package work

const (
MaxSizeServiceCode = 4000000 // WC = 4000000: The maximum size of service code in octets.
MaxNumberOfEntries = 1 << 11 // WM = 2^11: The maximum number of entries in a work-package manifest.
NumberOfErasureCodecPiecesInSegment = 6 // WP = 6: The number of erasure-coded pieces in a segment.
SizeOfErasureCodecPiecesInOctets = 684 // WE = 684: The basic size of erasure-coded pieces in octets.
Expand Down

0 comments on commit a43ec12

Please sign in to comment.