Skip to content

Commit d9593ab

Browse files
xJonathanLEIincrypto32
authored andcommitted
feat(starknet): data source validation
1 parent 1778c42 commit d9593ab

File tree

2 files changed

+107
-7
lines changed

2 files changed

+107
-7
lines changed

chain/starknet/src/chain.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,75 @@ impl TriggersAdapterTrait<Chain> for TriggersAdapter {
425425
}))
426426
}
427427
}
428+
429+
#[cfg(test)]
430+
mod tests {
431+
use std::sync::Arc;
432+
433+
use graph::blockchain::DataSource as _;
434+
435+
use crate::{
436+
data_source::{
437+
DataSource, Mapping, MappingBlockHandler, MappingEventHandler, STARKNET_KIND,
438+
},
439+
felt::Felt,
440+
};
441+
442+
#[test]
443+
fn validate_no_handler() {
444+
let ds = new_data_source(None);
445+
446+
let errs = ds.validate();
447+
assert_eq!(errs.len(), 1, "{:?}", ds);
448+
assert_eq!(
449+
errs[0].to_string(),
450+
"data source does not define any handler"
451+
);
452+
}
453+
454+
#[test]
455+
fn validate_address_without_event_handler() {
456+
let mut ds = new_data_source(Some([1u8; 32].into()));
457+
ds.mapping.block_handler = Some(MappingBlockHandler {
458+
handler: "asdf".into(),
459+
});
460+
461+
let errs = ds.validate();
462+
assert_eq!(errs.len(), 1, "{:?}", ds);
463+
assert_eq!(
464+
errs[0].to_string(),
465+
"data source cannot have source address without event handlers"
466+
);
467+
}
468+
469+
#[test]
470+
fn validate_no_address_with_event_handler() {
471+
let mut ds = new_data_source(None);
472+
ds.mapping.event_handlers.push(MappingEventHandler {
473+
handler: "asdf".into(),
474+
event_selector: [2u8; 32].into(),
475+
});
476+
477+
let errs = ds.validate();
478+
assert_eq!(errs.len(), 1, "{:?}", ds);
479+
assert_eq!(errs[0].to_string(), "subgraph source address is required");
480+
}
481+
482+
fn new_data_source(address: Option<Felt>) -> DataSource {
483+
DataSource {
484+
kind: STARKNET_KIND.to_string(),
485+
network: "starknet-mainnet".into(),
486+
name: "asd".to_string(),
487+
source: crate::data_source::Source {
488+
start_block: 10,
489+
end_block: None,
490+
address,
491+
},
492+
mapping: Mapping {
493+
block_handler: None,
494+
event_handlers: vec![],
495+
runtime: Arc::new(vec![]),
496+
},
497+
}
498+
}
499+
}

chain/starknet/src/data_source.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use graph::{
22
anyhow::{anyhow, Error},
33
blockchain::{self, Block as BlockchainBlock, TriggerWithHandler},
44
components::{link_resolver::LinkResolver, store::StoredDynamicDataSource},
5-
data::subgraph::DataSourceContext,
5+
data::subgraph::{DataSourceContext, SubgraphManifestValidationError},
66
prelude::{async_trait, BlockNumber, DataSourceTemplateInfo, Deserialize, Link, Logger},
77
semver,
88
};
@@ -16,10 +16,11 @@ use crate::{
1616
trigger::{StarknetEventTrigger, StarknetTrigger},
1717
};
1818

19+
pub const STARKNET_KIND: &str = "starknet";
1920
const BLOCK_HANDLER_KIND: &str = "block";
2021
const EVENT_HANDLER_KIND: &str = "event";
2122

22-
#[derive(Clone)]
23+
#[derive(Debug, Clone)]
2324
pub struct DataSource {
2425
pub kind: String,
2526
pub network: String,
@@ -28,7 +29,7 @@ pub struct DataSource {
2829
pub mapping: Mapping,
2930
}
3031

31-
#[derive(Clone)]
32+
#[derive(Debug, Clone)]
3233
pub struct Mapping {
3334
pub block_handler: Option<MappingBlockHandler>,
3435
pub event_handlers: Vec<MappingEventHandler>,
@@ -44,7 +45,7 @@ pub struct UnresolvedDataSource {
4445
pub mapping: UnresolvedMapping,
4546
}
4647

47-
#[derive(Clone, PartialEq, Eq, Deserialize)]
48+
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
4849
#[serde(rename_all = "camelCase")]
4950
pub struct Source {
5051
pub start_block: BlockNumber,
@@ -63,12 +64,12 @@ pub struct UnresolvedMapping {
6364
pub file: Link,
6465
}
6566

66-
#[derive(Clone, PartialEq, Eq, Deserialize)]
67+
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
6768
pub struct MappingBlockHandler {
6869
pub handler: String,
6970
}
7071

71-
#[derive(Clone, PartialEq, Eq, Deserialize)]
72+
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
7273
pub struct MappingEventHandler {
7374
pub handler: String,
7475
pub event_selector: Felt,
@@ -201,7 +202,34 @@ impl blockchain::DataSource<Chain> for DataSource {
201202
}
202203

203204
fn validate(&self) -> Vec<Error> {
204-
Default::default()
205+
let mut errors = Vec::new();
206+
207+
if self.kind != STARKNET_KIND {
208+
errors.push(anyhow!(
209+
"data source has invalid `kind`, expected {} but found {}",
210+
STARKNET_KIND,
211+
self.kind
212+
))
213+
}
214+
215+
// Validate that there's at least one handler of any kind
216+
if self.mapping.block_handler.is_none() && self.mapping.event_handlers.is_empty() {
217+
errors.push(anyhow!("data source does not define any handler"));
218+
}
219+
220+
// Validate that `source` address must not be present if there's no event handler
221+
if self.mapping.event_handlers.is_empty() && self.address().is_some() {
222+
errors.push(anyhow!(
223+
"data source cannot have source address without event handlers"
224+
));
225+
}
226+
227+
// Validate that `source` address must be present when there's at least 1 event handler
228+
if !self.mapping.event_handlers.is_empty() && self.address().is_none() {
229+
errors.push(SubgraphManifestValidationError::SourceAddressRequired.into());
230+
}
231+
232+
errors
205233
}
206234

207235
fn api_version(&self) -> semver::Version {

0 commit comments

Comments
 (0)