|
|
|
@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime;
@@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime;
|
|
|
|
|
extern Value dumpprivkey(const Array& params, bool fHelp); |
|
|
|
|
extern Value importprivkey(const Array& params, bool fHelp); |
|
|
|
|
|
|
|
|
|
const Object emptyobj; |
|
|
|
|
|
|
|
|
|
Object JSONRPCError(int code, const string& message) |
|
|
|
|
{ |
|
|
|
|
Object error; |
|
|
|
@ -111,6 +113,33 @@ HexBits(unsigned int nBits)
@@ -111,6 +113,33 @@ HexBits(unsigned int nBits)
|
|
|
|
|
return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
enum DecomposeMode { |
|
|
|
|
DM_NONE = 0, |
|
|
|
|
DM_HASH, |
|
|
|
|
DM_HEX, |
|
|
|
|
DM_ASM, |
|
|
|
|
DM_OBJ, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
enum DecomposeMode |
|
|
|
|
FindDecompose(const Object& decompositions, const char* pcType, const char* pcDefault) |
|
|
|
|
{ |
|
|
|
|
Value val = find_value(decompositions, pcType); |
|
|
|
|
std::string strDecompose = (val.type() == null_type) ? pcDefault : val.get_str(); |
|
|
|
|
|
|
|
|
|
if (strDecompose == "no") |
|
|
|
|
return DM_NONE; |
|
|
|
|
if (strDecompose == "hash") |
|
|
|
|
return DM_HASH; |
|
|
|
|
if (strDecompose == "hex") |
|
|
|
|
return DM_HEX; |
|
|
|
|
if (strDecompose == "asm") |
|
|
|
|
return DM_ASM; |
|
|
|
|
if (strDecompose == "obj") |
|
|
|
|
return DM_OBJ; |
|
|
|
|
throw JSONRPCError(-18, "Invalid decomposition"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void WalletTxToJSON(const CWalletTx& wtx, Object& entry) |
|
|
|
|
{ |
|
|
|
|
int confirms = wtx.GetDepthInMainChain(); |
|
|
|
@ -126,11 +155,74 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
@@ -126,11 +155,74 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
|
|
|
|
|
entry.push_back(Pair(item.first, item.second)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TxToJSON(const CTransaction &tx, Object& entry) |
|
|
|
|
void |
|
|
|
|
ScriptSigToJSON(const CTxIn& txin, Object& out) |
|
|
|
|
{ |
|
|
|
|
out.push_back(Pair("asm", txin.scriptSig.ToString())); |
|
|
|
|
out.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); |
|
|
|
|
|
|
|
|
|
CTransaction txprev; |
|
|
|
|
uint256 hashTxprevBlock; |
|
|
|
|
if (!GetTransaction(txin.prevout.hash, txprev, hashTxprevBlock)) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
txnouttype type; |
|
|
|
|
vector<CBitcoinAddress> addresses; |
|
|
|
|
int nRequired; |
|
|
|
|
|
|
|
|
|
if (!ExtractAddresses(txprev.vout[txin.prevout.n].scriptPubKey, type, |
|
|
|
|
addresses, nRequired)) |
|
|
|
|
{ |
|
|
|
|
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD))); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
out.push_back(Pair("type", GetTxnOutputType(type))); |
|
|
|
|
if (type == TX_MULTISIG) |
|
|
|
|
{ |
|
|
|
|
// TODO: Need to handle this specially since not all input addresses are required...
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Array a; |
|
|
|
|
BOOST_FOREACH(const CBitcoinAddress& addr, addresses) |
|
|
|
|
a.push_back(addr.ToString()); |
|
|
|
|
out.push_back(Pair("addresses", a)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) |
|
|
|
|
{ |
|
|
|
|
txnouttype type; |
|
|
|
|
vector<CBitcoinAddress> addresses; |
|
|
|
|
int nRequired; |
|
|
|
|
|
|
|
|
|
out.push_back(Pair("asm", scriptPubKey.ToString())); |
|
|
|
|
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); |
|
|
|
|
|
|
|
|
|
if (!ExtractAddresses(scriptPubKey, type, addresses, nRequired)) |
|
|
|
|
{ |
|
|
|
|
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD))); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
out.push_back(Pair("reqSigs", nRequired)); |
|
|
|
|
out.push_back(Pair("type", GetTxnOutputType(type))); |
|
|
|
|
|
|
|
|
|
Array a; |
|
|
|
|
BOOST_FOREACH(const CBitcoinAddress& addr, addresses) |
|
|
|
|
a.push_back(addr.ToString()); |
|
|
|
|
out.push_back(Pair("addresses", a)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TxToJSON(const CTransaction &tx, Object& entry, const Object& decompositions) |
|
|
|
|
{ |
|
|
|
|
entry.push_back(Pair("version", tx.nVersion)); |
|
|
|
|
entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); |
|
|
|
|
entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); |
|
|
|
|
|
|
|
|
|
enum DecomposeMode decomposeScript = FindDecompose(decompositions, "script", "asm"); |
|
|
|
|
|
|
|
|
|
Array vin; |
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) |
|
|
|
|
{ |
|
|
|
@ -143,7 +235,25 @@ void TxToJSON(const CTransaction &tx, Object& entry)
@@ -143,7 +235,25 @@ void TxToJSON(const CTransaction &tx, Object& entry)
|
|
|
|
|
prevout.push_back(Pair("hash", txin.prevout.hash.GetHex())); |
|
|
|
|
prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n)); |
|
|
|
|
in.push_back(Pair("prevout", prevout)); |
|
|
|
|
switch (decomposeScript) { |
|
|
|
|
case DM_NONE: |
|
|
|
|
break; |
|
|
|
|
case DM_HEX: |
|
|
|
|
in.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); |
|
|
|
|
break; |
|
|
|
|
case DM_ASM: |
|
|
|
|
in.push_back(Pair("scriptSig", txin.scriptSig.ToString())); |
|
|
|
|
break; |
|
|
|
|
case DM_OBJ: |
|
|
|
|
{ |
|
|
|
|
Object o; |
|
|
|
|
ScriptSigToJSON(txin, o); |
|
|
|
|
in.push_back(Pair("scriptSig", o)); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
throw JSONRPCError(-18, "Invalid script decomposition"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); |
|
|
|
|
vin.push_back(in); |
|
|
|
@ -154,12 +264,32 @@ void TxToJSON(const CTransaction &tx, Object& entry)
@@ -154,12 +264,32 @@ void TxToJSON(const CTransaction &tx, Object& entry)
|
|
|
|
|
{ |
|
|
|
|
Object out; |
|
|
|
|
out.push_back(Pair("value", ValueFromAmount(txout.nValue))); |
|
|
|
|
switch (decomposeScript) { |
|
|
|
|
case DM_NONE: |
|
|
|
|
break; |
|
|
|
|
case DM_HEX: |
|
|
|
|
out.push_back(Pair("scriptPubKey", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end()))); |
|
|
|
|
break; |
|
|
|
|
case DM_ASM: |
|
|
|
|
out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString())); |
|
|
|
|
break; |
|
|
|
|
case DM_OBJ: |
|
|
|
|
{ |
|
|
|
|
Object o; |
|
|
|
|
ScriptPubKeyToJSON(txout.scriptPubKey, o); |
|
|
|
|
out.push_back(Pair("scriptPubKey", o)); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
throw JSONRPCError(-18, "Invalid script decomposition"); |
|
|
|
|
} |
|
|
|
|
vout.push_back(out); |
|
|
|
|
} |
|
|
|
|
entry.push_back(Pair("vout", vout)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions); |
|
|
|
|
|
|
|
|
|
string AccountFromValue(const Value& value) |
|
|
|
|
{ |
|
|
|
|
string strAccount = value.get_str(); |
|
|
|
@ -168,10 +298,13 @@ string AccountFromValue(const Value& value)
@@ -168,10 +298,13 @@ string AccountFromValue(const Value& value)
|
|
|
|
|
return strAccount; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) |
|
|
|
|
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions) |
|
|
|
|
{ |
|
|
|
|
Object result; |
|
|
|
|
result.push_back(Pair("hash", block.GetHash().GetHex())); |
|
|
|
|
CMerkleTx txGen(block.vtx[0]); |
|
|
|
|
txGen.SetMerkleBranch(&block); |
|
|
|
|
result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); |
|
|
|
|
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); |
|
|
|
|
result.push_back(Pair("height", blockindex->nHeight)); |
|
|
|
|
result.push_back(Pair("version", block.nVersion)); |
|
|
|
@ -180,10 +313,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
@@ -180,10 +313,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
|
|
|
|
|
result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); |
|
|
|
|
result.push_back(Pair("bits", HexBits(block.nBits))); |
|
|
|
|
result.push_back(Pair("difficulty", GetDifficulty(blockindex))); |
|
|
|
|
Array txhashes; |
|
|
|
|
|
|
|
|
|
enum DecomposeMode decomposeTxn = FindDecompose(decompositions, "tx", "hash"); |
|
|
|
|
if (decomposeTxn) |
|
|
|
|
{ |
|
|
|
|
Array txs; |
|
|
|
|
switch (decomposeTxn) { |
|
|
|
|
case DM_OBJ: |
|
|
|
|
BOOST_FOREACH (const CTransaction&tx, block.vtx) |
|
|
|
|
txhashes.push_back(tx.GetHash().GetHex()); |
|
|
|
|
result.push_back(Pair("tx", txhashes)); |
|
|
|
|
{ |
|
|
|
|
Object entry; |
|
|
|
|
AnyTxToJSON(tx.GetHash(), &tx, entry, decompositions); |
|
|
|
|
txs.push_back(entry); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case DM_HEX: |
|
|
|
|
BOOST_FOREACH (const CTransaction&tx, block.vtx) |
|
|
|
|
{ |
|
|
|
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
ssTx << tx; |
|
|
|
|
|
|
|
|
|
txs.push_back(HexStr(ssTx.begin(), ssTx.end())); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case DM_HASH: |
|
|
|
|
BOOST_FOREACH (const CTransaction&tx, block.vtx) |
|
|
|
|
txs.push_back(tx.GetHash().GetHex()); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
throw JSONRPCError(-18, "Invalid transaction decomposition"); |
|
|
|
|
} |
|
|
|
|
result.push_back(Pair("tx", txs)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (blockindex->pprev) |
|
|
|
|
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); |
|
|
|
@ -194,6 +355,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
@@ -194,6 +355,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
/// Note: This interface may still be subject to change.
|
|
|
|
|
///
|
|
|
|
@ -1498,23 +1660,14 @@ Value listsinceblock(const Array& params, bool fHelp)
@@ -1498,23 +1660,14 @@ Value listsinceblock(const Array& params, bool fHelp)
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Value gettransaction(const Array& params, bool fHelp) |
|
|
|
|
void |
|
|
|
|
AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions) |
|
|
|
|
{ |
|
|
|
|
if (fHelp || params.size() != 1) |
|
|
|
|
throw runtime_error( |
|
|
|
|
"gettransaction <txid>\n" |
|
|
|
|
"Get detailed information about <txid>"); |
|
|
|
|
|
|
|
|
|
uint256 hash; |
|
|
|
|
hash.SetHex(params[0].get_str()); |
|
|
|
|
|
|
|
|
|
Object entry; |
|
|
|
|
|
|
|
|
|
if (pwalletMain->mapWallet.count(hash)) |
|
|
|
|
{ |
|
|
|
|
const CWalletTx& wtx = pwalletMain->mapWallet[hash]; |
|
|
|
|
|
|
|
|
|
TxToJSON(wtx, entry); |
|
|
|
|
TxToJSON(wtx, entry, decompositions); |
|
|
|
|
|
|
|
|
|
int64 nCredit = wtx.GetCredit(); |
|
|
|
|
int64 nDebit = wtx.GetDebit(); |
|
|
|
@ -1535,10 +1688,12 @@ Value gettransaction(const Array& params, bool fHelp)
@@ -1535,10 +1688,12 @@ Value gettransaction(const Array& params, bool fHelp)
|
|
|
|
|
{ |
|
|
|
|
CTransaction tx; |
|
|
|
|
uint256 hashBlock = 0; |
|
|
|
|
if (GetTransaction(hash, tx, hashBlock)) |
|
|
|
|
if ((!ptx) && GetTransaction(hash, tx, hashBlock)) |
|
|
|
|
ptx = &tx; |
|
|
|
|
if (ptx) |
|
|
|
|
{ |
|
|
|
|
entry.push_back(Pair("txid", hash.GetHex())); |
|
|
|
|
TxToJSON(tx, entry); |
|
|
|
|
TxToJSON(*ptx, entry, decompositions); |
|
|
|
|
if (hashBlock == 0) |
|
|
|
|
entry.push_back(Pair("confirmations", 0)); |
|
|
|
|
else |
|
|
|
@ -1561,6 +1716,22 @@ Value gettransaction(const Array& params, bool fHelp)
@@ -1561,6 +1716,22 @@ Value gettransaction(const Array& params, bool fHelp)
|
|
|
|
|
else |
|
|
|
|
throw JSONRPCError(-5, "No information available about transaction"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Value gettransaction(const Array& params, bool fHelp) |
|
|
|
|
{ |
|
|
|
|
if (fHelp || params.size() < 1 || params.size() > 2) |
|
|
|
|
throw runtime_error( |
|
|
|
|
"gettransaction <txid> [decompositions]\n" |
|
|
|
|
"Get detailed information about <txid>"); |
|
|
|
|
|
|
|
|
|
uint256 hash; |
|
|
|
|
hash.SetHex(params[0].get_str()); |
|
|
|
|
|
|
|
|
|
Object entry; |
|
|
|
|
|
|
|
|
|
AnyTxToJSON(hash, NULL, entry, |
|
|
|
|
(params.size() > 1) ? params[1].get_obj() : emptyobj); |
|
|
|
|
|
|
|
|
|
return entry; |
|
|
|
|
} |
|
|
|
@ -2042,9 +2213,9 @@ Value getblockhash(const Array& params, bool fHelp)
@@ -2042,9 +2213,9 @@ Value getblockhash(const Array& params, bool fHelp)
|
|
|
|
|
|
|
|
|
|
Value getblock(const Array& params, bool fHelp) |
|
|
|
|
{ |
|
|
|
|
if (fHelp || params.size() != 1) |
|
|
|
|
if (fHelp || params.size() < 1 || params.size() > 2) |
|
|
|
|
throw runtime_error( |
|
|
|
|
"getblock <hash>\n" |
|
|
|
|
"getblock <hash> [decompositions]\n" |
|
|
|
|
"Returns details of a block with given block-hash."); |
|
|
|
|
|
|
|
|
|
std::string strHash = params[0].get_str(); |
|
|
|
@ -2057,7 +2228,8 @@ Value getblock(const Array& params, bool fHelp)
@@ -2057,7 +2228,8 @@ Value getblock(const Array& params, bool fHelp)
|
|
|
|
|
CBlockIndex* pblockindex = mapBlockIndex[hash]; |
|
|
|
|
block.ReadFromDisk(pblockindex, true); |
|
|
|
|
|
|
|
|
|
return blockToJSON(block, pblockindex); |
|
|
|
|
return blockToJSON(block, pblockindex, |
|
|
|
|
(params.size() > 1) ? params[1].get_obj() : emptyobj); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -2715,7 +2887,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
@@ -2715,7 +2887,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
|
|
|
|
|
if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|
|
|
|
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]); |
|
|
|
|
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|
|
|
|
if (strMethod == "getblock" && n > 1) ConvertTo<Object>(params[1]); |
|
|
|
|
if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|
|
|
|
if (strMethod == "gettransaction" && n > 1) ConvertTo<Object>(params[1]); |
|
|
|
|
if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]); |
|
|
|
|
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]); |
|
|
|
|
if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]); |
|
|
|
|