Advanced Usage
Advanced configuration and usage patterns for the Succinct Prover Network.
To use advanced features, you must set up a ProverClient
using ProverClient::builder().network()
instead of ProverClient::from_env()
.
// Default network client (uses `NETWORK_PRIVATE_KEY` env variable)
let client = ProverClient::builder()
.network()
.build();
// Network client with custom parameters
let client = ProverClient::builder()
.network()
.private_key("<PRIVATE_KEY>")
.rpc_url("<RPC_URL>")
.build();
You can see a full list of the builder parameters you can configure in the sp1-sdk docs.rs.
Skip Simulation
Skipping simulation locally can save minutes of latency depending on proof request size.
By default, the SDK will simulate program execution locally before submitting a proof request. This simulation takes anywhere from a few seconds to many minutes, depending on the size of your program. By adding .skip_simulation(true)
, you can skip the simulation step and send the proof optimistically. However, this means that if the program fails to execute, the proof request will fail with an "Unexecutable" error.
Since the network uses PGUs (prover gas units) for fee calculation, each request has a gas_limit
parameter that sets the maximum PGUs allowed for proof generation. This value is normally set during simulation. If you skip simulation, you should manually set a gas_limit
high enough to cover typical gas usage of your program.
let proof = client.prove(&pk, stdin)
.compressed()
.skip_simulation(true) // Skip simulation
.gas_limit(10_000_000_000) // 10B PGUs
.run()
.unwrap();
Timeout Configuration
If you set the timeout too low, it may be impossible for provers to fulfill.
Set custom timeouts for proof requests. If a proof request is not fulfilled within the timeout, it will be aborted and fees will not be refunded.
use std::time::Duration;
let proof = client.prove(&pk, &stdin)
.timeout(Duration::from_secs(3600)) // 1 hour timeout
.run()
.await?;
Auction Configuration
Make sure to disable default features and enable the network
feature on sp1-sdk
in script/Cargo.toml
:
[dependencies]
sp1-sdk = { version = "...", default-features = false, features = ["network"] }
Max Price Per PGU
Prover gas units (PGUs) measure the computational work required to generate a proof. The max_price_per_pgu
parameter lets requesters specify the maximum amount of PROVE they are willing to pay per PGU, protecting them from unexpected price escalation. If a value is not specified, a default value will be used.
If you set max_price_per_pgu
too low, the proof request may not receive any bids from provers. For most use cases, it is recommended to use the default setting.
use sp1_sdk::network::FulfillmentStrategy;
let proof = client.prove(&pk, &stdin)
.compressed()
.strategy(FulfillmentStrategy::Auction)
.max_price_per_pgu(1_000_000_000_000u64) // 1 PROVE per 1M PGUs
.run()
.await?;
Auction Timeout
The auction_timeout
parameter determines how long to wait for provers to bid on the proof request. If no provers bid on the request within this timeout, the proof request will be canceled. If a value is not specified, the default is 30 seconds.
use std::time::Duration;
use sp1_sdk::network::FulfillmentStrategy;
let proof = client.prove(&pk, &stdin)
.compressed()
.strategy(FulfillmentStrategy::Auction)
.auction_timeout(Duration::from_secs(300)) // 5 minutes
.run()
.await?;
Min Auction Period
The min_auction_period
parameter determines how long to wait before settling the auction for the proof request. The minimum auction period ensures bidders have time to discover and compete for the proof request. The auction only settles after both the minimum time has passed AND at least one bid is received. If a value is not specified, the default is 1 second.
If you don't have strict latency requirements, it is recommended to use 10-15 seconds for the minimum auction period to ensure all bidders have a chance to bid and you get the best price.
use std::time::Duration;
use sp1_sdk::network::FulfillmentStrategy;
let proof = client.prove(&pk, &stdin)
.compressed()
.strategy(FulfillmentStrategy::Auction)
.min_auction_period(Duration::from_secs(15)) // 15 seconds
.run()
.await?;
Whitelist
The whitelist
parameter lets you specify a list of prover addresses that are allowed to bid on the proof request. If a value is not specified, a default set of reliable provers will be used.
use sp1_sdk::network::FulfillmentStrategy;
let whitelist = vec![Address::from_str("0x123").unwrap(), Address::from_str("0x456").unwrap()];
let proof = client.prove(&pk, &stdin)
.compressed()
.strategy(FulfillmentStrategy::Auction)
.whitelist(Some(whitelist))
.run()
.await?;
Async Operations
For non-blocking proof requests, use the async methods to submit and track proofs separately:
use sp1_sdk::network::ProofRequestStatus;
// Submit proof request
let request_id = client.prove(&pk, &stdin)
.compressed()
.request_async()
.await?;
// Get proof status
let (status, maybe_proof) = client.get_proof_status(request_id).await?;
// Get request info
let maybe_request = client.get_proof_request(request_id).await?;
// Wait for completion (with optional timeouts)
let request_timeout = Some(Duration::from_secs(3600));
let auction_timeout = Some(Duration::from_secs(900));
let proof = client.wait_proof(request_id, Some(request_timeout), Some(auction_timeout))
.await?;
When you use wait_proof
and specify an auction timeout, the proof request will be canceled if no bids are received within the auction timeout.
If you don't use wait_proof
and a proof request has not received any bids, you can leave it alone until the request times out, or you can explicitly cancel it:
client.cancel_request(request_id).await?;
AWS KMS Requester Account
As of sp1-sdk >= v5.2.1
, you can pass a signer
instead using of the NETWORK_PRIVATE_KEY
environment variable or the private_key
argument. This lets you use AWS KMS without storing your private key in plaintext.
Make sure the Key ARN is in this format: arn:aws:kms:REGION:ACCOUNT:key/KEY_ID
.
// Network client with AWS KMS signer
let signer = NetworkSigner::aws_kms("<KMS_KEY_ARN>").await.unwrap();
let client = ProverClient::builder()
.network()
.signer(signer)
.build();
AWS Credentials
To use the AWS KMS signer, you need AWS credentials configured on your host machine via one of:
- Environment variables (
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
) - IAM role with appropriate permissions attached to your instance or container
- AWS credentials file
The credentials must have the kms:Sign
and kms:GetPublicKey
permissions.
Create a KMS key
You can create a KMS key in the AWS Console or via the AWS CLI. Make sure to select:
- Type: Asymmetric
- Usage: Sign and Verify
- Spec:
ECC_SECG_P256K1
- Signing algorithm:
ECDSA_SHA_256
For more details, see the AWS KMS Developer Guide.
Get the Address
To get the address that corresponds to the KMS key, you can either print it when setting up the NetworkSigner
or use a script.
let signer = NetworkSigner::aws_kms("<KMS_KEY_ARN>").await.unwrap();
println!("address: {:?}", signer.address());
Or use a simple Python script:
import boto3
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from eth_utils import keccak, to_checksum_address
# 1. Fetch the DER‐encoded public key from KMS
kms = boto3.client("kms")
resp = kms.get_public_key(
KeyId="<KMS_KEY_ARN>"
)
pub_der = resp["PublicKey"]
# 2. Load it and extract (x, y)
pub = serialization.load_der_public_key(pub_der, backend=default_backend())
nums = pub.public_numbers()
raw = nums.x.to_bytes(32, "big") + nums.y.to_bytes(32, "big")
# 3. Keccak hash, take last 20 bytes, checksum it
addr = to_checksum_address(keccak(raw)[-20:])
print(addr)
Make sure that the machine running the script has AWS credentials with kms:GetPublicKey
permissions.