200 lines
8.0 KiB
Rust
200 lines
8.0 KiB
Rust
// file: crates/ksp-app-backfill-desk/unit_tests/backfill_request.rs
|
|
// version: 4
|
|
|
|
fn ready_options() -> crate::BackfillDeskOptionsDto {
|
|
let limits = crate::backfill_request_limits();
|
|
assert!(limits.is_ok());
|
|
let limits = match limits {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => crate::BackfillRequestLimitsDto {
|
|
default_hydration_concurrency: 1,
|
|
default_max_candidates: 1,
|
|
default_max_pages: 1,
|
|
default_page_size: 1,
|
|
max_hydration_concurrency: 1,
|
|
max_candidates: 1,
|
|
max_pages: 1,
|
|
max_page_size: 1,
|
|
max_signature_text_bytes: 88,
|
|
min_signature_text_bytes: 64,
|
|
},
|
|
};
|
|
return crate::BackfillDeskOptionsDto {
|
|
commitments: crate::backfill_commitment_codes(),
|
|
composition_ready: true,
|
|
configured_networks: vec!["mainnet".to_owned()],
|
|
http_routes: vec![
|
|
crate::BackfillHttpRouteOptionDto {
|
|
pooled: true,
|
|
providers: vec!["publicnode".to_owned(), "solana-public".to_owned()],
|
|
role: "backfill_pool".to_owned(),
|
|
},
|
|
crate::BackfillHttpRouteOptionDto { pooled: false, providers: vec!["publicnode".to_owned()], role: "backfill_publicnode".to_owned() },
|
|
],
|
|
limits,
|
|
network_coherent: true,
|
|
program_id_options: crate::program_id_autocomplete_options(),
|
|
scope_kinds: crate::backfill_scope_kind_codes(),
|
|
store_diagnostic: std::option::Option::None,
|
|
store_network: std::option::Option::Some("mainnet".to_owned()),
|
|
store_ready: true,
|
|
transport_diagnostic: std::option::Option::None,
|
|
transport_ready: true,
|
|
};
|
|
}
|
|
|
|
fn request(scope_kind: &str) -> crate::BackfillStartRequestDto {
|
|
return crate::BackfillStartRequestDto {
|
|
address: std::option::Option::Some("11111111111111111111111111111111".to_owned()),
|
|
anchor_signature: std::option::Option::None,
|
|
commitment: "finalized".to_owned(),
|
|
explicit_signatures: std::vec::Vec::new(),
|
|
hydration_concurrency: 4,
|
|
http_role: "backfill_pool".to_owned(),
|
|
max_candidates: 100,
|
|
max_pages: 10,
|
|
min_context_slot: std::option::Option::Some("123456".to_owned()),
|
|
page_size: 100,
|
|
scope_kind: scope_kind.to_owned(),
|
|
};
|
|
}
|
|
|
|
fn job_id() -> std::option::Option<ksp_job_api::JobId> {
|
|
let job_id = ksp_job_api::JobId::new("request-mapping-test");
|
|
assert!(job_id.is_ok());
|
|
return match job_id {
|
|
std::result::Result::Ok(value) => std::option::Option::Some(value),
|
|
std::result::Result::Err(_) => std::option::Option::None,
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn latest_address_maps_to_backend_network_role_commitment_and_bounds() {
|
|
let job_id = job_id();
|
|
let job_id = match job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mapped = crate::map_backfill_request(request("latest_address"), &ready_options(), job_id);
|
|
assert!(mapped.is_ok());
|
|
let mapped = match mapped {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(mapped.network().as_str(), "mainnet");
|
|
assert_eq!(mapped.role().as_str(), "backfill_pool");
|
|
assert_eq!(mapped.commitment(), ksp_job_backfill_lib::BackfillCommitment::Finalized);
|
|
assert_eq!(mapped.scope().kind(), ksp_job_backfill_lib::BackfillScopeKind::LatestAddress);
|
|
assert_eq!(mapped.page_size(), 100);
|
|
assert_eq!(mapped.max_pages(), 10);
|
|
assert_eq!(mapped.max_candidates(), 100);
|
|
assert_eq!(mapped.hydration_concurrency(), 4);
|
|
assert_eq!(mapped.min_context_slot(), std::option::Option::Some(123456));
|
|
}
|
|
|
|
#[test]
|
|
fn before_and_after_scopes_require_an_exact_anchor_shape() {
|
|
for scope_kind in ["before_address", "after_address"] {
|
|
let job_id = job_id();
|
|
let job_id = match job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut input = request(scope_kind);
|
|
input.anchor_signature = std::option::Option::Some("1".repeat(64));
|
|
let mapped = crate::map_backfill_request(input, &ready_options(), job_id);
|
|
assert!(mapped.is_ok(), "scope {scope_kind} should map with a bounded anchor");
|
|
}
|
|
let job_id = job_id();
|
|
let job_id = match job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let missing_anchor = crate::map_backfill_request(request("before_address"), &ready_options(), job_id);
|
|
assert!(missing_anchor.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn explicit_signatures_reject_address_context_and_deduplicate_in_job_contract() {
|
|
let request_job_id = job_id();
|
|
let request_job_id = match request_job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut input = request("explicit_signatures");
|
|
input.address = std::option::Option::None;
|
|
input.min_context_slot = std::option::Option::None;
|
|
input.explicit_signatures = vec!["1".repeat(64), "1".repeat(64), "2".repeat(64)];
|
|
let mapped = crate::map_backfill_request(input, &ready_options(), request_job_id);
|
|
assert!(mapped.is_ok());
|
|
let mapped = match mapped {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let signatures = mapped.scope().signatures();
|
|
assert!(signatures.is_some());
|
|
if let std::option::Option::Some(signatures) = signatures {
|
|
assert_eq!(signatures.len(), 2);
|
|
}
|
|
let mut hostile = request("explicit_signatures");
|
|
hostile.address = std::option::Option::None;
|
|
hostile.min_context_slot = std::option::Option::None;
|
|
hostile.explicit_signatures = vec![" 1".to_owned()];
|
|
let hostile_job_id = job_id();
|
|
let hostile_job_id = match hostile_job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
assert!(crate::map_backfill_request(hostile, &ready_options(), hostile_job_id).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn route_inventory_and_composition_are_revalidated_before_mapping() {
|
|
let first_job_id = job_id();
|
|
let first_job_id = match first_job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut unknown_route = request("latest_address");
|
|
unknown_route.http_role = "provider-from-frontend".to_owned();
|
|
let rejected = crate::map_backfill_request(unknown_route, &ready_options(), first_job_id);
|
|
assert!(rejected.is_err());
|
|
let mut unavailable = ready_options();
|
|
unavailable.composition_ready = false;
|
|
let second_job_id = job_id();
|
|
let second_job_id = match second_job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
assert!(crate::map_backfill_request(request("latest_address"), &unavailable, second_job_id).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn request_preview_never_contains_address_or_signature_values() {
|
|
let job_id = job_id();
|
|
let job_id = match job_id {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mapped = crate::map_backfill_request(request("latest_address"), &ready_options(), job_id);
|
|
assert!(mapped.is_ok());
|
|
let mapped = match mapped {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let preview = crate::project_backfill_request(&mapped);
|
|
assert!(preview.is_ok());
|
|
let preview = match preview {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let serialized = serde_json::to_string(&preview);
|
|
assert!(serialized.is_ok());
|
|
if let std::result::Result::Ok(serialized) = serialized {
|
|
assert!(!serialized.contains("11111111111111111111111111111111"));
|
|
assert!(!serialized.contains(&"1".repeat(64)));
|
|
assert!(serialized.contains("mainnet"));
|
|
assert!(serialized.contains("backfill_pool"));
|
|
}
|
|
}
|