Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions validator/server_arb/proof_enhancer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2025, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE.md
package server_arb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing that's not really apparent yet is how you'll use this interface.
Having it in server_arb suggests the intention is to have the execution client connect to the custom_da proof enhancer directly.
I think (not sure) a better option would be that the arbitrator will keep working as it is (almost stateless, responds to requests without making them), and have the consensus side so all the custom-da communication, including enhancing proofs (after it got the response from arbitrator and before it sends it to a one-step-proof).
In that case server_arb will be left unaffected.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I put it in the wrong place. I'll move it to validator/proofenhancement/


import (
"context"
"fmt"

"github.com/offchainlabs/nitro/arbutil"
)

const (
// Enhancement flag in machine status byte
ProofEnhancementFlag = 0x80

// Marker bytes for different enhancement types
MarkerCustomDAReadPreimage = 0xDA
MarkerCustomDAValidateCertificate = 0xDB
)

// ProofEnhancer enhances one-step proofs with additional data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be helpful to add information about why exactly these proofs need to be enhanced here for future reference. This will help folks understand the rationale without having to hunt down the source PR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some more description to the comments here.

type ProofEnhancer interface {
// EnhanceProof checks if enhancement is needed and applies it
// Returns the enhanced proof or the original if no enhancement needed
EnhanceProof(ctx context.Context, messageNum arbutil.MessageIndex, proof []byte) ([]byte, error)
}

// ProofEnhancementManager manages multiple proof enhancers by marker type
type ProofEnhancementManager struct {
enhancers map[byte]ProofEnhancer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A type alias for byte here would make it clear it is a ProofMarkerType

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the type alias.

}

// NewProofEnhancementManager creates a new proof enhancement manager
func NewProofEnhancementManager() *ProofEnhancementManager {
return &ProofEnhancementManager{
enhancers: make(map[byte]ProofEnhancer),
}
}

// RegisterEnhancer registers an enhancer for a specific marker byte
func (m *ProofEnhancementManager) RegisterEnhancer(marker byte, enhancer ProofEnhancer) {
m.enhancers[marker] = enhancer
}

// EnhanceProof implements ProofEnhancer interface
func (m *ProofEnhancementManager) EnhanceProof(ctx context.Context, messageNum arbutil.MessageIndex, proof []byte) ([]byte, error) {
if len(proof) == 0 {
return proof, nil
}

// Check if enhancement flag is set
if proof[0]&ProofEnhancementFlag == 0 {
return proof, nil // No enhancement needed
}

// Find marker at end of proof
if len(proof) < 1 { // Need at least the marker byte
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this come before the enhancement flag check, otherwise we will panic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above we're checking if len(proof) == 0, so we know there's at least 1 byte before checking proof[0].

I changed this line to be len(proof) < 2 since we need the enhancement flag and the marker byte.

return nil, fmt.Errorf("proof too short for enhancement: %d bytes", len(proof))
}

marker := proof[len(proof)-1]
enhancer, exists := m.enhancers[marker]
if !exists {
return nil, fmt.Errorf("unknown enhancement marker: 0x%02x", marker)
}

// Remove enhancement flag from machine status
enhancedProof := make([]byte, len(proof))
copy(enhancedProof, proof)
enhancedProof[0] &= ^byte(ProofEnhancementFlag)

// Let specific enhancer handle the proof
return enhancer.EnhanceProof(ctx, messageNum, enhancedProof)
}
Loading
Loading