Skip to content

Commit

Permalink
feat: use execution status to split proofs
Browse files Browse the repository at this point in the history
  • Loading branch information
ratankaliani committed Dec 17, 2024
1 parent 1b516bb commit efc7036
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 31 deletions.
37 changes: 26 additions & 11 deletions proposer/op/proposer/prove.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (l *L2OutputSubmitter) ProcessProvingRequests() error {
l.Metr.RecordError("get_proof_status", 1)
return err
}
if proofStatus.Status == SP1FulfillmentStatusFulfilled {
if proofStatus.FulfillmentStatus == SP1FulfillmentStatusFulfilled {
// Update the proof in the DB and update status to COMPLETE.
l.Log.Info("Fulfilled Proof", "id", req.ProverRequestID)
err = l.db.AddFulfilledProof(req.ID, proofStatus.Proof)
Expand All @@ -50,7 +50,7 @@ func (l *L2OutputSubmitter) ProcessProvingRequests() error {
continue
}

if proofStatus.Status == SP1FulfillmentStatusUnfulfillable {
if proofStatus.FulfillmentStatus == SP1FulfillmentStatusUnfulfillable {
// Record the failure reason.
l.Log.Info("Proof is unfulfillable", "id", req.ProverRequestID)
l.Metr.RecordProveFailure("unfulfillable")
Expand Down Expand Up @@ -88,22 +88,37 @@ func (l *L2OutputSubmitter) ProcessWitnessgenRequests() error {
// If an error response is received:
// - Range Proof: Split in two if the block range is > 1. Retry the same request if range is 1 block.
// - Agg Proof: Retry the same request.
// TODO: Once the reserved strategy adds an execution error, update this to retry only when there's an execution error returned.
// TODO: With a new allocator, there will not be OOM issues.
func (l *L2OutputSubmitter) RetryRequest(req *ent.ProofRequest, status ProofStatusResponse) error {
err := l.db.UpdateProofStatus(req.ID, proofrequest.StatusFAILED)
if err != nil {
l.Log.Error("failed to update proof status", "err", err)
return err
}

// TODO: Once execution errors are added, update this to split the range only when there's an execution error returned on
// a SPAN proof.
// Retry same request.
err = l.db.NewEntry(req.Type, req.StartBlock, req.EndBlock)
if err != nil {
l.Log.Error("failed to retry proof request", "err", err)
return err
// If there's an execution error AND the request is a SPAN proof AND the block range is > 1, split the request into two requests.
// This is likely caused by an SP1 OOM due to a large block range with many transactions.
// TODO: This solution can be removed once the embedded allocator is used, because then the programs
// will never OOM.
if req.Type == proofrequest.TypeSPAN && status.ExecutionStatus == SP1ExecutionStatusUnexecutable && req.EndBlock-req.StartBlock > 1 {
// Split the request into two requests.
midBlock := (req.StartBlock + req.EndBlock) / 2
err = l.db.NewEntry(req.Type, req.StartBlock, midBlock)
if err != nil {
l.Log.Error("failed to retry first half of proof request", "err", err)
return err
}
err = l.db.NewEntry(req.Type, midBlock+1, req.EndBlock)
if err != nil {
l.Log.Error("failed to retry second half of proof request", "err", err)
return err
}
} else {
// Retry the same request.
err = l.db.NewEntry(req.Type, req.StartBlock, req.EndBlock)
if err != nil {
l.Log.Error("failed to retry proof request", "err", err)
return err
}
}

return nil
Expand Down
18 changes: 15 additions & 3 deletions proposer/op/proposer/rpc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (d UnclaimDescription) String() string {
}
}

// SP1ProofStatus represents the status of a proof in the SP1 network.
// SP1FulfillmentStatus represents the status of a proof in the SP1 network.
type SP1FulfillmentStatus int

const (
Expand All @@ -64,8 +64,20 @@ const (
SP1FulfillmentStatusUnfulfillable
)

// SP1ExecutionStatus represents the status of the execution of a proof in the SP1 network.
type SP1ExecutionStatus int

const (
SP1ExecutionStatusUnspecified SP1ExecutionStatus = iota
SP1ExecutionStatusUnexecuted
SP1ExecutionStatusExecuted
SP1ExecutionStatusUnexecutable
)

// ProofStatusResponse is the response type for the `/status/:proof_id` RPC from the op-succinct-server.
type ProofStatusResponse struct {
Status SP1FulfillmentStatus `json:"status"`
Proof []byte `json:"proof"`
FulfillmentStatus SP1FulfillmentStatus `json:"fulfillment_status"`
ExecutionStatus SP1ExecutionStatus `json:"execution_status"`
Proof []byte `json:"proof"`
}

37 changes: 23 additions & 14 deletions proposer/succinct/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use op_succinct_proposer::{
use sp1_sdk::{
network_v2::{
client::NetworkClient,
proto::network::{FulfillmentStatus, FulfillmentStrategy, ProofMode},
proto::network::{ExecutionStatus, FulfillmentStatus, FulfillmentStrategy, ProofMode},
},
utils, HashableKey, NetworkProverV2, ProverClient, SP1Proof, SP1ProofWithPublicValues,
};
Expand Down Expand Up @@ -400,7 +400,8 @@ async fn request_mock_span_proof(
Ok((
StatusCode::OK,
Json(ProofStatus {
status: sp1_sdk::network::proto::network::ProofStatus::ProofFulfilled.into(),
fulfillment_status: FulfillmentStatus::Fulfilled.into(),
execution_status: ExecutionStatus::UnspecifiedExecutionStatus.into(),
proof: proof_bytes,
}),
))
Expand Down Expand Up @@ -489,7 +490,8 @@ async fn request_mock_agg_proof(
Ok((
StatusCode::OK,
Json(ProofStatus {
status: sp1_sdk::network::proto::network::ProofStatus::ProofFulfilled.into(),
fulfillment_status: FulfillmentStatus::Fulfilled.into(),
execution_status: ExecutionStatus::UnspecifiedExecutionStatus.into(),
proof: proof.bytes(),
}),
))
Expand Down Expand Up @@ -517,7 +519,8 @@ async fn get_proof_status(
return Ok((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ProofStatus {
status: FulfillmentStatus::UnspecifiedFulfillmentStatus.into(),
fulfillment_status: FulfillmentStatus::UnspecifiedFulfillmentStatus.into(),
execution_status: ExecutionStatus::UnspecifiedExecutionStatus.into(),
proof: vec![],
}),
));
Expand All @@ -526,16 +529,17 @@ async fn get_proof_status(
return Ok((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ProofStatus {
status: FulfillmentStatus::UnspecifiedFulfillmentStatus.into(),
fulfillment_status: FulfillmentStatus::UnspecifiedFulfillmentStatus.into(),
execution_status: ExecutionStatus::UnspecifiedExecutionStatus.into(),
proof: vec![],
}),
));
}
};

// TODO: Use execution error for reserved once it's added.
let status = status.fulfillment_status();
if status == FulfillmentStatus::Fulfilled {
let fulfillment_status = status.fulfillment_status;
let execution_status = status.execution_status;
if fulfillment_status == FulfillmentStatus::Fulfilled as i32 {
let proof: SP1ProofWithPublicValues = maybe_proof.unwrap();

match proof.proof {
Expand All @@ -547,7 +551,8 @@ async fn get_proof_status(
return Ok((
StatusCode::OK,
Json(ProofStatus {
status: status.into(),
fulfillment_status: fulfillment_status.into(),
execution_status: execution_status.into(),
proof: proof_bytes,
}),
));
Expand All @@ -558,7 +563,8 @@ async fn get_proof_status(
return Ok((
StatusCode::OK,
Json(ProofStatus {
status: status.into(),
fulfillment_status: fulfillment_status.into(),
execution_status: execution_status.into(),
proof: proof_bytes,
}),
));
Expand All @@ -569,26 +575,29 @@ async fn get_proof_status(
return Ok((
StatusCode::OK,
Json(ProofStatus {
status: status.into(),
fulfillment_status: fulfillment_status.into(),
execution_status: execution_status.into(),
proof: proof_bytes,
}),
));
}
_ => (),
}
} else if status == FulfillmentStatus::Unfulfillable {
} else if fulfillment_status == FulfillmentStatus::Unfulfillable as i32 {
return Ok((
StatusCode::OK,
Json(ProofStatus {
status: status.into(),
fulfillment_status: fulfillment_status.into(),
execution_status: execution_status.into(),
proof: vec![],
}),
));
}
Ok((
StatusCode::OK,
Json(ProofStatus {
status: status.into(),
fulfillment_status: fulfillment_status.into(),
execution_status: execution_status.into(),
proof: vec![],
}),
))
Expand Down
6 changes: 3 additions & 3 deletions proposer/succinct/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ impl From<String> for UnclaimDescription {
#[derive(Serialize, Deserialize)]
/// The status of a proof request.
pub struct ProofStatus {
// Note: Can't use `SP1FulfillmentStatus` directly because `Serialize_repr` and `Deserialize_repr` aren't derived on it.
// serde_repr::Serialize_repr and Deserialize_repr are necessary to use `SP1FulfillmentStatus` in this struct.
pub status: i32,
// Note: Can't use `FulfillmentStatus`/`ExecutionStatus` directly because `Serialize_repr` and `Deserialize_repr` aren't derived on it.
pub fulfillment_status: i32,
pub execution_status: i32,
pub proof: Vec<u8>,
}

Expand Down

0 comments on commit efc7036

Please sign in to comment.