Plumb TransactionError through Rpc
This commit is contained in:
committed by
Tyera Eulberg
parent
569a289a6f
commit
90c1300bb6
114
core/src/rpc.rs
114
core/src/rpc.rs
@ -8,13 +8,12 @@ use bincode::{deserialize, serialize};
|
|||||||
use bs58;
|
use bs58;
|
||||||
use jsonrpc_core::{Error, Metadata, Result};
|
use jsonrpc_core::{Error, Metadata, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use solana_client::rpc_signature_status::RpcSignatureStatus;
|
|
||||||
use solana_drone::drone::request_airdrop_transaction;
|
use solana_drone::drone::request_airdrop_transaction;
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::account::Account;
|
use solana_sdk::account::Account;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::Signature;
|
||||||
use solana_sdk::transaction::{self, Transaction, TransactionError};
|
use solana_sdk::transaction::{self, Transaction};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::{SocketAddr, UdpSocket};
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@ -189,7 +188,11 @@ pub trait RpcSol {
|
|||||||
fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<String>;
|
fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<String>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSignatureStatus")]
|
#[rpc(meta, name = "getSignatureStatus")]
|
||||||
fn get_signature_status(&self, _: Self::Metadata, _: String) -> Result<RpcSignatureStatus>;
|
fn get_signature_status(
|
||||||
|
&self,
|
||||||
|
_: Self::Metadata,
|
||||||
|
_: String,
|
||||||
|
) -> Result<Option<transaction::Result<()>>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getTransactionCount")]
|
#[rpc(meta, name = "getTransactionCount")]
|
||||||
fn get_transaction_count(&self, _: Self::Metadata) -> Result<u64>;
|
fn get_transaction_count(&self, _: Self::Metadata) -> Result<u64>;
|
||||||
@ -221,14 +224,14 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
_: Self::Metadata,
|
_: Self::Metadata,
|
||||||
_: String,
|
_: String,
|
||||||
) -> Result<usize>;
|
) -> Result<Option<usize>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSignatureConfirmation")]
|
#[rpc(meta, name = "getSignatureConfirmation")]
|
||||||
fn get_signature_confirmation(
|
fn get_signature_confirmation(
|
||||||
&self,
|
&self,
|
||||||
_: Self::Metadata,
|
_: Self::Metadata,
|
||||||
_: String,
|
_: String,
|
||||||
) -> Result<(usize, RpcSignatureStatus)>;
|
) -> Result<Option<(usize, transaction::Result<()>)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RpcSolImpl;
|
pub struct RpcSolImpl;
|
||||||
@ -237,8 +240,12 @@ impl RpcSol for RpcSolImpl {
|
|||||||
|
|
||||||
fn confirm_transaction(&self, meta: Self::Metadata, id: String) -> Result<bool> {
|
fn confirm_transaction(&self, meta: Self::Metadata, id: String) -> Result<bool> {
|
||||||
debug!("confirm_transaction rpc request received: {:?}", id);
|
debug!("confirm_transaction rpc request received: {:?}", id);
|
||||||
self.get_signature_status(meta, id)
|
self.get_signature_status(meta, id).map(|status_option| {
|
||||||
.map(|status| status == RpcSignatureStatus::Confirmed)
|
if status_option.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
status_option.unwrap().is_ok()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> {
|
fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> {
|
||||||
@ -265,57 +272,36 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.get_recent_blockhash())
|
.get_recent_blockhash())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_signature_status(&self, meta: Self::Metadata, id: String) -> Result<RpcSignatureStatus> {
|
fn get_signature_status(
|
||||||
self.get_signature_confirmation(meta, id).map(|x| x.1)
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
id: String,
|
||||||
|
) -> Result<Option<transaction::Result<()>>> {
|
||||||
|
self.get_signature_confirmation(meta, id)
|
||||||
|
.map(|res| res.map(|x| x.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_num_blocks_since_signature_confirmation(
|
fn get_num_blocks_since_signature_confirmation(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
id: String,
|
id: String,
|
||||||
) -> Result<usize> {
|
) -> Result<Option<usize>> {
|
||||||
self.get_signature_confirmation(meta, id).map(|x| x.0)
|
self.get_signature_confirmation(meta, id)
|
||||||
|
.map(|res| res.map(|x| x.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_signature_confirmation(
|
fn get_signature_confirmation(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
id: String,
|
id: String,
|
||||||
) -> Result<(usize, RpcSignatureStatus)> {
|
) -> Result<Option<(usize, transaction::Result<()>)>> {
|
||||||
debug!("get_signature_confirmation rpc request received: {:?}", id);
|
debug!("get_signature_confirmation rpc request received: {:?}", id);
|
||||||
let signature = verify_signature(&id)?;
|
let signature = verify_signature(&id)?;
|
||||||
let res = meta
|
Ok(meta
|
||||||
.request_processor
|
.request_processor
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_signature_confirmation_status(signature);
|
.get_signature_confirmation_status(signature))
|
||||||
|
|
||||||
let status = {
|
|
||||||
if let Some((count, res)) = res {
|
|
||||||
let res = match res {
|
|
||||||
Ok(_) => RpcSignatureStatus::Confirmed,
|
|
||||||
Err(TransactionError::AccountInUse) => RpcSignatureStatus::AccountInUse,
|
|
||||||
Err(TransactionError::AccountLoadedTwice) => {
|
|
||||||
RpcSignatureStatus::AccountLoadedTwice
|
|
||||||
}
|
|
||||||
Err(TransactionError::InstructionError(_, _)) => {
|
|
||||||
RpcSignatureStatus::ProgramRuntimeError
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
trace!("mapping {:?} to GenericFailure", err);
|
|
||||||
RpcSignatureStatus::GenericFailure
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(count, res)
|
|
||||||
} else {
|
|
||||||
(0, RpcSignatureStatus::SignatureNotFound)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!(
|
|
||||||
"get_signature_confirmation rpc request status: {:?}",
|
|
||||||
status
|
|
||||||
);
|
|
||||||
Ok(status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_transaction_count(&self, meta: Self::Metadata) -> Result<u64> {
|
fn get_transaction_count(&self, meta: Self::Metadata) -> Result<u64> {
|
||||||
@ -453,8 +439,10 @@ mod tests {
|
|||||||
use jsonrpc_core::{MetaIoHandler, Response};
|
use jsonrpc_core::{MetaIoHandler, Response};
|
||||||
use solana_sdk::genesis_block::GenesisBlock;
|
use solana_sdk::genesis_block::GenesisBlock;
|
||||||
use solana_sdk::hash::{hash, Hash};
|
use solana_sdk::hash::{hash, Hash};
|
||||||
|
use solana_sdk::instruction::InstructionError;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||||
use solana_sdk::system_transaction;
|
use solana_sdk::system_transaction;
|
||||||
|
use solana_sdk::transaction::TransactionError;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair) {
|
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair) {
|
||||||
@ -466,6 +454,9 @@ mod tests {
|
|||||||
let tx = system_transaction::transfer(&alice, pubkey, 20, blockhash, 0);
|
let tx = system_transaction::transfer(&alice, pubkey, 20, blockhash, 0);
|
||||||
bank.process_transaction(&tx).expect("process transaction");
|
bank.process_transaction(&tx).expect("process transaction");
|
||||||
|
|
||||||
|
let tx = system_transaction::transfer(&alice, &alice.pubkey(), 20, blockhash, 0);
|
||||||
|
let _ = bank.process_transaction(&tx);
|
||||||
|
|
||||||
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
||||||
StorageState::default(),
|
StorageState::default(),
|
||||||
JsonRpcConfig::default(),
|
JsonRpcConfig::default(),
|
||||||
@ -601,9 +592,14 @@ mod tests {
|
|||||||
tx.signatures[0]
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":"Confirmed","id":1}}"#);
|
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
||||||
|
let expected = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": expected_res,
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
let expected: Response =
|
let expected: Response =
|
||||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
serde_json::from_value(expected).expect("expected response deserialization");
|
||||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
@ -614,10 +610,36 @@ mod tests {
|
|||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
tx.signatures[0]
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}}"#);
|
let expected_res: Option<String> = None;
|
||||||
|
let expected = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": expected_res,
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
let expected: Response =
|
let expected: Response =
|
||||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
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, &alice.pubkey(), 20, blockhash, 0);
|
||||||
|
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::DuplicateAccountIndex),
|
||||||
|
));
|
||||||
|
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"))
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
|
@ -7,7 +7,7 @@ use bincode::serialize;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
/// Reasons the runtime might have rejected an instruction.
|
/// Reasons the runtime might have rejected an instruction.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum InstructionError {
|
pub enum InstructionError {
|
||||||
/// Deprecated! Use CustomError instead!
|
/// Deprecated! Use CustomError instead!
|
||||||
/// The program instruction returned an error
|
/// The program instruction returned an error
|
||||||
|
@ -10,7 +10,7 @@ use bincode::serialize;
|
|||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
/// Reasons a transaction might be rejected.
|
/// Reasons a transaction might be rejected.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum TransactionError {
|
pub enum TransactionError {
|
||||||
/// This Pubkey is being processed in another transaction
|
/// This Pubkey is being processed in another transaction
|
||||||
AccountInUse,
|
AccountInUse,
|
||||||
|
Reference in New Issue
Block a user