1 use crate::http::{BinaryResponse, JsonResponse};
2 use crate::utils::hex_to_work;
3 use crate::{BlockHeaderData, BlockSourceError};
5 use bitcoin::blockdata::block::{Block, Header};
6 use bitcoin::consensus::encode;
7 use bitcoin::hash_types::{BlockHash, TxMerkleNode, Txid};
8 use bitcoin::hashes::hex::FromHex;
9 use bitcoin::Transaction;
13 use std::convert::From;
14 use std::convert::TryFrom;
15 use std::convert::TryInto;
16 use std::str::FromStr;
17 use bitcoin::hashes::Hash;
19 impl TryInto<serde_json::Value> for JsonResponse {
20 type Error = std::io::Error;
21 fn try_into(self) -> Result<serde_json::Value, std::io::Error> { Ok(self.0) }
24 /// Conversion from `std::io::Error` into `BlockSourceError`.
25 impl From<std::io::Error> for BlockSourceError {
26 fn from(e: std::io::Error) -> BlockSourceError {
28 std::io::ErrorKind::InvalidData => BlockSourceError::persistent(e),
29 std::io::ErrorKind::InvalidInput => BlockSourceError::persistent(e),
30 _ => BlockSourceError::transient(e),
35 /// Parses binary data as a block.
36 impl TryInto<Block> for BinaryResponse {
37 type Error = std::io::Error;
39 fn try_into(self) -> std::io::Result<Block> {
40 match encode::deserialize(&self.0) {
41 Err(_) => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid block data")),
42 Ok(block) => Ok(block),
47 /// Parses binary data as a block hash.
48 impl TryInto<BlockHash> for BinaryResponse {
49 type Error = std::io::Error;
51 fn try_into(self) -> std::io::Result<BlockHash> {
52 BlockHash::from_slice(&self.0).map_err(|_|
53 std::io::Error::new(std::io::ErrorKind::InvalidData, "bad block hash length")
58 /// Converts a JSON value into block header data. The JSON value may be an object representing a
59 /// block header or an array of such objects. In the latter case, the first object is converted.
60 impl TryInto<BlockHeaderData> for JsonResponse {
61 type Error = std::io::Error;
63 fn try_into(self) -> std::io::Result<BlockHeaderData> {
64 let header = match self.0 {
65 serde_json::Value::Array(mut array) if !array.is_empty() => array.drain(..).next().unwrap(),
66 serde_json::Value::Object(_) => self.0,
67 _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unexpected JSON type")),
70 if !header.is_object() {
71 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON object"));
74 // Add an empty previousblockhash for the genesis block.
75 match header.try_into() {
76 Err(_) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid header data")),
77 Ok(header) => Ok(header),
82 impl TryFrom<serde_json::Value> for BlockHeaderData {
85 fn try_from(response: serde_json::Value) -> Result<Self, ()> {
86 macro_rules! get_field { ($name: expr, $ty_access: tt) => {
87 response.get($name).ok_or(())?.$ty_access().ok_or(())?
92 version: bitcoin::blockdata::block::Version::from_consensus(
93 get_field!("version", as_i64).try_into().map_err(|_| ())?
95 prev_blockhash: if let Some(hash_str) = response.get("previousblockhash") {
96 BlockHash::from_str(hash_str.as_str().ok_or(())?).map_err(|_| ())?
97 } else { BlockHash::all_zeros() },
98 merkle_root: TxMerkleNode::from_str(get_field!("merkleroot", as_str)).map_err(|_| ())?,
99 time: get_field!("time", as_u64).try_into().map_err(|_| ())?,
100 bits: bitcoin::CompactTarget::from_consensus(
101 u32::from_be_bytes(<[u8; 4]>::from_hex(get_field!("bits", as_str)).map_err(|_| ())?)
103 nonce: get_field!("nonce", as_u64).try_into().map_err(|_| ())?,
105 chainwork: hex_to_work(get_field!("chainwork", as_str)).map_err(|_| ())?,
106 height: get_field!("height", as_u64).try_into().map_err(|_| ())?,
111 /// Converts a JSON value into a block. Assumes the block is hex-encoded in a JSON string.
112 impl TryInto<Block> for JsonResponse {
113 type Error = std::io::Error;
115 fn try_into(self) -> std::io::Result<Block> {
116 match self.0.as_str() {
117 None => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string")),
118 Some(hex_data) => match Vec::<u8>::from_hex(hex_data) {
119 Err(_) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hex data")),
120 Ok(block_data) => match encode::deserialize(&block_data) {
121 Err(_) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid block data")),
122 Ok(block) => Ok(block),
129 /// Converts a JSON value into the best block hash and optional height.
130 impl TryInto<(BlockHash, Option<u32>)> for JsonResponse {
131 type Error = std::io::Error;
133 fn try_into(self) -> std::io::Result<(BlockHash, Option<u32>)> {
134 if !self.0.is_object() {
135 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON object"));
138 let hash = match &self.0["bestblockhash"] {
139 serde_json::Value::String(hex_data) => match BlockHash::from_str(&hex_data) {
140 Err(_) => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hex data")),
141 Ok(block_hash) => block_hash,
143 _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string")),
146 let height = match &self.0["blocks"] {
147 serde_json::Value::Null => None,
148 serde_json::Value::Number(height) => match height.as_u64() {
149 None => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid height")),
150 Some(height) => match height.try_into() {
151 Err(_) => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid height")),
152 Ok(height) => Some(height),
155 _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON number")),
162 impl TryInto<Txid> for JsonResponse {
163 type Error = std::io::Error;
164 fn try_into(self) -> std::io::Result<Txid> {
165 let hex_data = self.0.as_str().ok_or(Self::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string" ))?;
166 Txid::from_str(hex_data).map_err(|err|Self::Error::new(std::io::ErrorKind::InvalidData, err.to_string() ))
170 /// Converts a JSON value into a transaction. WATCH OUT! this cannot be used for zero-input transactions
171 /// (e.g. createrawtransaction). See <https://github.com/rust-bitcoin/rust-bitcoincore-rpc/issues/197>
172 impl TryInto<Transaction> for JsonResponse {
173 type Error = std::io::Error;
174 fn try_into(self) -> std::io::Result<Transaction> {
175 let hex_tx = if self.0.is_object() {
176 // result is json encoded
177 match &self.0["hex"] {
178 // result has hex field
179 serde_json::Value::String(hex_data) => match self.0["complete"] {
180 // result may or may not be signed (e.g. signrawtransactionwithwallet)
181 serde_json::Value::Bool(x) => {
183 let reason = match &self.0["errors"][0]["error"] {
184 serde_json::Value::String(x) => x.as_str(),
185 _ => "Unknown error",
188 return Err(std::io::Error::new(
189 std::io::ErrorKind::InvalidData,
190 format!("transaction couldn't be signed. {}", reason),
196 // result is a complete transaction (e.g. getrawtranaction verbose)
199 _ => return Err(std::io::Error::new(
200 std::io::ErrorKind::InvalidData,
201 "expected JSON string",
205 // result is plain text (e.g. getrawtransaction no verbose)
206 match self.0.as_str() {
207 Some(hex_tx) => hex_tx,
209 return Err(std::io::Error::new(
210 std::io::ErrorKind::InvalidData,
211 "expected JSON string",
217 match Vec::<u8>::from_hex(hex_tx) {
218 Err(_) => Err(std::io::Error::new(
219 std::io::ErrorKind::InvalidData,
222 Ok(tx_data) => match encode::deserialize(&tx_data) {
223 Err(_) => Err(std::io::Error::new(
224 std::io::ErrorKind::InvalidData,
225 "invalid transaction",
233 impl TryInto<BlockHash> for JsonResponse {
234 type Error = std::io::Error;
236 fn try_into(self) -> std::io::Result<BlockHash> {
237 match self.0.as_str() {
238 None => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string")),
239 Some(hex_data) if hex_data.len() != 64 =>
240 Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hash length")),
241 Some(hex_data) => BlockHash::from_str(hex_data)
242 .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hex data")),
247 /// The REST `getutxos` endpoint retuns a whole pile of data we don't care about and one bit we do
248 /// - whether the `hit bitmap` field had any entries. Thus we condense the result down into only
250 pub(crate) struct GetUtxosResponse {
251 pub(crate) hit_bitmap_nonempty: bool
254 impl TryInto<GetUtxosResponse> for JsonResponse {
255 type Error = std::io::Error;
257 fn try_into(self) -> std::io::Result<GetUtxosResponse> {
259 self.0.as_object().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected an object"))?
260 .get("bitmap").ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "missing bitmap field"))?
261 .as_str().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "bitmap should be an str"))?;
262 let mut hit_bitmap_nonempty = false;
263 for c in bitmap_str.chars() {
264 if c < '0' || c > '9' {
265 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid byte"));
267 if c > '0' { hit_bitmap_nonempty = true; }
269 Ok(GetUtxosResponse { hit_bitmap_nonempty })
274 pub(crate) mod tests {
276 use bitcoin::blockdata::constants::genesis_block;
277 use bitcoin::hashes::Hash;
278 use bitcoin::network::constants::Network;
280 use serde_json::value::Number;
281 use serde_json::Value;
283 /// Converts from `BlockHeaderData` into a `GetHeaderResponse` JSON value.
284 impl From<BlockHeaderData> for serde_json::Value {
285 fn from(data: BlockHeaderData) -> Self {
286 let BlockHeaderData { chainwork, height, header } = data;
288 "chainwork": chainwork.to_be_bytes().as_hex().to_string(),
290 "version": header.version.to_consensus(),
291 "merkleroot": header.merkle_root.to_string(),
293 "nonce": header.nonce,
294 "bits": header.bits.to_consensus().to_be_bytes().as_hex().to_string(),
295 "previousblockhash": header.prev_blockhash.to_string(),
301 fn into_block_header_from_json_response_with_unexpected_type() {
302 let response = JsonResponse(serde_json::json!(42));
303 match TryInto::<BlockHeaderData>::try_into(response) {
305 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
306 assert_eq!(e.get_ref().unwrap().to_string(), "unexpected JSON type");
308 Ok(_) => panic!("Expected error"),
313 fn into_block_header_from_json_response_with_unexpected_header_type() {
314 let response = JsonResponse(serde_json::json!([42]));
315 match TryInto::<BlockHeaderData>::try_into(response) {
317 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
318 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON object");
320 Ok(_) => panic!("Expected error"),
325 fn into_block_header_from_json_response_with_invalid_header_response() {
326 let block = genesis_block(Network::Bitcoin);
327 let mut response = JsonResponse(BlockHeaderData {
328 chainwork: block.header.work(),
332 response.0["chainwork"].take();
334 match TryInto::<BlockHeaderData>::try_into(response) {
336 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
337 assert_eq!(e.get_ref().unwrap().to_string(), "invalid header data");
339 Ok(_) => panic!("Expected error"),
344 fn into_block_header_from_json_response_with_invalid_header_data() {
345 let block = genesis_block(Network::Bitcoin);
346 let mut response = JsonResponse(BlockHeaderData {
347 chainwork: block.header.work(),
351 response.0["chainwork"] = serde_json::json!("foobar");
353 match TryInto::<BlockHeaderData>::try_into(response) {
355 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
356 assert_eq!(e.get_ref().unwrap().to_string(), "invalid header data");
358 Ok(_) => panic!("Expected error"),
363 fn into_block_header_from_json_response_with_valid_header() {
364 let block = genesis_block(Network::Bitcoin);
365 let response = JsonResponse(BlockHeaderData {
366 chainwork: block.header.work(),
371 match TryInto::<BlockHeaderData>::try_into(response) {
372 Err(e) => panic!("Unexpected error: {:?}", e),
374 assert_eq!(data.chainwork, block.header.work());
375 assert_eq!(data.height, 0);
376 assert_eq!(data.header, block.header);
382 fn into_block_header_from_json_response_with_valid_header_array() {
383 let genesis_block = genesis_block(Network::Bitcoin);
384 let best_block_header = Header {
385 prev_blockhash: genesis_block.block_hash(),
386 ..genesis_block.header
388 let chainwork = genesis_block.header.work() + best_block_header.work();
389 let response = JsonResponse(serde_json::json!([
390 serde_json::Value::from(BlockHeaderData {
391 chainwork, height: 1, header: best_block_header,
393 serde_json::Value::from(BlockHeaderData {
394 chainwork: genesis_block.header.work(), height: 0, header: genesis_block.header,
398 match TryInto::<BlockHeaderData>::try_into(response) {
399 Err(e) => panic!("Unexpected error: {:?}", e),
401 assert_eq!(data.chainwork, chainwork);
402 assert_eq!(data.height, 1);
403 assert_eq!(data.header, best_block_header);
409 fn into_block_header_from_json_response_without_previous_block_hash() {
410 let block = genesis_block(Network::Bitcoin);
411 let mut response = JsonResponse(BlockHeaderData {
412 chainwork: block.header.work(),
416 response.0.as_object_mut().unwrap().remove("previousblockhash");
418 match TryInto::<BlockHeaderData>::try_into(response) {
419 Err(e) => panic!("Unexpected error: {:?}", e),
420 Ok(BlockHeaderData { chainwork: _, height: _, header }) => {
421 assert_eq!(header, block.header);
427 fn into_block_from_invalid_binary_response() {
428 let response = BinaryResponse(b"foo".to_vec());
429 match TryInto::<Block>::try_into(response) {
431 Ok(_) => panic!("Expected error"),
436 fn into_block_from_valid_binary_response() {
437 let genesis_block = genesis_block(Network::Bitcoin);
438 let response = BinaryResponse(encode::serialize(&genesis_block));
439 match TryInto::<Block>::try_into(response) {
440 Err(e) => panic!("Unexpected error: {:?}", e),
441 Ok(block) => assert_eq!(block, genesis_block),
446 fn into_block_from_json_response_with_unexpected_type() {
447 let response = JsonResponse(serde_json::json!({ "result": "foo" }));
448 match TryInto::<Block>::try_into(response) {
450 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
451 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
453 Ok(_) => panic!("Expected error"),
458 fn into_block_from_json_response_with_invalid_hex_data() {
459 let response = JsonResponse(serde_json::json!("foobar"));
460 match TryInto::<Block>::try_into(response) {
462 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
463 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
465 Ok(_) => panic!("Expected error"),
470 fn into_block_from_json_response_with_invalid_block_data() {
471 let response = JsonResponse(serde_json::json!("abcd"));
472 match TryInto::<Block>::try_into(response) {
474 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
475 assert_eq!(e.get_ref().unwrap().to_string(), "invalid block data");
477 Ok(_) => panic!("Expected error"),
482 fn into_block_from_json_response_with_valid_block_data() {
483 let genesis_block = genesis_block(Network::Bitcoin);
484 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&genesis_block)));
485 match TryInto::<Block>::try_into(response) {
486 Err(e) => panic!("Unexpected error: {:?}", e),
487 Ok(block) => assert_eq!(block, genesis_block),
492 fn into_block_hash_from_json_response_with_unexpected_type() {
493 let response = JsonResponse(serde_json::json!("foo"));
494 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
496 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
497 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON object");
499 Ok(_) => panic!("Expected error"),
504 fn into_block_hash_from_json_response_with_unexpected_bestblockhash_type() {
505 let response = JsonResponse(serde_json::json!({ "bestblockhash": 42 }));
506 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
508 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
509 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
511 Ok(_) => panic!("Expected error"),
516 fn into_block_hash_from_json_response_with_invalid_hex_data() {
517 let response = JsonResponse(serde_json::json!({ "bestblockhash": "foobar"} ));
518 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
520 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
521 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
523 Ok(_) => panic!("Expected error"),
528 fn into_block_hash_from_json_response_without_height() {
529 let block = genesis_block(Network::Bitcoin);
530 let response = JsonResponse(serde_json::json!({
531 "bestblockhash": block.block_hash().to_string(),
533 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
534 Err(e) => panic!("Unexpected error: {:?}", e),
535 Ok((hash, height)) => {
536 assert_eq!(hash, block.block_hash());
537 assert!(height.is_none());
543 fn into_block_hash_from_json_response_with_unexpected_blocks_type() {
544 let block = genesis_block(Network::Bitcoin);
545 let response = JsonResponse(serde_json::json!({
546 "bestblockhash": block.block_hash().to_string(),
549 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
551 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
552 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON number");
554 Ok(_) => panic!("Expected error"),
559 fn into_block_hash_from_json_response_with_invalid_height() {
560 let block = genesis_block(Network::Bitcoin);
561 let response = JsonResponse(serde_json::json!({
562 "bestblockhash": block.block_hash().to_string(),
563 "blocks": std::u64::MAX,
565 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
567 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
568 assert_eq!(e.get_ref().unwrap().to_string(), "invalid height");
570 Ok(_) => panic!("Expected error"),
575 fn into_block_hash_from_json_response_with_height() {
576 let block = genesis_block(Network::Bitcoin);
577 let response = JsonResponse(serde_json::json!({
578 "bestblockhash": block.block_hash().to_string(),
581 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
582 Err(e) => panic!("Unexpected error: {:?}", e),
583 Ok((hash, height)) => {
584 assert_eq!(hash, block.block_hash());
585 assert_eq!(height.unwrap(), 1);
591 fn into_txid_from_json_response_with_unexpected_type() {
592 let response = JsonResponse(serde_json::json!({ "result": "foo" }));
593 match TryInto::<Txid>::try_into(response) {
595 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
596 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
598 Ok(_) => panic!("Expected error"),
603 fn into_txid_from_json_response_with_invalid_hex_data() {
604 let response = JsonResponse(serde_json::json!("foobar"));
605 match TryInto::<Txid>::try_into(response) {
607 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
608 assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 6 (expected 64)");
610 Ok(_) => panic!("Expected error"),
615 fn into_txid_from_json_response_with_invalid_txid_data() {
616 let response = JsonResponse(serde_json::json!("abcd"));
617 match TryInto::<Txid>::try_into(response) {
619 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
620 assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 4 (expected 64)");
622 Ok(_) => panic!("Expected error"),
627 fn into_txid_from_json_response_with_valid_txid_data() {
628 let target_txid = Txid::from_slice(&[1; 32]).unwrap();
629 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&target_txid)));
630 match TryInto::<Txid>::try_into(response) {
631 Err(e) => panic!("Unexpected error: {:?}", e),
632 Ok(txid) => assert_eq!(txid, target_txid),
637 fn into_txid_from_bitcoind_rpc_json_response() {
638 let mut rpc_response = serde_json::json!(
639 {"error": "", "id": "770", "result": "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"}
642 let r: std::io::Result<Txid> = JsonResponse(rpc_response.get_mut("result").unwrap().take())
645 r.unwrap().to_string(),
646 "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"
650 // TryInto<Transaction> can be used in two ways, first with plain hex response where data is
651 // the hex encoded transaction (e.g. as a result of getrawtransaction) or as a JSON object
652 // where the hex encoded transaction can be found in the hex field of the object (if present)
653 // (e.g. as a result of signrawtransactionwithwallet).
655 // plain hex transaction
658 fn into_tx_from_json_response_with_invalid_hex_data() {
659 let response = JsonResponse(serde_json::json!("foobar"));
660 match TryInto::<Transaction>::try_into(response) {
662 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
663 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
665 Ok(_) => panic!("Expected error"),
670 fn into_tx_from_json_response_with_invalid_data_type() {
671 let response = JsonResponse(Value::Number(Number::from_f64(1.0).unwrap()));
672 match TryInto::<Transaction>::try_into(response) {
674 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
675 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
677 Ok(_) => panic!("Expected error"),
682 fn into_tx_from_json_response_with_invalid_tx_data() {
683 let response = JsonResponse(serde_json::json!("abcd"));
684 match TryInto::<Transaction>::try_into(response) {
686 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
687 assert_eq!(e.get_ref().unwrap().to_string(), "invalid transaction");
689 Ok(_) => panic!("Expected error"),
694 fn into_tx_from_json_response_with_valid_tx_data_plain() {
695 let genesis_block = genesis_block(Network::Bitcoin);
696 let target_tx = genesis_block.txdata.get(0).unwrap();
697 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&target_tx)));
698 match TryInto::<Transaction>::try_into(response) {
699 Err(e) => panic!("Unexpected error: {:?}", e),
700 Ok(tx) => assert_eq!(&tx, target_tx),
705 fn into_tx_from_json_response_with_valid_tx_data_hex_field() {
706 let genesis_block = genesis_block(Network::Bitcoin);
707 let target_tx = genesis_block.txdata.get(0).unwrap();
708 let response = JsonResponse(serde_json::json!({"hex": encode::serialize_hex(&target_tx)}));
709 match TryInto::<Transaction>::try_into(response) {
710 Err(e) => panic!("Unexpected error: {:?}", e),
711 Ok(tx) => assert_eq!(&tx, target_tx),
715 // transaction in hex field of JSON object
718 fn into_tx_from_json_response_with_no_hex_field() {
719 let response = JsonResponse(serde_json::json!({ "error": "foo" }));
720 match TryInto::<Transaction>::try_into(response) {
722 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
724 e.get_ref().unwrap().to_string(),
725 "expected JSON string"
728 Ok(_) => panic!("Expected error"),
733 fn into_tx_from_json_response_not_signed() {
734 let response = JsonResponse(serde_json::json!({ "hex": "foo", "complete": false }));
735 match TryInto::<Transaction>::try_into(response) {
737 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
739 e.get_ref().unwrap().to_string().contains(
740 "transaction couldn't be signed")
743 Ok(_) => panic!("Expected error"),