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