aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/rpcwallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r--src/wallet/rpcwallet.cpp176
1 files changed, 143 insertions, 33 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index ae89b3c0a1..d4015f6c89 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -108,7 +108,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
std::string rbfStatus = "no";
if (confirms <= 0) {
LOCK(mempool.cs);
- RBFTransactionState rbfState = IsRBFOptIn(wtx, mempool);
+ RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool);
if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN)
rbfStatus = "unknown";
else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125)
@@ -1110,7 +1110,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
- "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
+ "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
@@ -1154,11 +1154,10 @@ class Witnessifier : public boost::static_visitor<bool>
{
public:
CWallet * const pwallet;
- CScriptID result;
+ CTxDestination result;
+ bool already_witness;
- explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
-
- bool operator()(const CNoDestination &dest) const { return false; }
+ explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
bool operator()(const CKeyID &keyID) {
if (pwallet) {
@@ -1172,9 +1171,7 @@ public:
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false;
}
- pwallet->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ return ExtractDestination(witscript, result);
}
return false;
}
@@ -1185,7 +1182,8 @@ public:
int witnessversion;
std::vector<unsigned char> witprog;
if (subscript.IsWitnessProgram(witnessversion, witprog)) {
- result = scriptID;
+ ExtractDestination(subscript, result);
+ already_witness = true;
return true;
}
CScript witscript = GetScriptForWitness(subscript);
@@ -1197,12 +1195,27 @@ public:
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false;
}
- pwallet->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ return ExtractDestination(witscript, result);
}
return false;
}
+
+ bool operator()(const WitnessV0KeyHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ template<typename T>
+ bool operator()(const T& dest) { return false; }
};
UniValue addwitnessaddress(const JSONRPCRequest& request)
@@ -1212,17 +1225,18 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
{
- std::string msg = "addwitnessaddress \"address\"\n"
- "\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
+ std::string msg = "addwitnessaddress \"address\" ( p2sh )\n"
+ "\nAdd a witness address for a script (with pubkey or redeemscript known). Requires a new wallet backup.\n"
"It returns the witness script.\n"
"\nArguments:\n"
"1. \"address\" (string, required) An address known to the wallet\n"
+ "2. p2sh (bool, optional, default=true) Embed inside P2SH\n"
"\nResult:\n"
- "\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
+ "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n"
"}\n"
;
throw std::runtime_error(msg);
@@ -1240,13 +1254,31 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
+ bool p2sh = true;
+ if (!request.params[1].isNull()) {
+ p2sh = request.params[1].get_bool();
+ }
+
Witnessifier w(pwallet);
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
}
- pwallet->SetAddressBook(w.result, "", "receive");
+ CScript witprogram = GetScriptForDestination(w.result);
+
+ if (p2sh) {
+ w.result = CScriptID(witprogram);
+ }
+
+ if (w.already_witness) {
+ if (!(dest == w.result)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types");
+ }
+ } else {
+ pwallet->AddCScript(witprogram);
+ pwallet->SetAddressBook(w.result, "", "receive");
+ }
return EncodeDestination(w.result);
}
@@ -1861,19 +1893,20 @@ UniValue listsinceblock(const JSONRPCRequest& request)
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (!request.params[0].isNull()) {
+ if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it != mapBlockIndex.end()) {
- paltindex = pindex = it->second;
- if (chainActive[pindex->nHeight] != pindex) {
- // the block being asked for is a part of a deactivated chain;
- // we don't want to depend on its perceived height in the block
- // chain, we want to instead use the last common ancestor
- pindex = chainActive.FindFork(pindex);
- }
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ paltindex = pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex) {
+ // the block being asked for is a part of a deactivated chain;
+ // we don't want to depend on its perceived height in the block
+ // chain, we want to instead use the last common ancestor
+ pindex = chainActive.FindFork(pindex);
}
}
@@ -2018,7 +2051,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -2147,7 +2180,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
@@ -2211,7 +2244,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
@@ -2262,7 +2295,7 @@ UniValue walletlock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) {
+ if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
@@ -2302,7 +2335,7 @@ UniValue encryptwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) {
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
@@ -3180,6 +3213,81 @@ UniValue generate(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, num_generate, max_tries, true);
}
+UniValue rescanblockchain(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() > 2) {
+ throw std::runtime_error(
+ "rescanblockchain (\"start_height\") (\"stop_height\")\n"
+ "\nRescan the local blockchain for wallet related transactions.\n"
+ "\nArguments:\n"
+ "1. \"start_height\" (numeric, optional) block height where the rescan should start\n"
+ "2. \"stop_height\" (numeric, optional) the last block height that should be scanned\n"
+ "\nResult:\n"
+ "{\n"
+ " \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
+ " \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("rescanblockchain", "100000 120000")
+ + HelpExampleRpc("rescanblockchain", "100000, 120000")
+ );
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ CBlockIndex *pindexStart = chainActive.Genesis();
+ CBlockIndex *pindexStop = nullptr;
+ if (!request.params[0].isNull()) {
+ pindexStart = chainActive[request.params[0].get_int()];
+ if (!pindexStart) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
+ }
+ }
+
+ if (!request.params[1].isNull()) {
+ pindexStop = chainActive[request.params[1].get_int()];
+ if (!pindexStop) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
+ }
+ else if (pindexStop->nHeight < pindexStart->nHeight) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
+ }
+ }
+
+ // We can't rescan beyond non-pruned blocks, stop and throw an error
+ if (fPruneMode) {
+ CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
+ while (block && block->nHeight >= pindexStart->nHeight) {
+ if (!(block->nStatus & BLOCK_HAVE_DATA)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ }
+ block = block->pprev;
+ }
+ }
+
+ CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
+ if (!stopBlock) {
+ if (pwallet->IsAbortingRescan()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
+ }
+ // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
+ stopBlock = pindexStop ? pindexStop : chainActive.Tip();
+ }
+ else {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
+ }
+
+ UniValue response(UniValue::VOBJ);
+ response.pushKV("start_height", pindexStart->nHeight);
+ response.pushKV("stop_height", stopBlock->nHeight);
+ return response;
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -3190,6 +3298,7 @@ extern UniValue importwallet(const JSONRPCRequest& request);
extern UniValue importprunedfunds(const JSONRPCRequest& request);
extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
+extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -3199,7 +3308,7 @@ static const CRPCCommand commands[] =
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
{ "wallet", "abortrescan", &abortrescan, {} },
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
- { "wallet", "addwitnessaddress", &addwitnessaddress, {"address"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
@@ -3244,6 +3353,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+ { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} },
};