v0.2.3-pre.005
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":{"slot":431000061,"blockTime":1787000201,"transaction":["3Bxs4NN8M2Yn4TLb","base58"],"meta":null,"version":"legacy","transactionIndex":0},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":{"slot":431000062,"blockTime":1787000202,"transaction":["AQIDBAUGBwg=","base64"],"meta":null,"version":0,"transactionIndex":1},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":{"slot":431000060,"blockTime":null,"transaction":"3Bxs4NN8M2Yn4TLb","meta":null,"version":"legacy"},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","error":{"code":-32015,"message":"Transaction version (1) is not supported by the requesting client. Please try the request again with the following configuration parameter: \"maxSupportedTransactionVersion\": 1"},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":{"slot":431000063,"blockTime":1787000203,"transaction":{"signatures":["fixture-signature"],"message":{"header":{"numRequiredSignatures":1,"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":1},"accountKeys":["11111111111111111111111111111111","SysvarRent111111111111111111111111111111111"],"recentBlockhash":"11111111111111111111111111111111","instructions":[{"programIdIndex":0,"accounts":[0,1],"data":"3Bxs4NN8","stackHeight":1}],"addressTableLookups":null}},"meta":{"err":null,"status":{"Ok":null},"fee":5000,"preBalances":[100000,1],"postBalances":[95000,1],"innerInstructions":[],"logMessages":["Program 11111111111111111111111111111111 invoke [1]","Program 11111111111111111111111111111111 success"],"preTokenBalances":[],"postTokenBalances":[],"rewards":null,"loadedAddresses":{"writable":[],"readonly":[]},"returnData":{"programId":"11111111111111111111111111111111","data":["AQID","base64"]},"computeUnitsConsumed":150,"costUnits":190},"version":0,"transactionIndex":7},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":{"slot":431000064,"blockTime":1787000204,"transaction":{"signatures":["fixture-signature-parsed"],"message":{"accountKeys":[{"pubkey":"11111111111111111111111111111111","signer":true,"writable":true,"source":"transaction"},{"pubkey":"SysvarRent111111111111111111111111111111111","signer":false,"writable":false,"source":"transaction"}],"recentBlockhash":"11111111111111111111111111111111","instructions":[{"program":"system","programId":"11111111111111111111111111111111","stackHeight":1,"parsed":{"type":"transfer","info":{"lamports":1,"source":"11111111111111111111111111111111","destination":"SysvarRent111111111111111111111111111111111"}}}]}},"meta":{"err":null,"status":{"Ok":null},"fee":5000,"preBalances":[100000,1],"postBalances":[95000,1],"innerInstructions":null,"logMessages":null,"preTokenBalances":[],"postTokenBalances":[],"rewards":null,"returnData":null,"computeUnitsConsumed":150,"costUnits":190},"version":"legacy","transactionIndex":null},"id":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"jsonrpc":"2.0","result":null,"id":1}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
/// Binary encoding accepted for serialized transaction input payloads.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
@@ -20,7 +20,6 @@ impl SolanaTransactionBinaryEncoding {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn from_wire(value: &str) -> std::option::Option<Self> {
|
||||
return match value {
|
||||
"base58" => std::option::Option::Some(Self::Base58),
|
||||
@@ -167,7 +166,6 @@ impl SolanaGetTransactionConfig {
|
||||
|
||||
/// Serializes the modern config to its Solana JSON-RPC wire object.
|
||||
#[must_use]
|
||||
#[cfg(test)]
|
||||
pub(crate) fn to_json_value(self) -> serde_json::Value {
|
||||
let mut object = serde_json::Map::new();
|
||||
if let std::option::Option::Some(commitment) = self.commitment {
|
||||
@@ -827,7 +825,6 @@ pub enum SolanaEncodedTransaction {
|
||||
|
||||
impl SolanaEncodedTransaction {
|
||||
/// Decodes the untagged transaction wire union without decoding transaction bytes.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
return match value {
|
||||
serde_json::Value::String(data) => std::result::Result::Ok(Self::LegacyBinary(data)),
|
||||
@@ -848,7 +845,6 @@ pub enum SolanaTransactionVersion {
|
||||
}
|
||||
|
||||
impl SolanaTransactionVersion {
|
||||
#[cfg(test)]
|
||||
fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
return match value {
|
||||
serde_json::Value::String(value) if value == "legacy" => std::result::Result::Ok(Self::Legacy),
|
||||
@@ -926,7 +922,6 @@ impl SolanaConfirmedTransaction {
|
||||
}
|
||||
|
||||
/// Decodes one non-null confirmed transaction without decoding Program-specific transaction internals.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
let decoded = crate::decode_wire_json::<WireConfirmedTransaction>(method, value);
|
||||
let wire = match decoded {
|
||||
@@ -1251,6 +1246,74 @@ impl crate::HttpTransportPool {
|
||||
};
|
||||
}
|
||||
|
||||
/// Executes the current object-form `getTransaction` request through the common KSP HTTP transport path.
|
||||
///
|
||||
/// `None` omits the optional second parameter. `Some(config)` sends the modern object form exactly, including an empty `{}` object when the
|
||||
/// caller explicitly supplies an empty modern configuration object.
|
||||
pub async fn get_transaction(
|
||||
&self,
|
||||
role: &crate::HttpRoleName,
|
||||
signature: &str,
|
||||
config: std::option::Option<&crate::SolanaGetTransactionConfig>,
|
||||
) -> ksp_core_lib::Result<std::option::Option<crate::SolanaConfirmedTransaction>> {
|
||||
if let std::option::Option::Some(config) = config
|
||||
&& config.commitment() == std::option::Option::Some(crate::SolanaCommitment::Processed)
|
||||
{
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_INVALID_RPC_PARAMETERS,
|
||||
"getTransaction commitment must be confirmed or finalized when explicitly provided",
|
||||
)
|
||||
.with_context("rpc_method", "getTransaction")
|
||||
.with_context("commitment", "processed"),
|
||||
);
|
||||
}
|
||||
let mut params = std::vec![serde_json::Value::String(signature.to_owned())];
|
||||
if let std::option::Option::Some(config) = config {
|
||||
params.push((*config).to_json_value());
|
||||
}
|
||||
return self.execute_get_transaction(role, params).await;
|
||||
}
|
||||
|
||||
/// Executes the deprecated bare-encoding `getTransaction` request form retained by Solana RPC for backwards compatibility.
|
||||
#[deprecated(note = "use HttpTransportPool::get_transaction with SolanaGetTransactionConfig; the bare encoding request form is deprecated")]
|
||||
pub async fn get_transaction_legacy(
|
||||
&self,
|
||||
role: &crate::HttpRoleName,
|
||||
signature: &str,
|
||||
encoding: crate::SolanaTransactionEncoding,
|
||||
) -> ksp_core_lib::Result<std::option::Option<crate::SolanaConfirmedTransaction>> {
|
||||
ksp_logging_lib::warn!(
|
||||
target: crate::TRACING_TARGET,
|
||||
rpc_method = "getTransaction",
|
||||
request_form = "bare_encoding",
|
||||
encoding = encoding.as_str(),
|
||||
"deprecated Solana HTTP RPC request form used"
|
||||
);
|
||||
let params = std::vec![serde_json::Value::String(signature.to_owned()), serde_json::Value::String(encoding.as_str().to_owned()),];
|
||||
return self.execute_get_transaction(role, params).await;
|
||||
}
|
||||
|
||||
async fn execute_get_transaction(
|
||||
&self,
|
||||
role: &crate::HttpRoleName,
|
||||
params: std::vec::Vec<serde_json::Value>,
|
||||
) -> ksp_core_lib::Result<std::option::Option<crate::SolanaConfirmedTransaction>> {
|
||||
let value = self.execute_transaction_rpc("getTransaction", role, params).await;
|
||||
let value = match value {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
if value.is_null() {
|
||||
return std::result::Result::Ok(std::option::Option::None);
|
||||
}
|
||||
let transaction = crate::SolanaConfirmedTransaction::decode_wire("getTransaction", value);
|
||||
return match transaction {
|
||||
std::result::Result::Ok(transaction) => std::result::Result::Ok(std::option::Option::Some(transaction)),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
/// Executes typed `getTransactionCount` through the common KSP HTTP transport path.
|
||||
pub async fn get_transaction_count(
|
||||
&self,
|
||||
@@ -1450,7 +1513,6 @@ fn decode_confirmation_status(
|
||||
return std::result::Result::Ok(std::option::Option::Some(status));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn decode_binary_transaction_tuple(method: &str, values: std::vec::Vec<serde_json::Value>) -> ksp_core_lib::Result<crate::SolanaEncodedTransaction> {
|
||||
if values.len() != 2 {
|
||||
return std::result::Result::Err(invalid_transaction_wire(method, "transaction", "encoded transaction tuple must contain data and encoding"));
|
||||
@@ -1490,7 +1552,6 @@ fn decode_binary_transaction_tuple(method: &str, values: std::vec::Vec<serde_jso
|
||||
return std::result::Result::Ok(crate::SolanaEncodedTransaction::Binary { data, encoding });
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn decode_transaction_version_field(
|
||||
method: &str,
|
||||
field: crate::SolanaWireField<serde_json::Value>,
|
||||
@@ -1597,7 +1658,6 @@ struct WireSignatureStatus {
|
||||
confirmation_status: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WireConfirmedTransaction {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/tests/public_api.rs
|
||||
// version: 12
|
||||
// version: 13
|
||||
|
||||
//! Integration tests for the public `ksp-onchain-transport-lib` consumer contract.
|
||||
|
||||
@@ -285,3 +285,18 @@ fn public_transaction_pre_004_additional_read_wrappers_are_available_from_crate_
|
||||
let _get_signatures_for_address = ksp_onchain_transport_lib::HttpTransportPool::get_signatures_for_address;
|
||||
let _get_signature_statuses = ksp_onchain_transport_lib::HttpTransportPool::get_signature_statuses;
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[test]
|
||||
fn public_transaction_pre_005_get_transaction_complete_request_forms_are_available_from_crate_root() {
|
||||
let _get_transaction = ksp_onchain_transport_lib::HttpTransportPool::get_transaction;
|
||||
let _get_transaction_legacy = ksp_onchain_transport_lib::HttpTransportPool::get_transaction_legacy;
|
||||
let config = ksp_onchain_transport_lib::SolanaGetTransactionConfig::new(
|
||||
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed),
|
||||
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::JsonParsed),
|
||||
std::option::Option::Some(0),
|
||||
);
|
||||
assert_eq!(config.commitment(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed));
|
||||
assert_eq!(config.encoding(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::JsonParsed));
|
||||
assert_eq!(config.max_supported_transaction_version(), std::option::Option::Some(0));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
//! Release-level completeness canaries for the `0.2.1` HTTP foundation contract.
|
||||
|
||||
@@ -291,3 +291,38 @@ fn release_pre_004_transaction_read_subset_is_exact_and_retry_safe() {
|
||||
assert_eq!(actual.len(), 7);
|
||||
assert_eq!(deferred.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_pre_005_transaction_read_subset_adds_complete_get_transaction_without_advancing_writes_or_simulation() {
|
||||
let mut expected = std::vec![
|
||||
"getFeeForMessage",
|
||||
"getLatestBlockhash",
|
||||
"getRecentPrioritizationFees",
|
||||
"getSignaturesForAddress",
|
||||
"getSignatureStatuses",
|
||||
"getTransaction",
|
||||
"getTransactionCount",
|
||||
"isBlockhashValid",
|
||||
];
|
||||
let deferred = std::vec!["requestAirdrop", "sendTransaction", "simulateTransaction"];
|
||||
let mut actual = std::vec::Vec::new();
|
||||
for method_name in &expected {
|
||||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 Transaction descriptor must exist");
|
||||
actual.push(descriptor.method());
|
||||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||||
}
|
||||
let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist");
|
||||
assert!(get_transaction.request_form_status().has_deprecated_legacy());
|
||||
for method_name in &deferred {
|
||||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered");
|
||||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||||
}
|
||||
actual.sort_unstable();
|
||||
expected.sort_unstable();
|
||||
assert_eq!(actual, expected);
|
||||
assert_eq!(actual.len(), 8);
|
||||
assert_eq!(deferred.len(), 3);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
#[test]
|
||||
fn transaction_encoding_strings_match_current_and_legacy_wire_labels() {
|
||||
@@ -686,3 +686,191 @@ async fn typed_get_signature_statuses_rejects_response_count_mismatch() {
|
||||
assert_eq!(error.context()[2].value(), "1");
|
||||
handle.join().expect("fixture server must join");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_modern_supports_omitted_and_explicit_empty_config() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_transaction.null.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let result = pool
|
||||
.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::None)
|
||||
.await
|
||||
.expect("getTransaction without config must succeed");
|
||||
assert!(result.is_none());
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
assert_eq!(transaction_request_body(request.as_str())["params"], serde_json::json!(["fixture-signature"]));
|
||||
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_transaction.null.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let config = crate::SolanaGetTransactionConfig::default();
|
||||
let result = pool
|
||||
.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("getTransaction with explicit empty modern config must succeed");
|
||||
assert!(result.is_none());
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
assert_eq!(transaction_request_body(request.as_str())["params"], serde_json::json!(["fixture-signature", {}]));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_modern_serializes_full_config_and_preserves_rich_json_parsed_wire() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_transaction.json_parsed.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let config = crate::SolanaGetTransactionConfig::new(
|
||||
std::option::Option::Some(crate::SolanaCommitment::Confirmed),
|
||||
std::option::Option::Some(crate::SolanaTransactionEncoding::JsonParsed),
|
||||
std::option::Option::Some(0),
|
||||
);
|
||||
let result = pool
|
||||
.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("modern getTransaction fixture must succeed")
|
||||
.expect("modern getTransaction fixture must contain a transaction");
|
||||
assert_eq!(result.slot(), 431_000_064);
|
||||
assert_eq!(result.block_time(), std::option::Option::Some(1_787_000_204));
|
||||
assert_eq!(result.version().value(), std::option::Option::Some(&crate::SolanaTransactionVersion::Legacy));
|
||||
assert!(result.transaction_index().is_null());
|
||||
let transaction = match result.transaction() {
|
||||
crate::SolanaEncodedTransaction::Json(value) => value,
|
||||
_ => panic!("jsonParsed response must remain a JSON object"),
|
||||
};
|
||||
assert_eq!(transaction["message"]["accountKeys"][0]["source"], serde_json::json!("transaction"));
|
||||
assert_eq!(transaction["message"]["instructions"][0]["parsed"]["type"], serde_json::json!("transfer"));
|
||||
let meta = result.meta().value().expect("metadata must be present");
|
||||
assert_eq!(meta["computeUnitsConsumed"], serde_json::json!(150));
|
||||
assert_eq!(meta["costUnits"], serde_json::json!(190));
|
||||
assert!(meta["loadedAddresses"].is_null());
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["method"], serde_json::json!("getTransaction"));
|
||||
assert_eq!(
|
||||
body["params"],
|
||||
serde_json::json!([
|
||||
"fixture-signature",
|
||||
{"commitment":"confirmed","encoding":"jsonParsed","maxSupportedTransactionVersion":0}
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_modern_covers_all_agave_v4_2_1_encoding_labels_and_response_shapes() {
|
||||
let cases = [
|
||||
(crate::SolanaTransactionEncoding::Binary, include_str!("../fixtures/http/get_transaction.binary_legacy.json")),
|
||||
(crate::SolanaTransactionEncoding::Base58, include_str!("../fixtures/http/get_transaction.base58.json")),
|
||||
(crate::SolanaTransactionEncoding::Base64, include_str!("../fixtures/http/get_transaction.base64.json")),
|
||||
(crate::SolanaTransactionEncoding::Json, include_str!("../fixtures/http/get_transaction.json.json")),
|
||||
(crate::SolanaTransactionEncoding::JsonParsed, include_str!("../fixtures/http/get_transaction.json_parsed.json")),
|
||||
];
|
||||
for (encoding, fixture) in cases {
|
||||
let (url, handle) = serve_transaction_once(fixture);
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let config = crate::SolanaGetTransactionConfig::new(std::option::Option::None, std::option::Option::Some(encoding), std::option::Option::None);
|
||||
let result = pool
|
||||
.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("encoding-specific modern getTransaction must succeed")
|
||||
.expect("encoding-specific modern getTransaction must contain a transaction");
|
||||
match encoding {
|
||||
crate::SolanaTransactionEncoding::Binary => assert!(matches!(result.transaction(), crate::SolanaEncodedTransaction::LegacyBinary(_))),
|
||||
crate::SolanaTransactionEncoding::Base58 => assert!(matches!(
|
||||
result.transaction(),
|
||||
crate::SolanaEncodedTransaction::Binary { encoding: crate::SolanaTransactionBinaryEncoding::Base58, .. }
|
||||
)),
|
||||
crate::SolanaTransactionEncoding::Base64 => assert!(matches!(
|
||||
result.transaction(),
|
||||
crate::SolanaEncodedTransaction::Binary { encoding: crate::SolanaTransactionBinaryEncoding::Base64, .. }
|
||||
)),
|
||||
crate::SolanaTransactionEncoding::Json | crate::SolanaTransactionEncoding::JsonParsed => {
|
||||
assert!(matches!(result.transaction(), crate::SolanaEncodedTransaction::Json(_)));
|
||||
},
|
||||
}
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
let body = transaction_request_body(request.as_str());
|
||||
assert_eq!(body["params"], serde_json::json!(["fixture-signature", {"encoding":encoding.as_str()}]));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_legacy_covers_all_bare_encoding_labels() {
|
||||
let cases = [
|
||||
(crate::SolanaTransactionEncoding::Binary, include_str!("../fixtures/http/get_transaction.binary_legacy.json")),
|
||||
(crate::SolanaTransactionEncoding::Base58, include_str!("../fixtures/http/get_transaction.base58.json")),
|
||||
(crate::SolanaTransactionEncoding::Base64, include_str!("../fixtures/http/get_transaction.base64.json")),
|
||||
(crate::SolanaTransactionEncoding::Json, include_str!("../fixtures/http/get_transaction.json.json")),
|
||||
(crate::SolanaTransactionEncoding::JsonParsed, include_str!("../fixtures/http/get_transaction.json_parsed.json")),
|
||||
];
|
||||
for (encoding, fixture) in cases {
|
||||
let (url, handle) = serve_transaction_once(fixture);
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let result = pool
|
||||
.get_transaction_legacy(&crate::HttpRoleName::new("default"), "fixture-signature", encoding)
|
||||
.await
|
||||
.expect("legacy bare-encoding getTransaction must succeed");
|
||||
assert!(result.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!("getTransaction"));
|
||||
assert_eq!(body["params"], serde_json::json!(["fixture-signature", encoding.as_str()]));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_preserves_raw_json_meta_version_and_transaction_index() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_transaction.json.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let config = crate::SolanaGetTransactionConfig::new(
|
||||
std::option::Option::Some(crate::SolanaCommitment::Finalized),
|
||||
std::option::Option::Some(crate::SolanaTransactionEncoding::Json),
|
||||
std::option::Option::Some(0),
|
||||
);
|
||||
let result = pool
|
||||
.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config))
|
||||
.await
|
||||
.expect("raw JSON getTransaction must succeed")
|
||||
.expect("raw JSON getTransaction must contain a transaction");
|
||||
assert_eq!(result.version().value(), std::option::Option::Some(&crate::SolanaTransactionVersion::Number(0)));
|
||||
assert_eq!(result.transaction_index().value(), std::option::Option::Some(&7));
|
||||
let meta = result.meta().value().expect("metadata must be present");
|
||||
assert_eq!(meta["status"], serde_json::json!({"Ok":null}));
|
||||
assert_eq!(meta["loadedAddresses"]["writable"], serde_json::json!([]));
|
||||
assert_eq!(meta["returnData"]["data"], serde_json::json!(["AQID", "base64"]));
|
||||
assert_eq!(meta["costUnits"], serde_json::json!(190));
|
||||
let request = handle.join().expect("fixture server must join");
|
||||
assert_eq!(
|
||||
transaction_request_body(request.as_str())["params"],
|
||||
serde_json::json!([
|
||||
"fixture-signature",
|
||||
{"commitment":"finalized","encoding":"json","maxSupportedTransactionVersion":0}
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn typed_get_transaction_preserves_unsupported_version_rpc_error() {
|
||||
let (url, handle) = serve_transaction_once(include_str!("../fixtures/http/get_transaction.error_unsupported_version.json"));
|
||||
let pool = transaction_pool_for_url(url.as_str());
|
||||
let config = crate::SolanaGetTransactionConfig::new(
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(crate::SolanaTransactionEncoding::Base64),
|
||||
std::option::Option::Some(0),
|
||||
);
|
||||
let result = pool.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config)).await;
|
||||
let error = result.expect_err("unsupported transaction version 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_transaction_rejects_processed_commitment_before_io() {
|
||||
let pool = transaction_pool_for_url("http://127.0.0.1:9");
|
||||
let config = crate::SolanaGetTransactionConfig::new(
|
||||
std::option::Option::Some(crate::SolanaCommitment::Processed),
|
||||
std::option::Option::Some(crate::SolanaTransactionEncoding::Json),
|
||||
std::option::Option::None,
|
||||
);
|
||||
let result = pool.get_transaction(&crate::HttpRoleName::new("default"), "fixture-signature", std::option::Option::Some(&config)).await;
|
||||
let error = result.expect_err("processed getTransaction commitment must reject before I/O");
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RPC_PARAMETERS);
|
||||
assert_eq!(error.context()[1].key(), "commitment");
|
||||
assert_eq!(error.context()[1].value(), "processed");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user