|
|
|
@ -196,189 +196,6 @@ Value decoderawtransaction(const Array& params, bool fHelp)
@@ -196,189 +196,6 @@ Value decoderawtransaction(const Array& params, bool fHelp)
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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,\"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" |
|
|
|
|
"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 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()); |
|
|
|
|
|
|
|
|
|
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); |
|
|
|
|
|
|
|
|
|
vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); |
|
|
|
|
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
vector<CTransaction> txVariants; |
|
|
|
|
while (!ssData.empty()) |
|
|
|
|
{ |
|
|
|
|
try { |
|
|
|
|
CTransaction tx; |
|
|
|
|
ssData >> tx; |
|
|
|
|
txVariants.push_back(tx); |
|
|
|
|
} |
|
|
|
|
catch (std::exception &e) { |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (txVariants.empty()) |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); |
|
|
|
|
|
|
|
|
|
// mergedTx will end up with all the signatures; it
|
|
|
|
|
// starts as a clone of the rawtx:
|
|
|
|
|
CTransaction mergedTx(txVariants[0]); |
|
|
|
|
bool fComplete = true; |
|
|
|
|
|
|
|
|
|
// Fetch previous transactions (inputs):
|
|
|
|
|
CCoinsView viewDummy; |
|
|
|
|
CCoinsViewCache view(viewDummy); |
|
|
|
|
{ |
|
|
|
|
LOCK(mempool.cs); |
|
|
|
|
CCoinsViewCache &viewChain = *pcoinsTip; |
|
|
|
|
CCoinsViewMemPool viewMempool(viewChain, mempool); |
|
|
|
|
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { |
|
|
|
|
const uint256& prevHash = txin.prevout.hash; |
|
|
|
|
CCoins coins; |
|
|
|
|
view.GetCoins(prevHash, coins); // this is certainly allowed to fail
|
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
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 = vchSecret.GetKey(); |
|
|
|
|
tempKeystore.AddKey(key); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
EnsureWalletIsUnlocked(); |
|
|
|
|
|
|
|
|
|
// Add previous txouts given in the RPC call:
|
|
|
|
|
if (params.size() > 1 && params[1].type() != null_type) |
|
|
|
|
{ |
|
|
|
|
Array prevTxs = params[1].get_array(); |
|
|
|
|
BOOST_FOREACH(Value& p, prevTxs) |
|
|
|
|
{ |
|
|
|
|
if (p.type() != obj_type) |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); |
|
|
|
|
|
|
|
|
|
Object prevOut = p.get_obj(); |
|
|
|
|
|
|
|
|
|
RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); |
|
|
|
|
|
|
|
|
|
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"); |
|
|
|
|
|
|
|
|
|
vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); |
|
|
|
|
CScript scriptPubKey(pkData.begin(), pkData.end()); |
|
|
|
|
|
|
|
|
|
CCoins coins; |
|
|
|
|
/*
|
|
|
|
|
if (view.GetCoins(txid, coins)) { |
|
|
|
|
if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { |
|
|
|
|
string err("Previous output scriptPubKey mismatch:\n"); |
|
|
|
|
err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ |
|
|
|
|
scriptPubKey.ToString(); |
|
|
|
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); |
|
|
|
|
} |
|
|
|
|
// 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); |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
// if redeemScript given and not using the local wallet (private keys
|
|
|
|
|
// given), add redeemScript to the tempKeystore so it can be signed:
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); |
|
|
|
|
|
|
|
|
|
int nHashType = SIGHASH_ALL; |
|
|
|
|
if (params.size() > 3 && params[3].type() != null_type) |
|
|
|
|
{ |
|
|
|
|
static map<string, int> mapSigHashValues = |
|
|
|
|
boost::assign::map_list_of |
|
|
|
|
(string("ALL"), int(SIGHASH_ALL)) |
|
|
|
|
(string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) |
|
|
|
|
(string("NONE"), int(SIGHASH_NONE)) |
|
|
|
|
(string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) |
|
|
|
|
(string("SINGLE"), int(SIGHASH_SINGLE)) |
|
|
|
|
(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) |
|
|
|
|
; |
|
|
|
|
string strHashType = params[3].get_str(); |
|
|
|
|
if (mapSigHashValues.count(strHashType)) |
|
|
|
|
nHashType = mapSigHashValues[strHashType]; |
|
|
|
|
else |
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Sign what we can:
|
|
|
|
|
/* [MF]
|
|
|
|
|
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) |
|
|
|
|
{ |
|
|
|
|
CTxIn& txin = mergedTx.vin[i]; |
|
|
|
|
CCoins coins; |
|
|
|
|
if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) |
|
|
|
|
{ |
|
|
|
|
fComplete = false; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; |
|
|
|
|
|
|
|
|
|
txin.scriptSig.clear(); |
|
|
|
|
// 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) |
|
|
|
|
{ |
|
|
|
|
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); |
|
|
|
|
} |
|
|
|
|
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)) |
|
|
|
|
fComplete = false; |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
Object result; |
|
|
|
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
ssTx << mergedTx; |
|
|
|
|
result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end()))); |
|
|
|
|
result.push_back(Pair("complete", fComplete)); |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Value sendrawtransaction(const Array& params, bool fHelp) |
|
|
|
|
{ |
|
|
|
|
if (fHelp || params.size() < 1 || params.size() > 1) |
|
|
|
@ -431,7 +248,7 @@ Value sendnewusertransaction(const Array& params, bool fHelp)
@@ -431,7 +248,7 @@ Value sendnewusertransaction(const Array& params, bool fHelp)
|
|
|
|
|
throw runtime_error( |
|
|
|
|
"sendnewusertransaction <username>\n" |
|
|
|
|
"Send a transaction registering a previously created new user\n" |
|
|
|
|
"using createuserkey or imported to the wallet\n" |
|
|
|
|
"using createwalletuser or imported to the wallet\n" |
|
|
|
|
"Submits raw transaction (serialized, hex-encoded) to local node and network."); |
|
|
|
|
|
|
|
|
|
if (params[0].type() != str_type) |
|
|
|
|