|
|
|
@ -18,6 +18,39 @@ using namespace boost;
@@ -18,6 +18,39 @@ using namespace boost;
|
|
|
|
|
using namespace boost::assign; |
|
|
|
|
using namespace json_spirit; |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Utilities: convert hex-encoded Values
|
|
|
|
|
// (throws error if not hex).
|
|
|
|
|
//
|
|
|
|
|
uint256 ParseHashV(const Value& v, string strName) |
|
|
|
|
{ |
|
|
|
|
string strHex; |
|
|
|
|
if (v.type() == str_type) |
|
|
|
|
strHex = v.get_str(); |
|
|
|
|
if (!IsHex(strHex)) // Note: IsHex("") is false
|
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
|
|
uint256 result; |
|
|
|
|
result.SetHex(strHex); |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
uint256 ParseHashO(const Object& o, string strKey) |
|
|
|
|
{ |
|
|
|
|
return ParseHashV(find_value(o, strKey), strKey); |
|
|
|
|
} |
|
|
|
|
vector<unsigned char> ParseHexV(const Value& v, string strName) |
|
|
|
|
{ |
|
|
|
|
string strHex; |
|
|
|
|
if (v.type() == str_type) |
|
|
|
|
strHex = v.get_str(); |
|
|
|
|
if (!IsHex(strHex)) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
|
|
return ParseHex(strHex); |
|
|
|
|
} |
|
|
|
|
vector<unsigned char> ParseHexO(const Object& o, string strKey) |
|
|
|
|
{ |
|
|
|
|
return ParseHexV(find_value(o, strKey), strKey); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) |
|
|
|
|
{ |
|
|
|
|
txnouttype type; |
|
|
|
@ -109,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
@@ -109,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
"If verbose is non-zero, returns an Object\n" |
|
|
|
|
"with information about <txid>."); |
|
|
|
|
|
|
|
|
|
uint256 hash; |
|
|
|
|
hash.SetHex(params[0].get_str()); |
|
|
|
|
uint256 hash = ParseHashV(params[0], "parameter 1"); |
|
|
|
|
|
|
|
|
|
bool fVerbose = false; |
|
|
|
|
if (params.size() > 1) |
|
|
|
@ -178,10 +210,10 @@ Value listunspent(const Array& params, bool fHelp)
@@ -178,10 +210,10 @@ Value listunspent(const Array& params, bool fHelp)
|
|
|
|
|
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if(setAddress.size()) |
|
|
|
|
if (setAddress.size()) |
|
|
|
|
{ |
|
|
|
|
CTxDestination address; |
|
|
|
|
if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) |
|
|
|
|
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if (!setAddress.count(address)) |
|
|
|
@ -194,6 +226,17 @@ Value listunspent(const Array& params, bool fHelp)
@@ -194,6 +226,17 @@ Value listunspent(const Array& params, bool fHelp)
|
|
|
|
|
entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); |
|
|
|
|
entry.push_back(Pair("vout", out.i)); |
|
|
|
|
entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); |
|
|
|
|
if (pk.IsPayToScriptHash()) |
|
|
|
|
{ |
|
|
|
|
CTxDestination address; |
|
|
|
|
if (ExtractDestination(pk, address)) |
|
|
|
|
{ |
|
|
|
|
const CScriptID& hash = boost::get<const CScriptID&>(address); |
|
|
|
|
CScript redeemScript; |
|
|
|
|
if (pwalletMain->GetCScript(hash, redeemScript)) |
|
|
|
|
entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
entry.push_back(Pair("amount",ValueFromAmount(nValue))); |
|
|
|
|
entry.push_back(Pair("confirmations",out.nDepth)); |
|
|
|
|
results.push_back(entry); |
|
|
|
@ -221,16 +264,11 @@ Value createrawtransaction(const Array& params, bool fHelp)
@@ -221,16 +264,11 @@ Value createrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
|
|
|
|
|
CTransaction rawTx; |
|
|
|
|
|
|
|
|
|
BOOST_FOREACH(Value& input, inputs) |
|
|
|
|
BOOST_FOREACH(const Value& input, inputs) |
|
|
|
|
{ |
|
|
|
|
const Object& o = input.get_obj(); |
|
|
|
|
|
|
|
|
|
const Value& txid_v = find_value(o, "txid"); |
|
|
|
|
if (txid_v.type() != str_type) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); |
|
|
|
|
string txid = txid_v.get_str(); |
|
|
|
|
if (!IsHex(txid)) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); |
|
|
|
|
uint256 txid = ParseHashO(o, "txid"); |
|
|
|
|
|
|
|
|
|
const Value& vout_v = find_value(o, "vout"); |
|
|
|
|
if (vout_v.type() != int_type) |
|
|
|
@ -239,7 +277,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
@@ -239,7 +277,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
if (nOutput < 0) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); |
|
|
|
|
|
|
|
|
|
CTxIn in(COutPoint(uint256(txid), nOutput)); |
|
|
|
|
CTxIn in(COutPoint(txid, nOutput)); |
|
|
|
|
rawTx.vin.push_back(in); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -274,9 +312,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
@@ -274,9 +312,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
"decoderawtransaction <hex string>\n" |
|
|
|
|
"Return a JSON object representing the serialized, hex-encoded transaction."); |
|
|
|
|
|
|
|
|
|
RPCTypeCheck(params, list_of(str_type)); |
|
|
|
|
|
|
|
|
|
vector<unsigned char> txData(ParseHex(params[0].get_str())); |
|
|
|
|
vector<unsigned char> txData(ParseHexV(params[0], "argument")); |
|
|
|
|
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
CTransaction tx; |
|
|
|
|
try { |
|
|
|
@ -296,7 +332,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
@@ -296,7 +332,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
{ |
|
|
|
|
if (fHelp || params.size() < 1 || params.size() > 4) |
|
|
|
|
throw runtime_error( |
|
|
|
|
"signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n" |
|
|
|
|
"signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n" |
|
|
|
|
"Sign inputs for raw transaction (serialized, hex-encoded).\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 block chain.\n" |
|
|
|
@ -311,7 +347,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
@@ -311,7 +347,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
|
|
|
|
|
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); |
|
|
|
|
|
|
|
|
|
vector<unsigned char> txData(ParseHex(params[0].get_str())); |
|
|
|
|
vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); |
|
|
|
|
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
vector<CTransaction> txVariants; |
|
|
|
|
while (!ssData.empty()) |
|
|
|
@ -352,6 +388,28 @@ Value signrawtransaction(const Array& params, bool fHelp)
@@ -352,6 +388,28 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool fGivenKeys = false; |
|
|
|
|
CBasicKeyStore tempKeystore; |
|
|
|
|
if (params.size() > 2 && params[2].type() != null_type) |
|
|
|
|
{ |
|
|
|
|
fGivenKeys = true; |
|
|
|
|
Array keys = params[2].get_array(); |
|
|
|
|
BOOST_FOREACH(Value k, keys) |
|
|
|
|
{ |
|
|
|
|
CBitcoinSecret vchSecret; |
|
|
|
|
bool fGood = vchSecret.SetString(k.get_str()); |
|
|
|
|
if (!fGood) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); |
|
|
|
|
CKey key; |
|
|
|
|
bool fCompressed; |
|
|
|
|
CSecret secret = vchSecret.GetSecret(fCompressed); |
|
|
|
|
key.SetSecret(secret, fCompressed); |
|
|
|
|
tempKeystore.AddKey(key); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
EnsureWalletIsUnlocked(); |
|
|
|
|
|
|
|
|
|
// Add previous txouts given in the RPC call:
|
|
|
|
|
if (params.size() > 1 && params[1].type() != null_type) |
|
|
|
|
{ |
|
|
|
@ -363,22 +421,15 @@ Value signrawtransaction(const Array& params, bool fHelp)
@@ -363,22 +421,15 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
|
|
|
|
|
Object prevOut = p.get_obj(); |
|
|
|
|
|
|
|
|
|
RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); |
|
|
|
|
RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type)); |
|
|
|
|
|
|
|
|
|
string txidHex = find_value(prevOut, "txid").get_str(); |
|
|
|
|
if (!IsHex(txidHex)) |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal"); |
|
|
|
|
uint256 txid; |
|
|
|
|
txid.SetHex(txidHex); |
|
|
|
|
uint256 txid = ParseHashO(prevOut, "txid"); |
|
|
|
|
|
|
|
|
|
int nOut = find_value(prevOut, "vout").get_int(); |
|
|
|
|
if (nOut < 0) |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); |
|
|
|
|
|
|
|
|
|
string pkHex = find_value(prevOut, "scriptPubKey").get_str(); |
|
|
|
|
if (!IsHex(pkHex)) |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal"); |
|
|
|
|
vector<unsigned char> pkData(ParseHex(pkHex)); |
|
|
|
|
vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); |
|
|
|
|
CScript scriptPubKey(pkData.begin(), pkData.end()); |
|
|
|
|
|
|
|
|
|
CCoins coins; |
|
|
|
@ -391,33 +442,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
@@ -391,33 +442,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
} |
|
|
|
|
// what todo if txid is known, but the actual output isn't?
|
|
|
|
|
} |
|
|
|
|
if ((unsigned int)nOut >= coins.vout.size()) |
|
|
|
|
coins.vout.resize(nOut+1); |
|
|
|
|
coins.vout[nOut].scriptPubKey = scriptPubKey; |
|
|
|
|
coins.vout[nOut].nValue = 0; // we don't know the actual output value
|
|
|
|
|
view.SetCoins(txid, coins); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool fGivenKeys = false; |
|
|
|
|
CBasicKeyStore tempKeystore; |
|
|
|
|
if (params.size() > 2 && params[2].type() != null_type) |
|
|
|
|
{ |
|
|
|
|
fGivenKeys = true; |
|
|
|
|
Array keys = params[2].get_array(); |
|
|
|
|
BOOST_FOREACH(Value k, keys) |
|
|
|
|
{ |
|
|
|
|
CBitcoinSecret vchSecret; |
|
|
|
|
bool fGood = vchSecret.SetString(k.get_str()); |
|
|
|
|
if (!fGood) |
|
|
|
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key"); |
|
|
|
|
CKey key; |
|
|
|
|
bool fCompressed; |
|
|
|
|
CSecret secret = vchSecret.GetSecret(fCompressed); |
|
|
|
|
key.SetSecret(secret, fCompressed); |
|
|
|
|
tempKeystore.AddKey(key); |
|
|
|
|
// if redeemScript given and not using the local wallet (private keys
|
|
|
|
|
// given), add redeemScript to the tempKeystore so it can be signed:
|
|
|
|
|
Value v = find_value(prevOut, "redeemScript"); |
|
|
|
|
if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null)) |
|
|
|
|
{ |
|
|
|
|
vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); |
|
|
|
|
CScript redeemScript(rsData.begin(), rsData.end()); |
|
|
|
|
tempKeystore.AddCScript(redeemScript); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
EnsureWalletIsUnlocked(); |
|
|
|
|
|
|
|
|
|
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); |
|
|
|
|
|
|
|
|
@ -484,10 +525,8 @@ Value sendrawtransaction(const Array& params, bool fHelp)
@@ -484,10 +525,8 @@ Value sendrawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
"sendrawtransaction <hex string>\n" |
|
|
|
|
"Submits raw transaction (serialized, hex-encoded) to local node and network."); |
|
|
|
|
|
|
|
|
|
RPCTypeCheck(params, list_of(str_type)); |
|
|
|
|
|
|
|
|
|
// parse hex string from parameter
|
|
|
|
|
vector<unsigned char> txData(ParseHex(params[0].get_str())); |
|
|
|
|
vector<unsigned char> txData(ParseHexV(params[0], "parameter")); |
|
|
|
|
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
CTransaction tx; |
|
|
|
|
|
|
|
|
|