output_script.cpp raw

   1  // Copyright (c) 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 <key_io.h>
   7  #include <outputtype.h>
   8  #include <pubkey.h>
   9  #include <rpc/protocol.h>
  10  #include <rpc/request.h>
  11  #include <rpc/server.h>
  12  #include <rpc/util.h>
  13  #include <script/descriptor.h>
  14  #include <script/script.h>
  15  #include <script/signingprovider.h>
  16  #include <tinyformat.h>
  17  #include <univalue.h>
  18  #include <util/check.h>
  19  #include <util/strencodings.h>
  20  
  21  #include <cstdint>
  22  #include <memory>
  23  #include <optional>
  24  #include <string>
  25  #include <tuple>
  26  #include <vector>
  27  
  28  static RPCHelpMan validateaddress()
  29  {
  30      return RPCHelpMan{
  31          "validateaddress",
  32          "\nReturn information about the given limenka address.\n",
  33          {
  34              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The limenka address to validate"},
  35              {"address_type", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "DEPRECATED", RPCArgOptions{.hidden=true}},
  36          },
  37          RPCResult{
  38              RPCResult::Type::OBJ, "", "",
  39              {
  40                  {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
  41                  {RPCResult::Type::STR, "address", /*optional=*/true, "The limenka address validated"},
  42                  {RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded output script generated by the address"},
  43                  {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"},
  44                  {RPCResult::Type::BOOL, "iswitness", /*optional=*/true, "If the address is a witness address"},
  45                  {RPCResult::Type::NUM, "witness_version", /*optional=*/true, "The version number of the witness program"},
  46                  {RPCResult::Type::STR_HEX, "witness_program", /*optional=*/true, "The hex value of the witness program"},
  47                  {RPCResult::Type::STR, "error", /*optional=*/true, "Error message, if any"},
  48                  {RPCResult::Type::NUM, "error_index", /*optional=*/true, "DEPRECATED. The index of the first likely error location, if known"},
  49                  {RPCResult::Type::ARR, "error_locations", /*optional=*/true, "Indices of likely error locations in address, if known (e.g. Bech32 errors)",
  50                      {
  51                          {RPCResult::Type::NUM, "index", "index of a potential error"},
  52                      }},
  53              }
  54          },
  55          RPCExamples{
  56              HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
  57              HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"")
  58          },
  59          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
  60          {
  61              std::string error_msg;
  62              std::vector<int> error_locations;
  63              CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg, &error_locations);
  64  
  65              // Merely validate address_type is an actual address type, so we don't silently ignore potential future parameters
  66              if (!request.params[1].isNull()) {
  67                  if (!ParseOutputType(request.params[1].get_str())) {
  68                      throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown address type '%s'", request.params[1].get_str()));
  69                  }
  70              }
  71  
  72              const bool isValid = IsValidDestination(dest);
  73              CHECK_NONFATAL(isValid == error_msg.empty());
  74  
  75              UniValue ret(UniValue::VOBJ);
  76              ret.pushKV("isvalid", isValid);
  77              if (isValid) {
  78                  std::string currentAddress = EncodeDestination(dest);
  79                  ret.pushKV("address", currentAddress);
  80  
  81                  CScript scriptPubKey = GetScriptForDestination(dest);
  82                  ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
  83  
  84                  UniValue detail = DescribeAddress(dest);
  85                  ret.pushKVs(std::move(detail));
  86              } else {
  87                  if (!error_locations.empty()) {
  88                      ret.pushKV("error_index", error_locations.at(0));
  89                  }
  90                  UniValue error_indices(UniValue::VARR);
  91                  for (int i : error_locations) error_indices.push_back(i);
  92                  ret.pushKV("error_locations", std::move(error_indices));
  93                  ret.pushKV("error", error_msg);
  94              }
  95  
  96              return ret;
  97          },
  98      };
  99  }
 100  
 101  static RPCHelpMan createmultisig()
 102  {
 103      return RPCHelpMan{"createmultisig",
 104          "\nCreates a multi-signature address with n signature of m keys required.\n"
 105          "It returns a json object with the address and redeemScript.\n"
 106          "Public keys can be sorted according to BIP67 during the request if required.\n",
 107          {
 108              {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys."},
 109              {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex-encoded public keys.",
 110                  {
 111                      {"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"},
 112                  }},
 113              {"options|address_type", {RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Type::STR}, RPCArg::Optional::OMITTED, "",
 114                  {
 115                      {"address_type", RPCArg::Type::STR, RPCArg::Default{"legacy"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\".", RPCArgOptions{.also_positional = true}},
 116                      {"sort", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to sort public keys according to BIP67."},
 117                  },
 118                  RPCArgOptions{.oneline_description="options"}},
 119          },
 120          RPCResult{
 121              RPCResult::Type::OBJ, "", "",
 122              {
 123                  {RPCResult::Type::STR, "address", "The value of the new multisig address."},
 124                  {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script."},
 125                  {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
 126                  {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Any warnings resulting from the creation of this multisig",
 127                  {
 128                      {RPCResult::Type::STR, "", ""},
 129                  }},
 130              }
 131          },
 132          RPCExamples{
 133              "\nCreate a multisig address from 2 public keys\n"
 134              + HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") +
 135              "\nAs a JSON-RPC call\n"
 136              + HelpExampleRpc("createmultisig", "2, [\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\",\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\"]")
 137                  },
 138          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 139          {
 140              int required = request.params[0].getInt<int>();
 141  
 142              bool sort = false;
 143              OutputType output_type = OutputType::LEGACY;
 144  
 145              if (request.params[2].isStr()) {
 146                  // backward compatibility
 147                  std::optional<OutputType> parsed = ParseOutputType(request.params[2].get_str());
 148                  if (!parsed) {
 149                      throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[2].get_str()));
 150                  }
 151                  output_type = parsed.value();
 152              } else if (!request.params[2].isNull()) {
 153                  const UniValue& options = request.params[2].get_obj();
 154                  RPCTypeCheckObj(options,
 155                      {
 156                          {"address_type", UniValueType(UniValue::VSTR)},
 157                          {"sort", UniValueType(UniValue::VBOOL)},
 158                      },
 159                      true, true);
 160  
 161                  if (options.exists("address_type")) {
 162                      std::optional<OutputType> parsed = ParseOutputType(options["address_type"].get_str());
 163                      if (!parsed) {
 164                          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", options["address_type"].get_str()));
 165                      }
 166                      output_type = parsed.value();
 167                  }
 168  
 169                  if (options.exists("sort")) {
 170                      sort = options["sort"].get_bool();
 171                  }
 172              }
 173              if (output_type == OutputType::BECH32M) {
 174                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "createmultisig cannot create bech32m multisig addresses");
 175              }
 176  
 177              // Get the public keys
 178              const UniValue& keys = request.params[1].get_array();
 179              std::vector<CPubKey> pubkeys;
 180              pubkeys.reserve(keys.size());
 181              for (unsigned int i = 0; i < keys.size(); ++i) {
 182                  pubkeys.push_back(HexToPubKey(keys[i].get_str()));
 183                  if (sort && !pubkeys.back().IsCompressed()) {
 184                      throw std::runtime_error(strprintf("Compressed key required for BIP67: %s", keys[i].get_str()));
 185                  }
 186              }
 187  
 188              FlatSigningProvider keystore;
 189              CScript inner;
 190              const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner, sort);
 191  
 192              // Make the descriptor
 193              std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), keystore);
 194  
 195              UniValue result(UniValue::VOBJ);
 196              result.pushKV("address", EncodeDestination(dest));
 197              result.pushKV("redeemScript", HexStr(inner));
 198              result.pushKV("descriptor", descriptor->ToString());
 199  
 200              UniValue warnings(UniValue::VARR);
 201              if (descriptor->GetOutputType() != output_type) {
 202                  // Only warns if the user has explicitly chosen an address type we cannot generate
 203                  warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present.");
 204              }
 205              PushWarnings(warnings, result);
 206  
 207              return result;
 208          },
 209      };
 210  }
 211  
 212  static RPCHelpMan getdescriptorinfo()
 213  {
 214      const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)";
 215  
 216      return RPCHelpMan{"getdescriptorinfo",
 217          {"\nAnalyses a descriptor.\n"},
 218          {
 219              {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
 220          },
 221          RPCResult{
 222              RPCResult::Type::OBJ, "", "",
 223              {
 224                  {RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys. For a multipath descriptor, only the first will be returned."},
 225                  {RPCResult::Type::ARR, "multipath_expansion", /*optional=*/true, "All descriptors produced by expanding multipath derivation elements. Only if the provided descriptor specifies multipath derivation elements.",
 226                  {
 227                      {RPCResult::Type::STR, "", ""},
 228                  }},
 229                  {RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},
 230                  {RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},
 231                  {RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},
 232                  {RPCResult::Type::BOOL, "hasprivatekeys", "Whether the input descriptor contained at least one private key"},
 233              }
 234          },
 235          RPCExamples{
 236              "Analyse a descriptor\n" +
 237              HelpExampleCli("getdescriptorinfo", "\"" + EXAMPLE_DESCRIPTOR + "\"") +
 238              HelpExampleRpc("getdescriptorinfo", "\"" + EXAMPLE_DESCRIPTOR + "\"")
 239          },
 240          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 241          {
 242              FlatSigningProvider provider;
 243              std::string error;
 244              auto descs = Parse(request.params[0].get_str(), provider, error);
 245              if (descs.empty()) {
 246                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
 247              }
 248  
 249              UniValue result(UniValue::VOBJ);
 250              result.pushKV("descriptor", descs.at(0)->ToString());
 251  
 252              if (descs.size() > 1) {
 253                  UniValue multipath_descs(UniValue::VARR);
 254                  for (const auto& d : descs) {
 255                      multipath_descs.push_back(d->ToString());
 256                  }
 257                  result.pushKV("multipath_expansion", multipath_descs);
 258              }
 259  
 260              result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str()));
 261              result.pushKV("isrange", descs.at(0)->IsRange());
 262              result.pushKV("issolvable", descs.at(0)->IsSolvable());
 263              result.pushKV("hasprivatekeys", provider.keys.size() > 0);
 264              return result;
 265          },
 266      };
 267  }
 268  
 269  static UniValue DeriveAddresses(const Descriptor* desc, int64_t range_begin, int64_t range_end, FlatSigningProvider& key_provider)
 270  {
 271      UniValue addresses(UniValue::VARR);
 272  
 273      for (int64_t i = range_begin; i <= range_end; ++i) {
 274          FlatSigningProvider provider;
 275          std::vector<CScript> scripts;
 276          if (!desc->Expand(i, key_provider, scripts, provider)) {
 277              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");
 278          }
 279  
 280          for (const CScript& script : scripts) {
 281              CTxDestination dest;
 282              if (!ExtractDestination(script, dest)) {
 283                  // ExtractDestination no longer returns true for P2PK since it doesn't have a corresponding address
 284                  // However combo will output P2PK and should just ignore that script
 285                  if (scripts.size() > 1 && std::get_if<PubKeyDestination>(&dest)) {
 286                      continue;
 287                  }
 288                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor does not have a corresponding address");
 289              }
 290  
 291              addresses.push_back(EncodeDestination(dest));
 292          }
 293      }
 294  
 295      // This should not be possible, but an assert seems overkill:
 296      if (addresses.empty()) {
 297          throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result");
 298      }
 299  
 300      return addresses;
 301  }
 302  
 303  static RPCHelpMan deriveaddresses()
 304  {
 305      const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
 306  
 307      return RPCHelpMan{"deriveaddresses",
 308          {"\nDerives one or more addresses corresponding to an output descriptor.\n"
 309           "Examples of output descriptors are:\n"
 310           "    pkh(<pubkey>)                                     P2PKH outputs for the given pubkey\n"
 311           "    wpkh(<pubkey>)                                    Native segwit P2PKH outputs for the given pubkey\n"
 312           "    sh(multi(<n>,<pubkey>,<pubkey>,...))              P2SH-multisig outputs for the given threshold and pubkeys\n"
 313           "    raw(<hex script>)                                 Outputs whose output script equals the specified hex-encoded bytes\n"
 314           "    tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...))   P2TR-multisig outputs for the given threshold and pubkeys\n"
 315           "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
 316           "or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
 317           "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
 318          {
 319              {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
 320              {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
 321              {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
 322                  {
 323                      {"require_checksum", RPCArg::Type::BOOL, RPCArg::Default{true}, "Require a checksum. If a checksum is provided it will be verified regardless of this parameter."},
 324                  },
 325                  RPCArgOptions{.oneline_description="options"}
 326              },
 327          },
 328          {
 329              RPCResult{"for single derivation descriptors",
 330                  RPCResult::Type::ARR, "", "",
 331                  {
 332                      {RPCResult::Type::STR, "address", "the derived addresses"},
 333                  }
 334              },
 335              RPCResult{"for multipath descriptors",
 336                  RPCResult::Type::ARR, "", "The derived addresses for each of the multipath expansions of the descriptor, in multipath specifier order",
 337                  {
 338                      {
 339                          RPCResult::Type::ARR, "", "The derived addresses for a multipath descriptor expansion",
 340                          {
 341                              {RPCResult::Type::STR, "address", "the derived address"},
 342                          },
 343                      },
 344                  },
 345              },
 346          },
 347          RPCExamples{
 348              "First three native segwit receive addresses:\n" +
 349              HelpExampleCli("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\" \"[0,2]\"") +
 350              HelpExampleRpc("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\", \"[0,2]\"") +
 351              "Derive the PKH address from a WIF, which has a built-in checksum:\n" +
 352              HelpExampleCli("deriveaddresses", "\"pkh(cPsQTSmMZ8e3AEUWGjS73f5R364yJxH6RxcgnwbHjbKbFPUP2Dtu)\" null '{\"require_checksum\": false}'")
 353          },
 354          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 355          {
 356              const std::string desc_str = request.params[0].get_str();
 357              bool require_checksum = true;
 358  
 359              if (!request.params[2].isNull()) {
 360                  const UniValue& options = request.params[2];
 361                  RPCTypeCheckObj(options,
 362                      {
 363                          {"require_checksum", UniValueType(UniValue::VBOOL)},
 364                      },
 365                      true, true);
 366  
 367                  if (options.exists("require_checksum")) {
 368                      require_checksum = options["require_checksum"].get_bool();
 369                  }
 370              }
 371  
 372              int64_t range_begin = 0;
 373              int64_t range_end = 0;
 374  
 375              if (request.params.size() >= 2 && !request.params[1].isNull()) {
 376                  std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
 377              }
 378  
 379              FlatSigningProvider key_provider;
 380              std::string error;
 381              auto descs = Parse(desc_str, key_provider, error, require_checksum);
 382              if (descs.empty()) {
 383                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
 384              }
 385              auto& desc = descs.at(0);
 386              if (!desc->IsRange() && !request.params[1].isNull()) {
 387                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
 388              }
 389  
 390              if (desc->IsRange() && request.params[1].isNull()) {
 391                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor");
 392              }
 393  
 394              UniValue addresses = DeriveAddresses(desc.get(), range_begin, range_end, key_provider);
 395  
 396              if (descs.size() == 1) {
 397                  return addresses;
 398              }
 399  
 400              UniValue ret(UniValue::VARR);
 401              ret.push_back(addresses);
 402              for (size_t i = 1; i < descs.size(); ++i) {
 403                  ret.push_back(DeriveAddresses(descs.at(i).get(), range_begin, range_end, key_provider));
 404              }
 405              return ret;
 406          },
 407      };
 408  }
 409  
 410  void RegisterOutputScriptRPCCommands(CRPCTable& t)
 411  {
 412      static const CRPCCommand commands[]{
 413          {"util", &validateaddress},
 414          {"util", &createmultisig},
 415          {"util", &deriveaddresses},
 416          {"util", &getdescriptorinfo},
 417      };
 418      for (const auto& c : commands) {
 419          t.appendCommand(c.name, &c);
 420      }
 421  }
 422