mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Add an option to use specific address as a source of funds in protx rpc commands (otherwise use payoutAddress/operatorPayoutAddress) (#2581)
* Add an option to use specific address as a source of funds in protx rpc commands * fix typo "must" * Always use payoutAddress (or operatorPayoutAddress) as a default if no fundAddress was specified * make sure we actually selected some inputs * fundAddress -> feeSourceAddress * Align help text with new logic * fix protx_update_service * fix protx_revoke * Add fRequireAllInputs to CCoinControl and use it in FundSpecialTx This avoids adding all inputs even though they are not needed. * Allow to specify empty operator payout address and simplify fee code in update_service DIP3 tests were failing to call "protx update_service" as it did not accept an empty "operatorPayoutAddress". This also simplifies handling of the feeSourceAddr. * Specify source for funds and fees in DIP3 tests
This commit is contained in:
parent
33f78d70e8
commit
0dce846d5a
@ -415,6 +415,7 @@ class DIP3Test(BitcoinTestFramework):
|
||||
mn.p2p_port = p2p_port(mn.idx)
|
||||
|
||||
blsKey = node.bls('generate')
|
||||
mn.fundsAddr = node.getnewaddress()
|
||||
mn.ownerAddr = node.getnewaddress()
|
||||
mn.operatorAddr = blsKey['public']
|
||||
mn.votingAddr = mn.ownerAddr
|
||||
@ -426,9 +427,11 @@ class DIP3Test(BitcoinTestFramework):
|
||||
# create a protx MN and also fund it (using collateral inside ProRegTx)
|
||||
def create_mn_protx_fund(self, node, idx, alias, legacy_mn_key=None):
|
||||
mn = self.create_mn_protx_base(node, idx, alias, legacy_mn_key=legacy_mn_key)
|
||||
node.sendtoaddress(mn.fundsAddr, 1000.001)
|
||||
|
||||
mn.collateral_address = node.getnewaddress()
|
||||
|
||||
mn.protx_hash = node.protx('register_fund', mn.collateral_address, '127.0.0.1:%d' % mn.p2p_port, mn.ownerAddr, mn.operatorAddr, mn.votingAddr, 0, mn.collateral_address)
|
||||
mn.protx_hash = node.protx('register_fund', mn.collateral_address, '127.0.0.1:%d' % mn.p2p_port, mn.ownerAddr, mn.operatorAddr, mn.votingAddr, 0, mn.collateral_address, mn.fundsAddr)
|
||||
mn.collateral_txid = mn.protx_hash
|
||||
mn.collateral_vout = -1
|
||||
|
||||
@ -444,9 +447,11 @@ class DIP3Test(BitcoinTestFramework):
|
||||
# create a protx MN which refers to an existing collateral
|
||||
def create_mn_protx(self, node, idx, alias, collateral_txid, collateral_vout, legacy_mn_key=None):
|
||||
mn = self.create_mn_protx_base(node, idx, alias, legacy_mn_key=legacy_mn_key)
|
||||
node.sendtoaddress(mn.fundsAddr, 0.001)
|
||||
|
||||
mn.rewards_address = node.getnewaddress()
|
||||
|
||||
mn.protx_hash = node.protx('register', collateral_txid, collateral_vout, '127.0.0.1:%d' % mn.p2p_port, mn.ownerAddr, mn.operatorAddr, mn.votingAddr, 0, mn.rewards_address)
|
||||
mn.protx_hash = node.protx('register', collateral_txid, collateral_vout, '127.0.0.1:%d' % mn.p2p_port, mn.ownerAddr, mn.operatorAddr, mn.votingAddr, 0, mn.rewards_address, mn.fundsAddr)
|
||||
mn.collateral_txid = collateral_txid
|
||||
mn.collateral_vout = collateral_vout
|
||||
|
||||
@ -476,14 +481,16 @@ class DIP3Test(BitcoinTestFramework):
|
||||
return mn
|
||||
|
||||
def update_mn_payee(self, mn, payee):
|
||||
self.nodes[0].protx('update_registrar', mn.protx_hash, '', '', payee)
|
||||
self.nodes[0].sendtoaddress(mn.fundsAddr, 0.001)
|
||||
self.nodes[0].protx('update_registrar', mn.protx_hash, '', '', payee, mn.fundsAddr)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
info = self.nodes[0].protx('info', mn.protx_hash)
|
||||
assert(info['state']['payoutAddress'] == payee)
|
||||
|
||||
def test_protx_update_service(self, mn):
|
||||
self.nodes[0].protx('update_service', mn.protx_hash, '127.0.0.2:%d' % mn.p2p_port, mn.blsMnkey)
|
||||
self.nodes[0].sendtoaddress(mn.fundsAddr, 0.001)
|
||||
self.nodes[0].protx('update_service', mn.protx_hash, '127.0.0.2:%d' % mn.p2p_port, mn.blsMnkey, "", mn.fundsAddr)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
for node in self.nodes:
|
||||
@ -493,7 +500,7 @@ class DIP3Test(BitcoinTestFramework):
|
||||
assert_equal(mn_list['%s-%d' % (mn.collateral_txid, mn.collateral_vout)]['address'], '127.0.0.2:%d' % mn.p2p_port)
|
||||
|
||||
# undo
|
||||
self.nodes[0].protx('update_service', mn.protx_hash, '127.0.0.1:%d' % mn.p2p_port, mn.blsMnkey)
|
||||
self.nodes[0].protx('update_service', mn.protx_hash, '127.0.0.1:%d' % mn.p2p_port, mn.blsMnkey, "", mn.fundsAddr)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
def force_finish_mnsync(self, node):
|
||||
@ -732,16 +739,20 @@ class DIP3Test(BitcoinTestFramework):
|
||||
|
||||
def test_fail_create_protx(self, node):
|
||||
# Try to create ProTx (should still fail)
|
||||
fund_address = node.getnewaddress()
|
||||
address = node.getnewaddress()
|
||||
node.sendtoaddress(fund_address, 1000.001) # +0.001 for fees
|
||||
key = node.getnewaddress()
|
||||
blsKey = node.bls('generate')
|
||||
assert_raises_jsonrpc(None, "bad-tx-type", node.protx, 'register_fund', address, '127.0.0.1:10000', key, blsKey['public'], key, 0, address)
|
||||
assert_raises_jsonrpc(None, "bad-tx-type", node.protx, 'register_fund', address, '127.0.0.1:10000', key, blsKey['public'], key, 0, address, fund_address)
|
||||
|
||||
def test_success_create_protx(self, node):
|
||||
fund_address = node.getnewaddress()
|
||||
address = node.getnewaddress()
|
||||
txid = node.sendtoaddress(fund_address, 1000.001) # +0.001 for fees
|
||||
key = node.getnewaddress()
|
||||
blsKey = node.bls('generate')
|
||||
txid = node.protx('register_fund', address, '127.0.0.1:10000', key, blsKey['public'], key, 0, address)
|
||||
node.protx('register_fund', address, '127.0.0.1:10000', key, blsKey['public'], key, 0, address, fund_address)
|
||||
rawtx = node.getrawtransaction(txid, 1)
|
||||
self.mine_double_spend(node, rawtx['vin'], address, use_mnmerkleroot_from_tip=True)
|
||||
self.sync_all()
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "validation.h"
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/coincontrol.h"
|
||||
#include "wallet/wallet.h"
|
||||
#endif//ENABLE_WALLET
|
||||
|
||||
@ -89,32 +90,69 @@ static CBLSSecretKey ParseBLSSecretKey(const std::string& hexKey, const std::str
|
||||
#ifdef ENABLE_WALLET
|
||||
|
||||
template<typename SpecialTxPayload>
|
||||
static void FundSpecialTx(CMutableTransaction& tx, SpecialTxPayload payload)
|
||||
static void FundSpecialTx(CMutableTransaction& tx, const SpecialTxPayload& payload, const CTxDestination& fundDest)
|
||||
{
|
||||
assert(pwalletMain != NULL);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CTxDestination nodest = CNoDestination();
|
||||
if (fundDest == nodest) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No source of funds specified");
|
||||
}
|
||||
|
||||
CDataStream ds(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ds << payload;
|
||||
tx.vExtraPayload.assign(ds.begin(), ds.end());
|
||||
|
||||
static CTxOut dummyTxOut(0, CScript() << OP_RETURN);
|
||||
std::vector<CRecipient> vecSend;
|
||||
bool dummyTxOutAdded = false;
|
||||
|
||||
if (tx.vout.empty()) {
|
||||
// add dummy txout as FundTransaction requires at least one output
|
||||
// add dummy txout as CreateTransaction requires at least one recipient
|
||||
tx.vout.emplace_back(dummyTxOut);
|
||||
dummyTxOutAdded = true;
|
||||
}
|
||||
|
||||
for (const auto& txOut : tx.vout) {
|
||||
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
|
||||
vecSend.push_back(recipient);
|
||||
}
|
||||
|
||||
CCoinControl coinControl;
|
||||
coinControl.destChange = fundDest;
|
||||
coinControl.fRequireAllInputs = false;
|
||||
|
||||
std::vector<COutput> vecOutputs;
|
||||
pwalletMain->AvailableCoins(vecOutputs);
|
||||
|
||||
for (const auto& out : vecOutputs) {
|
||||
CTxDestination txDest;
|
||||
if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, txDest) && txDest == fundDest) {
|
||||
coinControl.Select(COutPoint(out.tx->tx->GetHash(), out.i));
|
||||
}
|
||||
}
|
||||
|
||||
if (!coinControl.HasSelected()) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No funds at specified address");
|
||||
}
|
||||
|
||||
CWalletTx wtx;
|
||||
CReserveKey reservekey(pwalletMain);
|
||||
CAmount nFee;
|
||||
CFeeRate feeRate = CFeeRate(0);
|
||||
int nChangePos = -1;
|
||||
std::string strFailReason;
|
||||
std::set<int> setSubtractFeeFromOutputs;
|
||||
if (!pwalletMain->FundTransaction(tx, nFee, false, feeRate, nChangePos, strFailReason, false, false, setSubtractFeeFromOutputs, true, CNoDestination())) {
|
||||
|
||||
if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFee, nChangePos, strFailReason, &coinControl, false, ALL_COINS, false, tx.vExtraPayload.size())) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
|
||||
}
|
||||
|
||||
tx.vin = wtx.tx->vin;
|
||||
tx.vout = wtx.tx->vout;
|
||||
|
||||
if (dummyTxOutAdded && tx.vout.size() > 1) {
|
||||
// FundTransaction added a change output, so we don't need the dummy txout anymore
|
||||
// Removing it results in slight overpayment of fees, but we ignore this for now (as it's a very low amount)
|
||||
// CreateTransaction added a change output, so we don't need the dummy txout anymore.
|
||||
// Removing it results in slight overpayment of fees, but we ignore this for now (as it's a very low amount).
|
||||
auto it = std::find(tx.vout.begin(), tx.vout.end(), dummyTxOut);
|
||||
assert(it != tx.vout.end());
|
||||
tx.vout.erase(it);
|
||||
@ -186,7 +224,7 @@ static std::string SignAndSendSpecialTx(const CMutableTransaction& tx)
|
||||
void protx_register_fund_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx register_fund \"collateralAddress\" \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\"\n"
|
||||
"protx register_fund \"collateralAddress\" \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\" ( \"fundAddress\" )\n"
|
||||
"\nCreates, funds and sends a ProTx to the network. The resulting transaction will move 1000 Dash\n"
|
||||
"to the address specified by collateralAddress and will then function as the collateral of your\n"
|
||||
"masternode.\n"
|
||||
@ -198,7 +236,7 @@ void protx_register_fund_help()
|
||||
"2. \"ipAndPort\" (string, required) IP and port in the form \"IP:PORT\".\n"
|
||||
" Must be unique on the network. Can be set to 0, which will require a ProUpServTx afterwards.\n"
|
||||
"3. \"ownerKeyAddr\" (string, required) The owner key used for payee updates and proposal voting.\n"
|
||||
" The private key belonging to this address be known in your wallet. The address must\n"
|
||||
" The private key belonging to this address must be known in your wallet. The address must\n"
|
||||
" be unused and must differ from the collateralAddress\n"
|
||||
"4. \"operatorPubKey\" (string, required) The operator BLS public key. The private key does not have to be known.\n"
|
||||
" It has to match the private key which is later used when operating the masternode.\n"
|
||||
@ -207,7 +245,10 @@ void protx_register_fund_help()
|
||||
" If set to \"0\" or an empty string, ownerAddr will be used.\n"
|
||||
"6. \"operatorReward\" (numeric, required) The fraction in % to share with the operator. The value must be\n"
|
||||
" between 0.00 and 100.00.\n"
|
||||
"7. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments."
|
||||
"7. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments.\n"
|
||||
"8. \"fundAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
|
||||
" If not specified, payoutAddress is the one that is going to be used.\n"
|
||||
" The private key belonging to this address must be known in your wallet.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("protx", "register_fund \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\" \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
|
||||
);
|
||||
@ -216,7 +257,7 @@ void protx_register_fund_help()
|
||||
void protx_register_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx register \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\"\n"
|
||||
"protx register \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\" ( \"feeSourceAddress\" )\n"
|
||||
"\nSame as \"protx register_fund\", but with an externally referenced collateral.\n"
|
||||
"The collateral is specified through \"collateralHash\" and \"collateralIndex\" and must be an unspent\n"
|
||||
"transaction output. It must also not be used by any other masternode.\n"
|
||||
@ -224,6 +265,7 @@ void protx_register_help()
|
||||
"1. \"collateralHash\" (string, required) The collateral transaction hash.\n"
|
||||
"2. collateralIndex (numeric, required) The collateral transaction output index.\n"
|
||||
"3., 4., 5. ... See help text of \"protx register_fund\"\n"
|
||||
"feeSourceAddress See help text for \"fundAddress\" of \"protx register_fund\"\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("protx", "register \"0123456701234567012345670123456701234567012345670123456701234567\" 0 \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
|
||||
);
|
||||
@ -232,12 +274,13 @@ void protx_register_help()
|
||||
void protx_register_prepare_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx register_prepare \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\"\n"
|
||||
"protx register_prepare \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerKeyAddr\" \"operatorPubKey\" \"votingKeyAddr\" operatorReward \"payoutAddress\" ( \"feeSourceAddress\" )\n"
|
||||
"\nCreates an unsigned ProTx and returns it. The ProTx must be signed externally with the collateral\n"
|
||||
"key and then passed to \"protx register_submit\". The prepared transaction will also contain inputs\n"
|
||||
"and outputs to cover fees.\n"
|
||||
"\nArguments:\n"
|
||||
"1., 2., 3., ... See help text of \"protx register\".\n"
|
||||
"feeSourceAddress See help text for \"fundAddress\" of \"protx register_fund\"\n"
|
||||
"\nResult:\n"
|
||||
"{ (json object)\n"
|
||||
" \"tx\" : (string) The serialized ProTx in hex format.\n"
|
||||
@ -271,11 +314,11 @@ UniValue protx_register(const JSONRPCRequest& request)
|
||||
bool isFundRegister = request.params[0].get_str() == "register_fund";
|
||||
bool isPrepareRegister = request.params[0].get_str() == "register_prepare";
|
||||
|
||||
if (isFundRegister && (request.fHelp || request.params.size() != 8)) {
|
||||
if (isFundRegister && (request.fHelp || (request.params.size() != 8 && request.params.size() != 9))) {
|
||||
protx_register_fund_help();
|
||||
} else if (isExternalRegister && (request.fHelp || request.params.size() != 9)) {
|
||||
} else if (isExternalRegister && (request.fHelp || (request.params.size() != 9 && request.params.size() != 10))) {
|
||||
protx_register_help();
|
||||
} else if (isPrepareRegister && (request.fHelp || request.params.size() != 9)) {
|
||||
} else if (isPrepareRegister && (request.fHelp || (request.params.size() != 9 && request.params.size() != 10))) {
|
||||
protx_register_prepare_help();
|
||||
}
|
||||
|
||||
@ -353,7 +396,14 @@ UniValue protx_register(const JSONRPCRequest& request)
|
||||
ptx.vchSig.resize(65);
|
||||
}
|
||||
|
||||
FundSpecialTx(tx, ptx);
|
||||
CBitcoinAddress fundAddress = payoutAddress;
|
||||
if (request.params.size() > paramIdx + 6) {
|
||||
fundAddress = CBitcoinAddress(request.params[paramIdx + 6].get_str());
|
||||
if (!fundAddress.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[paramIdx + 6].get_str());
|
||||
}
|
||||
|
||||
FundSpecialTx(tx, ptx, fundAddress.Get());
|
||||
UpdateSpecialTxInputsHash(tx, ptx);
|
||||
|
||||
if (isFundRegister) {
|
||||
@ -435,7 +485,7 @@ UniValue protx_register_submit(const JSONRPCRequest& request)
|
||||
void protx_update_service_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx update_service \"proTxHash\" \"ipAndPort\" \"operatorKey\" (\"operatorPayoutAddress\")\n"
|
||||
"protx update_service \"proTxHash\" \"ipAndPort\" \"operatorKey\" (\"operatorPayoutAddress\" \"feeSourceAddress\" )\n"
|
||||
"\nCreates and sends a ProUpServTx to the network. This will update the IP address\n"
|
||||
"of a masternode.\n"
|
||||
"If this is done for a masternode that got PoSe-banned, the ProUpServTx will also revive this masternode.\n"
|
||||
@ -447,6 +497,9 @@ void protx_update_service_help()
|
||||
" registered operator public key.\n"
|
||||
"4. \"operatorPayoutAddress\" (string, optional) The address used for operator reward payments.\n"
|
||||
" Only allowed when the ProRegTx had a non-zero operatorReward value.\n"
|
||||
"5. \"feeSourceAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
|
||||
" If not specified, operatorPayoutAddress is the one that is going to be used.\n"
|
||||
" The private key belonging to this address must be known in your wallet.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("protx", "update_service \"0123456701234567012345670123456701234567012345670123456701234567\" \"1.2.3.4:1234\" 5a2e15982e62f1e0b7cf9783c64cf7e3af3f90a52d6c40f6f95d624c0b1621cd")
|
||||
);
|
||||
@ -454,7 +507,7 @@ void protx_update_service_help()
|
||||
|
||||
UniValue protx_update_service(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || (request.params.size() != 4 && request.params.size() != 5))
|
||||
if (request.fHelp || (request.params.size() < 4 || request.params.size() > 6))
|
||||
protx_update_service_help();
|
||||
|
||||
CProUpServTx ptx;
|
||||
@ -467,14 +520,6 @@ UniValue protx_update_service(const JSONRPCRequest& request)
|
||||
|
||||
CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[3].get_str(), "operatorKey");
|
||||
|
||||
if (request.params.size() > 4) {
|
||||
CBitcoinAddress payoutAddress(request.params[4].get_str());
|
||||
if (!payoutAddress.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid operator payout address: %s", request.params[4].get_str()));
|
||||
}
|
||||
ptx.scriptOperatorPayout = GetScriptForDestination(payoutAddress.Get());
|
||||
}
|
||||
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(ptx.proTxHash);
|
||||
if (!dmn) {
|
||||
throw std::runtime_error(strprintf("masternode with proTxHash %s not found", ptx.proTxHash.ToString()));
|
||||
@ -488,7 +533,41 @@ UniValue protx_update_service(const JSONRPCRequest& request)
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_UPDATE_SERVICE;
|
||||
|
||||
FundSpecialTx(tx, ptx);
|
||||
// param operatorPayoutAddress
|
||||
if (request.params.size() >= 5) {
|
||||
if (request.params[4].get_str().empty() || request.params[4].get_str() == "0") {
|
||||
ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout;
|
||||
} else {
|
||||
CBitcoinAddress payoutAddress(request.params[4].get_str());
|
||||
if (!payoutAddress.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid operator payout address: %s", request.params[4].get_str()));
|
||||
}
|
||||
ptx.scriptOperatorPayout = GetScriptForDestination(payoutAddress.Get());
|
||||
}
|
||||
} else {
|
||||
ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout;
|
||||
}
|
||||
|
||||
CTxDestination feeSource;
|
||||
|
||||
// param feeSourceAddress
|
||||
if (request.params.size() >= 6) {
|
||||
CBitcoinAddress feeSourceAddress = CBitcoinAddress(request.params[5].get_str());
|
||||
if (!feeSourceAddress.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str());
|
||||
feeSource = feeSourceAddress.Get();
|
||||
} else {
|
||||
if (ptx.scriptOperatorPayout != CScript()) {
|
||||
// use operator reward address as default source for fees
|
||||
ExtractDestination(ptx.scriptOperatorPayout, feeSource);
|
||||
} else {
|
||||
// use payout address as default source for fees
|
||||
ExtractDestination(dmn->pdmnState->scriptPayout, feeSource);
|
||||
}
|
||||
}
|
||||
|
||||
FundSpecialTx(tx, ptx, feeSource);
|
||||
|
||||
SignSpecialTxPayloadByHash(tx, ptx, keyOperator);
|
||||
SetTxPayload(tx, ptx);
|
||||
|
||||
@ -498,7 +577,7 @@ UniValue protx_update_service(const JSONRPCRequest& request)
|
||||
void protx_update_registrar_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx update_registrar \"proTxHash\" \"operatorKeyAddr\" \"votingKeyAddr\" \"payoutAddress\"\n"
|
||||
"protx update_registrar \"proTxHash\" \"operatorKeyAddr\" \"votingKeyAddr\" \"payoutAddress\" ( \"feeSourceAddress\" )\n"
|
||||
"\nCreates and sends a ProUpRegTx to the network. This will update the operator key, voting key and payout\n"
|
||||
"address of the masternode specified by \"proTxHash\".\n"
|
||||
"The owner key of the masternode must be known to your wallet.\n"
|
||||
@ -512,6 +591,9 @@ void protx_update_registrar_help()
|
||||
" If set to \"0\" or an empty string, the last on-chain voting key of the masternode will be used.\n"
|
||||
"4. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments\n"
|
||||
" If set to \"0\" or an empty string, the last on-chain payout address of the masternode will be used.\n"
|
||||
"5. \"feeSourceAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
|
||||
" If not specified, payoutAddress is the one that is going to be used.\n"
|
||||
" The private key belonging to this address must be known in your wallet.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("protx", "update_registrar \"0123456701234567012345670123456701234567012345670123456701234567\" \"982eb34b7c7f614f29e5c665bc3605f1beeef85e3395ca12d3be49d2868ecfea5566f11cedfad30c51b2403f2ad95b67\" \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\"")
|
||||
);
|
||||
@ -519,7 +601,7 @@ void protx_update_registrar_help()
|
||||
|
||||
UniValue protx_update_registrar(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 5) {
|
||||
if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6)) {
|
||||
protx_update_registrar_help();
|
||||
}
|
||||
|
||||
@ -560,7 +642,14 @@ UniValue protx_update_registrar(const JSONRPCRequest& request)
|
||||
// make sure we get anough fees added
|
||||
ptx.vchSig.resize(65);
|
||||
|
||||
FundSpecialTx(tx, ptx);
|
||||
CBitcoinAddress feeSourceAddress = payoutAddress;
|
||||
if (request.params.size() > 5) {
|
||||
feeSourceAddress = CBitcoinAddress(request.params[5].get_str());
|
||||
if (!feeSourceAddress.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str());
|
||||
}
|
||||
|
||||
FundSpecialTx(tx, ptx, feeSourceAddress.Get());
|
||||
SignSpecialTxPayloadByHash(tx, ptx, keyOwner);
|
||||
SetTxPayload(tx, ptx);
|
||||
|
||||
@ -570,7 +659,7 @@ UniValue protx_update_registrar(const JSONRPCRequest& request)
|
||||
void protx_revoke_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx revoke \"proTxHash\" \"operatorKey\" ( reason )\n"
|
||||
"protx revoke \"proTxHash\" \"operatorKey\" ( reason \"feeSourceAddress\")\n"
|
||||
"\nCreates and sends a ProUpRevTx to the network. This will revoke the operator key of the masternode and\n"
|
||||
"put it into the PoSe-banned state. It will also set the service field of the masternode\n"
|
||||
"to zero. Use this in case your operator key got compromised or you want to stop providing your service\n"
|
||||
@ -579,7 +668,10 @@ void protx_revoke_help()
|
||||
"1. \"proTxHash\" (string, required) The hash of the initial ProRegTx.\n"
|
||||
"2. \"operatorKey\" (string, required) The operator private key belonging to the\n"
|
||||
" registered operator public key.\n"
|
||||
"3. reason (numeric, optional) The reason for revocation.\n"
|
||||
"3. reason (numeric, optional) The reason for revocation.\n"
|
||||
"4. \"feeSourceAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
|
||||
" If not specified, operatorPayoutAddress specified earlier is the one that is going to be used.\n"
|
||||
" The private key belonging to this address must be known in your wallet.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("protx", "revoke \"0123456701234567012345670123456701234567012345670123456701234567\" \"072f36a77261cdd5d64c32d97bac417540eddca1d5612f416feb07ff75a8e240\"")
|
||||
);
|
||||
@ -587,7 +679,7 @@ void protx_revoke_help()
|
||||
|
||||
UniValue protx_revoke(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || (request.params.size() != 3 && request.params.size() != 4)) {
|
||||
if (request.fHelp || (request.params.size() < 3 || request.params.size() > 5)) {
|
||||
protx_revoke_help();
|
||||
}
|
||||
|
||||
@ -618,7 +710,25 @@ UniValue protx_revoke(const JSONRPCRequest& request)
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_UPDATE_REVOKE;
|
||||
|
||||
FundSpecialTx(tx, ptx);
|
||||
if (request.params.size() > 4) {
|
||||
CBitcoinAddress feeSourceAddress = CBitcoinAddress(request.params[4].get_str());
|
||||
if (!feeSourceAddress.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[4].get_str());
|
||||
FundSpecialTx(tx, ptx, feeSourceAddress.Get());
|
||||
} else if (dmn->pdmnState->scriptOperatorPayout != CScript()) {
|
||||
// Using funds from previousely specified operator payout address
|
||||
CTxDestination txDest;
|
||||
ExtractDestination(dmn->pdmnState->scriptOperatorPayout, txDest);
|
||||
FundSpecialTx(tx, ptx, txDest);
|
||||
} else if (dmn->pdmnState->scriptPayout != CScript()) {
|
||||
// Using funds from previousely specified masternode payout address
|
||||
CTxDestination txDest;
|
||||
ExtractDestination(dmn->pdmnState->scriptPayout, txDest);
|
||||
FundSpecialTx(tx, ptx, txDest);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No payout or fee source addresses found, can't revoke");
|
||||
}
|
||||
|
||||
SignSpecialTxPayloadByHash(tx, ptx, keyOperator);
|
||||
SetTxPayload(tx, ptx);
|
||||
|
||||
|
@ -14,8 +14,10 @@ public:
|
||||
CTxDestination destChange;
|
||||
bool fUsePrivateSend;
|
||||
bool fUseInstantSend;
|
||||
//! If false, allows unselected inputs, but requires all selected inputs be used
|
||||
//! If false, allows unselected inputs, but requires all selected inputs be used if fAllowOtherInputs is true (default)
|
||||
bool fAllowOtherInputs;
|
||||
//! If false, only include as many inputs as necessary to fulfill a coin selection request. Only usable together with fAllowOtherInputs
|
||||
bool fRequireAllInputs;
|
||||
//! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
|
||||
bool fAllowWatchOnly;
|
||||
//! Minimum absolute fee (not per kilobyte)
|
||||
@ -36,6 +38,7 @@ public:
|
||||
{
|
||||
destChange = CNoDestination();
|
||||
fAllowOtherInputs = false;
|
||||
fRequireAllInputs = true;
|
||||
fAllowWatchOnly = false;
|
||||
setSelected.clear();
|
||||
fUseInstantSend = false;
|
||||
|
@ -2889,6 +2889,11 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
||||
}
|
||||
nValueRet += out.tx->tx->vout[out.i].nValue;
|
||||
setCoinsRet.insert(std::make_pair(out.tx, out.i));
|
||||
|
||||
if (!coinControl->fRequireAllInputs && nValueRet >= nTargetValue) {
|
||||
// stop when we added at least one input and enough inputs to have at least nTargetValue funds
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (nValueRet >= nTargetValue);
|
||||
|
Loading…
Reference in New Issue
Block a user