* Add a flag to simulateTransaction to use most recent blockhash (cherry picked from commit96cef5260c
) * rename flag (cherry picked from commite14f3eb529
) * sigVerify conflicts with replace, add tests (cherry picked from commit660d37aadf
) Co-authored-by: Justin Starry <justin@solana.com>
This commit is contained in:
@ -28,6 +28,8 @@ pub struct RpcSendTransactionConfig {
|
||||
pub struct RpcSimulateTransactionConfig {
|
||||
#[serde(default)]
|
||||
pub sig_verify: bool,
|
||||
#[serde(default)]
|
||||
pub replace_recent_blockhash: bool,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
|
@ -3141,15 +3141,24 @@ pub mod rpc_full {
|
||||
debug!("simulate_transaction rpc request received");
|
||||
let config = config.unwrap_or_default();
|
||||
let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base58);
|
||||
let (_, transaction) = deserialize_transaction(data, encoding)?;
|
||||
let (_, mut transaction) = deserialize_transaction(data, encoding)?;
|
||||
|
||||
if config.sig_verify {
|
||||
if config.replace_recent_blockhash {
|
||||
return Err(Error::invalid_params(
|
||||
"sigVerify may not be used with replaceRecentBlockhash",
|
||||
));
|
||||
}
|
||||
|
||||
if let Err(e) = verify_transaction(&transaction) {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
let bank = &*meta.bank(config.commitment);
|
||||
if config.replace_recent_blockhash {
|
||||
transaction.message.recent_blockhash = bank.last_blockhash();
|
||||
}
|
||||
let (result, logs) = bank.simulate_transaction(transaction);
|
||||
|
||||
Ok(new_response(
|
||||
@ -4854,6 +4863,8 @@ pub mod tests {
|
||||
let tx_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
|
||||
tx.signatures[0] = Signature::default();
|
||||
let tx_badsig_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
|
||||
tx.message.recent_blockhash = Hash::default();
|
||||
let tx_invalid_recent_blockhash = bs58::encode(serialize(&tx).unwrap()).into_string();
|
||||
|
||||
bank.freeze(); // Ensure the root bank is frozen, `start_rpc_handler_with_tx()` doesn't do this
|
||||
|
||||
@ -4929,6 +4940,75 @@ pub mod tests {
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}"]}}"#,
|
||||
tx_serialized_encoded,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"context":{"slot":0},
|
||||
"value":{"err":null, "logs":[
|
||||
"Program 11111111111111111111111111111111 invoke [1]",
|
||||
"Program 11111111111111111111111111111111 success"
|
||||
]}
|
||||
},
|
||||
"id": 1,
|
||||
});
|
||||
let expected: Response =
|
||||
serde_json::from_value(expected).expect("expected response deserialization");
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(expected, result);
|
||||
|
||||
// Enabled both sigVerify=true and replaceRecentBlockhash=true
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {}]}}"#,
|
||||
tx_serialized_encoded,
|
||||
json!({
|
||||
"sigVerify": true,
|
||||
"replaceRecentBlockhash": true,
|
||||
})
|
||||
.to_string()
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let expected = json!({
|
||||
"jsonrpc":"2.0",
|
||||
"error": {
|
||||
"code": ErrorCode::InvalidParams,
|
||||
"message": "sigVerify may not be used with replaceRecentBlockhash"
|
||||
},
|
||||
"id":1
|
||||
});
|
||||
let expected: Response =
|
||||
serde_json::from_value(expected).expect("expected response deserialization");
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(expected, result);
|
||||
|
||||
// Bad recent blockhash with replaceRecentBlockhash=false
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"replaceRecentBlockhash": false}}]}}"#,
|
||||
tx_invalid_recent_blockhash,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let expected = json!({
|
||||
"jsonrpc":"2.0",
|
||||
"result": {
|
||||
"context":{"slot":0},
|
||||
"value":{"err": "BlockhashNotFound", "logs":[]}
|
||||
},
|
||||
"id":1
|
||||
});
|
||||
|
||||
let expected: Response =
|
||||
serde_json::from_value(expected).expect("expected response deserialization");
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(expected, result);
|
||||
|
||||
// Bad recent blockhash with replaceRecentBlockhash=true
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"replaceRecentBlockhash": true}}]}}"#,
|
||||
tx_invalid_recent_blockhash,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta);
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
@ -4941,6 +5021,7 @@ pub mod tests {
|
||||
},
|
||||
"id": 1,
|
||||
});
|
||||
|
||||
let expected: Response =
|
||||
serde_json::from_value(expected).expect("expected response deserialization");
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
|
@ -3231,9 +3231,11 @@ Simulate sending a transaction
|
||||
|
||||
- `<string>` - Transaction, as an encoded string. The transaction must have a valid blockhash, but is not required to be signed.
|
||||
- `<object>` - (optional) Configuration object containing the following field:
|
||||
- `sigVerify: <bool>` - if true the transaction signatures will be verified (default: false)
|
||||
- `sigVerify: <bool>` - if true the transaction signatures will be verified (default: false, conflicts with `replaceRecentBlockhash`)
|
||||
- `commitment: <string>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to simulate the transaction at (default: `"finalized"`).
|
||||
- `encoding: <string>` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`).
|
||||
- `replaceRecentBlockhash: <bool>` - (optional) if true the transaction recent blockhash will be replaced with the most recent blockhash.
|
||||
(default: false, conflicts with `sigVerify`)
|
||||
|
||||
#### Results:
|
||||
|
||||
|
Reference in New Issue
Block a user