automerge
This commit is contained in:
@ -116,10 +116,12 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
let status = if self.url == "sig_not_found" {
|
let status = if self.url == "sig_not_found" {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
let err = status.clone().err();
|
||||||
Some(TransactionStatus {
|
Some(TransactionStatus {
|
||||||
status,
|
status,
|
||||||
slot: 1,
|
slot: 1,
|
||||||
confirmations: Some(0),
|
confirmations: Some(0),
|
||||||
|
err,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
serde_json::to_value(Response {
|
serde_json::to_value(Response {
|
||||||
|
@ -4,7 +4,7 @@ use solana_sdk::{
|
|||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
transaction::Result,
|
transaction::{Result, TransactionError},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
||||||
|
|
||||||
@ -54,6 +54,12 @@ pub struct RpcKeyedAccount {
|
|||||||
pub account: RpcAccount,
|
pub account: RpcAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcSignatureResult {
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
/// A duplicate representation of a Message for pretty JSON serialization
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -1982,10 +1982,20 @@ mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == success_signature.to_string() {
|
if transaction.signatures[0] == success_signature.to_string() {
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
let meta = meta.unwrap();
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
|
assert_eq!(meta.status, Ok(()));
|
||||||
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
@ -2530,10 +2530,20 @@ pub(crate) mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == signatures[0].to_string() {
|
if transaction.signatures[0] == signatures[0].to_string() {
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
let meta = meta.unwrap();
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
|
assert_eq!(meta.status, Ok(()));
|
||||||
} else if transaction.signatures[0] == signatures[1].to_string() {
|
} else if transaction.signatures[0] == signatures[1].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
@ -460,10 +460,12 @@ impl JsonRpcRequestProcessor {
|
|||||||
.get_confirmation_count(slot)
|
.get_confirmation_count(slot)
|
||||||
.or(Some(0))
|
.or(Some(0))
|
||||||
};
|
};
|
||||||
|
let err = status.clone().err();
|
||||||
TransactionStatus {
|
TransactionStatus {
|
||||||
slot,
|
slot,
|
||||||
status,
|
status,
|
||||||
confirmations,
|
confirmations,
|
||||||
|
err,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2416,11 +2418,21 @@ pub mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
assert_eq!(meta.status, Ok(()));
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
@ -2450,11 +2462,21 @@ pub mod tests {
|
|||||||
let decoded_transaction: Transaction =
|
let decoded_transaction: Transaction =
|
||||||
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
||||||
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
assert_eq!(meta.status, Ok(()));
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
@ -4,8 +4,10 @@ use crate::rpc_subscriptions::{Confirmations, RpcSubscriptions, SlotInfo};
|
|||||||
use jsonrpc_core::{Error, ErrorCode, Result};
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
||||||
use solana_client::rpc_response::{Response as RpcResponse, RpcAccount, RpcKeyedAccount};
|
use solana_client::rpc_response::{
|
||||||
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature, transaction};
|
Response as RpcResponse, RpcAccount, RpcKeyedAccount, RpcSignatureResult,
|
||||||
|
};
|
||||||
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
use std::sync::{atomic, Arc};
|
use std::sync::{atomic, Arc};
|
||||||
|
|
||||||
// Suppress needless_return due to
|
// Suppress needless_return due to
|
||||||
@ -74,7 +76,7 @@ pub trait RpcSolPubSub {
|
|||||||
fn signature_subscribe(
|
fn signature_subscribe(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<transaction::Result<()>>>,
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
);
|
);
|
||||||
@ -225,7 +227,7 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||||||
fn signature_subscribe(
|
fn signature_subscribe(
|
||||||
&self,
|
&self,
|
||||||
_meta: Self::Metadata,
|
_meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<transaction::Result<()>>>,
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
) {
|
) {
|
||||||
@ -385,7 +387,7 @@ mod tests {
|
|||||||
|
|
||||||
// Test signature confirmation notification
|
// Test signature confirmation notification
|
||||||
let (response, _) = robust_poll_or_panic(receiver);
|
let (response, _) = robust_poll_or_panic(receiver);
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
let expected_res = RpcSignatureResult { err: None };
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "signatureNotification",
|
"method": "signatureNotification",
|
||||||
|
@ -8,7 +8,9 @@ use jsonrpc_pubsub::{
|
|||||||
SubscriptionId,
|
SubscriptionId,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_client::rpc_response::{Response, RpcAccount, RpcKeyedAccount, RpcResponseContext};
|
use solana_client::rpc_response::{
|
||||||
|
Response, RpcAccount, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult,
|
||||||
|
};
|
||||||
use solana_ledger::bank_forks::BankForks;
|
use solana_ledger::bank_forks::BankForks;
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -66,7 +68,7 @@ type RpcProgramSubscriptions = RwLock<
|
|||||||
type RpcSignatureSubscriptions = RwLock<
|
type RpcSignatureSubscriptions = RwLock<
|
||||||
HashMap<
|
HashMap<
|
||||||
Signature,
|
Signature,
|
||||||
HashMap<SubscriptionId, (Sink<Response<transaction::Result<()>>>, Confirmations)>,
|
HashMap<SubscriptionId, (Sink<Response<RpcSignatureResult>>, Confirmations)>,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
type RpcSlotSubscriptions = RwLock<HashMap<SubscriptionId, Sink<SlotInfo>>>;
|
type RpcSlotSubscriptions = RwLock<HashMap<SubscriptionId, Sink<SlotInfo>>>;
|
||||||
@ -207,11 +209,15 @@ fn filter_account_result(
|
|||||||
Box::new(iter::empty())
|
Box::new(iter::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_signature_result<S>(result: Option<S>, _root: Slot) -> Box<dyn Iterator<Item = S>>
|
fn filter_signature_result(
|
||||||
where
|
result: Option<transaction::Result<()>>,
|
||||||
S: 'static + Clone + Serialize,
|
_root: Slot,
|
||||||
{
|
) -> Box<dyn Iterator<Item = RpcSignatureResult>> {
|
||||||
Box::new(result.into_iter())
|
Box::new(
|
||||||
|
result
|
||||||
|
.into_iter()
|
||||||
|
.map(|result| RpcSignatureResult { err: result.err() }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_program_results(
|
fn filter_program_results(
|
||||||
@ -430,7 +436,7 @@ impl RpcSubscriptions {
|
|||||||
signature: Signature,
|
signature: Signature,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
sub_id: SubscriptionId,
|
sub_id: SubscriptionId,
|
||||||
subscriber: Subscriber<Response<transaction::Result<()>>>,
|
subscriber: Subscriber<Response<RpcSignatureResult>>,
|
||||||
) {
|
) {
|
||||||
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
||||||
add_subscription(
|
add_subscription(
|
||||||
@ -890,7 +896,7 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subscriptions.notify_subscribers(1, &bank_forks);
|
subscriptions.notify_subscribers(1, &bank_forks);
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
let expected_res = RpcSignatureResult { err: None };
|
||||||
|
|
||||||
struct Notification {
|
struct Notification {
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
@ -9,16 +9,12 @@ use reqwest::{self, header::CONTENT_TYPE};
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_client::{get_rpc_request_str, RpcClient},
|
rpc_client::{get_rpc_request_str, RpcClient},
|
||||||
rpc_response::Response,
|
rpc_response::{Response, RpcSignatureResult},
|
||||||
};
|
};
|
||||||
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig, hash::Hash, pubkey::Pubkey, signature::Signer,
|
||||||
hash::Hash,
|
system_transaction, transaction::Transaction,
|
||||||
pubkey::Pubkey,
|
|
||||||
signature::Signer,
|
|
||||||
system_transaction,
|
|
||||||
transaction::{self, Transaction},
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
@ -225,7 +221,7 @@ fn test_rpc_subscriptions() {
|
|||||||
// Track when subscriptions are ready
|
// Track when subscriptions are ready
|
||||||
let (ready_sender, ready_receiver) = channel::<()>();
|
let (ready_sender, ready_receiver) = channel::<()>();
|
||||||
// Track when status notifications are received
|
// Track when status notifications are received
|
||||||
let (status_sender, status_receiver) = channel::<(String, Response<transaction::Result<()>>)>();
|
let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
|
||||||
|
|
||||||
// Create the pub sub runtime
|
// Create the pub sub runtime
|
||||||
let mut rt = Runtime::new().unwrap();
|
let mut rt = Runtime::new().unwrap();
|
||||||
@ -305,7 +301,7 @@ fn test_rpc_subscriptions() {
|
|||||||
let timeout = deadline.saturating_duration_since(Instant::now());
|
let timeout = deadline.saturating_duration_since(Instant::now());
|
||||||
match status_receiver.recv_timeout(timeout) {
|
match status_receiver.recv_timeout(timeout) {
|
||||||
Ok((sig, result)) => {
|
Ok((sig, result)) => {
|
||||||
assert!(result.value.is_ok());
|
assert!(result.value.err.is_none());
|
||||||
assert!(signature_set.remove(&sig));
|
assert!(signature_set.remove(&sig));
|
||||||
}
|
}
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
|
@ -299,12 +299,13 @@ The result field will be an object with the following fields:
|
|||||||
* `transactions: <array>` - an array of JSON objects containing:
|
* `transactions: <array>` - an array of JSON objects containing:
|
||||||
* `transaction: <object|string>` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
* `transaction: <object|string>` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||||
* `meta: <object>` - transaction status metadata object, containing `null` or:
|
* `meta: <object>` - transaction status metadata object, containing `null` or:
|
||||||
* `status: <object>` - Transaction status:
|
* `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)
|
||||||
* `"Ok": null` - Transaction was successful
|
* `fee: <u64>` - fee this transaction was charged, as u64 integer
|
||||||
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L18)
|
* `preBalances: <array>` - array of u64 account balances from before the transaction was processed
|
||||||
* `fee: <u64>` - fee this transaction was charged, as u64 integer
|
* `postBalances: <array>` - array of u64 account balances after the transaction was processed
|
||||||
* `preBalances: <array>` - array of u64 account balances from before the transaction was processed
|
* DEPRECATED: `status: <object>` - Transaction status
|
||||||
* `postBalances: <array>` - array of u64 account balances after the transaction was processed
|
* `"Ok": <null>` - Transaction was successful
|
||||||
|
* `"Err": <ERR>` - Transaction failed with TransactionError
|
||||||
* `rewards: <array>` - an array of JSON objects containing:
|
* `rewards: <array>` - an array of JSON objects containing:
|
||||||
* `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
* `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
||||||
* `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
* `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
||||||
@ -316,13 +317,13 @@ The result field will be an object with the following fields:
|
|||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]}' localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary"]}' localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Transaction Structure
|
#### Transaction Structure
|
||||||
@ -703,9 +704,10 @@ An array of:
|
|||||||
* `<object>`
|
* `<object>`
|
||||||
* `slot: <u64>` - The slot the transaction was processed
|
* `slot: <u64>` - The slot the transaction was processed
|
||||||
* `confirmations: <usize | null>` - Number of blocks since signature confirmation, null if rooted
|
* `confirmations: <usize | null>` - Number of blocks since signature confirmation, null if rooted
|
||||||
* `status: <object>` - Transaction status
|
* `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)
|
||||||
|
* DEPRECATED: `status: <object>` - Transaction status
|
||||||
* `"Ok": <null>` - Transaction was successful
|
* `"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)
|
* `"Err": <ERR>` - Transaction failed with TransactionError
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
@ -714,10 +716,10 @@ An array of:
|
|||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]]}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 72, "confirmations": 10, "status": {"Ok": null}}, null]},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 72, "confirmations": 10, "err": null, "status": {"Ok": null}}, null]},"id":1}
|
||||||
|
|
||||||
// Result, first transaction rooted
|
// Result, first transaction rooted
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 48, "confirmations": null, "status": {"Ok": null}}, null]},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 48, "confirmations": null, "err": null, "status": {"Ok": null}}, null]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getSlot
|
### getSlot
|
||||||
@ -1226,7 +1228,7 @@ Subscribe to a transaction signature to receive notification when the transactio
|
|||||||
#### Notification Format:
|
#### Notification Format:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": "Confirmed","subscription":0}}
|
{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": {"err": null}, "subscription":0}}
|
||||||
```
|
```
|
||||||
|
|
||||||
### signatureUnsubscribe
|
### signatureUnsubscribe
|
||||||
|
@ -37,8 +37,8 @@ use solana_sdk::{
|
|||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, EncodedTransaction, Rewards, TransactionEncoding, TransactionStatusMeta,
|
ConfirmedBlock, EncodedTransaction, Rewards, RpcTransactionStatusMeta, TransactionEncoding,
|
||||||
TransactionWithStatusMeta,
|
TransactionStatusMeta, TransactionWithStatusMeta,
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
||||||
use std::{
|
use std::{
|
||||||
@ -1500,7 +1500,8 @@ impl Blockstore {
|
|||||||
meta: self
|
meta: self
|
||||||
.transaction_status_cf
|
.transaction_status_cf
|
||||||
.get((slot, signature))
|
.get((slot, signature))
|
||||||
.expect("Expect database get to succeed"),
|
.expect("Expect database get to succeed")
|
||||||
|
.map(RpcTransactionStatusMeta::from),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -4848,7 +4849,7 @@ pub mod tests {
|
|||||||
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_transactions: Vec<(Transaction, Option<TransactionStatusMeta>)> = entries
|
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatusMeta>)> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.filter(|entry| !entry.is_tick())
|
.filter(|entry| !entry.is_tick())
|
||||||
@ -4887,12 +4888,15 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
(
|
(
|
||||||
transaction,
|
transaction,
|
||||||
Some(TransactionStatusMeta {
|
Some(
|
||||||
status: Ok(()),
|
TransactionStatusMeta {
|
||||||
fee: 42,
|
status: Ok(()),
|
||||||
pre_balances,
|
fee: 42,
|
||||||
post_balances,
|
pre_balances,
|
||||||
}),
|
post_balances,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -4,7 +4,7 @@ use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient}
|
|||||||
use solana_metrics::{datapoint_error, datapoint_info};
|
use solana_metrics::{datapoint_error, datapoint_info};
|
||||||
use solana_sdk::{clock::Slot, program_utils::limited_deserialize, transaction::Transaction};
|
use solana_sdk::{clock::Slot, program_utils::limited_deserialize, transaction::Transaction};
|
||||||
use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup};
|
use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup};
|
||||||
use solana_transaction_status::{ConfirmedBlock, TransactionEncoding, TransactionStatusMeta};
|
use solana_transaction_status::{ConfirmedBlock, RpcTransactionStatusMeta, TransactionEncoding};
|
||||||
use std::{collections::HashMap, thread::sleep, time::Duration};
|
use std::{collections::HashMap, thread::sleep, time::Duration};
|
||||||
|
|
||||||
pub type PubkeyString = String;
|
pub type PubkeyString = String;
|
||||||
@ -41,7 +41,7 @@ pub struct StakeAccountsInfo {
|
|||||||
fn process_transaction(
|
fn process_transaction(
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
meta: &TransactionStatusMeta,
|
meta: &RpcTransactionStatusMeta,
|
||||||
stake_accounts: &mut HashMap<PubkeyString, StakeAccountInfo>,
|
stake_accounts: &mut HashMap<PubkeyString, StakeAccountInfo>,
|
||||||
) {
|
) {
|
||||||
let mut last_instruction = true;
|
let mut last_instruction = true;
|
||||||
@ -194,7 +194,7 @@ fn process_confirmed_block(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(meta) => {
|
Some(meta) => {
|
||||||
if meta.status.is_ok() {
|
if meta.err.is_none() {
|
||||||
if let Some(transaction) = rpc_transaction.transaction.decode() {
|
if let Some(transaction) = rpc_transaction.transaction.decode() {
|
||||||
if transaction.verify().is_ok() {
|
if transaction.verify().is_ok() {
|
||||||
process_transaction(slot, &transaction, &meta, stake_accounts);
|
process_transaction(slot, &transaction, &meta, stake_accounts);
|
||||||
|
@ -5,7 +5,7 @@ use bincode;
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
message::MessageHeader,
|
message::MessageHeader,
|
||||||
transaction::{Result, Transaction},
|
transaction::{Result, Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
/// A duplicate representation of a Message for pretty JSON serialization
|
||||||
@ -26,12 +26,35 @@ pub struct TransactionStatusMeta {
|
|||||||
pub post_balances: Vec<u64>,
|
pub post_balances: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcTransactionStatusMeta {
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
pub status: Result<()>, // This field is deprecated. See https://github.com/solana-labs/solana/issues/9302
|
||||||
|
pub fee: u64,
|
||||||
|
pub pre_balances: Vec<u64>,
|
||||||
|
pub post_balances: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TransactionStatusMeta> for RpcTransactionStatusMeta {
|
||||||
|
fn from(meta: TransactionStatusMeta) -> Self {
|
||||||
|
Self {
|
||||||
|
err: meta.status.clone().err(),
|
||||||
|
status: meta.status,
|
||||||
|
fee: meta.fee,
|
||||||
|
pre_balances: meta.pre_balances,
|
||||||
|
post_balances: meta.post_balances,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TransactionStatus {
|
pub struct TransactionStatus {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
pub confirmations: Option<usize>,
|
pub confirmations: Option<usize>,
|
||||||
pub status: Result<()>,
|
pub status: Result<()>,
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -74,7 +97,7 @@ pub struct RpcMessage {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TransactionWithStatusMeta {
|
pub struct TransactionWithStatusMeta {
|
||||||
pub transaction: EncodedTransaction,
|
pub transaction: EncodedTransaction,
|
||||||
pub meta: Option<TransactionStatusMeta>,
|
pub meta: Option<RpcTransactionStatusMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
|
Reference in New Issue
Block a user