feat: include replaced blockhash in RPC simulation response (#380)
* feat: include replaced blockhash in RPC simulation response * rename blockhash field to `replacement_blockhash` * add tests to ensure replacement_blockhash is returning correctly * fixed tests * fixed tests again for real this time?
This commit is contained in:
parent
de8e9e6850
commit
c207274e11
|
@ -424,6 +424,7 @@ pub struct RpcSimulateTransactionResult {
|
|||
pub units_consumed: Option<u64>,
|
||||
pub return_data: Option<UiTransactionReturnData>,
|
||||
pub inner_instructions: Option<Vec<UiInnerInstructions>>,
|
||||
pub replacement_blockhash: Option<RpcBlockhash>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -351,6 +351,7 @@ impl RpcSender for MockSender {
|
|||
units_consumed: None,
|
||||
return_data: None,
|
||||
inner_instructions: None,
|
||||
replacement_blockhash: None
|
||||
},
|
||||
})?,
|
||||
"getMinimumBalanceForRentExemption" => json![20],
|
||||
|
|
|
@ -14,7 +14,7 @@ use {
|
|||
solana_rpc_client::rpc_client::RpcClient,
|
||||
solana_rpc_client_api::{
|
||||
client_error::{ErrorKind as ClientErrorKind, Result as ClientResult},
|
||||
config::{RpcAccountInfoConfig, RpcSignatureSubscribeConfig},
|
||||
config::{RpcAccountInfoConfig, RpcSignatureSubscribeConfig, RpcSimulateTransactionConfig},
|
||||
request::RpcError,
|
||||
response::{Response as RpcResponse, RpcSignatureResult, SlotUpdate},
|
||||
},
|
||||
|
@ -139,6 +139,51 @@ fn test_rpc_send_tx() {
|
|||
info!("{:?}", json["result"]["value"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simulation_replaced_blockhash() -> ClientResult<()> {
|
||||
solana_logger::setup();
|
||||
|
||||
let alice = Keypair::new();
|
||||
let validator = TestValidator::with_no_fees(alice.pubkey(), None, SocketAddrSpace::Unspecified);
|
||||
let rpc_client = RpcClient::new(validator.rpc_url());
|
||||
|
||||
let bob = Keypair::new();
|
||||
let lamports = 50;
|
||||
|
||||
let res = rpc_client.simulate_transaction_with_config(
|
||||
&system_transaction::transfer(&alice, &bob.pubkey(), lamports, Hash::default()),
|
||||
RpcSimulateTransactionConfig {
|
||||
replace_recent_blockhash: true,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
assert!(
|
||||
res.value.replacement_blockhash.is_some(),
|
||||
"replaced_blockhash response is None"
|
||||
);
|
||||
let blockhash = res.value.replacement_blockhash.unwrap();
|
||||
// ensure nothing weird is going on
|
||||
assert_ne!(
|
||||
blockhash.blockhash,
|
||||
Hash::default().to_string(),
|
||||
"replaced_blockhash is default"
|
||||
);
|
||||
|
||||
let res = rpc_client.simulate_transaction_with_config(
|
||||
&system_transaction::transfer(&alice, &bob.pubkey(), lamports, Hash::default()),
|
||||
RpcSimulateTransactionConfig {
|
||||
replace_recent_blockhash: false,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
assert!(
|
||||
res.value.replacement_blockhash.is_none(),
|
||||
"replaced_blockhash is Some when nothing should be replaced"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rpc_invalid_requests() {
|
||||
solana_logger::setup();
|
||||
|
|
|
@ -3723,6 +3723,7 @@ pub mod rpc_full {
|
|||
units_consumed: Some(units_consumed),
|
||||
return_data: return_data.map(|return_data| return_data.into()),
|
||||
inner_instructions: None,
|
||||
replacement_blockhash: None,
|
||||
},
|
||||
}
|
||||
.into());
|
||||
|
@ -3768,15 +3769,24 @@ pub mod rpc_full {
|
|||
commitment,
|
||||
min_context_slot,
|
||||
})?;
|
||||
let mut blockhash: Option<RpcBlockhash> = None;
|
||||
if replace_recent_blockhash {
|
||||
if sig_verify {
|
||||
return Err(Error::invalid_params(
|
||||
"sigVerify may not be used with replaceRecentBlockhash",
|
||||
));
|
||||
}
|
||||
let recent_blockhash = bank.last_blockhash();
|
||||
unsanitized_tx
|
||||
.message
|
||||
.set_recent_blockhash(bank.last_blockhash());
|
||||
.set_recent_blockhash(recent_blockhash);
|
||||
let last_valid_block_height = bank
|
||||
.get_blockhash_last_valid_block_height(&recent_blockhash)
|
||||
.expect("bank blockhash queue should contain blockhash");
|
||||
blockhash.replace(RpcBlockhash {
|
||||
blockhash: recent_blockhash.to_string(),
|
||||
last_valid_block_height,
|
||||
});
|
||||
}
|
||||
|
||||
let transaction = sanitize_transaction(unsanitized_tx, bank)?;
|
||||
|
@ -3857,6 +3867,7 @@ pub mod rpc_full {
|
|||
units_consumed: Some(units_consumed),
|
||||
return_data: return_data.map(|return_data| return_data.into()),
|
||||
inner_instructions,
|
||||
replacement_blockhash: blockhash,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -6009,6 +6020,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData":null,
|
||||
"unitsConsumed":150,
|
||||
}
|
||||
|
@ -6094,6 +6106,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData":null,
|
||||
"unitsConsumed":150,
|
||||
}
|
||||
|
@ -6123,7 +6136,8 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
],
|
||||
"returnData":null,
|
||||
"replacementBlockhash": null,
|
||||
"returnData": null,
|
||||
"unitsConsumed":150,
|
||||
}
|
||||
},
|
||||
|
@ -6173,7 +6187,8 @@ pub mod tests {
|
|||
"accounts":null,
|
||||
"innerInstructions":null,
|
||||
"logs":[],
|
||||
"returnData":null,
|
||||
"replacementBlockhash": null,
|
||||
"returnData": null,
|
||||
"unitsConsumed":0,
|
||||
}
|
||||
},
|
||||
|
@ -6191,6 +6206,11 @@ pub mod tests {
|
|||
r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_invalid_recent_blockhash}", {{"replaceRecentBlockhash": true}}]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let latest_blockhash = bank.confirmed_last_blockhash();
|
||||
let expiry_slot = bank
|
||||
.get_blockhash_last_valid_block_height(&latest_blockhash)
|
||||
.expect("blockhash exists");
|
||||
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
|
@ -6203,6 +6223,10 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": {
|
||||
"blockhash": latest_blockhash.to_string(),
|
||||
"lastValidBlockHeight": expiry_slot
|
||||
},
|
||||
"returnData":null,
|
||||
"unitsConsumed":150,
|
||||
}
|
||||
|
@ -6347,6 +6371,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData": null,
|
||||
"unitsConsumed": 150,
|
||||
}
|
||||
|
@ -6427,6 +6452,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 success",
|
||||
"Program AddressLookupTab1e1111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData":null,
|
||||
"unitsConsumed":1200,
|
||||
}
|
||||
|
@ -6470,6 +6496,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 success",
|
||||
"Program AddressLookupTab1e1111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData":null,
|
||||
"unitsConsumed":1200,
|
||||
}
|
||||
|
@ -6556,6 +6583,7 @@ pub mod tests {
|
|||
"Program 11111111111111111111111111111111 success",
|
||||
"Program AddressLookupTab1e1111111111111111111111111 success"
|
||||
],
|
||||
"replacementBlockhash": null,
|
||||
"returnData":null,
|
||||
"unitsConsumed":1200,
|
||||
}
|
||||
|
@ -6931,7 +6959,7 @@ pub mod tests {
|
|||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","innerInstructions":null,"logs":[],"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","innerInstructions":null,"logs":[],"replacementBlockhash":null,"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue