Line data Source code
1 : // Copyright (c) 2018-2025 The Dash Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #ifndef BITCOIN_EVO_PROVIDERTX_H
6 : #define BITCOIN_EVO_PROVIDERTX_H
7 :
8 : #include <bls/bls.h>
9 : #include <evo/dmn_types.h>
10 : #include <evo/netinfo.h>
11 : #include <evo/specialtx.h>
12 : #include <primitives/transaction.h>
13 : #include <util/std23.h>
14 :
15 : #include <consensus/validation.h>
16 : #include <key_io.h>
17 : #include <netaddress.h>
18 : #include <pubkey.h>
19 :
20 : #include <univalue.h>
21 : #include <gsl/pointers.h>
22 :
23 : class CBlockIndex;
24 : class ChainstateManager;
25 : class TxValidationState;
26 : struct RPCResult;
27 :
28 : namespace ProTxVersion {
29 : enum : uint16_t {
30 : LegacyBLS = 1,
31 : BasicBLS = 2,
32 : ExtAddr = 3,
33 : };
34 :
35 : /** Get highest permissible ProTx version based on flags set. */
36 50303 : [[nodiscard]] constexpr uint16_t GetMax(const bool is_basic_scheme_active, const bool is_extended_addr)
37 : {
38 50303 : if (is_basic_scheme_active) {
39 50011 : if (is_extended_addr) {
40 : // Requires *both* forks to be active to use extended addresses. is_basic_scheme_active could
41 : // be set to false due to RPC specialization, so we must evaluate is_extended_addr *last* to
42 : // avoid accidentally upgrading a legacy BLS node to basic BLS due to v24 activation.
43 41560 : return ProTxVersion::ExtAddr;
44 : }
45 8451 : return ProTxVersion::BasicBLS;
46 : }
47 292 : return ProTxVersion::LegacyBLS;
48 50303 : }
49 :
50 : /** Get highest permissible ProTx version based on deployment status
51 : * Note: The override is needed because some RPCs need to use deployment status information for everything *except*
52 : * the BLS version upgrade since they are specializations for a specific BLS version. This is a one-off.
53 : * TODO: Resolve this oddity. Consider deprecating legacy BLS-only RPCs so we can remove them eventually.
54 : */
55 : template <typename T>
56 : [[nodiscard]] uint16_t GetMaxFromDeployment(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
57 : std::optional<bool> is_basic_override = std::nullopt);
58 : } // namespace ProTxVersion
59 :
60 36670 : class CProRegTx
61 : {
62 : public:
63 : static constexpr auto SPECIALTX_TYPE = TRANSACTION_PROVIDER_REGISTER;
64 :
65 16133 : uint16_t nVersion{ProTxVersion::LegacyBLS}; // message version
66 16133 : MnType nType{MnType::Regular};
67 16133 : uint16_t nMode{0}; // only 0 supported for now
68 16133 : COutPoint collateralOutpoint{uint256(), (uint32_t)-1}; // if hash is null, we refer to a ProRegTx output
69 16133 : std::shared_ptr<NetInfoInterface> netInfo{nullptr};
70 16133 : uint160 platformNodeID{};
71 16133 : uint16_t platformP2PPort{0};
72 16133 : uint16_t platformHTTPPort{0};
73 : CKeyID keyIDOwner;
74 : CBLSLazyPublicKey pubKeyOperator;
75 : CKeyID keyIDVoting;
76 16133 : uint16_t nOperatorReward{0};
77 : CScript scriptPayout;
78 : uint256 inputsHash; // replay protection
79 : std::vector<unsigned char> vchSig;
80 :
81 57591 : SERIALIZE_METHODS(CProRegTx, obj)
82 : {
83 19197 : READWRITE(
84 : obj.nVersion
85 : );
86 19197 : if (obj.nVersion == 0 ||
87 19195 : obj.nVersion > ProTxVersion::GetMax(/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true)) {
88 : // unknown version, bail out early
89 2 : return;
90 : }
91 :
92 19195 : READWRITE(
93 : obj.nType,
94 : obj.nMode,
95 : obj.collateralOutpoint,
96 : NetInfoSerWrapper(const_cast<std::shared_ptr<NetInfoInterface>&>(obj.netInfo),
97 : obj.nVersion >= ProTxVersion::ExtAddr),
98 : obj.keyIDOwner,
99 : CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == ProTxVersion::LegacyBLS)),
100 : obj.keyIDVoting,
101 : obj.nOperatorReward,
102 : obj.scriptPayout,
103 : obj.inputsHash
104 : );
105 19195 : if (obj.nType == MnType::Evo) {
106 1926 : READWRITE(
107 : obj.platformNodeID);
108 1926 : if (obj.nVersion < ProTxVersion::ExtAddr) {
109 1512 : READWRITE(
110 : obj.platformP2PPort,
111 : obj.platformHTTPPort);
112 1512 : }
113 1926 : }
114 19195 : if (!(s.GetType() & SER_GETHASH)) {
115 16536 : READWRITE(obj.vchSig);
116 16536 : }
117 19197 : }
118 :
119 : // When signing with the collateral key, we don't sign the hash but a generated message instead
120 : // This is needed for HW wallet support which can only sign text messages as of now
121 : std::string MakeSignString() const;
122 :
123 : std::string ToString() const;
124 :
125 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
126 : [[nodiscard]] UniValue ToJson() const;
127 :
128 : bool IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
129 : TxValidationState& state) const;
130 : };
131 :
132 16339 : class CProUpServTx
133 : {
134 : public:
135 : static constexpr auto SPECIALTX_TYPE = TRANSACTION_PROVIDER_UPDATE_SERVICE;
136 :
137 16339 : uint16_t nVersion{ProTxVersion::LegacyBLS}; // message version
138 16339 : MnType nType{MnType::Regular};
139 : uint256 proTxHash;
140 16339 : std::shared_ptr<NetInfoInterface> netInfo{nullptr};
141 16339 : uint160 platformNodeID{};
142 16339 : uint16_t platformP2PPort{0};
143 16339 : uint16_t platformHTTPPort{0};
144 : CScript scriptOperatorPayout;
145 : uint256 inputsHash; // replay protection
146 : CBLSSignature sig;
147 :
148 62664 : SERIALIZE_METHODS(CProUpServTx, obj)
149 : {
150 20888 : READWRITE(
151 : obj.nVersion
152 : );
153 20888 : if (obj.nVersion == 0 ||
154 20886 : obj.nVersion > ProTxVersion::GetMax(/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true)) {
155 : // unknown version, bail out early
156 2 : return;
157 : }
158 20886 : if (obj.nVersion >= ProTxVersion::BasicBLS) {
159 20347 : READWRITE(
160 : obj.nType);
161 20347 : }
162 20886 : READWRITE(
163 : obj.proTxHash,
164 : NetInfoSerWrapper(const_cast<std::shared_ptr<NetInfoInterface>&>(obj.netInfo),
165 : obj.nVersion >= ProTxVersion::ExtAddr),
166 : obj.scriptOperatorPayout,
167 : obj.inputsHash
168 : );
169 20886 : if (obj.nType == MnType::Evo) {
170 1321 : READWRITE(
171 : obj.platformNodeID);
172 1321 : if (obj.nVersion < ProTxVersion::ExtAddr) {
173 1039 : READWRITE(
174 : obj.platformP2PPort,
175 : obj.platformHTTPPort);
176 1039 : }
177 1321 : }
178 20886 : if (!(s.GetType() & SER_GETHASH)) {
179 16719 : READWRITE(
180 : CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.sig), (obj.nVersion == ProTxVersion::LegacyBLS))
181 : );
182 16719 : }
183 20888 : }
184 :
185 : std::string ToString() const;
186 :
187 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
188 : [[nodiscard]] UniValue ToJson() const;
189 :
190 : bool IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
191 : TxValidationState& state) const;
192 : };
193 :
194 1084 : class CProUpRegTx
195 : {
196 : public:
197 : static constexpr auto SPECIALTX_TYPE = TRANSACTION_PROVIDER_UPDATE_REGISTRAR;
198 :
199 542 : uint16_t nVersion{ProTxVersion::LegacyBLS}; // message version
200 : uint256 proTxHash;
201 542 : uint16_t nMode{0}; // only 0 supported for now
202 : CBLSLazyPublicKey pubKeyOperator;
203 : CKeyID keyIDVoting;
204 : CScript scriptPayout;
205 : uint256 inputsHash; // replay protection
206 : std::vector<unsigned char> vchSig;
207 :
208 2118 : SERIALIZE_METHODS(CProUpRegTx, obj)
209 : {
210 706 : READWRITE(
211 : obj.nVersion
212 : );
213 706 : if (obj.nVersion == 0 ||
214 704 : obj.nVersion > ProTxVersion::GetMax(/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true)) {
215 : // unknown version, bail out early
216 2 : return;
217 : }
218 704 : READWRITE(
219 : obj.proTxHash,
220 : obj.nMode,
221 : CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == ProTxVersion::LegacyBLS)),
222 : obj.keyIDVoting,
223 : obj.scriptPayout,
224 : obj.inputsHash
225 : );
226 704 : if (!(s.GetType() & SER_GETHASH)) {
227 550 : READWRITE(
228 : obj.vchSig
229 : );
230 550 : }
231 706 : }
232 :
233 : std::string ToString() const;
234 :
235 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
236 : [[nodiscard]] UniValue ToJson() const;
237 :
238 : bool IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
239 : TxValidationState& state) const;
240 : };
241 :
242 830 : class CProUpRevTx
243 : {
244 : public:
245 : static constexpr auto SPECIALTX_TYPE = TRANSACTION_PROVIDER_UPDATE_REVOKE;
246 :
247 : // these are just informational and do not have any effect on the revocation
248 : enum {
249 : REASON_NOT_SPECIFIED = 0,
250 : REASON_TERMINATION_OF_SERVICE = 1,
251 : REASON_COMPROMISED_KEYS = 2,
252 : REASON_CHANGE_OF_KEYS = 3,
253 : REASON_LAST = REASON_CHANGE_OF_KEYS
254 : };
255 :
256 415 : uint16_t nVersion{ProTxVersion::LegacyBLS}; // message version
257 : uint256 proTxHash;
258 415 : uint16_t nReason{REASON_NOT_SPECIFIED};
259 : uint256 inputsHash; // replay protection
260 : CBLSSignature sig;
261 :
262 1581 : SERIALIZE_METHODS(CProUpRevTx, obj)
263 : {
264 527 : READWRITE(
265 : obj.nVersion
266 : );
267 527 : if (obj.nVersion == 0 ||
268 527 : obj.nVersion > ProTxVersion::GetMax(/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true)) {
269 : // unknown version, bail out early
270 0 : return;
271 : }
272 527 : READWRITE(
273 : obj.proTxHash,
274 : obj.nReason,
275 : obj.inputsHash
276 : );
277 527 : if (!(s.GetType() & SER_GETHASH)) {
278 421 : READWRITE(
279 : CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.sig), (obj.nVersion == ProTxVersion::LegacyBLS))
280 : );
281 421 : }
282 527 : }
283 :
284 : std::string ToString() const;
285 :
286 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
287 : [[nodiscard]] UniValue ToJson() const;
288 :
289 : bool IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
290 : TxValidationState& state) const;
291 : };
292 :
293 : template <typename ProTx>
294 7864 : static bool CheckInputsHash(const CTransaction& tx, const ProTx& proTx, TxValidationState& state)
295 : {
296 7864 : if (uint256 inputsHash = CalcTxInputsHash(tx); inputsHash != proTx.inputsHash) {
297 0 : return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-inputs-hash");
298 : }
299 7864 : return true;
300 7864 : }
301 :
302 : #endif // BITCOIN_EVO_PROVIDERTX_H
|