zebra_chain/transaction/builder.rs
1//! Methods for building transactions.
2
3use crate::{
4 amount::{Amount, NonNegative},
5 block::Height,
6 parameters::{Network, NetworkUpgrade},
7 transaction::{LockTime, Transaction},
8 transparent,
9};
10
11impl Transaction {
12 /// Returns a new version 6 coinbase transaction for `network` and `height`,
13 /// which contains the specified `outputs`.
14 #[cfg(all(zcash_unstable = "nu7", feature = "tx_v6"))]
15 pub fn new_v6_coinbase(
16 network: &Network,
17 height: Height,
18 outputs: impl IntoIterator<Item = (Amount<NonNegative>, transparent::Script)>,
19 miner_data: Vec<u8>,
20 zip233_amount: Option<Amount<NonNegative>>,
21 #[cfg(zcash_unstable = "zip235")] miner_fee: Amount<NonNegative>,
22 ) -> Transaction {
23 // # Consensus
24 //
25 // These consensus rules apply to v5 coinbase transactions after NU5 activation:
26 //
27 // > If effectiveVersion ≥ 5 then this condition MUST hold:
28 // > tx_in_count > 0 or nSpendsSapling > 0 or
29 // > (nActionsOrchard > 0 and enableSpendsOrchard = 1).
30 //
31 // > A coinbase transaction for a block at block height greater than 0 MUST have
32 // > a script that, as its first item, encodes the block height as follows. ...
33 // > let heightBytes be the signed little-endian representation of height,
34 // > using the minimum nonzero number of bytes such that the most significant byte
35 // > is < 0x80. The length of heightBytes MUST be in the range {1 .. 5}.
36 // > Then the encoding is the length of heightBytes encoded as one byte,
37 // > followed by heightBytes itself. This matches the encoding used by Bitcoin
38 // > in the implementation of [BIP-34]
39 // > (but the description here is to be considered normative).
40 //
41 // > A coinbase transaction script MUST have length in {2 .. 100} bytes.
42 //
43 // Zebra adds extra coinbase data if configured to do so.
44 //
45 // Since we're not using a lock time, any sequence number is valid here.
46 // See `Transaction::lock_time()` for the relevant consensus rules.
47 //
48 // <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
49 let inputs = vec![transparent::Input::new_coinbase(height, miner_data, None)];
50
51 // > The block subsidy is composed of a miner subsidy and a series of funding streams.
52 //
53 // <https://zips.z.cash/protocol/protocol.pdf#subsidyconcepts>
54 //
55 // > The total value in zatoshi of transparent outputs from a coinbase transaction,
56 // > minus vbalanceSapling, minus vbalanceOrchard, MUST NOT be greater than
57 // > the value in zatoshi of block subsidy plus the transaction fees
58 // > paid by transactions in this block.
59 //
60 // > If effectiveVersion ≥ 5 then this condition MUST hold:
61 // > tx_out_count > 0 or nOutputsSapling > 0 or
62 // > (nActionsOrchard > 0 and enableOutputsOrchard = 1).
63 //
64 // <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
65 let outputs: Vec<_> = outputs
66 .into_iter()
67 .map(|(amount, lock_script)| transparent::Output::new(amount, lock_script))
68 .collect();
69 assert!(
70 !outputs.is_empty(),
71 "invalid coinbase transaction: must have at least one output"
72 );
73
74 Transaction::V6 {
75 // > The transaction version number MUST be 4 or 5. ...
76 // > If the transaction version number is 5 then the version group ID
77 // > MUST be 0x26A7270A.
78 // > If effectiveVersion ≥ 5, the nConsensusBranchId field MUST match the consensus
79 // > branch ID used for SIGHASH transaction hashes, as specified in [ZIP-244].
80 network_upgrade: NetworkUpgrade::current(network, height),
81
82 // There is no documented consensus rule for the lock time field in coinbase
83 // transactions, so we just leave it unlocked. (We could also set it to `height`.)
84 lock_time: LockTime::unlocked(),
85
86 // > The nExpiryHeight field of a coinbase transaction MUST be equal to its
87 // > block height.
88 expiry_height: height,
89
90 // > The NSM zip233_amount field [ZIP-233] must be set at minimum to 60% of miner fees [ZIP-235].
91 #[cfg(zcash_unstable = "zip235")]
92 zip233_amount: zip233_amount
93 .unwrap_or_else(|| ((miner_fee * 6).unwrap() / 10).unwrap()),
94 #[cfg(not(zcash_unstable = "zip235"))]
95 zip233_amount: zip233_amount.unwrap_or(Amount::zero()),
96
97 inputs,
98 outputs,
99
100 // Zebra does not support shielded coinbase yet.
101 //
102 // > In a version 5 coinbase transaction, the enableSpendsOrchard flag MUST be 0.
103 // > In a version 5 transaction, the reserved bits 2 .. 7 of the flagsOrchard field
104 // > MUST be zero.
105 //
106 // See the Zcash spec for additional shielded coinbase consensus rules.
107 sapling_shielded_data: None,
108 orchard_shielded_data: None,
109 }
110 }
111
112 /// Returns a new version 5 coinbase transaction for `network` and `height`,
113 /// which contains the specified `outputs`.
114 pub fn new_v5_coinbase(
115 network: &Network,
116 height: Height,
117 outputs: impl IntoIterator<Item = (Amount<NonNegative>, transparent::Script)>,
118 miner_data: Vec<u8>,
119 ) -> Transaction {
120 // # Consensus
121 //
122 // These consensus rules apply to v5 coinbase transactions after NU5 activation:
123 //
124 // > If effectiveVersion ≥ 5 then this condition MUST hold:
125 // > tx_in_count > 0 or nSpendsSapling > 0 or
126 // > (nActionsOrchard > 0 and enableSpendsOrchard = 1).
127 //
128 // > A coinbase transaction for a block at block height greater than 0 MUST have
129 // > a script that, as its first item, encodes the block height as follows. ...
130 // > let heightBytes be the signed little-endian representation of height,
131 // > using the minimum nonzero number of bytes such that the most significant byte
132 // > is < 0x80. The length of heightBytes MUST be in the range {1 .. 5}.
133 // > Then the encoding is the length of heightBytes encoded as one byte,
134 // > followed by heightBytes itself. This matches the encoding used by Bitcoin
135 // > in the implementation of [BIP-34]
136 // > (but the description here is to be considered normative).
137 //
138 // > A coinbase transaction script MUST have length in {2 .. 100} bytes.
139 //
140 // Zebra adds extra coinbase data if configured to do so.
141 //
142 // Since we're not using a lock time, any sequence number is valid here.
143 // See `Transaction::lock_time()` for the relevant consensus rules.
144 //
145 // <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
146 let inputs = vec![transparent::Input::new_coinbase(height, miner_data, None)];
147
148 // > The block subsidy is composed of a miner subsidy and a series of funding streams.
149 //
150 // <https://zips.z.cash/protocol/protocol.pdf#subsidyconcepts>
151 //
152 // > The total value in zatoshi of transparent outputs from a coinbase transaction,
153 // > minus vbalanceSapling, minus vbalanceOrchard, MUST NOT be greater than
154 // > the value in zatoshi of block subsidy plus the transaction fees
155 // > paid by transactions in this block.
156 //
157 // > If effectiveVersion ≥ 5 then this condition MUST hold:
158 // > tx_out_count > 0 or nOutputsSapling > 0 or
159 // > (nActionsOrchard > 0 and enableOutputsOrchard = 1).
160 //
161 // <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
162 let outputs: Vec<_> = outputs
163 .into_iter()
164 .map(|(amount, lock_script)| transparent::Output::new(amount, lock_script))
165 .collect();
166
167 assert!(
168 !outputs.is_empty(),
169 "invalid coinbase transaction: must have at least one output"
170 );
171
172 Transaction::V5 {
173 // > The transaction version number MUST be 4 or 5. ...
174 // > If the transaction version number is 5 then the version group ID
175 // > MUST be 0x26A7270A.
176 // > If effectiveVersion ≥ 5, the nConsensusBranchId field MUST match the consensus
177 // > branch ID used for SIGHASH transaction hashes, as specified in [ZIP-244].
178 network_upgrade: NetworkUpgrade::current(network, height),
179
180 // There is no documented consensus rule for the lock time field in coinbase
181 // transactions, so we just leave it unlocked. (We could also set it to `height`.)
182 lock_time: LockTime::unlocked(),
183
184 // > The nExpiryHeight field of a coinbase transaction MUST be equal to its
185 // > block height.
186 expiry_height: height,
187
188 inputs,
189 outputs,
190
191 // Zebra does not support shielded coinbase yet.
192 //
193 // > In a version 5 coinbase transaction, the enableSpendsOrchard flag MUST be 0.
194 // > In a version 5 transaction, the reserved bits 2 .. 7 of the flagsOrchard field
195 // > MUST be zero.
196 //
197 // See the Zcash spec for additional shielded coinbase consensus rules.
198 sapling_shielded_data: None,
199 orchard_shielded_data: None,
200 }
201 }
202
203 /// Returns a new version 4 coinbase transaction for `network` and `height`,
204 /// which contains the specified `outputs`.
205 ///
206 /// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
207 /// in the `getblocktemplate` RPC.
208 pub fn new_v4_coinbase(
209 height: Height,
210 outputs: impl IntoIterator<Item = (Amount<NonNegative>, transparent::Script)>,
211 miner_data: Vec<u8>,
212 ) -> Transaction {
213 // # Consensus
214 //
215 // See the other consensus rules above in new_v5_coinbase().
216 //
217 // > If effectiveVersion < 5, then at least one of tx_in_count, nSpendsSapling,
218 // > and nJoinSplit MUST be nonzero.
219 let inputs = vec![transparent::Input::new_coinbase(
220 height,
221 miner_data,
222 // zcashd uses a sequence number of u32::MAX.
223 Some(u32::MAX),
224 )];
225
226 // > If effectiveVersion < 5, then at least one of tx_out_count, nOutputsSapling,
227 // > and nJoinSplit MUST be nonzero.
228 let outputs: Vec<_> = outputs
229 .into_iter()
230 .map(|(amount, lock_script)| transparent::Output::new(amount, lock_script))
231 .collect();
232
233 assert!(
234 !outputs.is_empty(),
235 "invalid coinbase transaction: must have at least one output"
236 );
237
238 // > The transaction version number MUST be 4 or 5. ...
239 // > If the transaction version number is 4 then the version group ID MUST be 0x892F2085.
240 Transaction::V4 {
241 lock_time: LockTime::unlocked(),
242 expiry_height: height,
243 inputs,
244 outputs,
245 joinsplit_data: None,
246 sapling_shielded_data: None,
247 }
248 }
249}