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 #[cfg(feature = "rest-client")]
251 pub(crate) struct GetUtxosResponse {
252 pub(crate) hit_bitmap_nonempty: bool
255 #[cfg(feature = "rest-client")]
256 impl TryInto<GetUtxosResponse> for JsonResponse {
257 type Error = std::io::Error;
259 fn try_into(self) -> std::io::Result<GetUtxosResponse> {
261 self.0.as_object().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected an object"))?
262 .get("bitmap").ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "missing bitmap field"))?
263 .as_str().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "bitmap should be an str"))?;
264 let mut hit_bitmap_nonempty = false;
265 for c in bitmap_str.chars() {
266 if c < '0' || c > '9' {
267 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid byte"));
269 if c > '0' { hit_bitmap_nonempty = true; }
271 Ok(GetUtxosResponse { hit_bitmap_nonempty })
276 pub(crate) mod tests {
278 use bitcoin::blockdata::constants::genesis_block;
279 use bitcoin::hashes::Hash;
280 use bitcoin::network::Network;
282 use serde_json::value::Number;
283 use serde_json::Value;
285 /// Converts from `BlockHeaderData` into a `GetHeaderResponse` JSON value.
286 impl From<BlockHeaderData> for serde_json::Value {
287 fn from(data: BlockHeaderData) -> Self {
288 let BlockHeaderData { chainwork, height, header } = data;
290 "chainwork": chainwork.to_be_bytes().as_hex().to_string(),
292 "version": header.version.to_consensus(),
293 "merkleroot": header.merkle_root.to_string(),
295 "nonce": header.nonce,
296 "bits": header.bits.to_consensus().to_be_bytes().as_hex().to_string(),
297 "previousblockhash": header.prev_blockhash.to_string(),
303 fn into_block_header_from_json_response_with_unexpected_type() {
304 let response = JsonResponse(serde_json::json!(42));
305 match TryInto::<BlockHeaderData>::try_into(response) {
307 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
308 assert_eq!(e.get_ref().unwrap().to_string(), "unexpected JSON type");
310 Ok(_) => panic!("Expected error"),
315 fn into_block_header_from_json_response_with_unexpected_header_type() {
316 let response = JsonResponse(serde_json::json!([42]));
317 match TryInto::<BlockHeaderData>::try_into(response) {
319 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
320 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON object");
322 Ok(_) => panic!("Expected error"),
327 fn into_block_header_from_json_response_with_invalid_header_response() {
328 let block = genesis_block(Network::Bitcoin);
329 let mut response = JsonResponse(BlockHeaderData {
330 chainwork: block.header.work(),
334 response.0["chainwork"].take();
336 match TryInto::<BlockHeaderData>::try_into(response) {
338 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
339 assert_eq!(e.get_ref().unwrap().to_string(), "invalid header data");
341 Ok(_) => panic!("Expected error"),
346 fn into_block_header_from_json_response_with_invalid_header_data() {
347 let block = genesis_block(Network::Bitcoin);
348 let mut response = JsonResponse(BlockHeaderData {
349 chainwork: block.header.work(),
353 response.0["chainwork"] = serde_json::json!("foobar");
355 match TryInto::<BlockHeaderData>::try_into(response) {
357 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
358 assert_eq!(e.get_ref().unwrap().to_string(), "invalid header data");
360 Ok(_) => panic!("Expected error"),
365 fn into_block_header_from_json_response_with_valid_header() {
366 let block = genesis_block(Network::Bitcoin);
367 let response = JsonResponse(BlockHeaderData {
368 chainwork: block.header.work(),
373 match TryInto::<BlockHeaderData>::try_into(response) {
374 Err(e) => panic!("Unexpected error: {:?}", e),
376 assert_eq!(data.chainwork, block.header.work());
377 assert_eq!(data.height, 0);
378 assert_eq!(data.header, block.header);
384 fn into_block_header_from_json_response_with_valid_header_array() {
385 let genesis_block = genesis_block(Network::Bitcoin);
386 let best_block_header = Header {
387 prev_blockhash: genesis_block.block_hash(),
388 ..genesis_block.header
390 let chainwork = genesis_block.header.work() + best_block_header.work();
391 let response = JsonResponse(serde_json::json!([
392 serde_json::Value::from(BlockHeaderData {
393 chainwork, height: 1, header: best_block_header,
395 serde_json::Value::from(BlockHeaderData {
396 chainwork: genesis_block.header.work(), height: 0, header: genesis_block.header,
400 match TryInto::<BlockHeaderData>::try_into(response) {
401 Err(e) => panic!("Unexpected error: {:?}", e),
403 assert_eq!(data.chainwork, chainwork);
404 assert_eq!(data.height, 1);
405 assert_eq!(data.header, best_block_header);
411 fn into_block_header_from_json_response_without_previous_block_hash() {
412 let block = genesis_block(Network::Bitcoin);
413 let mut response = JsonResponse(BlockHeaderData {
414 chainwork: block.header.work(),
418 response.0.as_object_mut().unwrap().remove("previousblockhash");
420 match TryInto::<BlockHeaderData>::try_into(response) {
421 Err(e) => panic!("Unexpected error: {:?}", e),
422 Ok(BlockHeaderData { chainwork: _, height: _, header }) => {
423 assert_eq!(header, block.header);
429 fn into_block_from_invalid_binary_response() {
430 let response = BinaryResponse(b"foo".to_vec());
431 match TryInto::<Block>::try_into(response) {
433 Ok(_) => panic!("Expected error"),
438 fn into_block_from_valid_binary_response() {
439 let genesis_block = genesis_block(Network::Bitcoin);
440 let response = BinaryResponse(encode::serialize(&genesis_block));
441 match TryInto::<Block>::try_into(response) {
442 Err(e) => panic!("Unexpected error: {:?}", e),
443 Ok(block) => assert_eq!(block, genesis_block),
448 fn into_block_from_json_response_with_unexpected_type() {
449 let response = JsonResponse(serde_json::json!({ "result": "foo" }));
450 match TryInto::<Block>::try_into(response) {
452 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
453 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
455 Ok(_) => panic!("Expected error"),
460 fn into_block_from_json_response_with_invalid_hex_data() {
461 let response = JsonResponse(serde_json::json!("foobar"));
462 match TryInto::<Block>::try_into(response) {
464 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
465 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
467 Ok(_) => panic!("Expected error"),
472 fn into_block_from_json_response_with_invalid_block_data() {
473 let response = JsonResponse(serde_json::json!("abcd"));
474 match TryInto::<Block>::try_into(response) {
476 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
477 assert_eq!(e.get_ref().unwrap().to_string(), "invalid block data");
479 Ok(_) => panic!("Expected error"),
484 fn into_block_from_json_response_with_valid_block_data() {
485 let genesis_block = genesis_block(Network::Bitcoin);
486 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&genesis_block)));
487 match TryInto::<Block>::try_into(response) {
488 Err(e) => panic!("Unexpected error: {:?}", e),
489 Ok(block) => assert_eq!(block, genesis_block),
494 fn into_block_hash_from_json_response_with_unexpected_type() {
495 let response = JsonResponse(serde_json::json!("foo"));
496 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
498 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
499 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON object");
501 Ok(_) => panic!("Expected error"),
506 fn into_block_hash_from_json_response_with_unexpected_bestblockhash_type() {
507 let response = JsonResponse(serde_json::json!({ "bestblockhash": 42 }));
508 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
510 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
511 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
513 Ok(_) => panic!("Expected error"),
518 fn into_block_hash_from_json_response_with_invalid_hex_data() {
519 let response = JsonResponse(serde_json::json!({ "bestblockhash": "foobar"} ));
520 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
522 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
523 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
525 Ok(_) => panic!("Expected error"),
530 fn into_block_hash_from_json_response_without_height() {
531 let block = genesis_block(Network::Bitcoin);
532 let response = JsonResponse(serde_json::json!({
533 "bestblockhash": block.block_hash().to_string(),
535 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
536 Err(e) => panic!("Unexpected error: {:?}", e),
537 Ok((hash, height)) => {
538 assert_eq!(hash, block.block_hash());
539 assert!(height.is_none());
545 fn into_block_hash_from_json_response_with_unexpected_blocks_type() {
546 let block = genesis_block(Network::Bitcoin);
547 let response = JsonResponse(serde_json::json!({
548 "bestblockhash": block.block_hash().to_string(),
551 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
553 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
554 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON number");
556 Ok(_) => panic!("Expected error"),
561 fn into_block_hash_from_json_response_with_invalid_height() {
562 let block = genesis_block(Network::Bitcoin);
563 let response = JsonResponse(serde_json::json!({
564 "bestblockhash": block.block_hash().to_string(),
565 "blocks": std::u64::MAX,
567 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
569 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
570 assert_eq!(e.get_ref().unwrap().to_string(), "invalid height");
572 Ok(_) => panic!("Expected error"),
577 fn into_block_hash_from_json_response_with_height() {
578 let block = genesis_block(Network::Bitcoin);
579 let response = JsonResponse(serde_json::json!({
580 "bestblockhash": block.block_hash().to_string(),
583 match TryInto::<(BlockHash, Option<u32>)>::try_into(response) {
584 Err(e) => panic!("Unexpected error: {:?}", e),
585 Ok((hash, height)) => {
586 assert_eq!(hash, block.block_hash());
587 assert_eq!(height.unwrap(), 1);
593 fn into_txid_from_json_response_with_unexpected_type() {
594 let response = JsonResponse(serde_json::json!({ "result": "foo" }));
595 match TryInto::<Txid>::try_into(response) {
597 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
598 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
600 Ok(_) => panic!("Expected error"),
605 fn into_txid_from_json_response_with_invalid_hex_data() {
606 let response = JsonResponse(serde_json::json!("foobar"));
607 match TryInto::<Txid>::try_into(response) {
609 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
610 assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 6 (expected 64)");
612 Ok(_) => panic!("Expected error"),
617 fn into_txid_from_json_response_with_invalid_txid_data() {
618 let response = JsonResponse(serde_json::json!("abcd"));
619 match TryInto::<Txid>::try_into(response) {
621 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
622 assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 4 (expected 64)");
624 Ok(_) => panic!("Expected error"),
629 fn into_txid_from_json_response_with_valid_txid_data() {
630 let target_txid = Txid::from_slice(&[1; 32]).unwrap();
631 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&target_txid)));
632 match TryInto::<Txid>::try_into(response) {
633 Err(e) => panic!("Unexpected error: {:?}", e),
634 Ok(txid) => assert_eq!(txid, target_txid),
639 fn into_txid_from_bitcoind_rpc_json_response() {
640 let mut rpc_response = serde_json::json!(
641 {"error": "", "id": "770", "result": "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"}
644 let r: std::io::Result<Txid> = JsonResponse(rpc_response.get_mut("result").unwrap().take())
647 r.unwrap().to_string(),
648 "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"
652 // TryInto<Transaction> can be used in two ways, first with plain hex response where data is
653 // the hex encoded transaction (e.g. as a result of getrawtransaction) or as a JSON object
654 // where the hex encoded transaction can be found in the hex field of the object (if present)
655 // (e.g. as a result of signrawtransactionwithwallet).
657 // plain hex transaction
660 fn into_tx_from_json_response_with_invalid_hex_data() {
661 let response = JsonResponse(serde_json::json!("foobar"));
662 match TryInto::<Transaction>::try_into(response) {
664 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
665 assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
667 Ok(_) => panic!("Expected error"),
672 fn into_tx_from_json_response_with_invalid_data_type() {
673 let response = JsonResponse(Value::Number(Number::from_f64(1.0).unwrap()));
674 match TryInto::<Transaction>::try_into(response) {
676 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
677 assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
679 Ok(_) => panic!("Expected error"),
684 fn into_tx_from_json_response_with_invalid_tx_data() {
685 let response = JsonResponse(serde_json::json!("abcd"));
686 match TryInto::<Transaction>::try_into(response) {
688 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
689 assert_eq!(e.get_ref().unwrap().to_string(), "invalid transaction");
691 Ok(_) => panic!("Expected error"),
696 fn into_tx_from_json_response_with_valid_tx_data_plain() {
697 let genesis_block = genesis_block(Network::Bitcoin);
698 let target_tx = genesis_block.txdata.get(0).unwrap();
699 let response = JsonResponse(serde_json::json!(encode::serialize_hex(&target_tx)));
700 match TryInto::<Transaction>::try_into(response) {
701 Err(e) => panic!("Unexpected error: {:?}", e),
702 Ok(tx) => assert_eq!(&tx, target_tx),
707 fn into_tx_from_json_response_with_valid_tx_data_hex_field() {
708 let genesis_block = genesis_block(Network::Bitcoin);
709 let target_tx = genesis_block.txdata.get(0).unwrap();
710 let response = JsonResponse(serde_json::json!({"hex": encode::serialize_hex(&target_tx)}));
711 match TryInto::<Transaction>::try_into(response) {
712 Err(e) => panic!("Unexpected error: {:?}", e),
713 Ok(tx) => assert_eq!(&tx, target_tx),
717 // transaction in hex field of JSON object
720 fn into_tx_from_json_response_with_no_hex_field() {
721 let response = JsonResponse(serde_json::json!({ "error": "foo" }));
722 match TryInto::<Transaction>::try_into(response) {
724 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
726 e.get_ref().unwrap().to_string(),
727 "expected JSON string"
730 Ok(_) => panic!("Expected error"),
735 fn into_tx_from_json_response_not_signed() {
736 let response = JsonResponse(serde_json::json!({ "hex": "foo", "complete": false }));
737 match TryInto::<Transaction>::try_into(response) {
739 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
741 e.get_ref().unwrap().to_string().contains(
742 "transaction couldn't be signed")
745 Ok(_) => panic!("Expected error"),