commit
145634ed29
|
@ -1,6 +1,6 @@
|
|||
use v1::traits::BlockChain;
|
||||
use v1::types::{GetBlockResponse, VerboseBlock, RawBlock};
|
||||
use v1::types::{GetTxOutResponse, TxOutScriptPubKey};
|
||||
use v1::types::{GetTxOutResponse, TransactionOutputScript};
|
||||
use v1::types::GetTxOutSetInfoResponse;
|
||||
use v1::types::H256;
|
||||
use v1::types::U256;
|
||||
|
@ -144,7 +144,7 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
|
|||
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 {
|
||||
script: TransactionOutputScript {
|
||||
asm: script_asm,
|
||||
hex: script_bytes.clone().into(),
|
||||
req_sigs: script.num_signatures_required() as u32,
|
||||
|
@ -227,7 +227,7 @@ pub mod tests {
|
|||
use primitives::hash::H256 as GlobalH256;
|
||||
use v1::types::{VerboseBlock, RawBlock};
|
||||
use v1::traits::BlockChain;
|
||||
use v1::types::{GetTxOutResponse, TxOutScriptPubKey};
|
||||
use v1::types::{GetTxOutResponse, TransactionOutputScript};
|
||||
use v1::helpers::errors::block_not_found;
|
||||
use v1::types::Bytes;
|
||||
use v1::types::H256;
|
||||
|
@ -291,7 +291,7 @@ pub mod tests {
|
|||
bestblock: H256::from(0x56),
|
||||
confirmations: 777,
|
||||
value: 100000.56,
|
||||
script_pub_key: TxOutScriptPubKey {
|
||||
script: TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
|
@ -559,7 +559,7 @@ pub mod tests {
|
|||
bestblock: "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000".into(),
|
||||
confirmations: 1,
|
||||
value: 50.0,
|
||||
script_pub_key: TxOutScriptPubKey {
|
||||
script: TransactionOutputScript {
|
||||
asm: "OP_PUSHBYTES_65 0x04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f\nOP_CHECKSIG\n".to_owned(),
|
||||
hex: Bytes::from("4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"),
|
||||
req_sigs: 1,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use v1::traits::Raw;
|
||||
use v1::types::RawTransaction;
|
||||
use v1::types::{RawTransaction, TransactionInput, TransactionOutputs, Transaction, GetRawTransactionResponse};
|
||||
use v1::types::H256;
|
||||
use v1::helpers::errors::{execution, invalid_params};
|
||||
use jsonrpc_core::Error;
|
||||
use chain::Transaction;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use chain::Transaction as GlobalTransaction;
|
||||
use sync;
|
||||
use ser::{Reader, deserialize};
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
|
@ -13,7 +14,7 @@ pub struct RawClient<T: RawClientCoreApi> {
|
|||
}
|
||||
|
||||
pub trait RawClientCoreApi: Send + Sync + 'static {
|
||||
fn accept_transaction(&self, transaction: Transaction) -> Result<GlobalH256, String>;
|
||||
fn accept_transaction(&self, transaction: GlobalTransaction) -> Result<GlobalH256, String>;
|
||||
}
|
||||
|
||||
pub struct RawClientCore {
|
||||
|
@ -29,7 +30,7 @@ impl RawClientCore {
|
|||
}
|
||||
|
||||
impl RawClientCoreApi for RawClientCore {
|
||||
fn accept_transaction(&self, transaction: Transaction) -> Result<GlobalH256, String> {
|
||||
fn accept_transaction(&self, transaction: GlobalTransaction) -> Result<GlobalH256, String> {
|
||||
self.local_sync_node.accept_transaction(transaction)
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +51,18 @@ impl<T> Raw for RawClient<T> where T: RawClientCoreApi {
|
|||
.map(|h| h.reversed().into())
|
||||
.map_err(|e| execution(e))
|
||||
}
|
||||
|
||||
fn create_raw_transaction(&self, _inputs: Vec<TransactionInput>, _outputs: TransactionOutputs, _lock_time: Trailing<u32>) -> Result<RawTransaction, Error> {
|
||||
rpc_unimplemented!()
|
||||
}
|
||||
|
||||
fn decode_raw_transaction(&self, _transaction: RawTransaction) -> Result<Transaction, Error> {
|
||||
rpc_unimplemented!()
|
||||
}
|
||||
|
||||
fn get_raw_transaction(&self, _hash: H256, _verbose: Trailing<bool>) -> Result<GetRawTransactionResponse, Error> {
|
||||
rpc_unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -11,21 +11,27 @@ build_rpc_trait! {
|
|||
/// Parity-bitcoin blockchain data interface.
|
||||
pub trait BlockChain {
|
||||
/// Get hash of best block.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getbestblockhash", "params": [], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getbestblockhash")]
|
||||
fn best_block_hash(&self) -> Result<H256, Error>;
|
||||
/// Get hash of block at given height.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getblockhash", "params": [0], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getblockhash")]
|
||||
fn block_hash(&self, u32) -> Result<H256, Error>;
|
||||
/// Get proof-of-work difficulty as a multiple of the minimum difficulty
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getdifficulty", "params": [], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getdifficulty")]
|
||||
fn difficulty(&self) -> Result<f64, Error>;
|
||||
/// Get information on given block.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getblock", "params": ["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getblock")]
|
||||
fn block(&self, H256, Trailing<bool>) -> Result<GetBlockResponse, Error>;
|
||||
/// Get details about an unspent transaction output.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "gettxout", "params": ["4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", 0], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "gettxout")]
|
||||
fn transaction_out(&self, H256, u32, Trailing<bool>) -> Result<GetTxOutResponse, Error>;
|
||||
/// Get statistics about the unspent transaction output set.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "gettxoutsetinfo", "params": [], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "gettxoutsetinfo")]
|
||||
fn transaction_out_set_info(&self) -> Result<GetTxOutSetInfoResponse, Error>;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ build_rpc_trait! {
|
|||
/// Partiy-bitcoin miner data interface.
|
||||
pub trait Miner {
|
||||
/// Get block template for mining.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getblocktemplate", "params": [{"capabilities": ["coinbasetxn", "workid", "coinbase/append"]}], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getblocktemplate")]
|
||||
fn get_block_template(&self, BlockTemplateRequest) -> Result<BlockTemplate, Error>;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
use jsonrpc_macros::Trailing;
|
||||
use jsonrpc_core::Error;
|
||||
|
||||
use v1::types::RawTransaction;
|
||||
use v1::types::H256;
|
||||
use v1::types::RawTransaction;
|
||||
use v1::types::Transaction;
|
||||
use v1::types::TransactionInput;
|
||||
use v1::types::TransactionOutputs;
|
||||
use v1::types::GetRawTransactionResponse;
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Partiy-bitcoin raw data interface.
|
||||
pub trait Raw {
|
||||
/// Adds transaction to the memory pool && relays it to the peers.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "sendrawtransaction", "params": ["01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "sendrawtransaction")]
|
||||
fn send_raw_transaction(&self, RawTransaction) -> Result<H256, Error>;
|
||||
/// Create a transaction spending the given inputs and creating new outputs.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "createrawtransaction", "params": [[{"txid":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","vout":0}],{"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa":0.01}], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "createrawtransaction")]
|
||||
fn create_raw_transaction(&self, Vec<TransactionInput>, TransactionOutputs, Trailing<u32>) -> Result<RawTransaction, Error>;
|
||||
/// Return an object representing the serialized, hex-encoded transaction.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "decoderawtransaction", "params": ["01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "decoderawtransaction")]
|
||||
fn decode_raw_transaction(&self, RawTransaction) -> Result<Transaction, Error>;
|
||||
/// Return the raw transaction data.
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "getrawtransaction", "params": ["4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getrawtransaction")]
|
||||
fn get_raw_transaction(&self, H256, Trailing<bool>) -> Result<GetRawTransactionResponse, Error>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::bytes::Bytes;
|
||||
|
||||
/// Hex-encoded block
|
||||
pub type RawBlock = Bytes;
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use super::hash::H256;
|
||||
use super::raw_transaction::RawTransaction;
|
||||
use super::transaction::RawTransaction;
|
||||
use db;
|
||||
use miner;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use serde::{Serialize, Serializer};
|
||||
use super::hash::H256;
|
||||
use super::uint::U256;
|
||||
use super::raw_block::RawBlock;
|
||||
use super::block::RawBlock;
|
||||
|
||||
/// Response to getblock RPC request
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use super::address::Address;
|
||||
use super::bytes::Bytes;
|
||||
use super::hash::H256;
|
||||
use super::script::ScriptType;
|
||||
use super::transaction::TransactionOutputScript;
|
||||
|
||||
/// gettxout response
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
|
@ -15,36 +13,20 @@ pub struct GetTxOutResponse {
|
|||
pub value: f64,
|
||||
/// Script info
|
||||
#[serde(rename = "scriptPubKey")]
|
||||
pub script_pub_key: TxOutScriptPubKey,
|
||||
pub script: TransactionOutputScript,
|
||||
/// This transaction version
|
||||
pub version: i32,
|
||||
/// Is this transactio a coinbase transaction?
|
||||
pub coinbase: bool,
|
||||
}
|
||||
|
||||
/// Script pub key information
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TxOutScriptPubKey {
|
||||
/// Script code
|
||||
pub asm: String,
|
||||
/// Script hex
|
||||
pub hex: Bytes,
|
||||
/// Number of required signatures
|
||||
#[serde(rename = "reqSigs")]
|
||||
pub req_sigs: u32,
|
||||
/// Type of script
|
||||
#[serde(rename = "type")]
|
||||
pub script_type: ScriptType,
|
||||
/// Array of bitcoin addresses
|
||||
pub addresses: Vec<Address>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::super::bytes::Bytes;
|
||||
use super::super::hash::H256;
|
||||
use super::super::script::ScriptType;
|
||||
use super::super::transaction::TransactionOutputScript;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
@ -53,7 +35,7 @@ mod tests {
|
|||
bestblock: H256::from(0x56),
|
||||
confirmations: 777,
|
||||
value: 100000.56,
|
||||
script_pub_key: TxOutScriptPubKey {
|
||||
script: TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
|
@ -72,7 +54,7 @@ mod tests {
|
|||
bestblock: H256::from(0x56),
|
||||
confirmations: 777,
|
||||
value: 100000.56,
|
||||
script_pub_key: TxOutScriptPubKey {
|
||||
script: TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
|
@ -86,31 +68,4 @@ mod tests {
|
|||
serde_json::from_str::<GetTxOutResponse>(r#"{"bestblock":"5600000000000000000000000000000000000000000000000000000000000000","confirmations":777,"value":100000.56,"scriptPubKey":{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]},"version":33,"coinbase":false}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_out_script_pubkey_serialize() {
|
||||
let txout = TxOutScriptPubKey {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_out_script_pubkey_deserialize() {
|
||||
let txout = TxOutScriptPubKey {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TxOutScriptPubKey>(r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod address;
|
||||
mod block;
|
||||
mod block_template;
|
||||
mod block_template_request;
|
||||
mod bytes;
|
||||
|
@ -6,22 +7,23 @@ mod get_block_response;
|
|||
mod get_tx_out_response;
|
||||
mod get_tx_out_set_info_response;
|
||||
mod hash;
|
||||
mod raw_block;
|
||||
mod raw_transaction;
|
||||
mod script;
|
||||
mod transaction;
|
||||
mod uint;
|
||||
mod nodes;
|
||||
|
||||
pub use self::address::Address;
|
||||
pub use self::block::RawBlock;
|
||||
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, TxOutScriptPubKey};
|
||||
pub use self::get_tx_out_response::GetTxOutResponse;
|
||||
pub use self::get_tx_out_set_info_response::GetTxOutSetInfoResponse;
|
||||
pub use self::hash::{H160, H256};
|
||||
pub use self::raw_block::RawBlock;
|
||||
pub use self::raw_transaction::RawTransaction;
|
||||
pub use self::script::ScriptType;
|
||||
pub use self::transaction::{RawTransaction, Transaction, TransactionInput, TransactionOutput,
|
||||
TransactionInputScript, TransactionOutputScript, SignedTransactionInput, GetRawTransactionResponse,
|
||||
SignedTransactionOutput, TransactionOutputs};
|
||||
pub use self::uint::U256;
|
||||
pub use self::nodes::AddNodeOperation;
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
use super::bytes::Bytes;
|
||||
|
||||
pub type RawTransaction = Bytes;
|
|
@ -0,0 +1,428 @@
|
|||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
|
||||
use super::address::Address;
|
||||
use super::bytes::Bytes;
|
||||
use super::hash::H256;
|
||||
use super::script::ScriptType;
|
||||
|
||||
/// Hex-encoded transaction
|
||||
pub type RawTransaction = Bytes;
|
||||
|
||||
/// Transaction input
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransactionInput {
|
||||
/// Previous transaction id
|
||||
pub txid: H256,
|
||||
/// Previous transaction output index
|
||||
pub vout: u32,
|
||||
/// Sequence number
|
||||
pub sequence: Option<u32>,
|
||||
}
|
||||
|
||||
/// Transaction output
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransactionOutput {
|
||||
/// Receiver' address
|
||||
pub address: Address,
|
||||
/// Amount in BTC
|
||||
pub amount: f64,
|
||||
}
|
||||
|
||||
/// Transaction outputs, which serializes/deserializes as KV-map
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TransactionOutputs {
|
||||
/// Transaction outputs
|
||||
pub outputs: Vec<TransactionOutput>,
|
||||
}
|
||||
|
||||
/// Transaction input script
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransactionInputScript {
|
||||
/// Script code
|
||||
pub asm: String,
|
||||
/// Script hex
|
||||
pub hex: Bytes,
|
||||
}
|
||||
|
||||
/// Transaction output script
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransactionOutputScript {
|
||||
/// Script code
|
||||
pub asm: String,
|
||||
/// Script hex
|
||||
pub hex: Bytes,
|
||||
/// Number of required signatures
|
||||
#[serde(rename = "reqSigs")]
|
||||
pub req_sigs: u32,
|
||||
/// Type of script
|
||||
#[serde(rename = "type")]
|
||||
pub script_type: ScriptType,
|
||||
/// Array of bitcoin addresses
|
||||
pub addresses: Vec<Address>,
|
||||
}
|
||||
|
||||
/// Signed transaction input
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SignedTransactionInput {
|
||||
/// Previous transaction id
|
||||
pub txid: H256,
|
||||
/// Previous transaction output index
|
||||
pub vout: u32,
|
||||
/// Input script
|
||||
pub script_sig: TransactionInputScript,
|
||||
/// Sequence number
|
||||
pub sequence: u32,
|
||||
/// Hex-encoded witness data (if any)
|
||||
pub txinwitness: Vec<String>,
|
||||
}
|
||||
|
||||
/// Signed transaction output
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SignedTransactionOutput {
|
||||
/// Output value in BTC
|
||||
pub value: f64,
|
||||
/// Output index
|
||||
pub n: u32,
|
||||
/// Output script
|
||||
#[serde(rename = "scriptPubKey")]
|
||||
pub script: TransactionOutputScript,
|
||||
}
|
||||
|
||||
/// Transaction
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Transaction {
|
||||
/// Raw transaction
|
||||
pub hex: RawTransaction,
|
||||
/// The transaction id (same as provided)
|
||||
pub txid: H256,
|
||||
/// The transaction hash (differs from txid for witness transactions)
|
||||
pub hash: H256,
|
||||
/// The serialized transaction size
|
||||
pub size: usize,
|
||||
/// The virtual transaction size (differs from size for witness transactions)
|
||||
pub vsize: usize,
|
||||
/// The version
|
||||
pub version: i32,
|
||||
/// The lock time
|
||||
pub locktime: i32,
|
||||
/// Transaction inputs
|
||||
pub vin: Vec<SignedTransactionInput>,
|
||||
/// Transaction outputs
|
||||
pub vout: Vec<SignedTransactionOutput>,
|
||||
/// Hash of the block this transaction is included in
|
||||
pub blockhash: H256,
|
||||
/// Number of confirmations of this transaction
|
||||
pub confirmations: u32,
|
||||
/// The transaction time in seconds since epoch (Jan 1 1970 GMT)
|
||||
pub time: u32,
|
||||
/// The block time in seconds since epoch (Jan 1 1970 GMT)
|
||||
pub blocktime: u32,
|
||||
}
|
||||
|
||||
/// Return value of `getrawtransaction` method
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum GetRawTransactionResponse {
|
||||
/// Return value when asking for raw transaction
|
||||
Raw(RawTransaction),
|
||||
/// Return value when asking for verbose transaction
|
||||
Verbose(Transaction),
|
||||
}
|
||||
|
||||
impl Serialize for GetRawTransactionResponse {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
match *self {
|
||||
GetRawTransactionResponse::Raw(ref raw_transaction) => raw_transaction.serialize(serializer),
|
||||
GetRawTransactionResponse::Verbose(ref verbose_transaction) => verbose_transaction.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionOutputs {
|
||||
pub fn len(&self) -> usize {
|
||||
self.outputs.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TransactionOutputs {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
let mut state = try!(serializer.serialize_map(Some(self.len())));
|
||||
for output in &self.outputs {
|
||||
try!(serializer.serialize_map_key(&mut state, &output.address));
|
||||
try!(serializer.serialize_map_value(&mut state, &output.amount));
|
||||
}
|
||||
serializer.serialize_map_end(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for TransactionOutputs {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
|
||||
use serde::de::{Visitor, MapVisitor};
|
||||
|
||||
struct TransactionOutputsVisitor;
|
||||
|
||||
impl Visitor for TransactionOutputsVisitor {
|
||||
type Value = TransactionOutputs;
|
||||
|
||||
fn visit_map<V>(&mut self, mut visitor: V) -> Result<TransactionOutputs, V::Error> where V: MapVisitor {
|
||||
let mut outputs: Vec<TransactionOutput> = Vec::with_capacity(visitor.size_hint().0);
|
||||
|
||||
while let Some((address, amount)) = try!(visitor.visit()) {
|
||||
outputs.push(TransactionOutput {
|
||||
address: address,
|
||||
amount: amount,
|
||||
});
|
||||
}
|
||||
|
||||
try!(visitor.end());
|
||||
Ok(TransactionOutputs {
|
||||
outputs: outputs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize(TransactionOutputsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::super::bytes::Bytes;
|
||||
use super::super::hash::H256;
|
||||
use super::super::script::ScriptType;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn transaction_input_serialize() {
|
||||
let txinput = TransactionInput {
|
||||
txid: H256::from(7),
|
||||
vout: 33,
|
||||
sequence: Some(88),
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txinput).unwrap(), r#"{"txid":"0700000000000000000000000000000000000000000000000000000000000000","vout":33,"sequence":88}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_input_deserialize() {
|
||||
let txinput = TransactionInput {
|
||||
txid: H256::from(7),
|
||||
vout: 33,
|
||||
sequence: Some(88),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TransactionInput>(r#"{"txid":"0700000000000000000000000000000000000000000000000000000000000000","vout":33,"sequence":88}"#).unwrap(),
|
||||
txinput);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_output_serialize() {
|
||||
let txout = TransactionOutput {
|
||||
address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(),
|
||||
amount: 123.45,
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","amount":123.45}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_output_deserialize() {
|
||||
let txout = TransactionOutput {
|
||||
address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(),
|
||||
amount: 123.45,
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TransactionOutput>(r#"{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","amount":123.45}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_outputs_serialize() {
|
||||
let txout = TransactionOutputs {
|
||||
outputs: vec![
|
||||
TransactionOutput {
|
||||
address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(),
|
||||
amount: 123.45,
|
||||
},
|
||||
TransactionOutput {
|
||||
address: "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into(),
|
||||
amount: 67.89,
|
||||
},
|
||||
]
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa":123.45,"1H5m1XzvHsjWX3wwU781ubctznEpNACrNC":67.89}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_outputs_deserialize() {
|
||||
let txout = TransactionOutputs {
|
||||
outputs: vec![
|
||||
TransactionOutput {
|
||||
address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(),
|
||||
amount: 123.45,
|
||||
},
|
||||
TransactionOutput {
|
||||
address: "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into(),
|
||||
amount: 67.89,
|
||||
},
|
||||
]
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TransactionOutputs>(r#"{"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa":123.45,"1H5m1XzvHsjWX3wwU781ubctznEpNACrNC":67.89}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_input_script_serialize() {
|
||||
let txin = TransactionInputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txin).unwrap(), r#"{"asm":"Hello, world!!!","hex":"01020304"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_input_script_deserialize() {
|
||||
let txin = TransactionInputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TransactionInputScript>(r#"{"asm":"Hello, world!!!","hex":"01020304"}"#).unwrap(),
|
||||
txin);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_output_script_serialize() {
|
||||
let txout = TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_output_script_deserialize() {
|
||||
let txout = TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TransactionOutputScript>(r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_transaction_input_serialize() {
|
||||
let txin = SignedTransactionInput {
|
||||
txid: H256::from(77),
|
||||
vout: 13,
|
||||
script_sig: TransactionInputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
},
|
||||
sequence: 123,
|
||||
txinwitness: vec![],
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txin).unwrap(), r#"{"txid":"4d00000000000000000000000000000000000000000000000000000000000000","vout":13,"script_sig":{"asm":"Hello, world!!!","hex":"01020304"},"sequence":123,"txinwitness":[]}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_transaction_input_deserialize() {
|
||||
let txin = SignedTransactionInput {
|
||||
txid: H256::from(77),
|
||||
vout: 13,
|
||||
script_sig: TransactionInputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
},
|
||||
sequence: 123,
|
||||
txinwitness: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<SignedTransactionInput>(r#"{"txid":"4d00000000000000000000000000000000000000000000000000000000000000","vout":13,"script_sig":{"asm":"Hello, world!!!","hex":"01020304"},"sequence":123,"txinwitness":[]}"#).unwrap(),
|
||||
txin);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_transaction_output_serialize() {
|
||||
let txout = SignedTransactionOutput {
|
||||
value: 777.79,
|
||||
n: 12,
|
||||
script: TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
},
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"value":777.79,"n":12,"scriptPubKey":{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_transaction_output_deserialize() {
|
||||
let txout = SignedTransactionOutput {
|
||||
value: 777.79,
|
||||
n: 12,
|
||||
script: TransactionOutputScript {
|
||||
asm: "Hello, world!!!".to_owned(),
|
||||
hex: Bytes::new(vec![1, 2, 3, 4]),
|
||||
req_sigs: 777,
|
||||
script_type: ScriptType::Multisig,
|
||||
addresses: vec!["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into(), "1H5m1XzvHsjWX3wwU781ubctznEpNACrNC".into()],
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<SignedTransactionOutput>(r#"{"value":777.79,"n":12,"scriptPubKey":{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","1H5m1XzvHsjWX3wwU781ubctznEpNACrNC"]}}"#).unwrap(),
|
||||
txout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_serialize() {
|
||||
let tx = Transaction {
|
||||
hex: "DEADBEEF".into(),
|
||||
txid: H256::from(4),
|
||||
hash: H256::from(5),
|
||||
size: 33,
|
||||
vsize: 44,
|
||||
version: 55,
|
||||
locktime: 66,
|
||||
vin: vec![],
|
||||
vout: vec![],
|
||||
blockhash: H256::from(6),
|
||||
confirmations: 77,
|
||||
time: 88,
|
||||
blocktime: 99,
|
||||
};
|
||||
assert_eq!(serde_json::to_string(&tx).unwrap(), r#"{"hex":"deadbeef","txid":"0400000000000000000000000000000000000000000000000000000000000000","hash":"0500000000000000000000000000000000000000000000000000000000000000","size":33,"vsize":44,"version":55,"locktime":66,"vin":[],"vout":[],"blockhash":"0600000000000000000000000000000000000000000000000000000000000000","confirmations":77,"time":88,"blocktime":99}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_deserialize() {
|
||||
let tx = Transaction {
|
||||
hex: "DEADBEEF".into(),
|
||||
txid: H256::from(4),
|
||||
hash: H256::from(5),
|
||||
size: 33,
|
||||
vsize: 44,
|
||||
version: 55,
|
||||
locktime: 66,
|
||||
vin: vec![],
|
||||
vout: vec![],
|
||||
blockhash: H256::from(6),
|
||||
confirmations: 77,
|
||||
time: 88,
|
||||
blocktime: 99,
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::from_str::<Transaction>(r#"{"hex":"deadbeef","txid":"0400000000000000000000000000000000000000000000000000000000000000","hash":"0500000000000000000000000000000000000000000000000000000000000000","size":33,"vsize":44,"version":55,"locktime":66,"vin":[],"vout":[],"blockhash":"0600000000000000000000000000000000000000000000000000000000000000","confirmations":77,"time":88,"blocktime":99}"#).unwrap(),
|
||||
tx);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue