v0.2.3-pre.004
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
#[test]
|
||||
fn transaction_encoding_strings_match_current_and_legacy_wire_labels() {
|
||||
@@ -470,3 +470,219 @@ async fn typed_is_blockhash_valid_preserves_opaque_blockhash_and_contextual_bool
|
||||
assert_eq!(body["method"], serde_json::json!("isBlockhashValid"));
|
||||
assert_eq!(body["params"], serde_json::json!(["opaque-blockhash", {"commitment":"processed","minContextSlot":431000004}]));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_recent_prioritization_fees_serializes_addresses_and_preserves_server_order() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_recent_prioritization_fees.success.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let first = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let second = "SysvarRent111111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let first_text = first.to_string();
|
||||
let second_text = second.to_string();
|
||||
let accounts = std::vec![first, second];
|
||||
let fees = pool
|
||||
.get_recent_prioritization_fees(&crate::HttpRoleName::new("default"), std::option::Option::Some(accounts.as_slice()))
|
||||
.await
|
||||
.expect("getRecentPrioritizationFees fixture must succeed");
|
||||
assert_eq!(fees.len(), 2);
|
||||
assert_eq!(fees[0].slot(), 431_000_030);
|
||||
assert_eq!(fees[0].prioritization_fee(), 1_200);
|
||||
assert_eq!(fees[1].slot(), 431_000_029);
|
||||
assert_eq!(fees[1].prioritization_fee(), 0);
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["method"], serde_json::json!("getRecentPrioritizationFees"));
|
||||
assert_eq!(body["params"], serde_json::json!([[first_text, second_text]]));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_recent_prioritization_fees_omits_optional_accounts_and_rejects_more_than_128_before_io() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_recent_prioritization_fees.success.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let fees = pool
|
||||
.get_recent_prioritization_fees(&crate::HttpRoleName::new("default"), std::option::Option::None)
|
||||
.await
|
||||
.expect("getRecentPrioritizationFees without addresses must succeed");
|
||||
assert_eq!(fees.len(), 2);
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
assert_eq!(transaction_request_body(request.as_str())["params"], serde_json::json!([]));
|
||||
|
||||
let account = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let max_accounts = std::vec![account; 128];
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_recent_prioritization_fees.success.json"));
|
||||
let max_pool = transaction_pool_for_url(url.as_str());
|
||||
let fees = max_pool
|
||||
.get_recent_prioritization_fees(&crate::HttpRoleName::new("default"), std::option::Option::Some(max_accounts.as_slice()))
|
||||
.await
|
||||
.expect("exactly 128 prioritization-fee accounts must remain accepted");
|
||||
assert_eq!(fees.len(), 2);
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["params"][0].as_array().expect("address parameter must be an array").len(), 128);
|
||||
|
||||
let invalid_pool = transaction_pool_for_url("http://127.0.0.1:9");
|
||||
let accounts = std::vec![account; 129];
|
||||
let result = invalid_pool.get_recent_prioritization_fees(&crate::HttpRoleName::new("default"), std::option::Option::Some(accounts.as_slice())).await;
|
||||
let error = result.expect_err("more than 128 prioritization-fee accounts must reject before I/O");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RPC_PARAMETERS);
|
||||
assert_eq!(error.context()[1].key(), "account_count");
|
||||
assert_eq!(error.context()[1].value(), "129");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signatures_for_address_serializes_pagination_and_preserves_newest_first_result() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signatures_for_address.success.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let address = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let config = crate::SolanaSignaturesForAddressConfig::new(
|
||||
std::option::Option::Some("before-signature".to_owned()),
|
||||
std::option::Option::Some("until-signature".to_owned()),
|
||||
std::option::Option::Some(1_000),
|
||||
std::option::Option::Some(crate::SolanaCommitment::Finalized),
|
||||
std::option::Option::Some(431_000_000),
|
||||
);
|
||||
let signatures = pool
|
||||
.get_signatures_for_address(&crate::HttpRoleName::new("default"), &address, std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("getSignaturesForAddress fixture must succeed");
|
||||
assert_eq!(signatures.len(), 2);
|
||||
assert_eq!(signatures[0].signature(), "newest-signature");
|
||||
assert_eq!(signatures[0].slot(), 431_000_040);
|
||||
assert_eq!(signatures[0].memo(), std::option::Option::Some("memo-newest"));
|
||||
assert_eq!(signatures[0].block_time(), std::option::Option::Some(1_787_000_100));
|
||||
assert_eq!(signatures[0].confirmation_status(), std::option::Option::Some(crate::SolanaTransactionConfirmationStatus::Finalized));
|
||||
assert_eq!(signatures[0].transaction_index(), std::option::Option::Some(9));
|
||||
assert_eq!(signatures[1].signature(), "older-signature");
|
||||
assert!(signatures[1].err().is_some());
|
||||
assert_eq!(signatures[1].memo(), std::option::Option::None);
|
||||
assert_eq!(signatures[1].block_time(), std::option::Option::None);
|
||||
assert_eq!(signatures[1].transaction_index(), std::option::Option::None);
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["method"], serde_json::json!("getSignaturesForAddress"));
|
||||
assert_eq!(
|
||||
body["params"],
|
||||
serde_json::json!([
|
||||
address.to_string(),
|
||||
{
|
||||
"before":"before-signature",
|
||||
"until":"until-signature",
|
||||
"limit":1000,
|
||||
"commitment":"finalized",
|
||||
"minContextSlot":431000000
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signatures_for_address_rejects_limit_outside_1_to_1000_before_io() {
|
||||
let pool = transaction_pool_for_url("http://127.0.0.1:9");
|
||||
let address = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
for limit in [0_usize, 1_001_usize] {
|
||||
let config = crate::SolanaSignaturesForAddressConfig::new(
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(limit),
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
);
|
||||
let result = pool.get_signatures_for_address(&crate::HttpRoleName::new("default"), &address, std::option::Option::Some(&config)).await;
|
||||
let error = result.expect_err("out-of-range getSignaturesForAddress limit must reject before I/O");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RPC_PARAMETERS);
|
||||
assert_eq!(error.context()[1].key(), "limit");
|
||||
assert_eq!(error.context()[1].value(), limit.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signatures_for_address_preserves_rpc_application_error() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signatures_for_address.error.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let address = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let result = pool.get_signatures_for_address(&crate::HttpRoleName::new("default"), &address, std::option::Option::None).await;
|
||||
let error = result.expect_err("remote transaction-history error must remain an RPC application error");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_RPC_APPLICATION_ERROR);
|
||||
handle.join().expect("fixture server must join");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signature_statuses_preserves_positional_nulls_and_history_config() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signature_statuses.success.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let signatures = std::vec!["missing-signature".to_owned(), "finalized-signature".to_owned(), "confirmed-signature".to_owned()];
|
||||
let config = crate::SolanaSignatureStatusesConfig::new(std::option::Option::Some(true));
|
||||
let response = pool
|
||||
.get_signature_statuses(&crate::HttpRoleName::new("default"), signatures.as_slice(), std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("getSignatureStatuses fixture must succeed");
|
||||
assert_eq!(response.context().slot(), 431_000_050);
|
||||
assert_eq!(response.context().api_version(), std::option::Option::Some("4.2.1"));
|
||||
assert_eq!(response.value().len(), 3);
|
||||
assert!(response.value()[0].is_none());
|
||||
let finalized = response.value()[1].as_ref().expect("second positional status must be present");
|
||||
assert_eq!(finalized.slot(), 431_000_049);
|
||||
assert_eq!(finalized.confirmations(), std::option::Option::None);
|
||||
assert_eq!(finalized.status(), &serde_json::json!({"Ok":null}));
|
||||
assert_eq!(finalized.confirmation_status(), std::option::Option::Some(crate::SolanaTransactionConfirmationStatus::Finalized));
|
||||
let confirmed = response.value()[2].as_ref().expect("third positional status must be present");
|
||||
assert_eq!(confirmed.confirmations(), std::option::Option::Some(2));
|
||||
assert!(confirmed.err().is_some());
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["method"], serde_json::json!("getSignatureStatuses"));
|
||||
assert_eq!(body["params"], serde_json::json!([signatures, {"searchTransactionHistory":true}]));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signature_statuses_accepts_empty_input_and_omits_empty_config() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signature_statuses.empty.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let signatures = std::vec::Vec::<std::string::String>::new();
|
||||
let config = crate::SolanaSignatureStatusesConfig::default();
|
||||
let response = pool
|
||||
.get_signature_statuses(&crate::HttpRoleName::new("default"), signatures.as_slice(), std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("empty getSignatureStatuses input must remain accepted");
|
||||
assert!(response.value().is_empty());
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
assert_eq!(transaction_request_body(request.as_str())["params"], serde_json::json!([[]]));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signature_statuses_accepts_256_and_rejects_more_than_256_before_io() {
|
||||
let signatures = std::vec!["signature".to_owned(); 256];
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signature_statuses.max_256.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let response = pool
|
||||
.get_signature_statuses(&crate::HttpRoleName::new("default"), signatures.as_slice(), std::option::Option::None)
|
||||
.await
|
||||
.expect("exactly 256 signatures must remain accepted");
|
||||
assert_eq!(response.value().len(), 256);
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["params"][0].as_array().expect("signature parameter must be an array").len(), 256);
|
||||
|
||||
let invalid_pool = transaction_pool_for_url("http://127.0.0.1:9");
|
||||
let signatures = std::vec!["signature".to_owned(); 257];
|
||||
let result = invalid_pool.get_signature_statuses(&crate::HttpRoleName::new("default"), signatures.as_slice(), std::option::Option::None).await;
|
||||
let error = result.expect_err("more than 256 signatures must reject before I/O");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RPC_PARAMETERS);
|
||||
assert_eq!(error.context()[1].key(), "signature_count");
|
||||
assert_eq!(error.context()[1].value(), "257");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_signature_statuses_rejects_response_count_mismatch() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_signature_statuses.count_mismatch.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let requested = std::vec!["first".to_owned(), "second".to_owned()];
|
||||
let result = pool.get_signature_statuses(&crate::HttpRoleName::new("default"), requested.as_slice(), std::option::Option::None).await;
|
||||
let error = result.expect_err("status response count mismatch must reject typed decoding");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RESPONSE);
|
||||
assert_eq!(error.context()[1].key(), "expected_count");
|
||||
assert_eq!(error.context()[1].value(), "2");
|
||||
assert_eq!(error.context()[2].key(), "actual_count");
|
||||
assert_eq!(error.context()[2].value(), "1");
|
||||
handle.join().expect("fixture server must join");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user