Skip to content

Commit

Permalink
Review reports and implement exporting.
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-romano committed Jan 29, 2025
1 parent 70e04d2 commit 1dec4f2
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 18 deletions.
7 changes: 3 additions & 4 deletions internal/block/guarantee.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ type CredentialSignature struct {
Signature [crypto.Ed25519SignatureSize]byte // The Ed25519 signature
}

// WorkReport represents a work report in the JAM state (equation 11.2 v0.5.0)
// TODO: The total serialized size of a work-report may be no greater than MaxWorkPackageSizeBytes.
// WorkReport represents a work report in the JAM state (equation 11.2 v0.5.4)
type WorkReport struct {
WorkPackageSpecification WorkPackageSpecification // Work-package specification (s)
RefinementContext RefinementContext // Refinement context (x)
Expand All @@ -46,11 +45,11 @@ type WorkPackageSpecification struct {
SegmentCount uint16 // Segment count (n)
}

// RefinementContext describes the context of the chain at the point that the report’s corresponding work-package was evaluated.
// RefinementContext describes the context of the chain at the point that the report’s corresponding work-package was evaluated. 11.4 GP 0.5.4
type RefinementContext struct {
Anchor RefinementContextAnchor // Historical block anchor
LookupAnchor RefinementContextLookupAnchor // Historical block anchor
PrerequisiteWorkPackage []crypto.Hash // Prerequisite work package (p) (optional)
PrerequisiteWorkPackage []crypto.Hash // Prerequisite work package (p)
}

type RefinementContextAnchor struct {
Expand Down
40 changes: 39 additions & 1 deletion internal/polkavm/common.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package polkavm

import (
"fmt"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/merkle/binary_tree"
"github.com/eigerco/strawberry/internal/work"
"github.com/eigerco/strawberry/pkg/serialization/codec/jam"

"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/common"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/service"
"github.com/eigerco/strawberry/internal/state"
)
Expand Down Expand Up @@ -298,3 +303,36 @@ type RefineContextPair struct {
IntegratedPVMMap map[uint64]IntegratedPVM //m
Segments []Segment //e
}

// ComputePagedProofs P(s) → [E(J₆(s,i), L₆(s,i))₍l₎ | i ∈ ℕ₍⌈|s|/64⌉₎] (14.10 v0.5.4)
func ComputePagedProofs(r *RefineContextPair) ([]Segment, error) {
if len(r.Segments) == 0 {
return nil, fmt.Errorf("no segments provided")
}
blobs := make([][]byte, len(r.Segments))
for i, seg := range r.Segments {
blobs[i] = seg[:]
}
numPages := len(r.Segments) / work.SegmentsPerPage
pagedProofs := make([]Segment, numPages)

for pageIndex := 0; pageIndex < numPages; pageIndex++ {
// Get leaf hashes and proof for page
leafHashes := binary_tree.GetLeafPage(blobs, pageIndex, work.NumberOfErasureCodecPiecesInSegment, crypto.HashData)
proof := binary_tree.GeneratePageProof(blobs, pageIndex, work.NumberOfErasureCodecPiecesInSegment, crypto.HashData)

// Encode leaves and proof
marshalledLeaves, err := jam.Marshal(leafHashes)
if err != nil {
return nil, fmt.Errorf("failed to marshal leaf hashes: %w", err)
}
marshalledProof, err := jam.Marshal(proof)
if err != nil {
return nil, fmt.Errorf("failed to marshal proof: %w", err)
}
combined := append(marshalledLeaves, marshalledProof...)
padded := work.ZeroPadding(combined, work.SizeOfSegment)
copy(pagedProofs[pageIndex][:], padded)
}
return pagedProofs, nil
}
100 changes: 100 additions & 0 deletions internal/polkavm/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package polkavm

import (
"bytes"
"testing"

"github.com/eigerco/strawberry/internal/work"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// Helper functions
func createTestSegment(pattern byte) (seg Segment) {
for i := range seg {
seg[i] = pattern
}
return seg
}

func createSegments(count int) []Segment {
segments := make([]Segment, count)
for i := range segments {
segments[i] = createTestSegment(0x42)
}
return segments
}

func TestComputePagedProofs(t *testing.T) {
tests := []struct {
name string
inputSegments []Segment
expectError bool
errorMessage string
}{
{
name: "empty segments",
inputSegments: []Segment{},
expectError: true,
errorMessage: "no segments provided",
},
{
name: "single page of segments",
inputSegments: createSegments(work.SegmentsPerPage),
expectError: false,
},
{
name: "multiple pages of segments",
inputSegments: createSegments(work.SegmentsPerPage * 2),
expectError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := &RefineContextPair{
IntegratedPVMMap: make(map[uint64]IntegratedPVM),
Segments: tt.inputSegments,
}

proofs, err := ComputePagedProofs(ctx)

if tt.expectError {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.errorMessage)
return
}

require.NoError(t, err)
expectedNumPages := len(tt.inputSegments) / work.SegmentsPerPage
assert.Equal(t, expectedNumPages, len(proofs))
})
}
}

func TestComputePagedProofsConsistency(t *testing.T) {
// Create two identical sets of segments
segments1 := createSegments(work.SegmentsPerPage)
segments2 := createSegments(work.SegmentsPerPage)

ctx1 := &RefineContextPair{
IntegratedPVMMap: make(map[uint64]IntegratedPVM),
Segments: segments1,
}

ctx2 := &RefineContextPair{
IntegratedPVMMap: make(map[uint64]IntegratedPVM),
Segments: segments2,
}

proofs1, err := ComputePagedProofs(ctx1)
require.NoError(t, err)

proofs2, err := ComputePagedProofs(ctx2)
require.NoError(t, err)

assert.Equal(t, len(proofs1), len(proofs2))
for i := range proofs1 {
assert.True(t, bytes.Equal(proofs1[i][:], proofs2[i][:]))
}
}
2 changes: 1 addition & 1 deletion internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (sa ServiceAccount) AddPreimage(p []byte, currentTimeslot jamtime.Timeslot)
return nil
}

// LookupPreimage implements the historical lookup function (Λ) as defined in Equation (9.7 v0.5.0).
// LookupPreimage implements the historical lookup function (Λ) as defined in Equation (9.7 v0.5.4).
func (sa ServiceAccount) LookupPreimage(t jamtime.Timeslot, h crypto.Hash) []byte {
p, exists := sa.PreimageLookup[h]
if !exists {
Expand Down
2 changes: 1 addition & 1 deletion internal/statetransition/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -1367,7 +1367,7 @@ func ValidateExtrinsicGuarantees(
prerequisitePackageHashes[key] = struct{}{}
}

// Check total dependencies
// Check total dependencies. 11.3 GP 0.5.4
totalDeps := len(guarantee.WorkReport.RefinementContext.PrerequisiteWorkPackage) +
len(guarantee.WorkReport.SegmentRootLookup)
if totalDeps > common.WorkReportMaxSumOfDependencies {
Expand Down
5 changes: 3 additions & 2 deletions internal/work/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const (
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.
SizeOfSegment = NumberOfErasureCodecPiecesInSegment * SizeOfErasureCodecPiecesInOctets // WG = WP*WE = 4104: The size of a segment in octets.
MaxSizeOfEncodedWorkPackage = 12 * 1 << 20 // WB = 12*2^20 = 12MB: The maximum size of an encoded work-package together with its extrinsic data and import implications, in octets.
MaxAllocatedGasRefine = 500_000_000 // GR = 500, 000, 000: The gas allocated to invoke a work-package’s Refine logic.
SegmentsPerPage = 64
MaxSizeOfEncodedWorkPackage = 12 * 1 << 20 // WB = 12*2^20 = 12MB: The maximum size of an encoded work-package together with its extrinsic data and import implications, in octets.
MaxAllocatedGasRefine = 500_000_000 // GR = 500, 000, 000: The gas allocated to invoke a work-package’s Refine logic.
)
4 changes: 2 additions & 2 deletions internal/work/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Extrinsic struct {
Length uint32
}

// Item represents I (14.2 v0.5.2)
// Item represents I (14.2 v0.5.4)
type Item struct {
ServiceId uint32 // s ∈ N_S
CodeHash crypto.Hash // c ∈ H
Expand All @@ -37,7 +37,7 @@ func (w *Item) Size() uint64 {
return total
}

// ToWorkResult item-to-result function C (14.8 v0.5.2)
// ToWorkResult item-to-result function C (14.8 v0.5.4)
func (w *Item) ToWorkResult(o block.WorkResultOutputOrError) block.WorkResult {
payloadHash := crypto.HashData(w.Payload)

Expand Down
13 changes: 6 additions & 7 deletions internal/work/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ package work

import (
"fmt"

"github.com/eigerco/strawberry/internal/block"
"github.com/eigerco/strawberry/internal/common"
"github.com/eigerco/strawberry/internal/crypto"
"github.com/eigerco/strawberry/internal/service"
)

// Package represents P (14.2 v0.5.2)
// Package represents P (14.2 v0.5.4)
type Package struct {
AuthorizationToken []byte // j ∈ Y
AuthorizerService uint32 // h ∈ N_S
Expand All @@ -19,7 +18,7 @@ type Package struct {
WorkItems []Item // w ∈ ⟦I⟧
}

// ValidateNumberOfEntries (14.4 v0.5.2)
// ValidateNumberOfEntries (14.4 v0.5.4)
func (wp *Package) ValidateNumberOfEntries() error {
var totalExported, totalImported uint16
for _, w := range wp.WorkItems {
Expand All @@ -37,7 +36,7 @@ func (wp *Package) ValidateNumberOfEntries() error {
return nil
}

// ValidateSize (14.5 v0.5.2)
// ValidateSize (14.5 v0.5.4)
func (wp *Package) ValidateSize() error {
totalSize := uint64(len(wp.AuthorizationToken)) + uint64(len(wp.Parameterization))

Expand All @@ -52,7 +51,7 @@ func (wp *Package) ValidateSize() error {
return nil
}

// ValidateGas (14.7 v0.5.2)
// ValidateGas (14.7 v0.5.4)
func (wp *Package) ValidateGas() error {
var totalAccumulate, totalRefine uint64
for _, w := range wp.WorkItems {
Expand All @@ -70,7 +69,7 @@ func (wp *Package) ValidateGas() error {
return nil
}

// ComputeAuthorizerHashes (14.9 v0.5.2)
// ComputeAuthorizerHashes (14.9 v0.5.4)
func (wp *Package) ComputeAuthorizerHashes(
serviceState service.ServiceState,
) (authorizationCode []byte, impliedAuthorizerHash crypto.Hash, err error) {
Expand All @@ -85,7 +84,7 @@ func (wp *Package) ComputeAuthorizerHashes(
return authorizationCode, impliedAuthorizerHash, nil
}

// GetAuthorizationCode pc = Λ(δ[p.h], (p.x)^t, p.u) (14.9 v0.5.2)
// GetAuthorizationCode pc = Λ(δ[p.h], (p.x)^t, p.u) (14.9 v0.5.4)
func (wp *Package) GetAuthorizationCode(serviceState service.ServiceState) ([]byte, error) {
// Retrieve the service account by authorizer service index p.h
sa, exists := serviceState[block.ServiceId(wp.AuthorizerService)]
Expand Down

0 comments on commit 1dec4f2

Please sign in to comment.