Adjust RPC simulateTransaction endpoint to match v1.2 (#10443)
automerge
This commit is contained in:
@ -131,7 +131,7 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
sig_verify: bool,
|
sig_verify: bool,
|
||||||
) -> RpcResult<TransactionStatus> {
|
) -> RpcResult<RpcSimulateTransactionResult> {
|
||||||
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::SimulateTransaction,
|
RpcRequest::SimulateTransaction,
|
||||||
|
@ -228,6 +228,13 @@ pub struct RpcSignatureConfirmation {
|
|||||||
pub status: Result<()>,
|
pub status: Result<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcSimulateTransactionResult {
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
pub logs: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcStorageTurn {
|
pub struct RpcStorageTurn {
|
||||||
|
@ -752,14 +752,17 @@ fn verify_signature(input: &str) -> Result<Signature> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Run transactions against a frozen bank without committing the results
|
/// Run transactions against a frozen bank without committing the results
|
||||||
fn run_transaction_simulation(bank: &Bank, transaction: Transaction) -> transaction::Result<()> {
|
fn run_transaction_simulation(
|
||||||
|
bank: &Bank,
|
||||||
|
transaction: Transaction,
|
||||||
|
) -> (transaction::Result<()>, Vec<String>) {
|
||||||
assert!(bank.is_frozen(), "simulation bank must be frozen");
|
assert!(bank.is_frozen(), "simulation bank must be frozen");
|
||||||
|
|
||||||
let txs = &[transaction];
|
let txs = &[transaction];
|
||||||
let batch = bank.prepare_simulation_batch(txs);
|
let batch = bank.prepare_simulation_batch(txs);
|
||||||
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) =
|
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) =
|
||||||
bank.load_and_execute_transactions(&batch, solana_sdk::clock::MAX_PROCESSING_AGE);
|
bank.load_and_execute_transactions(&batch, solana_sdk::clock::MAX_PROCESSING_AGE);
|
||||||
executed[0].0.clone().map(|_| ())
|
(executed[0].0.clone().map(|_| ()), vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -966,7 +969,7 @@ pub trait RpcSol {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
data: String,
|
data: String,
|
||||||
config: Option<RpcSimulateTransactionConfig>,
|
config: Option<RpcSimulateTransactionConfig>,
|
||||||
) -> RpcResponse<TransactionStatus>;
|
) -> RpcResponse<RpcSimulateTransactionResult>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSlotLeader")]
|
#[rpc(meta, name = "getSlotLeader")]
|
||||||
fn get_slot_leader(
|
fn get_slot_leader(
|
||||||
@ -1511,7 +1514,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
|
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
|
||||||
if let Err(err) = run_transaction_simulation(&bank, transaction) {
|
if let (Err(err), _log_output) = run_transaction_simulation(&bank, transaction) {
|
||||||
// Note: it's possible that the transaction simulation failed but the actual
|
// Note: it's possible that the transaction simulation failed but the actual
|
||||||
// transaction would succeed, such as when a transaction depends on an earlier
|
// transaction would succeed, such as when a transaction depends on an earlier
|
||||||
// transaction that has yet to reach max confirmations. In these cases the user
|
// transaction that has yet to reach max confirmations. In these cases the user
|
||||||
@ -1546,7 +1549,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
data: String,
|
data: String,
|
||||||
config: Option<RpcSimulateTransactionConfig>,
|
config: Option<RpcSimulateTransactionConfig>,
|
||||||
) -> RpcResponse<TransactionStatus> {
|
) -> RpcResponse<RpcSimulateTransactionResult> {
|
||||||
let (_, transaction) = deserialize_bs58_transaction(data)?;
|
let (_, transaction) = deserialize_bs58_transaction(data)?;
|
||||||
let config = config.unwrap_or_default();
|
let config = config.unwrap_or_default();
|
||||||
|
|
||||||
@ -1557,18 +1560,19 @@ impl RpcSol for RpcSolImpl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
|
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
|
||||||
|
let logs = if result.is_ok() {
|
||||||
if result.is_ok() {
|
let sim_result = run_transaction_simulation(&bank, transaction);
|
||||||
result = run_transaction_simulation(&bank, transaction);
|
result = sim_result.0;
|
||||||
}
|
Some(sim_result.1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
new_response(
|
new_response(
|
||||||
&bank,
|
&bank,
|
||||||
TransactionStatus {
|
RpcSimulateTransactionResult {
|
||||||
slot: bank.slot(),
|
|
||||||
confirmations: Some(0),
|
|
||||||
status: result.clone(),
|
|
||||||
err: result.err(),
|
err: result.err(),
|
||||||
|
logs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -2504,7 +2508,7 @@ pub mod tests {
|
|||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":{"confirmations":0,"slot": 0,"status":{"Ok":null},"err":null}
|
"value":{"err":null, "logs":[]}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
});
|
});
|
||||||
@ -2524,7 +2528,7 @@ pub mod tests {
|
|||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":{"confirmations":0,"slot":0,"status":{"Err":"SignatureFailure"},"err":"SignatureFailure"}
|
"value":{"err":"SignatureFailure", "logs":null}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
});
|
});
|
||||||
@ -2544,7 +2548,7 @@ pub mod tests {
|
|||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":{"confirmations":0,"slot": 0,"status":{"Ok":null},"err":null}
|
"value":{"err":null, "logs":[]}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
});
|
});
|
||||||
@ -2564,7 +2568,7 @@ pub mod tests {
|
|||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":{"confirmations":0,"slot": 0,"status":{"Ok":null},"err":null}
|
"value":{"err":null, "logs":[]}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
});
|
});
|
||||||
|
@ -1198,6 +1198,10 @@ Simulate sending a transaction
|
|||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
An RpcResponse containing a TransactionStatus object
|
An RpcResponse containing a TransactionStatus object
|
||||||
|
The result will be an RpcResponse JSON object with `value` set to a JSON object with the following fields:
|
||||||
|
|
||||||
|
* `err: <object | null>` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
|
* `logs: <array | null>` - Array of log messages the transaction instructions output during execution, null if simulation failed before the transaction was able to execute (for example due to an invalid blockhash or signature verification failure)
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user