outputtype.cpp raw
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Limenka developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include <outputtype.h>
7
8 #include <pubkey.h>
9 #include <script/script.h>
10 #include <script/sign.h>
11 #include <script/signingprovider.h>
12 #include <util/vector.h>
13
14 #include <assert.h>
15 #include <optional>
16 #include <string>
17
18 static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
19 static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
20 static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
21 static const std::string OUTPUT_TYPE_STRING_BECH32M = "bech32m";
22 static const std::string OUTPUT_TYPE_STRING_P2SPKH = "p2spkh";
23 static const std::string OUTPUT_TYPE_STRING_UNKNOWN = "unknown";
24
25 std::optional<OutputType> ParseOutputType(const std::string& type)
26 {
27 if (type == OUTPUT_TYPE_STRING_LEGACY) {
28 return OutputType::LEGACY;
29 } else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
30 return OutputType::P2SH_SEGWIT;
31 } else if (type == OUTPUT_TYPE_STRING_BECH32) {
32 return OutputType::BECH32;
33 } else if (type == OUTPUT_TYPE_STRING_BECH32M) {
34 return OutputType::BECH32M;
35 } else if (type == OUTPUT_TYPE_STRING_P2SPKH) {
36 return OutputType::P2SPKH;
37 }
38 return std::nullopt;
39 }
40
41 const std::string& FormatOutputType(OutputType type)
42 {
43 switch (type) {
44 case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
45 case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
46 case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32;
47 case OutputType::BECH32M: return OUTPUT_TYPE_STRING_BECH32M;
48 case OutputType::P2SPKH: return OUTPUT_TYPE_STRING_P2SPKH;
49 case OutputType::UNKNOWN: return OUTPUT_TYPE_STRING_UNKNOWN;
50 } // no default case, so the compiler can warn about missing cases
51 assert(false);
52 }
53
54 CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
55 {
56 switch (type) {
57 case OutputType::LEGACY: return PKHash(key);
58 case OutputType::P2SH_SEGWIT:
59 case OutputType::BECH32: {
60 if (!key.IsCompressed()) return PKHash(key);
61 CTxDestination witdest = WitnessV0KeyHash(key);
62 CScript witprog = GetScriptForDestination(witdest);
63 if (type == OutputType::P2SH_SEGWIT) {
64 return ScriptHash(witprog);
65 } else {
66 return witdest;
67 }
68 }
69 case OutputType::BECH32M:
70 case OutputType::UNKNOWN: {} // This function should never be used with BECH32M or UNKNOWN, so let it assert
71 } // no default case, so the compiler can warn about missing cases
72 assert(false);
73 }
74
75 std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
76 {
77 PKHash keyid(key);
78 CTxDestination p2pkh{keyid};
79 if (key.IsCompressed() && g_implicit_segwit) {
80 CTxDestination segwit = WitnessV0KeyHash(keyid);
81 CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
82 return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
83 } else {
84 return Vector(std::move(p2pkh));
85 }
86 }
87
88 CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType type)
89 {
90 // Add script to keystore
91 keystore.scripts.emplace(CScriptID(script), script);
92
93 switch (type) {
94 case OutputType::LEGACY:
95 return ScriptHash(script);
96 case OutputType::P2SH_SEGWIT:
97 case OutputType::BECH32: {
98 CTxDestination witdest = WitnessV0ScriptHash(script);
99 CScript witprog = GetScriptForDestination(witdest);
100 // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
101 keystore.scripts.emplace(CScriptID(witprog), witprog);
102 if (type == OutputType::BECH32) {
103 return witdest;
104 } else {
105 return ScriptHash(witprog);
106 }
107 }
108 case OutputType::BECH32M:
109 case OutputType::P2SPKH:
110 case OutputType::UNKNOWN: {} // This function should not be used for BECH32M, P2SPKH, or UNKNOWN, so let it assert
111 } // no default case, so the compiler can warn about missing cases
112 assert(false);
113 }
114
115 std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
116 if (std::holds_alternative<PKHash>(dest) ||
117 std::holds_alternative<ScriptHash>(dest)) {
118 return OutputType::LEGACY;
119 }
120 if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
121 std::holds_alternative<WitnessV0ScriptHash>(dest)) {
122 return OutputType::BECH32;
123 }
124 if (std::holds_alternative<WitnessV1Taproot>(dest) ||
125 std::holds_alternative<WitnessUnknown>(dest)) {
126 return OutputType::BECH32M;
127 }
128 if (std::holds_alternative<WitnessV3SpkHash>(dest)) {
129 return OutputType::P2SPKH;
130 }
131 return std::nullopt;
132 }
133