continue work on gettxout
This commit is contained in:
parent
8185a2f7c7
commit
9e380b8ccd
|
@ -3,6 +3,9 @@
|
|||
mod codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
pub const EXECUTION_ERROR: i64 = -32015;
|
||||
pub const TRANSACTION_NOT_FOUND: i64 = -32096;
|
||||
pub const TRANSACTION_OUTPUT_NOT_FOUND: i64 = -32097;
|
||||
pub const TRANSACTION_OF_SIDE_BRANCH: i64 = -32098;
|
||||
pub const BLOCK_NOT_FOUND: i64 = -32099;
|
||||
}
|
||||
|
||||
|
@ -52,3 +55,27 @@ pub fn block_at_height_not_found<T: fmt::Debug>(data: T) -> Error {
|
|||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transaction_not_found<T: fmt::Debug>(data: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::TRANSACTION_NOT_FOUND),
|
||||
message: "Transaction with given hash is not found".into(),
|
||||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transaction_output_not_found<T: fmt::Debug>(data: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::TRANSACTION_OUTPUT_NOT_FOUND),
|
||||
message: "Transaction output is not found".into(),
|
||||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transaction_of_side_branch<T: fmt::Debug>(data: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::TRANSACTION_OF_SIDE_BRANCH),
|
||||
message: "Transaction is of side branch".into(),
|
||||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
use v1::traits::BlockChain;
|
||||
use v1::types::{GetBlockResponse, VerboseBlock, RawBlock};
|
||||
use v1::types::GetTxOutResponse;
|
||||
use v1::types::{GetTxOutResponse, TxOutScriptPubKey};
|
||||
use v1::types::GetTxOutSetInfoResponse;
|
||||
use v1::types::H256;
|
||||
use v1::types::U256;
|
||||
use v1::helpers::errors::{block_not_found, block_at_height_not_found};
|
||||
use v1::types::ScriptType;
|
||||
use v1::helpers::errors::{block_not_found, block_at_height_not_found, transaction_not_found,
|
||||
transaction_output_not_found, transaction_of_side_branch};
|
||||
use jsonrpc_macros::Trailing;
|
||||
use jsonrpc_core::Error;
|
||||
use db;
|
||||
use script::Script;
|
||||
use chain::OutPoint;
|
||||
use verification;
|
||||
use ser::serialize;
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
|
@ -23,6 +27,7 @@ pub trait BlockChainClientCoreApi: Send + Sync + 'static {
|
|||
fn difficulty(&self) -> f64;
|
||||
fn raw_block(&self, hash: GlobalH256) -> Option<RawBlock>;
|
||||
fn verbose_block(&self, hash: GlobalH256) -> Option<VerboseBlock>;
|
||||
fn verbose_transaction_out(&self, prev_out: OutPoint) -> Result<GetTxOutResponse, Error>;
|
||||
}
|
||||
|
||||
pub struct BlockChainClientCore {
|
||||
|
@ -92,6 +97,55 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn verbose_transaction_out(&self, prev_out: OutPoint) -> Result<GetTxOutResponse, Error> {
|
||||
let transaction = match self.storage.transaction(&prev_out.hash) {
|
||||
Some(transaction) => transaction,
|
||||
// no transaction => no response
|
||||
None => return Err(transaction_not_found(prev_out.hash)),
|
||||
};
|
||||
|
||||
if prev_out.index >= transaction.outputs.len() as u32 {
|
||||
return Err(transaction_output_not_found(prev_out));
|
||||
}
|
||||
|
||||
let meta = match self.storage.transaction_meta(&prev_out.hash) {
|
||||
Some(meta) => meta,
|
||||
// not in the main branch => no response
|
||||
None => return Err(transaction_of_side_branch(prev_out.hash)),
|
||||
};
|
||||
|
||||
let block_header = match self.storage.block_header(meta.height().into()) {
|
||||
Some(block_header) => block_header,
|
||||
// this is possible during reorgs
|
||||
None => return Err(transaction_not_found(prev_out.hash)),
|
||||
};
|
||||
|
||||
let best_block = self.storage.best_block().expect("storage with genesis block is required");
|
||||
if best_block.number < meta.height() {
|
||||
// this is possible during reorgs
|
||||
return Err(transaction_not_found(prev_out.hash));
|
||||
}
|
||||
|
||||
let ref script_bytes = transaction.outputs[prev_out.index as usize].script_pubkey;
|
||||
let script: Script = script_bytes.clone().into();
|
||||
let script_asm = format!("{}", script);
|
||||
|
||||
Ok(GetTxOutResponse {
|
||||
bestblock: block_header.hash().into(),
|
||||
confirmations: best_block.number - meta.height() + 1,
|
||||
value: 0.00000001f64 * (transaction.outputs[prev_out.index as usize].value as f64),
|
||||
script_pub_key: TxOutScriptPubKey {
|
||||
asm: script_asm,
|
||||
hex: script_bytes.clone().into(),
|
||||
req_sigs: 0, // TODO
|
||||
script_type: ScriptType::NonStandard, // TODO
|
||||
addresses: vec![],
|
||||
},
|
||||
version: transaction.version,
|
||||
coinbase: transaction.is_coinbase(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BlockChainClient<T> where T: BlockChainClientCoreApi {
|
||||
|
@ -138,8 +192,12 @@ impl<T> BlockChain for BlockChainClient<T> where T: BlockChainClientCoreApi {
|
|||
.ok_or(block_not_found(hash))
|
||||
}
|
||||
|
||||
fn transaction_out(&self, _transaction_hash: H256, _out_index: u32, _include_mempool: Trailing<bool>) -> Result<GetTxOutResponse, Error> {
|
||||
rpc_unimplemented!()
|
||||
fn transaction_out(&self, transaction_hash: H256, out_index: u32, _include_mempool: Trailing<bool>) -> Result<GetTxOutResponse, Error> {
|
||||
self.core.verbose_transaction_out(OutPoint { hash: transaction_hash.into(), index: out_index })
|
||||
.map(|mut response| {
|
||||
response.bestblock = response.bestblock.reversed();
|
||||
response
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_out_set_info(&self) -> Result<GetTxOutSetInfoResponse, Error> {
|
||||
|
@ -157,6 +215,7 @@ pub mod tests {
|
|||
use primitives::hash::H256 as GlobalH256;
|
||||
use v1::types::{VerboseBlock, RawBlock};
|
||||
use v1::traits::BlockChain;
|
||||
use v1::helpers::errors::block_not_found;
|
||||
use test_data;
|
||||
use super::*;
|
||||
|
||||
|
@ -208,6 +267,10 @@ pub mod tests {
|
|||
nextblockhash: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn verbose_transaction_out(&self, _prev_out: OutPoint) -> Result<GetTxOutResponse, Error> {
|
||||
Ok(GetTxOutResponse::default()) // TODO: non-default
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockChainClientCoreApi for ErrorBlockChainClientCore {
|
||||
|
@ -230,6 +293,10 @@ pub mod tests {
|
|||
fn verbose_block(&self, _hash: GlobalH256) -> Option<VerboseBlock> {
|
||||
None
|
||||
}
|
||||
|
||||
fn verbose_transaction_out(&self, prev_out: OutPoint) -> Result<GetTxOutResponse, Error> {
|
||||
Err(block_not_found(prev_out.hash))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -3,36 +3,50 @@ use super::hash::{H160, H256};
|
|||
use super::script::ScriptType;
|
||||
|
||||
/// gettxout response
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct GetTxOutResponse {
|
||||
/// Hash of the block this transaction output is included into.
|
||||
bestblock: H256,
|
||||
/// Why it's called 'best'? Who knows
|
||||
pub bestblock: H256,
|
||||
/// Number of confirmations of this transaction
|
||||
confirmations: u32,
|
||||
pub confirmations: u32,
|
||||
/// Transaction value in BTC
|
||||
value: f64,
|
||||
pub value: f64,
|
||||
/// Script info
|
||||
#[serde(rename = "scriptPubKey")]
|
||||
script_pub_key: TxOutScriptPubKey,
|
||||
pub script_pub_key: TxOutScriptPubKey,
|
||||
/// This transaction version
|
||||
version: i32,
|
||||
pub version: i32,
|
||||
/// Is this transactio a coinbase transaction?
|
||||
coinbase: bool,
|
||||
pub coinbase: bool,
|
||||
}
|
||||
|
||||
/// Script pub key information
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct TxOutScriptPubKey {
|
||||
/// Script code
|
||||
asm: String,
|
||||
pub asm: String,
|
||||
/// Script hex
|
||||
hex: Bytes,
|
||||
pub hex: Bytes,
|
||||
/// Number of required signatures
|
||||
#[serde(rename = "reqSigs")]
|
||||
req_sigs: u32,
|
||||
pub req_sigs: u32,
|
||||
/// Type of script
|
||||
#[serde(rename = "type")]
|
||||
script_type: ScriptType,
|
||||
pub script_type: ScriptType,
|
||||
/// Array of bitcoin addresses
|
||||
addresses: Vec<H160>,
|
||||
pub addresses: Vec<H160>,
|
||||
}
|
||||
|
||||
// TODO: remove me
|
||||
impl Default for TxOutScriptPubKey {
|
||||
fn default() -> Self {
|
||||
TxOutScriptPubKey {
|
||||
asm: String::default(),
|
||||
hex: Bytes::default(),
|
||||
req_sigs: u32::default(),
|
||||
script_type: ScriptType::NonStandard,
|
||||
addresses: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ pub use self::block_template::{BlockTemplate, BlockTemplateTransaction};
|
|||
pub use self::block_template_request::{BlockTemplateRequest, BlockTemplateRequestMode};
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::get_block_response::{GetBlockResponse, VerboseBlock};
|
||||
pub use self::get_tx_out_response::GetTxOutResponse;
|
||||
pub use self::get_tx_out_response::{GetTxOutResponse, TxOutScriptPubKey};
|
||||
pub use self::get_tx_out_set_info_response::GetTxOutSetInfoResponse;
|
||||
pub use self::hash::H256;
|
||||
pub use self::raw_block::RawBlock;
|
||||
|
|
Loading…
Reference in New Issue