Skip to content

Commit 8ea9c40

Browse files
authored
fix: unlock proregtx collateral on error (dashpay#5838)
1 parent f3f4c16 commit 8ea9c40

File tree

1 file changed

+50
-39
lines changed

1 file changed

+50
-39
lines changed

src/rpc/evo.cpp

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,6 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
648648

649649
ptx.collateralOutpoint = COutPoint(collateralHash, (uint32_t)collateralIndex);
650650
paramIdx += 2;
651-
652-
// TODO unlock on failure
653-
LOCK(wallet->cs_wallet);
654-
wallet->LockCoin(ptx.collateralOutpoint);
655651
}
656652

657653
if (request.params[paramIdx].get_str() != "") {
@@ -721,15 +717,14 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
721717
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[paramIdx + 6].get_str());
722718
}
723719

724-
FundSpecialTx(wallet.get(), tx, ptx, fundDest);
725-
UpdateSpecialTxInputsHash(tx, ptx);
726-
727720
bool fSubmit{true};
728721
if ((isExternalRegister || isFundRegister) && !request.params[paramIdx + 7].isNull()) {
729722
fSubmit = ParseBoolV(request.params[paramIdx + 7], "submit");
730723
}
731724

732725
if (isFundRegister) {
726+
FundSpecialTx(wallet.get(), tx, ptx, fundDest);
727+
UpdateSpecialTxInputsHash(tx, ptx);
733728
CAmount fundCollateral = GetMnType(mnType).collat_amount;
734729
uint32_t collateralIndex = (uint32_t) -1;
735730
for (uint32_t i = 0; i < tx.vout.size(); i++) {
@@ -746,41 +741,57 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
746741
} else {
747742
// referencing external collateral
748743

749-
Coin coin;
750-
if (!GetUTXOCoin(ptx.collateralOutpoint, coin)) {
751-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral not found: %s", ptx.collateralOutpoint.ToStringShort()));
752-
}
753-
CTxDestination txDest;
754-
ExtractDestination(coin.out.scriptPubKey, txDest);
755-
const PKHash *pkhash = std::get_if<PKHash>(&txDest);
756-
if (!pkhash) {
757-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral type not supported: %s", ptx.collateralOutpoint.ToStringShort()));
758-
}
759-
760-
if (isPrepareRegister) {
761-
// external signing with collateral key
762-
ptx.vchSig.clear();
763-
SetTxPayload(tx, ptx);
764-
765-
UniValue ret(UniValue::VOBJ);
766-
ret.pushKV("tx", EncodeHexTx(CTransaction(tx)));
767-
ret.pushKV("collateralAddress", EncodeDestination(txDest));
768-
ret.pushKV("signMessage", ptx.MakeSignString());
769-
return ret;
770-
} else {
771-
// lets prove we own the collateral
772-
LegacyScriptPubKeyMan* spk_man = wallet->GetLegacyScriptPubKeyMan();
773-
if (!spk_man) {
774-
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
744+
const bool unlockOnError = [&]() {
745+
if (LOCK(wallet->cs_wallet); !wallet->IsLockedCoin(ptx.collateralOutpoint.hash, ptx.collateralOutpoint.n)) {
746+
wallet->LockCoin(ptx.collateralOutpoint);
747+
return true;
748+
}
749+
return false;
750+
}();
751+
try {
752+
FundSpecialTx(wallet.get(), tx, ptx, fundDest);
753+
UpdateSpecialTxInputsHash(tx, ptx);
754+
Coin coin;
755+
if (!GetUTXOCoin(ptx.collateralOutpoint, coin)) {
756+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral not found: %s", ptx.collateralOutpoint.ToStringShort()));
757+
}
758+
CTxDestination txDest;
759+
ExtractDestination(coin.out.scriptPubKey, txDest);
760+
const PKHash* pkhash = std::get_if<PKHash>(&txDest);
761+
if (!pkhash) {
762+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral type not supported: %s", ptx.collateralOutpoint.ToStringShort()));
775763
}
776764

777-
CKey key;
778-
if (!spk_man->GetKey(ToKeyID(*pkhash), key)) {
779-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", EncodeDestination(txDest)));
765+
if (isPrepareRegister) {
766+
// external signing with collateral key
767+
ptx.vchSig.clear();
768+
SetTxPayload(tx, ptx);
769+
770+
UniValue ret(UniValue::VOBJ);
771+
ret.pushKV("tx", EncodeHexTx(CTransaction(tx)));
772+
ret.pushKV("collateralAddress", EncodeDestination(txDest));
773+
ret.pushKV("signMessage", ptx.MakeSignString());
774+
return ret;
775+
} else {
776+
// lets prove we own the collateral
777+
LegacyScriptPubKeyMan* spk_man = wallet->GetLegacyScriptPubKeyMan();
778+
if (!spk_man) {
779+
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
780+
}
781+
782+
CKey key;
783+
if (!spk_man->GetKey(ToKeyID(*pkhash), key)) {
784+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", EncodeDestination(txDest)));
785+
}
786+
SignSpecialTxPayloadByString(tx, ptx, key);
787+
SetTxPayload(tx, ptx);
788+
return SignAndSendSpecialTx(request, chainman, tx, fSubmit);
789+
}
790+
} catch (...) {
791+
if (unlockOnError) {
792+
WITH_LOCK(wallet->cs_wallet, wallet->UnlockCoin(ptx.collateralOutpoint));
780793
}
781-
SignSpecialTxPayloadByString(tx, ptx, key);
782-
SetTxPayload(tx, ptx);
783-
return SignAndSendSpecialTx(request, chainman, tx, fSubmit);
794+
throw;
784795
}
785796
}
786797
}

0 commit comments

Comments
 (0)