Skip to content
Draft
Show file tree
Hide file tree
Changes from 152 commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
3c64dcc
initial stateless-validation flag
kevaundray Jul 2, 2025
1a372d8
add initial execution payload proof store
kevaundray Jul 2, 2025
5e56ab8
add initial code to config subnets (without having subnets)
kevaundray Jul 2, 2025
ab60fbf
Add code for proof generation + some refactor
kevaundray Jul 2, 2025
2ec002d
gossip subnet
kevaundray Jul 2, 2025
260b642
proof broadcasting
kevaundray Jul 2, 2025
9f7fca3
remove unneeded methods
kevaundray Jul 2, 2025
4b07bdf
cargo fmt
kevaundray Jul 3, 2025
42c269e
make cli
kevaundray Jul 3, 2025
bc9fa8f
add code to re-evaluate blocks when a proof arrives
kevaundray Jul 3, 2025
089cf75
avoid duplicate blocks and cleanup pending blocks after some period
kevaundray Jul 3, 2025
b372270
add TODO about orphaned proofs
kevaundray Jul 3, 2025
38cb552
short lived write lock
kevaundray Jul 3, 2025
23008f4
rough architecture doc
kevaundray Jul 4, 2025
e3071aa
log lines
kevaundray Jul 4, 2025
98e350c
add proof subnets to whitelist
kevaundray Jul 4, 2025
c63f439
All nodes subscribe to all subnets
kevaundray Jul 4, 2025
0364285
fmt
kevaundray Jul 4, 2025
82557b7
add generate-execution-proofs flag
kevaundray Jul 4, 2025
7bea51d
remove `spawn_proof_generation_task`
kevaundray Jul 4, 2025
f42ee91
execution payload instead of hash
kevaundray Jul 6, 2025
b7c1dfe
typo in logs
kevaundray Jul 6, 2025
1a5be90
add execution state witness and random proof delays
kevaundray Jul 6, 2025
b5b922e
allow min_proofs parameter
kevaundray Jul 6, 2025
7100010
add cli arg for stateless-min-proofs
kevaundray Jul 6, 2025
bdd7ad2
check node level maximum against protocol level maximum
kevaundray Jul 6, 2025
a700e3b
docs
kevaundray Jul 6, 2025
2108ca3
refactor
kevaundray Jul 6, 2025
0cc34e4
make cli
kevaundray Jul 6, 2025
8708639
cargo fmt
kevaundray Jul 6, 2025
ee48e62
commit
kevaundray Jul 8, 2025
54f9f32
update logs
kevaundray Jul 12, 2025
d2afdec
refactor loggin and add proof delay
kevaundray Jul 13, 2025
5cf853b
refactor
kevaundray Jul 13, 2025
9156429
refactor
kevaundray Jul 13, 2025
855224d
be more concise
kevaundray Jul 13, 2025
5343347
tests
kevaundray Jul 13, 2025
c497fca
decrease number of proof generators
kevaundray Jul 13, 2025
bc281d3
refactor subnet_id
kevaundray Jul 16, 2025
9fc5733
refactor code
kevaundray Jul 16, 2025
9e70570
remove timestamp
kevaundray Jul 16, 2025
3d51683
add comment on version
kevaundray Jul 16, 2025
98d01df
Make ProofId::new failable
kevaundray Jul 16, 2025
0f9a272
remove return values -- tech debt
kevaundray Jul 16, 2025
1f48d27
api cleanup
kevaundray Jul 17, 2025
c3ea66e
add separate storage for broadcast_queue
kevaundray Jul 17, 2025
8950959
refactor
kevaundray Jul 17, 2025
682741a
make state machine clearer
kevaundray Jul 17, 2025
e8ae9cb
cleanup when proofs exceed max_attempts
kevaundray Jul 17, 2025
88ce599
guard broadcaster with stateless-validation flag
kevaundray Jul 17, 2025
bc72b4f
cargo fmt
kevaundray Jul 17, 2025
3a51953
remove unused parameter
kevaundray Jul 17, 2025
8c39d67
fix
kevaundray Jul 17, 2025
c45b7f3
refactor comments
kevaundray Jul 17, 2025
3c8bdcc
refactor
kevaundray Jul 17, 2025
b1b5d64
remove outdated comment
kevaundray Jul 17, 2025
0e7bbb1
remove unused methods
kevaundray Jul 17, 2025
b649fb2
typo
kevaundray Jul 17, 2025
3fea602
small comment on take_unqueued_proofs
kevaundray Jul 17, 2025
bf99fa3
cusot -> new and remove timestamp field
kevaundray Jul 17, 2025
bf122f5
remove ExecutionPayloadProof
kevaundray Jul 17, 2025
ac6a5bc
fix rename
kevaundray Jul 17, 2025
1d3d492
cleanup
kevaundray Jul 17, 2025
66be583
fix rename to generate_proof
kevaundray Jul 17, 2025
72ee1e2
move proof generation to separate module
kevaundray Jul 17, 2025
189a01c
move proofs to execution_proof_generation
kevaundray Jul 17, 2025
cdd79ae
add comments
kevaundray Jul 17, 2025
718122b
fix comments
kevaundray Jul 17, 2025
219edb9
rename to cleanup_pending_blocks
kevaundray Jul 17, 2025
97c4b29
comment
kevaundray Jul 17, 2025
6cdc7a0
small clean up of cleanup_pending_block
kevaundray Jul 17, 2025
e496b45
add comment on 1:1 being common
kevaundray Jul 17, 2025
80e0fc6
comments
kevaundray Jul 17, 2025
9ed554c
change visibility of private methods
kevaundray Jul 17, 2025
6d3a621
refactor
kevaundray Jul 17, 2025
ca49ad3
fmt
kevaundray Jul 17, 2025
6a44879
refactor tests
kevaundray Jul 17, 2025
82763b5
make ProvenBlockInfo private
kevaundray Jul 17, 2025
4c64988
add an impl block for test methods
kevaundray Jul 17, 2025
791bb96
cargo clippy
kevaundray Jul 17, 2025
29acac5
update doc comment for ExecutionPayloadProofStore
kevaundray Jul 17, 2025
4bd7692
decrease public API and temporarily use comments to organize code
kevaundray Jul 17, 2025
2ad9161
refactor more of the logging
kevaundray Jul 17, 2025
9e7a312
pull out execution proof changes from beacon_chain.rs
kevaundray Jul 17, 2025
34bfeb3
remove `cleanup_pending_blocks_older_than` method
kevaundray Jul 17, 2025
5440f97
remove unneeded methods
kevaundray Jul 17, 2025
9551136
refactor comments
kevaundray Jul 17, 2025
611715c
remove comment
kevaundray Jul 17, 2025
40de678
comments
kevaundray Jul 17, 2025
2346b5f
fix cli flag
kevaundray Jul 17, 2025
7005acb
make proof generation async
kevaundray Jul 17, 2025
0072d08
remove unused methods
kevaundray Jul 17, 2025
2b5b870
remove debug log
kevaundray Jul 17, 2025
1b6fde7
fix test
kevaundray Jul 17, 2025
843803e
clean up logging
kevaundray Jul 17, 2025
392269a
make cli
kevaundray Jul 17, 2025
7f1eb7f
less indenting
kevaundray Jul 17, 2025
a131e06
refactor logs
kevaundray Jul 17, 2025
88c48a2
add comment on code expectation
kevaundray Jul 17, 2025
75922d7
add comment
kevaundray Jul 17, 2025
c41a475
revert
kevaundray Jul 17, 2025
7de9914
use direct method to get execution payload
kevaundray Jul 17, 2025
59df8ff
cache proof generation
kevaundray Jul 17, 2025
dfad96b
cargo fmt
kevaundray Jul 17, 2025
3f0c9de
add comment
kevaundray Jul 17, 2025
94190c6
fix
kevaundray Jul 17, 2025
ff93ee1
more notes
kevaundray Jul 17, 2025
4e99f8d
top level import
kevaundray Jul 17, 2025
4de9df0
remove debug test
kevaundray Jul 17, 2025
ab30139
rename execution_payload_proof -> execution_proof_store
kevaundray Jul 17, 2025
19b6960
refactor rest of code
kevaundray Jul 17, 2025
588ba6a
fix tests
kevaundray Jul 17, 2025
c13724a
Merge branch 'unstable' into kw/exec-proofs
kevaundray Jul 17, 2025
b187aa9
remove out of place tests
kevaundray Jul 18, 2025
f176dde
Update beacon_node/beacon_chain/src/execution_payload.rs
kevaundray Jul 18, 2025
8fbe3f5
Update beacon_node/network/src/network_beacon_processor/gossip_method…
kevaundray Jul 18, 2025
dfbd22b
DA checker (#7)
kevaundray Sep 3, 2025
5e71b02
Merge branch 'unstable' into kw/exec-proofs
kevaundray Sep 3, 2025
709fdbc
add Gloas
kevaundray Sep 3, 2025
61046fe
fix
kevaundray Sep 3, 2025
b62dc76
fmt
kevaundray Sep 3, 2025
53550d8
consolidate merge
kevaundray Sep 3, 2025
4af1147
remove alias
kevaundray Sep 3, 2025
f45d010
partial change: Availability -> Importability
kevaundray Sep 3, 2025
c92826e
ImportableProofData
kevaundray Sep 3, 2025
3189def
change version from u32 to u64
kevaundray Sep 3, 2025
100074e
revert return param
kevaundray Sep 3, 2025
70995a3
fix compile: mainly changing Availability to Importability
kevaundray Sep 3, 2025
b5df3ff
fix test
kevaundray Sep 3, 2025
3485889
make proof processing similar to blob processing
kevaundray Sep 3, 2025
41b5ff6
fmt
kevaundray Sep 3, 2025
e145533
remove debug log
kevaundray Sep 3, 2025
c4a9590
add TODO
kevaundray Sep 3, 2025
04e21dd
change payload verification status if proofs are available
kevaundray Sep 3, 2025
34ed2b5
comments
kevaundray Sep 3, 2025
5013d84
revert Importability -> Availability
kevaundray Sep 3, 2025
3fa9929
remove import
kevaundray Sep 3, 2025
06c195b
use VerifiedExecutionProof in overflow_lru_cache
kevaundray Sep 3, 2025
26ee389
fmt
kevaundray Sep 3, 2025
5ef5f5e
create proofs during publish_block workflow
kevaundray Sep 13, 2025
bf156ce
remove proof generation from execution_payload
kevaundray Sep 13, 2025
5cb92a4
fmt
kevaundray Sep 13, 2025
2d92d5c
remove now unused channel
kevaundray Sep 13, 2025
ba72507
add proof networking code to execution_proof_network
kevaundray Sep 13, 2025
37ee3e7
generate proofs when forwarding and remove now duplicated code since …
kevaundray Sep 13, 2025
1a10639
remove debugging postfix
kevaundray Sep 13, 2025
715e650
Merge pull request #12 from kevaundray/kw/networking-exec-proof
kevaundray Sep 13, 2025
4ba3974
Merge branch 'unstable' into kw/exec-proofs
kevaundray Sep 13, 2025
b7754f1
add proofs to PeerSubnetInfo
kevaundray Sep 13, 2025
6e1ad67
cargo fmt
kevaundray Sep 13, 2025
2d9c7ac
add todo
kevaundray Sep 13, 2025
0caee2d
Merge remote-tracking branch 'sigp/unstable' into kw/exec-proofs
dapplion Sep 29, 2025
6bffe33
Lion minor review changes
dapplion Sep 29, 2025
7adbdd7
delete file
kevaundray Oct 13, 2025
e84526b
Merge branch 'unstable' into kw/exec-proofs
kevaundray Oct 13, 2025
471c3a9
Add SSE
kevaundray Oct 13, 2025
ff5e23d
add ENR
kevaundray Oct 13, 2025
088741c
change number of subnets to 1
kevaundray Oct 14, 2025
ebbad4c
Review PR
dapplion Oct 27, 2025
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
34 changes: 34 additions & 0 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3659,6 +3659,40 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.await
}

/// Checks if the provided execution proof(s) can make any cached blocks available/importable.
/// Otherwise caches the proof(s) in the data availability checker.
///
/// Note: Unlike blobs/data columns, execution proofs do not carry a signed header because
/// they arrive after the block has been made. So we do not perform any slashing-related checks for proofs.
pub async fn check_gossip_execution_proof_availability_and_import<
O: crate::observed_data_sidecars::ObservationStrategy,
>(
self: &Arc<Self>,
block_root: Hash256,
execution_proofs: impl IntoIterator<
Item = crate::execution_proof_verification::GossipVerifiedExecutionProof<T, O>,
>,
) -> Result<AvailabilityProcessingStatus, BlockError> {
let availability = self
.data_availability_checker
.put_gossip_verified_execution_proofs(block_root, execution_proofs)?;

// Note: the slot is only used for logging, default to 0 for now. The proof type may change
// in the future making the block's slot easily available.
let slot = self
.data_availability_checker
.get_cached_block(&block_root)
.map(|b| match b {
BlockProcessStatus::Unknown => Slot::new(0),
BlockProcessStatus::NotValidated(block, _)
| BlockProcessStatus::ExecutionValidated(block) => block.slot(),
})
.unwrap_or(Slot::new(0));

self.process_availability(slot, availability, || Ok(()))
.await
}

fn check_columns_for_slashability<'a>(
self: &Arc<Self>,
block_root: Hash256,
Expand Down
8 changes: 8 additions & 0 deletions beacon_node/beacon_chain/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,13 @@ where
};
debug!(?custody_context, "Loading persisted custody context");

// Extract execution proof requirements before moving chain_config
let min_execution_proofs_required = if self.chain_config.stateless_validation {
Some(self.chain_config.stateless_min_proofs_required)
} else {
None
};

let beacon_chain = BeaconChain {
spec: self.spec.clone(),
config: self.chain_config,
Expand Down Expand Up @@ -1019,6 +1026,7 @@ where
store,
custody_context,
self.spec,
min_execution_proofs_required,
)
.map_err(|e| format!("Error initializing DataAvailabilityChecker: {:?}", e))?,
),
Expand Down
32 changes: 32 additions & 0 deletions beacon_node/beacon_chain/src/chain_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,34 @@ pub struct ChainConfig {
pub prepare_payload_lookahead: Duration,
/// Use EL-free optimistic sync for the finalized part of the chain.
pub optimistic_finalized_sync: bool,
/// Enable stateless validation mode for new payloads.
///
/// Currently this means that the node will accept blocks optimistically
/// and maintain metadata about which blocks have been proven and which ones have not.
pub stateless_validation: bool,
/// Generate execution proofs for all blocks received.
///
/// Nodes that have this enabled will be used to bootstrap proofs into the subnets,
/// whether they are a proposer or not.
pub generate_execution_proofs: bool,
/// Maximum number of execution proof subnets this node will participate in.
///
/// This is a per-node configuration that must not exceed the protocol maximum
/// (MAX_EXECUTION_PROOF_SUBNETS). Nodes may choose to participate in fewer
/// subnets to reduce resource usage, but this limits the number of proofs they
/// can generate or validate.
///
/// TODO: We can remove the sequential allocations with a random allocation, so that lower numbered
/// TODO: subnets are not important. Current strategy is mostly POC.
///
/// Note: stateless_min_proofs_required must not exceed this value, as a node
/// cannot require more proofs than the number of subnets it participates in.
pub max_execution_proof_subnets: u64,
/// Minimum number of proofs required to consider a block valid in stateless mode.
///
/// Must be between 1 and max_execution_proof_subnets. Higher values provide
/// more security but may increase block validation latency.
pub stateless_min_proofs_required: usize,
/// The size of the shuffling cache,
pub shuffling_cache_size: usize,
/// If using a weak-subjectivity sync, whether we should download blocks all the way back to
Expand Down Expand Up @@ -144,6 +172,10 @@ impl Default for ChainConfig {
prepare_payload_lookahead: Duration::from_secs(4),
// This value isn't actually read except in tests.
optimistic_finalized_sync: true,
stateless_validation: false,
generate_execution_proofs: false,
max_execution_proof_subnets: 8,
stateless_min_proofs_required: 1,
shuffling_cache_size: crate::shuffling_cache::DEFAULT_CACHE_SIZE,
genesis_backfill: false,
complete_blob_backfill: false,
Expand Down
70 changes: 66 additions & 4 deletions beacon_node/beacon_chain/src/data_availability_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use tracing::{debug, error, instrument};
use types::blob_sidecar::{BlobIdentifier, BlobSidecar, FixedBlobSidecarList};
use types::{
BlobSidecarList, BlockImportSource, ChainSpec, DataColumnSidecar, DataColumnSidecarList, Epoch,
EthSpec, Hash256, SignedBeaconBlock, Slot,
EthSpec, ExecutionProof, Hash256, SignedBeaconBlock, Slot,
};

mod error;
Expand Down Expand Up @@ -100,8 +100,8 @@ pub enum DataColumnReconstructionResult<E: EthSpec> {

/// This type is returned after adding a block / blob to the `DataAvailabilityChecker`.
///
/// Indicates if the block is fully `Available` or if we need blobs or blocks
/// to "complete" the requirements for an `AvailableBlock`.
/// Indicates if the block is ready for import or if we need blobs, columns, or execution proofs
/// to "complete" the requirements for an importable block.
pub enum Availability<E: EthSpec> {
MissingComponents(Hash256),
Available(Box<AvailableExecutedBlock<E>>),
Expand All @@ -113,7 +113,9 @@ impl<E: EthSpec> Debug for Availability<E> {
Self::MissingComponents(block_root) => {
write!(f, "MissingComponents({})", block_root)
}
Self::Available(block) => write!(f, "Available({:?})", block.import_data.block_root),
Self::Available(block) => {
write!(f, "ReadyForImport({:?})", block.import_data.block_root)
}
}
}
}
Expand All @@ -126,12 +128,14 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
store: BeaconStore<T>,
custody_context: Arc<CustodyContext<T::EthSpec>>,
spec: Arc<ChainSpec>,
min_execution_proofs_required: Option<usize>,
) -> Result<Self, AvailabilityCheckError> {
let inner = DataAvailabilityCheckerInner::new(
OVERFLOW_LRU_CAPACITY,
store,
custody_context.clone(),
spec.clone(),
min_execution_proofs_required,
)?;
Ok(Self {
complete_blob_backfill,
Expand Down Expand Up @@ -210,6 +214,26 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
self.availability_cache.peek_data_columns(block_root)
}

/// Put gossip verified execution proofs into the availability cache.
///
/// This allows stateless validation nodes to collect proofs for execution payloads.
pub fn put_gossip_verified_execution_proofs<I, O>(
&self,
block_root: Hash256,
execution_proofs: I,
) -> Result<Availability<T::EthSpec>, AvailabilityCheckError>
where
I: IntoIterator<
Item = crate::execution_proof_verification::GossipVerifiedExecutionProof<T, O>,
>,
O: crate::observed_data_sidecars::ObservationStrategy,
{
self.availability_cache.put_execution_proofs(
block_root,
execution_proofs.into_iter().map(|v| v.into_inner()),
)
}

/// Put a list of blobs received via RPC into the availability cache. This performs KZG
/// verification on the blobs in the list.
#[instrument(skip_all, level = "trace")]
Expand Down Expand Up @@ -386,6 +410,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
block,
blob_data: AvailableBlockData::Blobs(blob_list),
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
}))
} else {
Expand All @@ -411,6 +436,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
.collect(),
),
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
}))
} else {
Expand All @@ -423,6 +449,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
block,
blob_data: AvailableBlockData::NoData,
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
}))
}
Expand Down Expand Up @@ -479,6 +506,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
block,
blob_data: AvailableBlockData::Blobs(blobs),
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
})
} else {
Expand All @@ -493,6 +521,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
data_columns.into_iter().map(|d| d.into_inner()).collect(),
),
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
})
} else {
Expand All @@ -504,6 +533,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
block,
blob_data: AvailableBlockData::NoData,
blobs_available_timestamp: None,
proof_data: ImportableProofData::NoneRequired,
spec: self.spec.clone(),
})
};
Expand All @@ -527,6 +557,13 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
self.da_check_required_for_epoch(epoch) && self.spec.is_peer_das_enabled_for_epoch(epoch)
}

/// Determines the execution proof requirements for an epoch.
/// - If the epoch is from prior to the data availability boundary, no execution proofs are required.
/// - This allows historical blocks to sync without waiting for execution proofs.
pub fn execution_proofs_required_for_epoch(&self, epoch: Epoch) -> bool {
self.da_check_required_for_epoch(epoch) // Only for recent blocks within DA boundary
}

/// See `Self::blobs_required_for_epoch`
fn blobs_required_for_block(&self, block: &SignedBeaconBlock<T::EthSpec>) -> bool {
block.num_expected_blobs() > 0 && self.blobs_required_for_epoch(block.epoch())
Expand Down Expand Up @@ -754,6 +791,25 @@ pub enum AvailableBlockData<E: EthSpec> {
DataColumns(DataColumnSidecarList<E>),
}

/// Execution proof data
///
/// The proofs that were collected that convinced the node that the
/// Block's execution payload was indeed valid.
#[derive(Debug, Clone)]
pub enum ImportableProofData {
/// Execution proofs that were used to validate this block.
/// The number of proofs is at least `min_proofs_required` because
/// that is needed for the block to be seen as available/importable.
///
/// TODO: Its possible for us to provide a proof that that the
/// ExecutionPayload was invalid. Is this useful? This would allow
/// us to distinguish between the case where the prover cannot create a
/// proof of a valid payload.
Proofs(Vec<ExecutionProof>),
/// This is the case when the node opts to not receive proofs
NoneRequired,
}

/// A fully available block that is ready to be imported into fork choice.
#[derive(Debug)]
pub struct AvailableBlock<E: EthSpec> {
Expand All @@ -762,6 +818,8 @@ pub struct AvailableBlock<E: EthSpec> {
blob_data: AvailableBlockData<E>,
/// Timestamp at which this block first became available (UNIX timestamp, time since 1970).
blobs_available_timestamp: Option<Duration>,
/// Execution proof data for this block
pub proof_data: ImportableProofData,
pub spec: Arc<ChainSpec>,
}

Expand All @@ -770,13 +828,15 @@ impl<E: EthSpec> AvailableBlock<E> {
block_root: Hash256,
block: Arc<SignedBeaconBlock<E>>,
data: AvailableBlockData<E>,
proof_data: ImportableProofData,
spec: Arc<ChainSpec>,
) -> Self {
Self {
block_root,
block,
blob_data: data,
blobs_available_timestamp: None,
proof_data,
spec,
}
}
Expand Down Expand Up @@ -828,6 +888,7 @@ impl<E: EthSpec> AvailableBlock<E> {
}
},
blobs_available_timestamp: self.blobs_available_timestamp,
proof_data: self.proof_data.clone(),
spec: self.spec.clone(),
})
}
Expand Down Expand Up @@ -1112,6 +1173,7 @@ mod test {
store,
custody_context,
spec,
None,
)
.expect("should initialise data availability checker")
}
Expand Down
Loading