Skip to content

Commit

Permalink
Proof aggregation improvements (#14)
Browse files Browse the repository at this point in the history
* Only clear pending proofs if the enclave returns an error

* Only generate batchSize proofs before aggregating

* Tiny logging improvement

* Fix count off-by-1
  • Loading branch information
mdehoog authored Nov 6, 2024
1 parent 1af0179 commit e9427f7
Showing 1 changed file with 28 additions and 21 deletions.
49 changes: 28 additions & 21 deletions op-proposer/proposer/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)

const aggregateBatchSize = 1000
Expand Down Expand Up @@ -257,25 +258,29 @@ func (l *L2OutputSubmitter) generateOutputs(ctx context.Context, latestOutput bi
}
}

for i := latestOutputNumber + 1; ; i++ {
block, err := l.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(i))
// calculate `aggregateBatchSize` proofs at once, which are then aggregated in `nextOutput`
for i := uint64(0); i < aggregateBatchSize; i++ {
number := i + latestOutputNumber + 1
block, err := l.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(number))
if errors.Is(err, ethereum.NotFound) {
return nil
break
}
if err != nil {
return fmt.Errorf("failed to get block %d: %w", i, err)
return fmt.Errorf("failed to get block %d: %w", number, err)
}

proposal, err := l.prover.Generate(ctx, block)
if err != nil {
return fmt.Errorf("failed to generate proof for block %d: %w", i, err)
return fmt.Errorf("failed to generate proof for block %d: %w", number, err)
}

l.Log.Info("Generated proof for block",
"block", l2BlockRefToBlockID(proposal.To), "l1Origin", proposal.To.L1Origin,
"withdrawals", proposal.Withdrawals, "output", proposal.Output.OutputRoot.String())
l.pending = append(l.pending, proposal)
}

return nil
}

func (l *L2OutputSubmitter) nextOutput(ctx context.Context, latestOutput bindings.TypesOutputProposal) (*Proposal, bool, error) {
Expand All @@ -285,32 +290,34 @@ func (l *L2OutputSubmitter) nextOutput(ctx context.Context, latestOutput binding
return nil, false, err
}

var proposals []*Proposal
for _, proposal := range l.pending {
if proposal.To.Number > latestSafe.Number {
break
}
proposals = append(proposals, proposal)
count := 0
for count < len(l.pending) && l.pending[count].To.Number < latestSafe.Number {
count++
}
if len(proposals) == 0 {
if count <= 0 {
return nil, false, nil
}
l.pending = l.pending[len(proposals):]

for len(proposals) > 1 {
batchLength := min(len(proposals), aggregateBatchSize)
batch := proposals[:batchLength]
for count > 1 {
batchLength := min(count, aggregateBatchSize)
batch := l.pending[:batchLength]
aggregated, err := l.prover.Aggregate(ctx, latestOutput.OutputRoot, batch)
if err != nil {
return nil, false, fmt.Errorf("failed to aggregate proofs: %w", err)
var rpcError rpc.Error
if errors.As(err, &rpcError) {
// if we received an explicit error from the enclave (like "invalid signer"), clear the pending proofs
l.Log.Warn("Non-recoverable error aggregating proofs", "err", err)
l.pending = nil
}
return nil, false, err
}
l.pending = append([]*Proposal{aggregated}, l.pending[batchLength:]...)
count -= batchLength - 1
l.Log.Info("Aggregated proofs",
"output", aggregated.Output.OutputRoot.String(), "blocks", batchLength, "remaining", len(proposals),
"output", aggregated.Output.OutputRoot.String(), "blocks", batchLength, "remaining", count-1,
"withdrawals", aggregated.Withdrawals, "from", aggregated.From.Number, "to", aggregated.To.Number)
proposals = append([]*Proposal{aggregated}, proposals[batchLength:]...)
}
proposal := proposals[0]
l.pending = append([]*Proposal{proposal}, l.pending...)
proposal := l.pending[0]

if proposal.To.Hash != latestSafe.Hash {
l.Log.Warn("Aggregated output does not match the latest batched block, possible reorg",
Expand Down

0 comments on commit e9427f7

Please sign in to comment.