1//! Transforms a JSON block template into a hex-encoded block proposal.
2//!
3//! Prints the parsed template and parsed proposal structures to stderr.
4//!
5//! For usage please refer to the program help: `block-template-to-proposal --help`
67mod args;
89use std::io::Read;
1011use color_eyre::eyre::Result;
12use serde_json::Value;
13use structopt::StructOpt;
1415use zebra_chain::{
16 parameters::NetworkUpgrade,
17 serialization::{DateTime32, ZcashSerialize},
18};
19use zebra_rpc::methods::types::{
20 get_block_template::{proposal::proposal_block_from_template, GetBlockTemplate},
21 long_poll::LONG_POLL_ID_LENGTH,
22};
23use zebra_utils::init_tracing;
2425/// The minimum number of characters in a valid `getblocktemplate JSON response.
26///
27/// The fields we use take up around ~800 bytes.
28const MIN_TEMPLATE_BYTES: usize = 500;
2930/// Process entry point for `block-template-to-proposal`
31#[allow(clippy::print_stdout, clippy::print_stderr)]
32fn main() -> Result<()> {
33// initialise
34init_tracing();
35 color_eyre::install()?;
3637// get arguments from command-line or stdin
38let args = args::Args::from_args();
3940let time_source = args.time_source;
4142// Get template from command-line or standard input
43let template = args.template.unwrap_or_else(|| {
44let mut template = String::new();
45let bytes_read = std::io::stdin().read_to_string(&mut template).expect("missing JSON block template: must be supplied on command-line or standard input");
4647if bytes_read < MIN_TEMPLATE_BYTES {
48panic!("JSON block template is too small: expected at least {MIN_TEMPLATE_BYTES} characters");
49 }
5051 template
52 });
5354// parse string to generic json
55let mut template: Value = serde_json::from_str(&template)?;
56eprintln!(
57"{}",
58 serde_json::to_string_pretty(&template).expect("re-serialization never fails")
59 );
6061let template_obj = template
62 .as_object_mut()
63 .expect("template must be a JSON object");
6465// replace zcashd keys that are incompatible with Zebra
6667 // the longpollid key is in a node-specific format, but this tool doesn't use it,
68 // so we can replace it with a dummy value
69template_obj["longpollid"] = "0".repeat(LONG_POLL_ID_LENGTH).into();
7071// provide dummy keys that Zebra requires but zcashd does not always have
7273 // the transaction.*.required keys are not used by this tool,
74 // so we can use any value here
75template_obj["coinbasetxn"]["required"] = true.into();
76for tx in template_obj["transactions"]
77 .as_array_mut()
78 .expect("transactions must be a JSON array")
79 {
80 tx["required"] = false.into();
81 }
8283// the maxtime field is used by this tool
84 // if it is missing, substitute a valid value
85let current_time: DateTime32 = template_obj["curtime"]
86 .to_string()
87 .parse()
88 .expect("curtime is always a valid DateTime32");
8990 template_obj.entry("maxtime").or_insert_with(|| {
91if time_source.uses_max_time() {
92eprintln!("maxtime field is missing, using curtime for maxtime: {current_time:?}");
93 }
9495 current_time.timestamp().into()
96 });
9798// parse the modified json to template type
99let template: GetBlockTemplate = serde_json::from_value(template)?;
100101// generate proposal according to arguments
102let proposal = proposal_block_from_template(&template, time_source, NetworkUpgrade::Nu5)?;
103eprintln!("{proposal:#?}");
104105let proposal = proposal
106 .zcash_serialize_to_vec()
107 .expect("serialization to Vec never fails");
108109println!("{}", hex::encode(proposal));
110111Ok(())
112}