zebra_chain/transaction/
builder.rs

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
//! Methods for building transactions.

use crate::{
    amount::{Amount, NonNegative},
    block::Height,
    parameters::{Network, NetworkUpgrade},
    transaction::{LockTime, Transaction},
    transparent,
};

impl Transaction {
    /// 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)>,
        extra_coinbase_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 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,
            Some(extra_coinbase_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_coinbase(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(
        _network: &Network,
        height: Height,
        outputs: impl IntoIterator<Item = (Amount<NonNegative>, transparent::Script)>,
        like_zcashd: bool,
        extra_coinbase_data: Vec<u8>,
    ) -> Transaction {
        let mut extra_data = None;
        let mut sequence = None;

        // `zcashd` includes an extra byte after the coinbase height in the coinbase data,
        // and a sequence number of u32::MAX.
        if like_zcashd {
            extra_data = Some(vec![0x00]);
            sequence = Some(u32::MAX);
        }

        // Override like_zcashd if extra_coinbase_data was supplied
        if !extra_coinbase_data.is_empty() {
            extra_data = Some(extra_coinbase_data);
        }

        // # 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, extra_data, sequence,
        )];

        // > 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_coinbase(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,

            // Zebra does not support shielded coinbase yet.
            joinsplit_data: None,
            sapling_shielded_data: None,
        }
    }
}