From 4d486e6a7b0970fdec47e57e951ee2fa940170d4 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 20 Mar 2019 11:49:17 -0400 Subject: [PATCH] add generatepegoutproof RPC call --- src/wallet/rpcwallet.cpp | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e0ef1965ff..b7419d5248 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6026,6 +6026,104 @@ UniValue destroyamount(const JSONRPCRequest& request) return tx->GetHash().GetHex(); } +// Only used for functionary integration tests +UniValue generatepegoutproof(const JSONRPCRequest& request) +{ + std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); + CWallet* const pwallet = wallet.get(); + + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() != 3) + throw std::runtime_error( + "generatepegoutproof sumkey btcpubkey onlinepubkey\n" + "\nONLY FOR TESTING: Generates pegout authorization proof for pegout based on the summed privkey and returns in hex. Result should be passed as an argument in `sendtomainchain`. Caution: Whitelist proof-validating mempools will filter incorrect pegoutproofs but aren't consensus enforced!\n" + "\nArguments:\n" + "1. \"sumkey\" (string, required) Base58 summed key of Bitcoin and offline key\n" + "2. \"btcpubkey\" (string, required) Hex pegout destination Bitcoin pubkey\n" + "3. \"onlinepubkey\" (string, required) hex `online pubkey`\n" + "\nResult:\n" + "\"pegoutproof\" (string, hex) pegout authorization proof to be passed into sendtomainchain\n" + + HelpExampleCli("generatepegoutproof", "\"cQtNrRngdc4RJ9CkuTVKVLyxPFsijiTJySob24xCdKXGohdFhXML\" \"02c611095119e3dc96db428a0e190a3e142237bcd2efa4fb358257497885af3ab6\" \"0390695fff5535780df1e04c1f6c10e7c0a399fa56cfce34bf8108d0a9bc7a437b\"") + + HelpExampleRpc("generatepegoutproof", "\"cQtNrRngdc4RJ9CkuTVKVLyxPFsijiTJySob24xCdKXGohdFhXML\" \"02c611095119e3dc96db428a0e190a3e142237bcd2efa4fb358257497885af3ab6\" \"0390695fff5535780df1e04c1f6c10e7c0a399fa56cfce34bf8108d0a9bc7a437b\"") + ); + + LOCK2(cs_main, pwallet->cs_wallet); + + if (!IsHex(request.params[1].get_str())) + throw JSONRPCError(RPC_TYPE_ERROR, "btcpubkey must be hex string"); + if (!IsHex(request.params[2].get_str())) + throw JSONRPCError(RPC_TYPE_ERROR, "onlinepubkey must be hex string"); + + //Parse private keys + + CKey summedSecret = DecodeSecret(request.params[0].get_str()); + if (!summedSecret.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid summed private key encoding"); + } + + std::vector sumprivkeybytes(summedSecret.begin(), summedSecret.end()); + std::vector btcpubkeybytes = ParseHex(request.params[1].get_str()); + std::vector onlinepubkeybytes = ParseHex(request.params[2].get_str()); + + //Parse onlinepubkey + CPubKey onlinepubkey; + onlinepubkey.Set(onlinepubkeybytes.begin(), onlinepubkeybytes.end()); + if (!onlinepubkey.IsFullyValid()) + throw JSONRPCError(RPC_WALLET_ERROR, "Invalid online pubkey"); + secp256k1_pubkey onlinepubkey_secp; + if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &onlinepubkey_secp, &onlinepubkeybytes[0], onlinepubkeybytes.size())) + throw JSONRPCError(RPC_WALLET_ERROR, "Invalid online pubkey"); + + CPAKList paklist = g_paklist_blockchain; + if (g_paklist_config) { + paklist = *g_paklist_config; + } + if (paklist.IsReject()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pegout freeze is under effect to aid a pak transition to a new list. Please consult the network operator."); + } + + //Find PAK online pubkey on PAK list + int whitelistindex=-1; + std::vector pak_online = paklist.OnlineKeys(); + for (unsigned int i=0; iGetKey(onlinepubkey.GetID(), masterOnlineKey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Given online key is in master set but not in wallet"); + + //Parse own offline pubkey + secp256k1_pubkey btcpubkey; + if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &btcpubkey, &btcpubkeybytes[0], btcpubkeybytes.size()) != 1) + throw JSONRPCError(RPC_WALLET_ERROR, "btcpubkey is invalid pubkey"); + + //Create, verify whitelist proof + secp256k1_whitelist_signature sig; + if(secp256k1_whitelist_sign(secp256k1_ctx, &sig, &paklist.OnlineKeys()[0], &paklist.OfflineKeys()[0], paklist.size(), &btcpubkey, masterOnlineKey.begin(), &sumprivkeybytes[0], whitelistindex, NULL, NULL) != 1) + throw JSONRPCError(RPC_WALLET_ERROR, "Pegout authorization proof signing failed"); + + if (secp256k1_whitelist_verify(secp256k1_ctx, &sig, &paklist.OnlineKeys()[0], &paklist.OfflineKeys()[0], paklist.size(), &btcpubkey) != 1) + throw JSONRPCError(RPC_WALLET_ERROR, "Pegout authorization proof was created and signed but is invalid"); + + //Serialize and return as hex + size_t expectedOutputSize = 1 + 32 * (1 + paklist.size()); + const size_t preSize = expectedOutputSize; + assert(1 + 32 * (1 + 256) >= expectedOutputSize); + unsigned char output[1 + 32 * (1 + 256)]; + secp256k1_whitelist_signature_serialize(secp256k1_ctx, output, &expectedOutputSize, &sig); + assert(expectedOutputSize == preSize); + std::vector voutput(output, output + expectedOutputSize / sizeof(output[0])); + + return HexStr(voutput.begin(), voutput.end()); +} + // END ELEMENTS commands // @@ -6124,6 +6222,7 @@ static const CRPCCommand commands[] = { "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind"}}, { "wallet", "reissueasset", &reissueasset, {"asset", "assetamount"}}, { "wallet", "destroyamount", &destroyamount, {"asset", "amount", "comment"} }, + { "hidden", "generatepegoutproof", &generatepegoutproof, {"sumkey", "btcpubkey", "onlinepubkey"} }, }; // clang-format on