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