From 21fc1c5a746bd31c6dc62dc8d7734a75c24eae39 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 28 Oct 2014 16:30:12 -0700 Subject: [PATCH] implement WalletListTransactions. --- src/bitcoindjs.cc | 224 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 2 deletions(-) diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 8103619b..0de10aba 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -296,6 +296,21 @@ process_packets(CNode* pfrom); static bool process_packet(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived); +static void +AcentryToJSON_V8(const CAccountingEntry& acentry, + const string& strAccount, Local& ret, int a_count); + +static void +WalletTxToJSON_V8(const CWalletTx& wtx, Local& entry); + +static void +MaybePushAddress_V8(Local& entry, const CTxDestination &dest); + +static void +ListTransactions_V8(const CWalletTx& wtx, const string& strAccount, + int nMinDepth, bool fLong, Local ret, + const isminefilter& filter); + extern "C" void init(Handle); @@ -3124,9 +3139,214 @@ NAN_METHOD(WalletListTransactions) { "Usage: bitcoindjs.walletListTransactions(options)"); } - // Local options = Local::Cast(args[0]); + Local options = Local::Cast(args[0]); - NanReturnValue(Undefined()); + std::string strAccount = "*"; + if (options->Get(NanNew("account"))->IsString()) { + String::Utf8Value acc_(options->Get(NanNew("account"))->ToString()); + strAccount = std::string(*acc_); + } + + int nCount = 10; + if (options->Get(NanNew("count"))->IsNumber()) { + nCount = options->Get(NanNew("count"))->ToInt32(); + } + + int nFrom = 0; + if (options->Get(NanNew("from"))->IsNumber()) { + nFrom = options->Get(NanNew("from"))->ToInt32(); + } + + isminefilter filter = ISMINE_SPENDABLE; + if (options->Get(NanNew("spendable"))->IsBoolean()) { + if (options->Get(NanNew("spendable"))->ToBoolean->IsTrue()) { + filter = filter | ISMINE_WATCH_ONLY; + } + } + + if (nCount < 0) { + return NanThrowError("Negative count"); + } + + if (nFrom < 0) { + return NanThrowError("Negative from"); + } + + Local ret = NanNew(); + + std::list acentries; + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + + // iterate backwards until we have nCount items to return: + int a_count = 0; + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); + it != txOrdered.rend(); + ++it) { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx != 0) { + ListTransactions_V8(*pwtx, strAccount, 0, true, ret, filter); + } + CAccountingEntry *const pacentry = (*it).second.second; + if (pacentry != 0) { + AcentryToJSON_V8(*pacentry, strAccount, ret, a_count); + a_count++; + } + if ((int)ret->Length() >= (nCount+nFrom)) { + break; + } + } + // ret is newest to oldest + + if (nFrom > (int)ret->Length()) { + nFrom = ret->Length(); + } + if ((nFrom + nCount) > (int)ret->Length()) { + nCount = ret->Length() - nFrom; + } + + // Array::iterator first = ret.begin(); + // std::advance(first, nFrom); + // Array::iterator last = ret.begin(); + // std::advance(last, nFrom+nCount); + // + // if (last != ret.end()) { + // ret.erase(last, ret.end()); + // } + // if (first != ret.begin()) { + // ret.erase(ret.begin(), first); + // } + // + // std::reverse(ret.begin(), ret.end()); // Return oldest to newest + + NanReturnValue(ret); +} + +static void +AcentryToJSON_V8(const CAccountingEntry& acentry, + const string& strAccount, Local& ret, int a_count) { + bool fAllAccounts = (strAccount == string("*")); + + if (fAllAccounts || acentry.strAccount == strAccount) { + Local entry = NanNew(); + entry->Set(NanNew("account"), NanNew(acentry.strAccount)); + entry->Set(NanNew("category"), NanNew("move")); + entry->Set(NanNew("time"), NanNew(acentry.nTime)); + entry->Set(NanNew("amount"), NanNew(acentry.nCreditDebit)); + entry->Set(NanNew("otheraccount"), NanNew(acentry.strOtherAccount)); + entry->Set(NanNew("comment"), NanNew(acentry.strComment)); + ret->Set(a_count, entry); + } +} + +static void +WalletTxToJSON_V8(const CWalletTx& wtx, Local& entry) { + int confirms = wtx.GetDepthInMainChain(); + entry->Set(NanNew("confirmations"), NanNew(confirms)); + if (wtx.IsCoinBase()) { + entry->Set(NanNew("generated"), NanNew(true)); + } + if (confirms > 0) { + entry->Set(NanNew("blockhash"), NanNew(wtx.hashBlock.GetHex())); + entry->Set(NanNew("blockindex"), NanNew(wtx.nIndex)); + entry->Set(NanNew("blocktime"), NanNew(mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + } + uint256 hash = wtx.GetHash(); + entry->Set(NanNew("txid"), NanNew(hash.GetHex())); + Local conflicts = NanNew(); + int i = 0; + BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts()) { + conflicts->Set(i, NanNew(conflict.GetHex())); + i++; + } + entry->Set(NanNew("walletconflicts"), conflicts); + entry->Set(NanNew("time"), NanNew(wtx.GetTxTime())); + entry->Set(NanNew("timereceived"), NanNew((int64_t)wtx.nTimeReceived)); + BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) { + entry->Set(NanNew(item.first), NanNew(item.second)); + } +} + +static void +MaybePushAddress_V8(Local& entry, const CTxDestination &dest) { + CBitcoinAddress addr; + if (addr.Set(dest)) { + entry->Set(NanNew("address"), addr.ToString()); + } +} + +static void +ListTransactions_V8(const CWalletTx& wtx, const string& strAccount, + int nMinDepth, bool fLong, Local ret, + const isminefilter& filter) { + CAmount nFee; + string strSentAccount; + list listReceived; + list listSent; + + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); + + bool fAllAccounts = (strAccount == string("*")); + bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); + + int i = 0; + // Sent + if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { + BOOST_FOREACH(const COutputEntry& s, listSent) { + Local entry = NanNew(); + if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) { + entry->Set(NanNew("involvesWatchonly", NanNew(true))); + } + entry->Set(NanNew("account", NanNew(strSentAccount))); + MaybePushAddress_V8(entry, s.destination); + entry->Set(NanNew("category", NanNew("send"))); + entry->Set(NanNew("amount", NanNew(-s.amount))); + entry->Set(NanNew("vout", NanNew(s.vout))); + entry->Set(NanNew("fee", NanNew(-nFee))); + if (fLong) { + WalletTxToJSON_V8(wtx, entry); + } + ret->Set(i, entry); + i++; + } + } + + i = 0; + // Received + if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { + BOOST_FOREACH(const COutputEntry& r, listReceived) { + string account; + if (pwalletMain->mapAddressBook.count(r.destination)) { + account = pwalletMain->mapAddressBook[r.destination].name; + } + if (fAllAccounts || (account == strAccount)) { + Local entry = NanNew(); + if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) { + entry->Set(NanNew("involvesWatchonly"), NanNew(true)); + } + entry->Set(NanNew("account"), NanNew(account)); + MaybePushAddress_V8(entry, r.destination); + if (wtx.IsCoinBase()) { + if (wtx.GetDepthInMainChain() < 1) { + entry->Set(NanNew("category"), NanNew("orphan")); + } else if (wtx.GetBlocksToMaturity() > 0) { + entry->Set(NanNew("category"), NanNew("immature")); + } else { + entry->Set(NanNew("category"), NanNew("generate")); + } + } else { + entry->Set(NanNew("category"), NanNew("receive")); + } + entry->Set(NanNew("amount"), NanNew(r.amount)); + // XXX What is COutputEntry::vout? + // entry->Set(NanNew("vout"), NanNew(r.vout)); + if (fLong) { + WalletTxToJSON_V8(wtx, entry); + } + ret->Set(i, entry); + i++; + } + } + } } /**