Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Add a flag to simulateTransaction to use most recent blockhash (backport #17485) #17497

Merged
merged 3 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client/src/rpc_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
83 changes: 82 additions & 1 deletion core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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",
Expand All @@ -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"))
Expand Down
4 changes: 3 additions & 1 deletion docs/src/developing/clients/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down