Undo getSignatureStatus breaking change, add getSignatureStatuses (#9228)

automerge
This commit is contained in:
Justin Starry 2020-04-02 02:30:58 +08:00 committed by GitHub
parent 9aab0b9388
commit c7ba1994ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 158 additions and 12 deletions

View File

@ -88,6 +88,21 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(), value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
})?, })?,
RpcRequest::GetSignatureStatus => { RpcRequest::GetSignatureStatus => {
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
Some(Err(TransactionError::AccountInUse))
} else if self.url == "instruction_error" {
Some(Err(TransactionError::InstructionError(
0,
InstructionError::UninitializedAccount,
)))
} else if self.url == "sig_not_found" {
None
} else {
Some(Ok(()))
};
serde_json::to_value(response).unwrap()
}
RpcRequest::GetSignatureStatuses => {
let status: transaction::Result<()> = if self.url == "account_in_use" { let status: transaction::Result<()> = if self.url == "account_in_use" {
Err(TransactionError::AccountInUse) Err(TransactionError::AccountInUse)
} else if self.url == "instruction_error" { } else if self.url == "instruction_error" {

View File

@ -119,13 +119,13 @@ impl RpcClient {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<Option<transaction::Result<()>>> { ) -> ClientResult<Option<transaction::Result<()>>> {
let signature_status = self.client.send( let signature_status = self.client.send(
&RpcRequest::GetSignatureStatus, &RpcRequest::GetSignatureStatuses,
json!([[signature.to_string()], commitment_config]), json!([[signature.to_string()], commitment_config]),
5, 5,
)?; )?;
let result: Response<Vec<Option<TransactionStatus>>> = let result: Response<Vec<Option<TransactionStatus>>> =
serde_json::from_value(signature_status) serde_json::from_value(signature_status)
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatus"))?; .map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
Ok(result.value[0] Ok(result.value[0]
.clone() .clone()
.map(|status_meta| status_meta.status)) .map(|status_meta| status_meta.status))
@ -949,20 +949,20 @@ impl RpcClient {
let response = self let response = self
.client .client
.send( .send(
&RpcRequest::GetSignatureStatus, &RpcRequest::GetSignatureStatuses,
json!([[signature.to_string()], CommitmentConfig::recent().ok()]), json!([[signature.to_string()], CommitmentConfig::recent().ok()]),
1, 1,
) )
.map_err(|err| err.into_with_command("GetSignatureStatus"))?; .map_err(|err| err.into_with_command("GetSignatureStatuses"))?;
let result: Response<Vec<Option<TransactionStatus>>> = serde_json::from_value(response) let result: Response<Vec<Option<TransactionStatus>>> = serde_json::from_value(response)
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatus"))?; .map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
let confirmations = result.value[0] let confirmations = result.value[0]
.clone() .clone()
.ok_or_else(|| { .ok_or_else(|| {
ClientError::new_with_command( ClientError::new_with_command(
ClientErrorKind::Custom("signature not found".to_string()), ClientErrorKind::Custom("signature not found".to_string()),
"GetSignatureStatus", "GetSignatureStatuses",
) )
})? })?
.confirmations .confirmations

View File

@ -23,6 +23,7 @@ pub enum RpcRequest {
GetFeeCalculatorForBlockhash, GetFeeCalculatorForBlockhash,
GetFeeRateGovernor, GetFeeRateGovernor,
GetSignatureStatus, GetSignatureStatus,
GetSignatureStatuses,
GetSlot, GetSlot,
GetSlotLeader, GetSlotLeader,
GetStorageTurn, GetStorageTurn,
@ -65,6 +66,7 @@ impl RpcRequest {
RpcRequest::GetFeeCalculatorForBlockhash => "getFeeCalculatorForBlockhash", RpcRequest::GetFeeCalculatorForBlockhash => "getFeeCalculatorForBlockhash",
RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor", RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
RpcRequest::GetSignatureStatus => "getSignatureStatus", RpcRequest::GetSignatureStatus => "getSignatureStatus",
RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
RpcRequest::GetSlot => "getSlot", RpcRequest::GetSlot => "getSlot",
RpcRequest::GetSlotLeader => "getSlotLeader", RpcRequest::GetSlotLeader => "getSlotLeader",
RpcRequest::GetStorageTurn => "getStorageTurn", RpcRequest::GetStorageTurn => "getStorageTurn",

View File

@ -23,7 +23,7 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
signature::Signature, signature::Signature,
timing::slot_duration_from_slots_per_year, timing::slot_duration_from_slots_per_year,
transaction::Transaction, transaction::{self, Transaction},
}; };
use solana_transaction_status::{ConfirmedBlock, TransactionEncoding, TransactionStatus}; use solana_transaction_status::{ConfirmedBlock, TransactionEncoding, TransactionStatus};
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY}; use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
@ -398,6 +398,16 @@ impl JsonRpcRequestProcessor {
} }
pub fn get_signature_status( pub fn get_signature_status(
&self,
signature: Signature,
commitment: Option<CommitmentConfig>,
) -> Option<transaction::Result<()>> {
self.bank(commitment)
.get_signature_status_slot(&signature)
.map(|(_, status)| status)
}
pub fn get_signature_statuses(
&self, &self,
signatures: Vec<Signature>, signatures: Vec<Signature>,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
@ -556,6 +566,14 @@ pub trait RpcSol {
#[rpc(meta, name = "getSignatureStatus")] #[rpc(meta, name = "getSignatureStatus")]
fn get_signature_status( fn get_signature_status(
&self,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>>;
#[rpc(meta, name = "getSignatureStatuses")]
fn get_signature_statuses(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
signature_strs: Vec<String>, signature_strs: Vec<String>,
@ -886,6 +904,20 @@ impl RpcSol for RpcSolImpl {
} }
fn get_signature_status( fn get_signature_status(
&self,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>> {
let signature = verify_signature(&signature_str)?;
Ok(meta
.request_processor
.read()
.unwrap()
.get_signature_status(signature, commitment))
}
fn get_signature_statuses(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
signature_strs: Vec<String>, signature_strs: Vec<String>,
@ -898,7 +930,7 @@ impl RpcSol for RpcSolImpl {
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_signature_status(signatures, commitment) .get_signature_statuses(signatures, commitment)
} }
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> { fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
@ -991,7 +1023,7 @@ impl RpcSol for RpcSolImpl {
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_signature_status(vec![signature], commitment.clone())? .get_signature_statuses(vec![signature], commitment.clone())?
.value[0] .value[0]
.clone() .clone()
.map(|x| x.status); .map(|x| x.status);
@ -1757,6 +1789,76 @@ pub mod tests {
#[test] #[test]
fn test_rpc_get_signature_status() { fn test_rpc_get_signature_status() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler {
io,
meta,
blockhash,
alice,
..
} = start_rpc_handler_with_tx(&bob_pubkey);
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta.clone());
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
// Test getSignatureStatus request on unprocessed tx
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta.clone());
let expected_res: Option<String> = None;
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
// Test getSignatureStatus request on a TransactionError
let tx = system_transaction::transfer(&alice, &bob_pubkey, std::u64::MAX, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta);
let expected_res: Option<transaction::Result<()>> = Some(Err(
TransactionError::InstructionError(0, InstructionError::Custom(1)),
));
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
}
#[test]
fn test_rpc_get_signature_statuses() {
let bob_pubkey = Pubkey::new_rand(); let bob_pubkey = Pubkey::new_rand();
let RpcHandler { let RpcHandler {
io, io,
@ -1768,7 +1870,7 @@ pub mod tests {
} = start_rpc_handler_with_tx(&bob_pubkey); } = start_rpc_handler_with_tx(&bob_pubkey);
let req = format!( let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#, r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
confirmed_block_signatures[0] confirmed_block_signatures[0]
); );
let res = io.handle_request_sync(&req, meta.clone()); let res = io.handle_request_sync(&req, meta.clone());
@ -1784,7 +1886,7 @@ pub mod tests {
// Test getSignatureStatus request on unprocessed tx // Test getSignatureStatus request on unprocessed tx
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash); let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
let req = format!( let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#, r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
tx.signatures[0] tx.signatures[0]
); );
let res = io.handle_request_sync(&req, meta.clone()); let res = io.handle_request_sync(&req, meta.clone());
@ -1796,7 +1898,7 @@ pub mod tests {
// Test getSignatureStatus request on a TransactionError // Test getSignatureStatus request on a TransactionError
let req = format!( let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#, r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
confirmed_block_signatures[1] confirmed_block_signatures[1]
); );
let res = io.handle_request_sync(&req, meta.clone()); let res = io.handle_request_sync(&req, meta.clone());

View File

@ -34,6 +34,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getProgramAccounts](jsonrpc-api.md#getprogramaccounts) * [getProgramAccounts](jsonrpc-api.md#getprogramaccounts)
* [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash) * [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash)
* [getSignatureStatus](jsonrpc-api.md#getsignaturestatus) * [getSignatureStatus](jsonrpc-api.md#getsignaturestatus)
* [getSignatureStatuses](jsonrpc-api.md#getsignaturestatuses)
* [getSlot](jsonrpc-api.md#getslot) * [getSlot](jsonrpc-api.md#getslot)
* [getSlotLeader](jsonrpc-api.md#getslotleader) * [getSlotLeader](jsonrpc-api.md#getslotleader)
* [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment) * [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment)
@ -660,6 +661,32 @@ Returns the status of a given signature. This method is similar to [confirmTrans
#### Parameters: #### Parameters:
* `<string>` - Signature of Transaction to confirm, as base-58 encoded string
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
* `<null>` - Unknown transaction
* `<object>` - Transaction status:
* `"Ok": <null>` - Transaction was successful
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"Ok": null},"id":1}
```
### getSignatureStatuses
Returns the statuses of a list of signatures. This method is similar to [confirmTransaction](jsonrpc-api.md#confirmtransaction) but provides more resolution for error events. This method only searches the recent status cache of signatures, which retains all active slots plus `MAX_RECENT_BLOCKHASHES` rooted slots.
#### Parameters:
* `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings * `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings
* `<object>` - (optional) Extended Rpc configuration, containing the following optional fields: * `<object>` - (optional) Extended Rpc configuration, containing the following optional fields:
* `commitment: <string>` - [Commitment](jsonrpc-api.md#configuring-state-commitment) * `commitment: <string>` - [Commitment](jsonrpc-api.md#configuring-state-commitment)