Skip to content

Commit

Permalink
add rpc fundrawtransaction
Browse files Browse the repository at this point in the history
add rpc fundrawtransaction
  • Loading branch information
khs130 committed Sep 6, 2019
1 parent 07f8bd6 commit 108f8f8
Show file tree
Hide file tree
Showing 12 changed files with 719 additions and 7 deletions.
3 changes: 3 additions & 0 deletions release/version_history.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@

# - ver:1.09.0
# 20181221 - changed Block reward value from 2500 to 500.

# - ver:1.10.0
# 20190906 - add rpc command fundrawtransaction
4 changes: 4 additions & 0 deletions src/rpc/rpcclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransaction", 1 },
{ "signrawtransaction", 2 },
{ "sendrawtransaction", 1 },
#ifdef FEATURE_HPAY_FUNDRAWTX
{ "fundrawtransaction", 1},
{ "fundrawtransaction", 2},
#endif
{ "gettxout", 1 },
{ "gettxout", 2 },
{ "lockunspent", 0 },
Expand Down
1 change: 1 addition & 0 deletions src/rpc/rpcclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
#define FEATURE_HPAY_FUNDRAWTX

#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_utils.h"
Expand Down
51 changes: 50 additions & 1 deletion src/rpc/rpchelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,56 @@ void mc_InitRPCHelpMap05()
+ HelpExampleCli("signrawtransaction", "\"myhex\"")
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
));


#ifdef FEATURE_HPAY_FUNDRAWTX
mapHelpStrings.insert(std::make_pair("fundrawtransaction",
"fundrawtransaction \"hexstring\" ( options iswitness )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
"The inputs added will not be signed, use signrawtransaction for that.\n"
"Note that all existing inputs must have their previous output transaction be in the wallet.\n"
"Note that all inputs selected must be of standard form and P2SH scripts must be\n"
"in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"
"\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
"2. options (object, optional)\n"
" {\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"changeAddress\" (string, optional, default pool address) The hdac address to receive the change\n"
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate 0.01 HDAC/kB\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.\n"
" [vout_index,...]\n"

" }\n"
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"

"\nResult:\n"
"{\n"
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
" \"fee\": n, (numeric) Fee in 0.01 the resulting transaction pays\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
"\nExamples:\n"
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
"\nAdd sufficient unsigned inputs to meet the output value\n"
+ HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
"\nSign the transaction\n"
+ HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
));
#endif /* FEATURE_HPAY_FUNDRAWTX */

mapHelpStrings.insert(std::make_pair("createkeypairs",
"createkeypairs ( count )\n"
"\nCreates public/private key pairs. These key pairs are not stored in the wallet.\n"
Expand Down
3 changes: 3 additions & 0 deletions src/rpc/rpclist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ static const CRPCCommand vRPCCommands[] =
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
#ifdef FEATURE_HPAY_FUNDRAWTX
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, false, false }, /* uses wallet if enabled */
#endif /* FEATURE_HPAY_FUNDRAWTX */
{ "rawtransactions", "appendrawchange", &appendrawchange, false, false, true },
{ "hidden", "appendrawmetadata", &appendrawmetadata, false, false, true },
{ "rawtransactions", "appendrawdata", &appendrawmetadata, false, false, true },
Expand Down
159 changes: 159 additions & 0 deletions src/rpc/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ using namespace std;
#include "utils/util.h"
#include "utils/utilmoneystr.h"
#include "wallet/wallettxs.h"
#ifdef FEATURE_HPAY_FUNDRAWTX
#include "wallet/coincontrol.h"
#endif /* FEATURE_HPAY_FUNDRAWTX */

bool OutputCanSend(COutput out);
uint32_t mc_CheckSigScriptForMutableTx(const unsigned char *src,int size);
Expand Down Expand Up @@ -1659,6 +1662,162 @@ Value decodescript(const Array& params, bool fHelp)
return r;
}

#ifdef FEATURE_HPAY_FUNDRAWTX
Value fundrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2)
throw runtime_error("Help message not found\n");

RPCTypeCheck(params, list_of(str_type)(obj_type));

CCoinControl coinControl;
bool changeAddress = 0;
int changePosition = -1;
bool lockUnspents = false;
Array subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs;

if (params.size() > 1)
{
if (params[1].type() == bool_type)
{
// backward compatibility bool only fallback
coinControl.fAllowWatchOnly = params[1].get_bool();
}
else
{
if (params.size() > 1 && params[1].type() != null_type)
{
if(params[1].type() == obj_type)
{
Object objParams = params[1].get_obj();
BOOST_FOREACH(const Pair& s, objParams)
{
if(s.name_ == "includeWatching")
{
if(s.value_.type() == bool_type)
{
coinControl.fAllowWatchOnly = s.value_.get_bool();
}
else
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'includeWatching' field, should be boolean");
}
}
if(s.name_ == "changeAddress")
{
if(s.value_.type() == str_type)
{
CBitcoinAddress address(s.value_.get_str());
coinControl.destChange = address.Get();
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid address: ")+s.value_.get_str());
if(!AddressCanReceive(address.Get()))
{
throw JSONRPCError(RPC_INSUFFICIENT_PERMISSIONS, "address doesn't have receive permission");
}
changeAddress = 1;
}
else
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'changeAddress' field, should be stribg");
}
}
if(s.name_ == "changePosition")
{
if(s.value_.type() == int_type)
{
changePosition = s.value_.get_int();
coinControl.fChangePosition = changePosition;
}
else
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'changePosition' field, should be integer");
}
}
if(s.name_ == "feeRate")
{
if(s.value_.type() == real_type)
{
if(s.value_.get_real() == 0)
{
// normal fee
}
else
{
CAmount nAmount = AmountFromValue(s.value_.get_real());
coinControl.nFeeRate = CFeeRate(nAmount, 1000);
coinControl.fOverrideFeeRate = true;
if(fDebug>1)LogPrintf("fundrawtransaction set %d feeRate %d \n",nAmount,coinControl.nFeeRate.ToString());
}
}
else
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'feeRate' field, should be real");
}
}
if(s.name_ == "subtractFeeFromOutputs")
{
if(s.value_.type() == array_type)
{
subtractFeeFromOutputs = s.value_.get_array();
}
else
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for 'subtractFeeFromOutputs' field, should be array");
}
}
}
}
}
}
}

// parse hex string from parameter
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}

if (tx.vout.size() == 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
}

if (changePosition != -1 &&
(changePosition < 0 || (unsigned int)changePosition > tx.vout.size())) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
}

for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++)
{
int pos = subtractFeeFromOutputs[idx].get_int();
if (setSubtractFeeFromOutputs.count(pos))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
if (pos < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
if (pos >= int(tx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
setSubtractFeeFromOutputs.insert(pos);
}

if(fDebug>1)LogPrintf("Befor fund pos %d %s\n",changePosition,tx.ToString());
CAmount nFeeOut;
string strFailReason;
if(!pwalletMain->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl))
{
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
if(fDebug>1)LogPrintf("After fund pos %d %s\n",changePosition,tx.ToString());

Object result;
result.push_back(Pair("hex", EncodeHexTx(CTransaction(tx))));
result.push_back(Pair("changepos", changePosition));
result.push_back(Pair("fee", ValueFromAmount(nFeeOut)));
return result;

}
#endif /* FEATURE_HPAY_FUNDRAWTX */

Value signrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
Expand Down
5 changes: 5 additions & 0 deletions src/rpc/rpcserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#ifndef BITCOIN_RPCSERVER_H
#define BITCOIN_RPCSERVER_H

#define FEATURE_HPAY_FUNDRAWTX

#include "structs/amount.h"
#include "rpc/rpcprotocol.h"
#include "structs/uint256.h"
Expand Down Expand Up @@ -307,6 +309,9 @@ extern json_spirit::Value createrawtransaction(const json_spirit::Array& params,
extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
#ifdef FEATURE_HPAY_FUNDRAWTX
extern json_spirit::Value fundrawtransaction(const json_spirit::Array& params, bool fHelp);
#endif /* FEATURE_HPAY_FUNDRAWTX */
extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp);

extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp
Expand Down
13 changes: 13 additions & 0 deletions src/rpc/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,14 @@ Value sendmany(const Array& params, bool fHelp)
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["comment"] = params[3].get_str();

#if defined (FEATURE_HPAY_SENDMANY_DEDUCT_FEE) || defined (FEATURE_HPAY_FUNDRAWTX)
vector<string> addrStrings;
std::set<int> setSubtractFeeFromOutputs;
int subtract_idx=0;
if (params.size() > 4)
addrStrings = ParseStringList(params[4]);
#endif /* FEATURE_HPAY_SENDMANY_DEDUCT_FEE */

set<CBitcoinAddress> setAddress;
vector<pair<CScript, CAmount> > vecSend;

Expand Down Expand Up @@ -1087,7 +1095,12 @@ Value sendmany(const Array& params, bool fHelp)
CReserveKey keyChange(pwalletMain);
CAmount nFeeRequired = 0;
string strFailReason;
#if defined (FEATURE_HPAY_SENDMANY_DEDUCT_FEE) || defined (FEATURE_HPAY_FUNDRAWTX)
int nChangePosRet = -1;
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, setSubtractFeeFromOutputs, strFailReason);
#else
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason);
#endif /* FEATURE_HPAY_FUNDRAWTX */
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);

Expand Down
2 changes: 1 addition & 1 deletion src/version/hdacversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#endif

#define HDAC_BUILD_MAJOR 1
#define HDAC_BUILD_MINOR 09
#define HDAC_BUILD_MINOR 10
#define HDAC_BUILD_REVISION 0
// Build version is major.minor.revision ( 1.08.0 )

Expand Down
25 changes: 22 additions & 3 deletions src/wallet/coincontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@
#ifndef BITCOIN_COINCONTROL_H
#define BITCOIN_COINCONTROL_H

#define FEATURE_HPAY_FUNDRAWTX

#include "primitives/transaction.h"

/** Coin Control Features. */
class CCoinControl
{
public:
CTxDestination destChange;

#ifdef FEATURE_HPAY_FUNDRAWTX
bool fAllowWatchOnly;
bool fAllowOtherInputs;
bool fOverrideFeeRate;
CFeeRate nFeeRate;
int fChangePosition;
#endif /* FEATURE_HPAY_FUNDRAWTX */
CCoinControl()
{
SetNull();
Expand All @@ -22,6 +30,12 @@ class CCoinControl
void SetNull()
{
destChange = CNoDestination();
#ifdef FEATURE_HPAY_FUNDRAWTX
fAllowWatchOnly = false;
fOverrideFeeRate = false;
nFeeRate = CFeeRate(0);
fChangePosition = -1;
#endif /* FEATURE_HPAY_FUNDRAWTX */
setSelected.clear();
}

Expand Down Expand Up @@ -50,12 +64,17 @@ class CCoinControl
{
setSelected.clear();
}

#ifdef FEATURE_HPAY_FUNDRAWTX
void ListSelected(std::vector<COutPoint>& vOutpoints) const
{
vOutpoints.assign(setSelected.begin(), setSelected.end());
}
#else
void ListSelected(std::vector<COutPoint>& vOutpoints)
{
vOutpoints.assign(setSelected.begin(), setSelected.end());
}

#endif
private:
std::set<COutPoint> setSelected;
};
Expand Down
Loading

0 comments on commit 108f8f8

Please sign in to comment.