aboutsummaryrefslogtreecommitdiff
path: root/src/rpcrawtransaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpcrawtransaction.cpp')
-rw-r--r--src/rpcrawtransaction.cpp87
1 files changed, 57 insertions, 30 deletions
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 66e4d85f3..08b0049b0 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -18,15 +18,7 @@ using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
-// These are all in bitcoinrpc.cpp:
-extern Object JSONRPCError(int code, const string& message);
-extern int64 AmountFromValue(const Value& value);
-extern Value ValueFromAmount(int64 amount);
-extern std::string HelpRequiringPassphrase();
-extern void EnsureWalletIsUnlocked();
-
-void
-ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{
txnouttype type;
vector<CTxDestination> addresses;
@@ -50,8 +42,7 @@ ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
out.push_back(Pair("addresses", a));
}
-void
-TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
+void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion));
@@ -100,6 +91,7 @@ TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
+ entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
}
else
entry.push_back(Pair("confirmations", 0));
@@ -144,24 +136,40 @@ Value getrawtransaction(const Array& params, bool fHelp)
Value listunspent(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 2)
+ if (fHelp || params.size() > 3)
throw runtime_error(
- "listunspent [minconf=1] [maxconf=999999]\n"
+ "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
"Returns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
+ "Optionally filtered to only include txouts paid to specified addresses.\n"
"Results are an array of Objects, each of which has:\n"
"{txid, vout, scriptPubKey, amount, confirmations}");
- RPCTypeCheck(params, list_of(int_type)(int_type));
+ RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
- int nMaxDepth = 999999;
+ int nMaxDepth = 9999999;
if (params.size() > 1)
nMaxDepth = params[1].get_int();
+ set<CBitcoinAddress> setAddress;
+ if (params.size() > 2)
+ {
+ Array inputs = params[2].get_array();
+ BOOST_FOREACH(Value& input, inputs)
+ {
+ CBitcoinAddress address(input.get_str());
+ if (!address.IsValid())
+ throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+input.get_str());
+ if (setAddress.count(address))
+ throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+input.get_str());
+ setAddress.insert(address);
+ }
+ }
+
Array results;
vector<COutput> vecOutputs;
pwalletMain->AvailableCoins(vecOutputs, false);
@@ -170,6 +178,16 @@ Value listunspent(const Array& params, bool fHelp)
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
+ if(setAddress.size())
+ {
+ CTxDestination address;
+ if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ continue;
+
+ if (!setAddress.count(address))
+ continue;
+ }
+
int64 nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
Object entry;
@@ -230,7 +248,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
- throw JSONRPCError(-5, string("Invalid Bitcoin address:")+s.name_);
+ throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
@@ -280,21 +298,18 @@ Value signrawtransaction(const Array& params, bool fHelp)
throw runtime_error(
"signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
"Sign inputs for raw transaction (serialized, hex-encoded).\n"
- "Second optional argument is an array of previous transaction outputs that\n"
+ "Second optional argument (may be null) is an array of previous transaction outputs that\n"
"this transaction depends on but may not yet be in the blockchain.\n"
- "Third optional argument is an array of base58-encoded private\n"
+ "Third optional argument (may be null) is an array of base58-encoded private\n"
"keys that, if given, will be the only keys used to sign the transaction.\n"
- "Fourth option is a string that is one of six values; ALL, NONE, SINGLE or\n"
+ "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
"ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
"Returns json object with keys:\n"
" hex : raw transaction with signature(s) (hex-encoded string)\n"
" complete : 1 if transaction has a complete set of signature (0 if not)"
+ HelpRequiringPassphrase());
- if (params.size() < 3)
- EnsureWalletIsUnlocked();
-
- RPCTypeCheck(params, list_of(str_type)(array_type)(array_type));
+ RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
vector<unsigned char> txData(ParseHex(params[0].get_str()));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
@@ -321,24 +336,29 @@ Value signrawtransaction(const Array& params, bool fHelp)
// Fetch previous transactions (inputs):
map<COutPoint, CScript> mapPrevOut;
+ for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
{
+ CTransaction tempTx;
MapPrevTx mapPrevTx;
CTxDB txdb("r");
map<uint256, CTxIndex> unused;
bool fInvalid;
- mergedTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
+
+ // FetchInputs aborts on failure, so we go one at a time.
+ tempTx.vin.push_back(mergedTx.vin[i]);
+ tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
// Copy results into mapPrevOut:
- BOOST_FOREACH(const CTxIn& txin, mergedTx.vin)
+ BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
{
const uint256& prevHash = txin.prevout.hash;
- if (mapPrevTx.count(prevHash))
+ if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
}
}
// Add previous txouts given in the RPC call:
- if (params.size() > 1)
+ if (params.size() > 1 && params[1].type() != null_type)
{
Array prevTxs = params[1].get_array();
BOOST_FOREACH(Value& p, prevTxs)
@@ -385,7 +405,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2)
+ if (params.size() > 2 && params[2].type() != null_type)
{
fGivenKeys = true;
Array keys = params[2].get_array();
@@ -402,10 +422,13 @@ Value signrawtransaction(const Array& params, bool fHelp)
tempKeystore.AddKey(key);
}
}
+ else
+ EnsureWalletIsUnlocked();
+
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
int nHashType = SIGHASH_ALL;
- if (params.size() > 3)
+ if (params.size() > 3 && params[3].type() != null_type)
{
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
@@ -423,6 +446,8 @@ Value signrawtransaction(const Array& params, bool fHelp)
throw JSONRPCError(-8, "Invalid sighash param");
}
+ bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
+
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
{
@@ -435,7 +460,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
const CScript& prevPubKey = mapPrevOut[txin.prevout];
txin.scriptSig.clear();
- SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
+ // Only sign SIGHASH_SINGLE if there's a corresponding output:
+ if (!fHashSingle || (i < mergedTx.vout.size()))
+ SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants)