From e2e0b0f5a9ff6152af9e74c838124ba023f5e77d Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Tue, 25 May 2021 13:01:21 -0700 Subject: [PATCH 1/3] Add a flag to simulateTransaction to use most recent blockhash (cherry picked from commit 96cef5260c4ed0d1b1fec9ba648f8eeea24e619e) --- client/src/rpc_config.rs | 2 ++ core/src/rpc.rs | 5 ++++- docs/src/developing/clients/jsonrpc-api.md | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/rpc_config.rs b/client/src/rpc_config.rs index bf97d1de55334d..ff19e6a521f298 100644 --- a/client/src/rpc_config.rs +++ b/client/src/rpc_config.rs @@ -28,6 +28,8 @@ pub struct RpcSendTransactionConfig { pub struct RpcSimulateTransactionConfig { #[serde(default)] pub sig_verify: bool, + #[serde(default)] + pub use_most_recent_blockhash: bool, #[serde(flatten)] pub commitment: Option, pub encoding: Option, diff --git a/core/src/rpc.rs b/core/src/rpc.rs index a81f1620236ba0..1b25bb019b30cf 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -3141,7 +3141,7 @@ 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 let Err(e) = verify_transaction(&transaction) { @@ -3150,6 +3150,9 @@ pub mod rpc_full { } let bank = &*meta.bank(config.commitment); + if config.use_most_recent_blockhash { + transaction.message.recent_blockhash = bank.last_blockhash(); + } let (result, logs) = bank.simulate_transaction(transaction); Ok(new_response( diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 65556b5bf0469e..7ae860618483ec 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -3234,6 +3234,7 @@ Simulate sending a transaction - `sigVerify: ` - if true the transaction signatures will be verified (default: false) - `commitment: ` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to simulate the transaction at (default: `"finalized"`). - `encoding: ` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`). + - `useMostRecentBlockhash: ` - (optional) if true the transaction recent blockhash will be ignored and overridden with the most recent blockhash. (default: false) #### Results: From 5ce5cf550ec3446a592fdb0ed6e904b8c011f961 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Tue, 25 May 2021 13:16:39 -0700 Subject: [PATCH 2/3] rename flag (cherry picked from commit e14f3eb529d7155df5e6f0a6aa4493c013242fec) --- client/src/rpc_config.rs | 2 +- core/src/rpc.rs | 2 +- docs/src/developing/clients/jsonrpc-api.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/rpc_config.rs b/client/src/rpc_config.rs index ff19e6a521f298..1061f30e5e63fc 100644 --- a/client/src/rpc_config.rs +++ b/client/src/rpc_config.rs @@ -29,7 +29,7 @@ pub struct RpcSimulateTransactionConfig { #[serde(default)] pub sig_verify: bool, #[serde(default)] - pub use_most_recent_blockhash: bool, + pub replace_recent_blockhash: bool, #[serde(flatten)] pub commitment: Option, pub encoding: Option, diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 1b25bb019b30cf..6d4d7f49d378ad 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -3150,7 +3150,7 @@ pub mod rpc_full { } let bank = &*meta.bank(config.commitment); - if config.use_most_recent_blockhash { + if config.replace_recent_blockhash { transaction.message.recent_blockhash = bank.last_blockhash(); } let (result, logs) = bank.simulate_transaction(transaction); diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 7ae860618483ec..3bb3c1a62793db 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -3234,7 +3234,7 @@ Simulate sending a transaction - `sigVerify: ` - if true the transaction signatures will be verified (default: false) - `commitment: ` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to simulate the transaction at (default: `"finalized"`). - `encoding: ` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`). - - `useMostRecentBlockhash: ` - (optional) if true the transaction recent blockhash will be ignored and overridden with the most recent blockhash. (default: false) + - `replaceRecentBlockhash: ` - (optional) if true the transaction recent blockhash will be replaced with the most recent blockhash. (default: false) #### Results: From 04026cbecd696cb358ac600f2a8fe0b9c59e3b1a Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Tue, 25 May 2021 14:04:17 -0700 Subject: [PATCH 3/3] sigVerify conflicts with replace, add tests (cherry picked from commit 660d37aadfee27a83a5986ecef98c63904b0274e) --- core/src/rpc.rs | 78 ++++++++++++++++++++++ docs/src/developing/clients/jsonrpc-api.md | 5 +- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 6d4d7f49d378ad..7d90bbba167487 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -3144,6 +3144,12 @@ pub mod rpc_full { 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); } @@ -4857,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 @@ -4932,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", @@ -4944,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")) diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 3bb3c1a62793db..40d1e971d3c076 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -3231,10 +3231,11 @@ Simulate sending a transaction - `` - Transaction, as an encoded string. The transaction must have a valid blockhash, but is not required to be signed. - `` - (optional) Configuration object containing the following field: - - `sigVerify: ` - if true the transaction signatures will be verified (default: false) + - `sigVerify: ` - if true the transaction signatures will be verified (default: false, conflicts with `replaceRecentBlockhash`) - `commitment: ` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to simulate the transaction at (default: `"finalized"`). - `encoding: ` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`). - - `replaceRecentBlockhash: ` - (optional) if true the transaction recent blockhash will be replaced with the most recent blockhash. (default: false) + - `replaceRecentBlockhash: ` - (optional) if true the transaction recent blockhash will be replaced with the most recent blockhash. + (default: false, conflicts with `sigVerify`) #### Results: