From 16db9644c22b06f8f56f10e6bc4b3274c6827c62 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Wed, 10 Jun 2015 17:24:11 -0400 Subject: [PATCH] Removed the wallet methods (we should not need them, but they can easily be put back in later if need be). --- src/bitcoindjs.cc | 2947 +-------------------------------------------- 1 file changed, 10 insertions(+), 2937 deletions(-) diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 8563a47f..5ee37318 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -1,6 +1,6 @@ /** - * bitcoind.js - a binding for node.js which links to libbitcoind.so. - * Copyright (c) 2014, BitPay (MIT License) + * bitcoind.js - a binding for node.js which links to libbitcoind.so/dylib. + * Copyright (c) 2015, BitPay (MIT License) * * bitcoindjs.cc: * A bitcoind node.js binding. @@ -211,7 +211,6 @@ NAN_METHOD(GetTransaction); NAN_METHOD(BroadcastTx); NAN_METHOD(VerifyBlock); NAN_METHOD(VerifyTransaction); -NAN_METHOD(FillTransaction); NAN_METHOD(GetInfo); NAN_METHOD(GetPeerInfo); NAN_METHOD(GetAddresses); @@ -233,42 +232,6 @@ NAN_METHOD(BlockFromHex); NAN_METHOD(TxFromHex); NAN_METHOD(HookPackets); -NAN_METHOD(WalletNewAddress); -NAN_METHOD(WalletGetAccountAddress); -NAN_METHOD(WalletSetAccount); -NAN_METHOD(WalletGetAccount); -NAN_METHOD(WalletGetRecipients); -NAN_METHOD(WalletSetRecipient); -NAN_METHOD(WalletRemoveRecipient); -NAN_METHOD(WalletSendTo); -NAN_METHOD(WalletSignMessage); -NAN_METHOD(WalletVerifyMessage); -NAN_METHOD(WalletGetBalance); -NAN_METHOD(WalletCreateMultiSigAddress); -NAN_METHOD(WalletGetUnconfirmedBalance); -NAN_METHOD(WalletSendFrom); -NAN_METHOD(WalletMove); -NAN_METHOD(WalletListTransactions); -NAN_METHOD(WalletReceivedByAddress); -NAN_METHOD(WalletListAccounts); -NAN_METHOD(WalletGetTransaction); -NAN_METHOD(WalletBackup); -NAN_METHOD(WalletPassphrase); -NAN_METHOD(WalletPassphraseChange); -NAN_METHOD(WalletLock); -NAN_METHOD(WalletEncrypt); -NAN_METHOD(WalletEncrypted); -NAN_METHOD(WalletKeyPoolRefill); -NAN_METHOD(WalletSetTxFee); -NAN_METHOD(WalletDumpKey); -NAN_METHOD(WalletImportKey); -NAN_METHOD(WalletDumpWallet); -NAN_METHOD(WalletImportWallet); -NAN_METHOD(WalletChangeLabel); -NAN_METHOD(WalletDeleteAccount); -NAN_METHOD(WalletIsMine); -NAN_METHOD(WalletRescan); - /** * Node.js Internal Function Templates */ @@ -321,42 +284,6 @@ async_broadcast_tx(uv_work_t *req); static void async_broadcast_tx_after(uv_work_t *req); -static void -async_wallet_sendto(uv_work_t *req); - -static void -async_wallet_sendto_after(uv_work_t *req); - -static void -async_wallet_sendfrom(uv_work_t *req); - -static void -async_wallet_sendfrom_after(uv_work_t *req); - -static void -async_import_key(uv_work_t *req); - -static void -async_import_key_after(uv_work_t *req); - -static void -async_dump_wallet(uv_work_t *req); - -static void -async_dump_wallet_after(uv_work_t *req); - -static void -async_import_wallet(uv_work_t *req); - -static void -async_import_wallet_after(uv_work_t *req); - -static void -async_rescan(uv_work_t *req); - -static void -async_rescan_after(uv_work_t *req); - static void async_block_tx(uv_work_t *req); @@ -399,24 +326,6 @@ 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, int *a_count); - -static int64_t -SatoshiFromAmount(const CAmount& amount); - static int get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx); @@ -546,72 +455,6 @@ struct async_broadcast_tx_data { Eternal callback; }; -/** - * async_wallet_sendto_data - */ - -struct async_wallet_sendto_data { - std::string err_msg; - std::string txid; - std::string address; - int64_t nAmount; - CWalletTx wtx; - Eternal callback; -}; - -/** - * async_wallet_sendfrom_data - */ - -struct async_wallet_sendfrom_data { - std::string err_msg; - std::string txid; - std::string address; - int64_t nAmount; - int nMinDepth; - CWalletTx wtx; - Eternal callback; -}; - -/** - * async_import_key_data - */ - -struct async_import_key_data { - std::string err_msg; - bool fRescan; - Eternal callback; -}; - -/** - * async_import_wallet_data - */ - -struct async_import_wallet_data { - std::string err_msg; - std::string path; - Eternal callback; -}; - -/** - * async_dump_wallet_data - */ - -struct async_dump_wallet_data { - std::string err_msg; - std::string path; - Eternal callback; -}; - -/** - * async_rescan_data - */ - -struct async_rescan_data { - std::string err_msg; - Eternal callback; -}; - /** * async_from_tx_data */ @@ -798,7 +641,7 @@ start_node(void) { noui_connect(); - (boost::thread *)new boost::thread(boost::bind(&start_node_thread)); + new boost::thread(boost::bind(&start_node_thread)); // Wait for wallet to be instantiated. This also avoids // a race condition with signals not being set up. @@ -813,7 +656,7 @@ start_node(void) { signal(SIGQUIT, SIG_DFL); // Hook into packet handling - (boost::thread *)new boost::thread(boost::bind(&hook_packets)); + new boost::thread(boost::bind(&hook_packets)); return 0; } @@ -916,15 +759,13 @@ start_node_thread(void) { boost::bind(&DetectShutdownThread, &threadGroup)); fRet = AppInit2(threadGroup); } catch (std::exception& e) { - // if (set_cooked()) { - // fprintf(stderr, "bitcoind.js: AppInit(): std::exception\n"); - // } - ; + if (set_cooked()) { + fprintf(stderr, "bitcoind.js: AppInit(): std::exception\n"); + } } catch (...) { - // if (set_cooked()) { - // fprintf(stderr, "bitcoind.js: AppInit(): other exception\n"); - // } - ; + if (set_cooked()) { + fprintf(stderr, "bitcoind.js: AppInit(): other exception\n"); + } } if (!fRet) { @@ -1472,94 +1313,6 @@ NAN_METHOD(VerifyTransaction) { NanReturnValue(NanNew(valid && standard)); } -/** - * FillTransaction() - * bitcoindjs.fillTransaction(tx, options); - * This will fill a javascript transaction object with the proper available - * unpsent outputs as inputs and sign them using internal bitcoind functions. - */ - -NAN_METHOD(FillTransaction) { - NanScope(); - - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.fillTransaction(tx, options)"); - } - - Local jstx = Local::Cast(args[0]); - - String::Utf8Value tx_hex_(jstx->Get(NanNew("hex"))->ToString()); - std::string tx_hex = std::string(*tx_hex_); - - CMutableTransaction ctx; - jstx_to_ctx(jstx, (CTransaction &)ctx); - - // Get total value of outputs - // Get the scriptPubKey of the first output (presumably our destination) - int64_t nValue = 0; - for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) { - const CTxOut& txout = ctx.vout[vo]; - int64_t value = txout.nValue; - nValue += value; - } - - if (nValue <= 0) { - return NanThrowError("Invalid amount"); - } - - // With v0.9.0: - // if (nValue + nTransactionFee > pwalletMain->GetBalance()) - // if (nValue + payTxFee > pwalletMain->GetBalance()) - // return NanThrowError("Insufficient funds"); - if (nValue > pwalletMain->GetBalance()) { - return NanThrowError("Insufficient funds"); - } - - // With v0.9.0: - // int64_t nFeeRet = nTransactionFee; - int64_t nFeeRet = 1000; - // int64_t nFeeRet = CFeeRate(nAmount, 1000); - - if (pwalletMain->IsLocked()) { - return NanThrowError("Wallet locked, unable to create transaction!"); - } - - CCoinControl* coinControl = new CCoinControl(); - - int64_t nTotalValue = nValue + nFeeRet; - set > setCoins; - int64_t nValueIn = 0; - - if (!pwalletMain->SelectCoins(nTotalValue, setCoins, nValueIn, coinControl)) { - return NanThrowError("Insufficient funds"); - } - - // Fill vin - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*, unsigned int)& coin, setCoins) { - ctx.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); - } - - // Sign - int nIn = 0; - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) { - if (!SignSignature( - (const CKeyStore&)*pwalletMain, - (const CTransaction&)*coin.first, - (CMutableTransaction&)ctx, - nIn++ - )) { - return NanThrowError("Signing transaction failed"); - } - } - - // Turn our CTransaction into a javascript Transaction - Local new_jstx = NanNew(); - ctx_to_jstx(ctx, 0, new_jstx); - - NanReturnValue(new_jstx); -} - /** * GetInfo() * bitcoindjs.getInfo() @@ -3487,2645 +3240,6 @@ process_packet(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTim return true; } -/** - * WalletNewAddress() - * bitcoindjs.walletNewAddress(options) - * Create a new address in the global pwalletMain. - */ - -NAN_METHOD(WalletNewAddress) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletNewAddress(options)"); - } - - // Parse the account first so we don't generate a key if there's an error - Local options = Local::Cast(args[0]); - String::Utf8Value name_(options->Get(NanNew("name"))->ToString()); - std::string strAccount = std::string(*name_); - - if (!pwalletMain->IsLocked()) { - // XXX Do this asynchronously - pwalletMain->TopUpKeyPool(); - } - - // Generate a new key that is added to wallet - CPubKey newKey; - - if (!pwalletMain->GetKeyFromPool(newKey)) { - // return NanThrowError("Keypool ran out, please call keypoolrefill first"); - // Call to EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - return NanThrowError("Please enter the wallet passphrase with walletpassphrase first."); - } - // XXX Do this asynchronously - pwalletMain->TopUpKeyPool(100); - if (pwalletMain->GetKeyPoolSize() < 100) { - return NanThrowError("Error refreshing keypool."); - } - } - - CKeyID keyID = newKey.GetID(); - - pwalletMain->SetAddressBook(keyID, strAccount, "receive"); - - NanReturnValue(NanNew(CBitcoinAddress(keyID).ToString())); -} - -// NOTE: This function was ripped out of the bitcoin core source. It needed to -// be modified to fit v8's error handling. -CBitcoinAddress GetAccountAddress(std::string strAccount, bool bForceNew=false) { - CWalletDB walletdb(pwalletMain->strWalletFile); - - CAccount account; - walletdb.ReadAccount(strAccount, account); - - bool bKeyUsed = false; - - // Check if the current key has been used - if (account.vchPubKey.IsValid()) { - CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); - ++it) { - const CWalletTx& wtx = (*it).second; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if (txout.scriptPubKey == scriptPubKey) { - bKeyUsed = true; - } - } - } - } - - // Generate a new key - if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { - if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) { - NanThrowError("Keypool ran out, please call keypoolrefill first"); - CBitcoinAddress addr; - return addr; - } - pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); - walletdb.WriteAccount(strAccount, account); - } - - return CBitcoinAddress(account.vchPubKey.GetID()); -} - -/** - * WalletGetAccountAddress() - * bitcoindjs.walletGetAccountAddress(options) - * Return the address tied to a specific account name. - */ - -NAN_METHOD(WalletGetAccountAddress) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletGetAccountAddress(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strAccount = std::string(EMPTY); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - if (strAccount == EMPTY) { - return NanThrowError("No account name provided."); - } - - std::string ret = GetAccountAddress(strAccount).ToString(); - - NanReturnValue(NanNew(ret)); -} - -/** - * WalletSetAccount() - * bitcoindjs.walletSetAccount(options) - * Return a new address if the account does not exist, or tie an account to an - * address. - */ - -NAN_METHOD(WalletSetAccount) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletSetAccount(options)"); - } - - // Parse the account first so we don't generate a key if there's an error - Local options = Local::Cast(args[0]); - - std::string strAddress = std::string(""); - if (options->Get(NanNew("address"))->IsString()) { - String::Utf8Value address_(options->Get(NanNew("address"))->ToString()); - strAddress = std::string(*address_); - } - - CBitcoinAddress address; - if (strAddress != "") { - address = CBitcoinAddress(strAddress); - if (!address.IsValid()) { - return NanThrowError("Invalid Bitcoin address"); - } - } - - std::string strAccount = std::string(EMPTY); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - if (strAddress != "") { - // If it isn't our address, create a recipient: - { - CTxDestination dest = address.Get(); - if (!IsMine(*pwalletMain, dest)) { - pwalletMain->SetAddressBook(dest, strAccount, "send"); - pwalletMain->SetAddressBook(dest, strAccount, "send"); - NanReturnValue(Undefined(isolate)); - } - } - // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwalletMain->mapAddressBook.count(address.Get())) { - string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(strOldAccount)) { - GetAccountAddress(strOldAccount, true); - } - pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); - } - } else { - // Generate a new key that is added to wallet - CPubKey newKey; - - if (!pwalletMain->GetKeyFromPool(newKey)) { - // return NanThrowError("Keypool ran out, please call keypoolrefill first"); - // Call to EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - return NanThrowError("Please enter the wallet passphrase with walletpassphrase first."); - } - // XXX Do this asynchronously - pwalletMain->TopUpKeyPool(100); - if (pwalletMain->GetKeyPoolSize() < 100) { - return NanThrowError("Error refreshing keypool."); - } - } - - CKeyID keyID = newKey.GetID(); - - pwalletMain->SetAddressBook(keyID, strAccount, "receive"); - } - - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletGetAccount() - * bitcoindjs.walletGetAccount(options) - * Get an account name based on address. - */ - -NAN_METHOD(WalletGetAccount) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletGetAccount(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value address_(options->Get(NanNew("address"))->ToString()); - std::string strAddress = std::string(*address_); - - CBitcoinAddress address(strAddress); - if (!address.IsValid()) { - return NanThrowError("Invalid Bitcoin address"); - } - - std::string strAccount; - map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); - if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) { - strAccount = (*mi).second.name; - } - - NanReturnValue(NanNew(strAccount)); -} - -/** - * WalletGetRecipients() - * bitcoindjs.walletGetRecipients() - * Get all recipients - */ - -NAN_METHOD(WalletGetRecipients) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletGetRecipients(options)"); - } - - Local options = Local::Cast(args[0]); - - Local array = NanNew(); - int i = 0; - - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (item.second.purpose == "send" && address.IsValid()) { - Local recipient = NanNew(); - recipient->Set(NanNew("label"), NanNew(strName)); - recipient->Set(NanNew("account"), NanNew(strName)); - recipient->Set(NanNew("name"), NanNew(strName)); - recipient->Set(NanNew("address"), NanNew(address.ToString())); - array->Set(i, recipient); - i++; - if (options->Get(NanNew("_label"))->IsString()) { - break; - } - } - } - - if (options->Get(NanNew("_label"))->IsString()) { - NanReturnValue(array->Get(0)); - } - - NanReturnValue(array); -} - -/** - * WalletSetRecipient() - * bitcoindjs.walletSetRecipient() - * Set a recipient - */ - -NAN_METHOD(WalletSetRecipient) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletSetRecipient(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - - std::string strAccount = std::string(EMPTY); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - if (strAccount == EMPTY) { - return NanThrowError("No account name provided."); - } - - CTxDestination address = CBitcoinAddress(addr).Get(); - pwalletMain->SetAddressBook(address, strAccount, "send"); - pwalletMain->SetAddressBook(address, strAccount, "send"); - - NanReturnValue(True(isolate)); -} - -/** - * WalletRemoveRecipient() - * bitcoindjs.walletRemoveRecipient() - * Remove a recipient - */ - -NAN_METHOD(WalletRemoveRecipient) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletRemoveRecipient(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - - CTxDestination address = CBitcoinAddress(addr).Get(); - - pwalletMain->DelAddressBook(address); - - NanReturnValue(True(isolate)); -} - -/** - * WalletSendTo() - * bitcoindjs.walletSendTo(options, callback) - * Send bitcoin to an address, automatically creating the transaction based on - * availing unspent outputs. - */ - -NAN_METHOD(WalletSendTo) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.walletSendTo(options, callback)"); - } - - Local options = Local::Cast(args[0]); - Local callback = Local::Cast(args[1]); - - async_wallet_sendto_data *data = new async_wallet_sendto_data(); - - data->err_msg = std::string(""); - Eternal eternal(isolate, callback); - data->callback = eternal; - - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - data->address = addr; - - // Amount - int64_t nAmount = options->Get(NanNew("amount"))->IntegerValue(); - data->nAmount = nAmount; - - // Wallet comments - CWalletTx wtx; - if (options->Get(NanNew("comment"))->IsString()) { - String::Utf8Value comment_(options->Get(NanNew("comment"))->ToString()); - std::string comment = std::string(*comment_); - wtx.mapValue["comment"] = comment; - } - if (options->Get(NanNew("to"))->IsString()) { - String::Utf8Value to_(options->Get(NanNew("to"))->ToString()); - std::string to = std::string(*to_); - wtx.mapValue["to"] = to; - } - data->wtx = wtx; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_wallet_sendto, - (uv_after_work_cb)async_wallet_sendto_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_wallet_sendto(uv_work_t *req) { - async_wallet_sendto_data* data = static_cast(req->data); - - CBitcoinAddress address(data->address); - - if (!address.IsValid()) { - data->err_msg = std::string("Invalid Bitcoin address"); - return; - } - - // Wallet Transaction - CWalletTx wtx = data->wtx; - - // Call to EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first."); - return; - } - - data->txid = wtx.GetHash().GetHex(); -} - -static void -async_wallet_sendto_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - async_wallet_sendto_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, NanNew(data->txid)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * WalletSendFrom() - * bitcoindjs.walletSendFrom(options, callback) - * Send bitcoin to a particular address from a particular owned account name. - * This once again automatically creates and signs a transaction based on any - * unspent outputs available. - */ - -NAN_METHOD(WalletSendFrom) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.walletSendFrom(options, callback)"); - } - - Local options = Local::Cast(args[0]); - Local callback = Local::Cast(args[1]); - - async_wallet_sendfrom_data *data = new async_wallet_sendfrom_data(); - - data->err_msg = std::string(""); - Eternal eternal(isolate, callback); - data->callback = eternal; - - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - data->address = addr; - - String::Utf8Value from_(options->Get(NanNew("from"))->ToString()); - std::string from = std::string(*from_); - std::string strAccount = from; - - int64_t nAmount = options->Get(NanNew("amount"))->IntegerValue(); - data->nAmount = nAmount; - - int nMinDepth = 1; - if (options->Get(NanNew("confirmations"))->IsNumber()) { - nMinDepth = options->Get(NanNew("confirmations"))->IntegerValue(); - } - data->nMinDepth = nMinDepth; - - CWalletTx wtx; - wtx.strFromAccount = strAccount; - if (options->Get(NanNew("comment"))->IsString()) { - String::Utf8Value comment_(options->Get(NanNew("comment"))->ToString()); - std::string comment = std::string(*comment_); - wtx.mapValue["comment"] = comment; - } - if (options->Get(NanNew("to"))->IsString()) { - String::Utf8Value to_(options->Get(NanNew("to"))->ToString()); - std::string to = std::string(*to_); - wtx.mapValue["to"] = to; - } - data->wtx = wtx; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_wallet_sendfrom, - (uv_after_work_cb)async_wallet_sendfrom_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_wallet_sendfrom(uv_work_t *req) { - async_wallet_sendfrom_data* data = static_cast(req->data); - - CBitcoinAddress address(data->address); - - if (!address.IsValid()) { - data->err_msg = std::string("Invalid Bitcoin address"); - return; - } - - int64_t nAmount = data->nAmount; - int nMinDepth = data->nMinDepth; - CWalletTx wtx = data->wtx; - std::string strAccount = data->wtx.strFromAccount; - - // Call to: EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first."); - return; - } - - // Check funds - double nBalance = (double)GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); - if (((double)(nAmount * 1.0) / 100000000) > nBalance) { - data->err_msg = std::string("Account has insufficient funds"); - return; - } - - data->txid = wtx.GetHash().GetHex(); -} - -static void -async_wallet_sendfrom_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_wallet_sendfrom_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, NanNew(data->txid)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * WalletMove() - * bitcoindjs.walletMove(options) - * Move BTC from one account to another - */ - -NAN_METHOD(WalletMove) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletMove(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strFrom; - if (options->Get(NanNew("from"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("from"))->ToString()); - strFrom = std::string(*s_); - } - - std::string strTo; - if (options->Get(NanNew("to"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("to"))->ToString()); - strTo = std::string(*s_); - } - - CAmount nAmount; - if (options->Get(NanNew("amount"))->IsNumber()) { - nAmount = (CAmount)options->Get(NanNew("amount"))->IntegerValue(); - } else { - return NanThrowError("No amount specified."); - } - - // DEPRECATED - // int nMinDepth = 1; - // if (options->Get(NanNew("confirmations"))->IsNumber()) { - // nMinDepth = options->Get(NanNew("confirmations"))->IntegerValue(); - // } - - std::string strComment; - if (options->Get(NanNew("comment"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("comment"))->ToString()); - strComment = std::string(*s_); - } - - CWalletDB walletdb(pwalletMain->strWalletFile); - if (!walletdb.TxnBegin()) { - return NanThrowError("database error"); - } - - int64_t nNow = GetAdjustedTime(); - - // Debit - CAccountingEntry debit; - debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); - debit.strAccount = strFrom; - debit.nCreditDebit = -nAmount; - debit.nTime = nNow; - debit.strOtherAccount = strTo; - debit.strComment = strComment; - walletdb.WriteAccountingEntry(debit); - - // Credit - CAccountingEntry credit; - credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); - credit.strAccount = strTo; - credit.nCreditDebit = nAmount; - credit.nTime = nNow; - credit.strOtherAccount = strFrom; - credit.strComment = strComment; - walletdb.WriteAccountingEntry(credit); - - if (!walletdb.TxnCommit()) { - return NanThrowError("database error"); - } - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletSignMessage() - * bitcoindjs.walletSignMessage(options) - * Sign any piece of text using a private key tied to an address. - */ - -NAN_METHOD(WalletSignMessage) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletSignMessage(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value strAddress_(options->Get(NanNew("address"))->ToString()); - std::string strAddress = std::string(*strAddress_); - String::Utf8Value strMessage_(options->Get(NanNew("message"))->ToString()); - std::string strMessage = std::string(*strMessage_); - - // Call to EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - return NanThrowError("Please enter the wallet passphrase with walletpassphrase first."); - } - - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) { - return NanThrowError("Invalid address"); - } - - CKeyID keyID; - if (!addr.GetKeyID(keyID)) { - return NanThrowError("Address does not refer to key"); - } - - CKey key; - if (!pwalletMain->GetKey(keyID, key)) { - return NanThrowError("Private key not available"); - } - - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - vector vchSig; - if (!key.SignCompact(ss.GetHash(), vchSig)) { - return NanThrowError("Sign failed"); - } - - std::string result = EncodeBase64(&vchSig[0], vchSig.size()); - - NanReturnValue(NanNew(result)); -} - -/** - * WalletVerifyMessage() - * bitcoindjs.walletVerifyMessage(options) - * Verify a signed message using any address' public key. - */ - -NAN_METHOD(WalletVerifyMessage) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletVerifyMessage(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value strAddress_(options->Get(NanNew("address"))->ToString()); - std::string strAddress = std::string(*strAddress_); - - String::Utf8Value strSign_(options->Get(NanNew("signature"))->ToString()); - std::string strSign = std::string(*strSign_); - - String::Utf8Value strMessage_(options->Get(NanNew("message"))->ToString()); - std::string strMessage = std::string(*strMessage_); - - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) { - return NanThrowError( "Invalid address"); - } - - CKeyID keyID; - if (!addr.GetKeyID(keyID)) { - return NanThrowError( "Address does not refer to key"); - } - - bool fInvalid = false; - vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); - - if (fInvalid) { - return NanThrowError( "Malformed base64 encoding"); - } - - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - CPubKey pubkey; - if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) { - NanReturnValue(NanNew(false)); - } - - NanReturnValue(NanNew(pubkey.GetID() == keyID)); -} - -/** - * WalletCreateMultiSigAddress() - * bitcoindjs.walletCreateMultiSigAddress(options) - * Create a multisig address for the global wallet. - */ - -CScript _createmultisig_redeemScript(int nRequired, Local keys) { - // Gather public keys - if (nRequired < 1) { - throw runtime_error("a multisignature address must require at least one key to redeem"); - } - if ((int)keys->Length() < nRequired) { - NanThrowError("not enough keys supplied"); - CScript s; - return s; - } - std::vector pubkeys; - pubkeys.resize(keys->Length()); - for (unsigned int i = 0; i < keys->Length(); i++) { - String::Utf8Value key_(keys->Get(i)->ToString()); - const std::string& ks = std::string(*key_); -#ifdef ENABLE_WALLET - // Case 1: Bitcoin address and we have full public key: - CBitcoinAddress address(ks); - if (pwalletMain && address.IsValid()) { - CKeyID keyID; - if (!address.GetKeyID(keyID)) { - NanThrowError("does not refer to a key"); - CScript s; - return s; - } - CPubKey vchPubKey; - if (!pwalletMain->GetPubKey(keyID, vchPubKey)) { - NanThrowError("no full public key for address"); - CScript s; - return s; - } - if (!vchPubKey.IsFullyValid()) { - NanThrowError("Invalid public key"); - CScript s; - return s; - } - pubkeys[i] = vchPubKey; - } - - // Case 2: hex public key - else -#endif - if (IsHex(ks)) { - CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsFullyValid()) { - NanThrowError("Invalid public key"); - CScript s; - return s; - } - pubkeys[i] = vchPubKey; - } else { - NanThrowError("Invalid public key"); - CScript s; - return s; - } - } - CScript result = GetScriptForMultisig(nRequired, pubkeys); - - if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) { - NanThrowError("redeemScript exceeds size limit"); - CScript s; - return s; - } - - return result; -} - -NAN_METHOD(WalletCreateMultiSigAddress) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletCreateMultiSigAddress(options)"); - } - - Local options = Local::Cast(args[0]); - - int nRequired = options->Get(NanNew("nRequired"))->IntegerValue(); - Local keys = Local::Cast(options->Get(NanNew("keys"))); - - // Gather public keys - if (nRequired < 1) { - return NanThrowError( - "a multisignature address must require at least one key to redeem"); - } - if ((int)keys->Length() < nRequired) { - char s[150] = {0}; - snprintf(s, sizeof(s), - "not enough keys supplied (got %u keys, but need at least %u to redeem)", - keys->Length(), nRequired); - NanThrowError(s); - NanReturnValue(Undefined(isolate)); - } - - std::string strAccount = ""; - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - // Construct using pay-to-script-hash: - CScript inner = _createmultisig_redeemScript(nRequired, keys); - - CScriptID innerID(inner); - pwalletMain->AddCScript(inner); - pwalletMain->SetAddressBook(innerID, strAccount, "send"); - - CBitcoinAddress address(innerID); - - Local result = NanNew(); - result->Set(NanNew("address"), NanNew(address.ToString())); - result->Set(NanNew("redeemScript"), NanNew(HexStr(inner.begin(), inner.end()))); - - NanReturnValue(result); -} - -/** - * WalletGetBalance() - * bitcoindjs.walletGetBalance(options) - * Get total balance of global wallet in satoshies in a javascript Number (up - * to 64 bits, only 32 if bitwise ops or floating point are used unfortunately. - * Obviously floating point is not necessary for satoshies). - */ - -NAN_METHOD(WalletGetBalance) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletGetBalance(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strAccount = "*"; - int nMinDepth = 1; - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("confirmations"))->IsNumber()) { - nMinDepth = options->Get(NanNew("confirmations"))->IntegerValue(); - } - - isminefilter filter = ISMINE_SPENDABLE; - - if (strAccount == "*") { - // Calculate total balance a different way from GetBalance() - // (GetBalance() sums up all unspent TxOuts) - // getbalance and getbalance '*' 0 should return the same number - CAmount nBalance = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end(); - ++it) { - const CWalletTx& wtx = (*it).second; - if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0) { - continue; - } - - CAmount allFee; - string strSentAccount; - list listReceived; - list listSent; - wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); - if (wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH(const COutputEntry& r, listReceived) { - nBalance += r.amount; - } - } - BOOST_FOREACH(const COutputEntry& s, listSent) { - nBalance -= s.amount; - } - nBalance -= allFee; - } - - NanReturnValue(NanNew(SatoshiFromAmount(nBalance))); - } - - CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter); - NanReturnValue(NanNew(SatoshiFromAmount(nBalance))); -} - -/** - * WalletGetUnconfirmedBalance() - * bitcoindjs.walletGetUnconfirmedBalance(options) - * Returns the unconfirmed balance in satoshies (including the transactions - * that have not yet been included in any block). - */ - -NAN_METHOD(WalletGetUnconfirmedBalance) { - NanScope(); - NanReturnValue(NanNew(pwalletMain->GetUnconfirmedBalance())); -} - -/** - * WalletListTransactions() - * bitcoindjs.walletListTransactions(options) - * List all transactions pertaining to any owned addreses. NOT YET IMPLEMENTED> - */ - -NAN_METHOD(WalletListTransactions) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletListTransactions(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strAccount = "*"; - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - int nCount = 10; - if (options->Get(NanNew("count"))->IsNumber()) { - nCount = (int)options->Get(NanNew("count"))->IntegerValue(); - } - - int nFrom = 0; - if (options->Get(NanNew("from"))->IsNumber()) { - nFrom = (int)options->Get(NanNew("from"))->IntegerValue(); - } - - 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, &a_count); - } - CAccountingEntry *const pacentry = (*it).second.second; - if (pacentry != 0) { - AcentryToJSON_V8(*pacentry, strAccount, ret, &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; - } - - NanReturnValue(ret); -} - -static void -AcentryToJSON_V8(const CAccountingEntry& acentry, - const string& strAccount, Local& ret, int *a_count) { - bool fAllAccounts = (strAccount == string("*")); - - int i = *a_count; - 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(i, entry); - i++; - } - *a_count = i; -} - -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)); - } - - std::string strHex = EncodeHexTx(static_cast(wtx)); - entry->Set(NanNew("hex"), NanNew(strHex)); -} - -static void -MaybePushAddress_V8(Local& entry, const CTxDestination &dest) { - CBitcoinAddress addr; - if (addr.Set(dest)) { - entry->Set(NanNew("address"), NanNew(addr.ToString())); - } -} - -static void -ListTransactions_V8(const CWalletTx& wtx, const string& strAccount, - int nMinDepth, bool fLong, Local ret, - const isminefilter& filter, int *a_count) { - 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 = *a_count; - // 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); - } else { - std::string strHex = EncodeHexTx(static_cast(wtx)); - entry->Set(NanNew("hex"), NanNew(strHex)); - } - ret->Set(i, entry); - i++; - } - } - - // 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); - } else { - std::string strHex = EncodeHexTx(static_cast(wtx)); - entry->Set(NanNew("hex"), NanNew(strHex)); - } - ret->Set(i, entry); - i++; - } - } - } - - *a_count = i; -} - -/** - * WalletReceivedByAddress() - * bitcoindjs.walletReceivedByAddress(options) - * List all transactions pertaining to any owned addreses. NOT YET IMPLEMENTED> - */ - -NAN_METHOD(WalletReceivedByAddress) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletReceivedByAddress(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - - // Bitcoin address - CBitcoinAddress address = CBitcoinAddress(addr); - if (!address.IsValid()) { - return NanThrowError("Invalid Bitcoin address"); - } - CScript scriptPubKey = GetScriptForDestination(address.Get()); - - if (!IsMine(*pwalletMain, scriptPubKey)) { - NanReturnValue(NanNew((double)0.0)); - } - - // Minimum confirmations - int nMinDepth = 1; - if (options->Get(NanNew("confirmations"))->IsNumber()) { - nMinDepth = (int)options->Get(NanNew("confirmations"))->IntegerValue(); - } - - // Tally - CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end(); - ++it) { - const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !IsFinalTx(wtx)) { - continue; - } - BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if (txout.scriptPubKey == scriptPubKey) { - if (wtx.GetDepthInMainChain() >= nMinDepth) { - nAmount += txout.nValue; - } - } - } - } - - NanReturnValue(NanNew((int64_t)nAmount)); -} - -/** - * WalletListAccounts() - * bitcoindjs.walletListAccounts(options) - * This will list all accounts, addresses, balanced, private keys, public keys, - * and whether these keys are in compressed format. - */ - -NAN_METHOD(WalletListAccounts) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletListAccounts(options)"); - } - - Local options = Local::Cast(args[0]); - - int nMinDepth = 1; - if (options->Get(NanNew("confirmations"))->IsNumber()) { - nMinDepth = options->Get(NanNew("confirmations"))->IntegerValue(); - } - - isminefilter includeWatchonly = ISMINE_SPENDABLE; - - map mapAccountBalances; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) { - if (IsMine(*pwalletMain, entry.first) & includeWatchonly) { // This address belongs to me - mapAccountBalances[entry.second.name] = 0; - } - } - - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - CAmount nFee; - std::string strSentAccount; - list listReceived; - list listSent; - int nDepth = wtx.GetDepthInMainChain(); - if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) { - continue; - } - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); - mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH(const COutputEntry& s, listSent) { - mapAccountBalances[strSentAccount] -= s.amount; - } - if (nDepth >= nMinDepth) { - BOOST_FOREACH(const COutputEntry& r, listReceived) { - if (pwalletMain->mapAddressBook.count(r.destination)) { - mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; - } else { - mapAccountBalances[""] += r.amount; - } - } - } - } - - list acentries; - CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); - BOOST_FOREACH(const CAccountingEntry& entry, acentries) { - mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - } - - Local obj = NanNew(); - BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) { - Local entry = NanNew(); - entry->Set(NanNew("balance"), NanNew(accountBalance.second)); - Local addr = NanNew(); - int i = 0; - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const std::string& strName = item.second.name; - if (strName == accountBalance.first && item.second.purpose != "send") { - Local a = NanNew(); - a->Set(NanNew("address"), NanNew(address.ToString())); - - CKeyID keyID; - if (!address.GetKeyID(keyID)) { - return NanThrowError("Address does not refer to a key"); - } - CKey vchSecret; - if (!pwalletMain->GetKey(keyID, vchSecret)) { - return NanThrowError("Private key for address is not known"); - } - - if (!pwalletMain->IsLocked()) { - std::string priv = CBitcoinSecret(vchSecret).ToString(); - a->Set(NanNew("privkeycompressed"), NanNew(vchSecret.IsCompressed())); - a->Set(NanNew("privkey"), NanNew(priv)); - } - - CPubKey vchPubKey; - pwalletMain->GetPubKey(keyID, vchPubKey); - a->Set(NanNew("pubkeycompressed"), NanNew(vchPubKey.IsCompressed())); - a->Set(NanNew("pubkey"), NanNew(HexStr(vchPubKey))); - - addr->Set(i, a); - i++; - } - } - entry->Set(NanNew("addresses"), addr); - entry->Set(NanNew("account"), NanNew(accountBalance.first)); - entry->Set(NanNew("name"), NanNew(accountBalance.first)); - entry->Set(NanNew("label"), NanNew(accountBalance.first)); - obj->Set(NanNew(accountBalance.first), entry); - } - - NanReturnValue(obj); -} - -/** - * WalletGetTransaction() - * bitcoindjs.walletGetTransaction(options) - * Get any transaction pertaining to any owned addresses. - */ - -NAN_METHOD(WalletGetTransaction) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletGetTransaction(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string txid; - if (options->Get(NanNew("txid"))->IsString()) { - String::Utf8Value txid_(options->Get(NanNew("txid"))->ToString()); - txid = std::string(*txid_); - } else { - return NanThrowError("txid not specified."); - } - - uint256 hash; - hash.SetHex(txid); - - isminefilter filter = ISMINE_SPENDABLE; - if (options->Get(NanNew("watch"))->IsBoolean() - && options->Get(NanNew("watch"))->ToBoolean()->IsTrue()) { - filter = filter | ISMINE_WATCH_ONLY; - } - - Local entry = NanNew(); - if (!pwalletMain->mapWallet.count(hash)) { - return NanThrowError("Invalid or non-wallet transaction id"); - } - - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - - CAmount nCredit = wtx.GetCredit(filter != 0); - CAmount nDebit = wtx.GetDebit(filter); - CAmount nNet = nCredit - nDebit; - CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0); - - entry->Set(NanNew("amount"), - NanNew(SatoshiFromAmount(nNet - nFee))); - - if (wtx.IsFromMe(filter)) { - entry->Set(NanNew("fee"), NanNew(SatoshiFromAmount(nFee))); - } - - WalletTxToJSON_V8(wtx, entry); - - Local details = NanNew(); - int a_count = 0; - // NOTE: fLong is set to false in rpcwallet.cpp - ListTransactions_V8(wtx, "*", 0, /*fLong=*/ true, details, filter, &a_count); - entry->Set(NanNew("details"), details); - - //std::string strHex = EncodeHexTx(static_cast(wtx)); - //entry->Set(NanNew("hex"), NanNew(strHex)); - - NanReturnValue(entry); -} - -/** - * WalletBackup() - * bitcoindjs.walletBackup(options) - * Backup the bdb wallet.dat to a particular location on filesystem. - */ - -NAN_METHOD(WalletBackup) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletBackup(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value path_(options->Get(NanNew("path"))->ToString()); - std::string strDest = std::string(*path_); - - if (!BackupWallet(*pwalletMain, strDest)) { - return NanThrowError("Wallet backup failed!"); - } - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletPassphrase() - * bitcoindjs.walletPassphrase(options) - * Unlock wallet if encrypted already. - */ - -NAN_METHOD(WalletPassphrase) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletPassphrase(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value passphrase_(options->Get(NanNew("passphrase"))->ToString()); - std::string strPassphrase = std::string(*passphrase_); - - if (!pwalletMain->IsCrypted()) { - return NanThrowError("Running with an unencrypted wallet, but walletpassphrase was called."); - } - - SecureString strWalletPass; - strWalletPass.reserve(100); - strWalletPass = strPassphrase.c_str(); - - if (strWalletPass.length() > 0) { - if (!pwalletMain->Unlock(strWalletPass)) { - return NanThrowError("The wallet passphrase entered was incorrect."); - } - } else { - return NanThrowError("No wallet passphrase provided."); - } - - // XXX Do this asynchronously - pwalletMain->TopUpKeyPool(); - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletPassphraseChange() - * bitcoindjs.walletPassphraseChange(options) - * Change the current passphrase for the encrypted wallet. - */ - -NAN_METHOD(WalletPassphraseChange) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletPassphraseChange(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value oldPass_(options->Get(NanNew("oldPass"))->ToString()); - std::string oldPass = std::string(*oldPass_); - - String::Utf8Value newPass_(options->Get(NanNew("newPass"))->ToString()); - std::string newPass = std::string(*newPass_); - - if (!pwalletMain->IsCrypted()) { - return NanThrowError("Running with an unencrypted wallet, but walletpassphrasechange was called."); - } - - SecureString strOldWalletPass; - strOldWalletPass.reserve(100); - strOldWalletPass = oldPass.c_str(); - - SecureString strNewWalletPass; - strNewWalletPass.reserve(100); - strNewWalletPass = newPass.c_str(); - - if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) { - return NanThrowError("Passphrases not provided."); - } - - if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) { - return NanThrowError("The wallet passphrase entered was incorrect."); - } - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletLock() - * bitcoindjs.walletLock(options) - * Forget the encrypted wallet passphrase and lock the wallet once again. - */ - -NAN_METHOD(WalletLock) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 0) { - return NanThrowError( - "Usage: bitcoindjs.walletLock([options])"); - } - - if (!pwalletMain->IsCrypted()) { - return NanThrowError("Running with an unencrypted wallet, but walletlock was called."); - } - - pwalletMain->Lock(); - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletEncrypt() - * bitcoindjs.walletEncrypt(options) - * Encrypt the global wallet with a particular passphrase. Requires restarted - * because Berkeley DB is bad. - */ - -NAN_METHOD(WalletEncrypt) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletEncrypt(options)"); - } - - Local options = Local::Cast(args[0]); - - String::Utf8Value passphrase_(options->Get(NanNew("passphrase"))->ToString()); - std::string strPass = std::string(*passphrase_); - - if (pwalletMain->IsCrypted()) { - return NanThrowError("Running with an encrypted wallet, but encryptwallet was called."); - } - - SecureString strWalletPass; - strWalletPass.reserve(100); - strWalletPass = strPass.c_str(); - - if (strWalletPass.length() < 1) { - return NanThrowError("No wallet passphrase provided."); - } - - if (!pwalletMain->EncryptWallet(strWalletPass)) { - return NanThrowError("Failed to encrypt the wallet."); - } - - // BDB seems to have a bad habit of writing old data into - // slack space in .dat files; that is bad if the old data is - // unencrypted private keys. So: - StartShutdown(); - - if (set_cooked()) { - printf( - "bitcoind.js:" - " wallet encrypted; bitcoind.js stopping," - " restart to run with encrypted wallet." - " The keypool has been flushed, you need" - " to make a new backup.\n" - ); - } - - NanReturnValue(Undefined(isolate)); -} - -/** - * WalletEncrypted() - * bitcoindjs.walletEncrypted() - * Check whether the wallet is encrypted. - */ - -NAN_METHOD(WalletEncrypted) { - NanScope(); - - if (args.Length() > 0) { - return NanThrowError( - "Usage: bitcoindjs.walletEncrypted()"); - } - - bool isLocked = false; - bool isEncrypted = false; - - isEncrypted = pwalletMain->IsCrypted(); - - if (isEncrypted) { - isLocked = pwalletMain->IsLocked(); - } - - Local result = NanNew(); - result->Set(NanNew("locked"), NanNew(isLocked)); - result->Set(NanNew("encrypted"), NanNew(isEncrypted)); - - NanReturnValue(result); -} - -/** - * WalletKeyPoolRefill() - * bitcoindjs.walletKeyPoolRefill(options) - * Refill key pool - */ - -NAN_METHOD(WalletKeyPoolRefill) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletKeyPoolRefill(options)"); - } - - Local options = Local::Cast(args[0]); - - // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool - unsigned int kpSize = 0; - if (options->Get(NanNew("size"))->IsNumber()) { - kpSize = (unsigned int)options->Get(NanNew("size"))->IntegerValue(); - } - - // EnsureWalletIsUnlocked(); - if (pwalletMain->IsLocked()) { - return NanThrowError("Please enter the wallet passphrase with walletpassphrase first."); - } - // XXX Do this asynchronously - pwalletMain->TopUpKeyPool(kpSize); - - if (pwalletMain->GetKeyPoolSize() < kpSize) { - return NanThrowError("Error refreshing keypool."); - } - - NanReturnValue(True(isolate)); -} - -/** - * WalletSetTxFee() - * bitcoindjs.walletSetTxFee(options) - * Set default global wallet transaction fee internally. - */ - -NAN_METHOD(WalletSetTxFee) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletSetTxFee(options)"); - } - - Local options = Local::Cast(args[0]); - - int64_t fee = options->Get(NanNew("fee"))->IntegerValue(); - - // Amount - CAmount nAmount = 0; - if (fee != 0.0) { - nAmount = fee; - } - - payTxFee = CFeeRate(nAmount, 1000); - - NanReturnValue(True(isolate)); -} - -/** - * WalletDumpKey() - * bitcoindjs.walletDumpKey(options) - * Dump private key - */ - -NAN_METHOD(WalletDumpKey) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletDumpKey(options)"); - } - - Local options = Local::Cast(args[0]); - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - std::string addr = std::string(*addr_); - - CBitcoinAddress address(addr); - - Local obj = NanNew(); - obj->Set(NanNew("address"), NanNew(address.ToString())); - - CKeyID keyID; - if (!address.GetKeyID(keyID)) { - return NanThrowError("Address does not refer to a key"); - } - CKey vchSecret; - if (!pwalletMain->GetKey(keyID, vchSecret)) { - return NanThrowError("Private key for address is not known"); - } - - if (!pwalletMain->IsCrypted()) { - std::string priv = CBitcoinSecret(vchSecret).ToString(); - obj->Set(NanNew("privkeycompressed"), NanNew(vchSecret.IsCompressed())); - obj->Set(NanNew("privkey"), NanNew(priv)); - } - - CPubKey vchPubKey; - pwalletMain->GetPubKey(keyID, vchPubKey); - obj->Set(NanNew("pubkeycompressed"), NanNew(vchPubKey.IsCompressed())); - obj->Set(NanNew("pubkey"), NanNew(HexStr(vchPubKey))); - - NanReturnValue(obj); -} - -/** - * WalletImportKey() - * bitcoindjs.walletImportKey(options) - * Import private key into global wallet using standard compressed bitcoind - * format. - */ - -NAN_METHOD(WalletImportKey) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletImportKey(options, callback)"); - } - - async_import_key_data *data = new async_import_key_data(); - - data->err_msg = std::string(""); - data->fRescan = false; - - Local options = Local::Cast(args[0]); - Local callback; - - if (args.Length() > 1 && args[1]->IsFunction()) { - callback = Local::Cast(args[1]); - Eternal eternal(isolate, callback); - data->callback = eternal; - } - - std::string strSecret = ""; - std::string strAccount = std::string(EMPTY); - - String::Utf8Value key_(options->Get(NanNew("key"))->ToString()); - strSecret = std::string(*key_); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value label_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*label_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value label_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*label_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value label_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*label_); - } - -rescan: - if (data->fRescan) { - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_import_key, - (uv_after_work_cb)async_import_key_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); - } - - // Whether to perform rescan after import - data->fRescan = args.Length() > 1 && args[1]->IsFunction() - ? true - : false; - - if (strAccount == EMPTY) { - if (data->fRescan) { - data->err_msg = std::string("No account name provided."); - goto rescan; - } else { - return NanThrowError("No account name provided."); - } - } - - // Call to: EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - if (data->fRescan) { - data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first."); - goto rescan; - } else { - return NanThrowError("Please enter the wallet passphrase with walletpassphrase first."); - } - } - - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - if (!fGood) { - if (data->fRescan) { - data->err_msg = std::string("Invalid private key encoding"); - goto rescan; - } else { - return NanThrowError("Invalid private key encoding"); - } - } - - CKey key = vchSecret.GetKey(); - if (!key.IsValid()) { - if (data->fRescan) { - data->err_msg = std::string("Private key outside allowed range"); - goto rescan; - } else { - return NanThrowError("Private key outside allowed range"); - } - } - - CPubKey pubkey = key.GetPubKey(); - CKeyID vchAddress = pubkey.GetID(); - { - LOCK2(cs_main, pwalletMain->cs_wallet); - - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, strAccount, "receive"); - - // Don't throw error in case a key is already there - if (pwalletMain->HaveKey(vchAddress)) { - NanReturnValue(Undefined(isolate)); - } - - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; - - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { - if (data->fRescan) { - data->err_msg = std::string("Error adding key to wallet"); - goto rescan; - } else { - return NanThrowError("Error adding key to wallet"); - } - } - - // whenever a key is imported, we need to scan the whole chain - pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' - } - - if (data->fRescan) { - goto rescan; - } - - NanReturnValue(Undefined(isolate)); -} - -static void -async_import_key(uv_work_t *req) { - async_import_key_data* data = static_cast(req->data); - if (data->err_msg != "") { - return; - } - if (data->fRescan) { - // This may take a long time, do it on the libuv thread pool: - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - } -} - -static void -async_import_key_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - async_import_key_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, True(isolate)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * WalletDumpWallet() - * bitcoindjs.walletDumpWallet(options, callback) - * Dump wallet to bitcoind plaintext format. - */ - -NAN_METHOD(WalletDumpWallet) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.walletDumpWallet(options, callback)"); - } - - async_dump_wallet_data *data = new async_dump_wallet_data(); - - data->err_msg = std::string(""); - - Local options = Local::Cast(args[0]); - Local callback = Local::Cast(args[1]); - - String::Utf8Value path_(options->Get(NanNew("path"))->ToString()); - std::string path = std::string(*path_); - - // Call to: EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first."); - } - - data->path = path; - Eternal eternal(isolate, callback); - data->callback = eternal; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_dump_wallet, - (uv_after_work_cb)async_dump_wallet_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_dump_wallet(uv_work_t *req) { - async_dump_wallet_data* data = static_cast(req->data); - if (data->err_msg != "") { - return; - } - - std::string path = data->path; - - ofstream file; - file.open(path.c_str()); - if (!file.is_open()) { - data->err_msg = std::string("Cannot open wallet dump file"); - } - - std::map mapKeyBirth; - std::set setKeyPool; - pwalletMain->GetKeyBirthTimes(mapKeyBirth); - pwalletMain->GetAllReserveKeys(setKeyPool); - - // sort time/key pairs - std::vector > vKeyBirth; - for (std::map::const_iterator it = mapKeyBirth.begin(); - it != mapKeyBirth.end(); - it++) { - vKeyBirth.push_back(std::make_pair(it->second, it->first)); - } - mapKeyBirth.clear(); - std::sort(vKeyBirth.begin(), vKeyBirth.end()); - - // produce output - file << strprintf("# Wallet dump created by bitcoind.js %s (%s)\n", - CLIENT_BUILD, CLIENT_DATE); - file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); - file << strprintf("# * Best block at time of backup was %i (%s),\n", - chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); - file << strprintf("# mined on %s\n", - EncodeDumpTime(chainActive.Tip()->GetBlockTime())); - file << "\n"; - for (std::vector >::const_iterator it = vKeyBirth.begin(); - it != vKeyBirth.end(); - it++) { - const CKeyID &keyid = it->second; - std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); - CKey key; - if (pwalletMain->GetKey(keyid, key)) { - if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("%s %s label=%s # addr=%s\n", - CBitcoinSecret(key).ToString(), - strTime, - EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), - strAddr); - } else if (setKeyPool.count(keyid)) { - file << strprintf("%s %s reserve=1 # addr=%s\n", - CBitcoinSecret(key).ToString(), - strTime, strAddr); - } else { - file << strprintf("%s %s change=1 # addr=%s\n", - CBitcoinSecret(key).ToString(), - strTime, strAddr); - } - } - } - file << "\n"; - file << "# End of dump\n"; - file.close(); -} - -static void -async_dump_wallet_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_dump_wallet_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, NanNew(data->path)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * WalletImportWallet() - * bitcoindjs.walletImportWallet(options, callback) - * Import bitcoind wallet from plaintext format. - */ - -NAN_METHOD(WalletImportWallet) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.walletImportWallet(options, callback)"); - } - - async_import_wallet_data *data = new async_import_wallet_data(); - - data->err_msg = std::string(""); - - Local options = Local::Cast(args[0]); - Local callback = Local::Cast(args[1]); - - String::Utf8Value path_(options->Get(NanNew("path"))->ToString()); - std::string path = std::string(*path_); - - // Call to: EnsureWalletIsUnlocked() - if (pwalletMain->IsLocked()) { - data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first."); - } - - data->path = path; - Eternal eternal(isolate, callback); - data->callback = eternal; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_import_wallet, - (uv_after_work_cb)async_import_wallet_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_import_wallet(uv_work_t *req) { - async_import_wallet_data* data = static_cast(req->data); - - std::string path = data->path; - - ifstream file; - file.open(path.c_str(), std::ios::in | std::ios::ate); - if (!file.is_open()) { - data->err_msg = std::string("Cannot open wallet dump file"); - } - - int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); - - bool fGood = true; - - int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); - file.seekg(0, file.beg); - - pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI - while (file.good()) { - pwalletMain->ShowProgress("", - std::max(1, std::min(99, - (int)(((double)file.tellg() / (double)nFilesize) * 100))) - ); - std::string line; - std::getline(file, line); - - if (line.empty() || line[0] == '#') { - continue; - } - - std::vector vstr; - boost::split(vstr, line, boost::is_any_of(" ")); - if (vstr.size() < 2) { - continue; - } - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) { - continue; - } - CKey key = vchSecret.GetKey(); - CPubKey pubkey = key.GetPubKey(); - CKeyID keyid = pubkey.GetID(); - if (pwalletMain->HaveKey(keyid)) { - // LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); - continue; - } - int64_t nTime = DecodeDumpTime(vstr[1]); - std::string strLabel; - bool fLabel = true; - for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { - if (boost::algorithm::starts_with(vstr[nStr], "#")) { - break; - } - if (vstr[nStr] == "change=1") { - fLabel = false; - } - if (vstr[nStr] == "reserve=1") { - fLabel = false; - } - if (boost::algorithm::starts_with(vstr[nStr], "label=")) { - strLabel = DecodeDumpString(vstr[nStr].substr(6)); - fLabel = true; - } - } - // LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { - fGood = false; - continue; - } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) { - pwalletMain->SetAddressBook(keyid, strLabel, "receive"); - } - nTimeBegin = std::min(nTimeBegin, nTime); - } - file.close(); - pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI - - CBlockIndex *pindex = chainActive.Tip(); - while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) { - pindex = pindex->pprev; - } - - if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey) { - pwalletMain->nTimeFirstKey = nTimeBegin; - } - - // LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); - pwalletMain->ScanForWalletTransactions(pindex); - pwalletMain->MarkDirty(); - - if (!fGood) { - data->err_msg = std::string("Cannot open wallet dump file"); - } -} - -static void -async_import_wallet_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_import_wallet_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, NanNew(data->path)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * WalletChangeLabel() - * bitcoindjs.walletChangeLabel(options) - * Change account label - */ - -NAN_METHOD(WalletChangeLabel) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletChangeLabel(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strAccount = std::string(EMPTY); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - std::string addr = std::string(""); - - if (options->Get(NanNew("address"))->IsString()) { - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - addr = std::string(*addr_); - } - - if (strAccount == EMPTY && addr == "") { - return NanThrowError("No address or account name entered."); - } - - if (strAccount == EMPTY && addr != "") { - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (address.ToString() == addr) { - strAccount = strName; - break; - } - } - } - - if (addr == "" && strAccount != EMPTY) { - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (strName == strAccount) { - addr = address.ToString(); - break; - } - } - } - - // If it isn't our address, create a recipient: - CTxDestination dest = CBitcoinAddress(addr).Get(); - - if (!IsMine(*pwalletMain, dest)) { - pwalletMain->SetAddressBook(dest, strAccount, "send"); - pwalletMain->SetAddressBook(dest, strAccount, "send"); - NanReturnValue(True(isolate)); - } - - // Rename our address: - pwalletMain->SetAddressBook(dest, strAccount, "receive"); - - NanReturnValue(True(isolate)); -} - -/** - * WalletDeleteAccount() - * bitcoindjs.walletDeleteAccount(options) - * Delete account and all associated addresses - */ - -NAN_METHOD(WalletDeleteAccount) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletDeleteAccount(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string strAccount = std::string(EMPTY); - - if (options->Get(NanNew("account"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("account"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("label"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("label"))->ToString()); - strAccount = std::string(*account_); - } - - if (options->Get(NanNew("name"))->IsString()) { - String::Utf8Value account_(options->Get(NanNew("name"))->ToString()); - strAccount = std::string(*account_); - } - - std::string addr = std::string(""); - - if (options->Get(NanNew("address"))->IsString()) { - String::Utf8Value addr_(options->Get(NanNew("address"))->ToString()); - addr = std::string(*addr_); - } - - // LOCK2(cs_main, pwalletMain->cs_wallet); - - CWalletDB walletdb(pwalletMain->strWalletFile); - - CAccount account; - walletdb.ReadAccount(strAccount, account); - - if (strAccount == EMPTY) { - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (address.ToString() == addr) { - strAccount = strName; - break; - } - } - } - - if (strAccount == EMPTY) { - if (addr == "") { - return NanThrowError("No account name specified."); - } else { - return NanThrowError("No account tied to specified address."); - } - } - - // Find all addresses that have the given account - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (strName == strAccount) { - walletdb.EraseName(address.ToString()); - walletdb.ErasePurpose(address.ToString()); - } - } - - NanReturnValue(True(isolate)); -} - -/** - * WalletIsMine() - * bitcoindjs.walletIsMine(options) - * Check whether address or scriptPubKey is owned by wallet. - */ - -NAN_METHOD(WalletIsMine) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.walletIsMine(options)"); - } - - Local options = Local::Cast(args[0]); - - std::string addr = std::string(""); - std::string spk = std::string(""); - - if (options->Get(NanNew("address"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("address"))->ToString()); - addr = std::string(*s_); - } - - if (options->Get(NanNew("scriptPubKey"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("scriptPubKey"))->ToString()); - spk = std::string(*s_); - } - - // Bitcoin address - CScript scriptPubKey; - if (addr != "") { - CBitcoinAddress address = CBitcoinAddress(addr); - if (!address.IsValid()) { - return NanThrowError("Invalid Bitcoin address"); - } - scriptPubKey = GetScriptForDestination(address.Get()); - } else { - scriptPubKey << ParseHex(spk); - } - - bool is_mine = IsMine(*pwalletMain, scriptPubKey); - - NanReturnValue(NanNew(is_mine)); -} - -/** - * WalletRescan() - * bitcoindjs.walletRescan(options, callback) - * Rescan blockchain - */ - -NAN_METHOD(WalletRescan) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 || !args[0]->IsObject() || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.walletRescan(options, callback)"); - } - - async_rescan_data *data = new async_rescan_data(); - - //Local options = Local::Cast(args[0]); - Local callback = Local::Cast(args[1]); - - data->err_msg = std::string(""); - Eternal eternal(isolate, callback); - data->callback = eternal; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_rescan, - (uv_after_work_cb)async_rescan_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_rescan(uv_work_t *req) { - // async_rescan_data* data = static_cast(req->data); - // This may take a long time, do it on the libuv thread pool: - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); -} - -static void -async_rescan_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_rescan_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, True(isolate)) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - /** * Conversions * cblock_to_jsblock(cblock, cblock_index, jsblock, is_new) @@ -7047,11 +4161,6 @@ error: } #endif -static int64_t -SatoshiFromAmount(const CAmount& amount) { - return (int64_t)amount; -} - /** * Helpers */ @@ -7091,13 +4200,9 @@ init(Handle target) { NODE_SET_METHOD(target, "broadcastTx", BroadcastTx); NODE_SET_METHOD(target, "verifyBlock", VerifyBlock); NODE_SET_METHOD(target, "verifyTransaction", VerifyTransaction); - NODE_SET_METHOD(target, "fillTransaction", FillTransaction); NODE_SET_METHOD(target, "getInfo", GetInfo); NODE_SET_METHOD(target, "getPeerInfo", GetPeerInfo); NODE_SET_METHOD(target, "getAddresses", GetAddresses); - NODE_SET_METHOD(target, "walletGetRecipients", WalletGetRecipients); - NODE_SET_METHOD(target, "walletSetRecipient", WalletSetRecipient); - NODE_SET_METHOD(target, "walletRemoveRecipient", WalletRemoveRecipient); NODE_SET_METHOD(target, "getProgress", GetProgress); NODE_SET_METHOD(target, "setGenerate", SetGenerate); NODE_SET_METHOD(target, "getGenerate", GetGenerate); @@ -7115,38 +4220,6 @@ init(Handle target) { NODE_SET_METHOD(target, "txFromHex", TxFromHex); NODE_SET_METHOD(target, "hookPackets", HookPackets); - NODE_SET_METHOD(target, "walletNewAddress", WalletNewAddress); - NODE_SET_METHOD(target, "walletGetAccountAddress", WalletGetAccountAddress); - NODE_SET_METHOD(target, "walletSetAccount", WalletSetAccount); - NODE_SET_METHOD(target, "walletGetAccount", WalletGetAccount); - NODE_SET_METHOD(target, "walletSendTo", WalletSendTo); - NODE_SET_METHOD(target, "walletSignMessage", WalletSignMessage); - NODE_SET_METHOD(target, "walletVerifyMessage", WalletVerifyMessage); - NODE_SET_METHOD(target, "walletGetBalance", WalletGetBalance); - NODE_SET_METHOD(target, "walletCreateMultiSigAddress", WalletCreateMultiSigAddress); - NODE_SET_METHOD(target, "walletGetUnconfirmedBalance", WalletGetUnconfirmedBalance); - NODE_SET_METHOD(target, "walletSendFrom", WalletSendFrom); - NODE_SET_METHOD(target, "walletMove", WalletMove); - NODE_SET_METHOD(target, "walletListTransactions", WalletListTransactions); - NODE_SET_METHOD(target, "walletReceivedByAddress", WalletReceivedByAddress); - NODE_SET_METHOD(target, "walletListAccounts", WalletListAccounts); - NODE_SET_METHOD(target, "walletGetTransaction", WalletGetTransaction); - NODE_SET_METHOD(target, "walletBackup", WalletBackup); - NODE_SET_METHOD(target, "walletPassphrase", WalletPassphrase); - NODE_SET_METHOD(target, "walletPassphraseChange", WalletPassphraseChange); - NODE_SET_METHOD(target, "walletLock", WalletLock); - NODE_SET_METHOD(target, "walletEncrypt", WalletEncrypt); - NODE_SET_METHOD(target, "walletEncrypted", WalletEncrypted); - NODE_SET_METHOD(target, "walletDumpKey", WalletDumpKey); - NODE_SET_METHOD(target, "walletKeyPoolRefill", WalletKeyPoolRefill); - NODE_SET_METHOD(target, "walletSetTxFee", WalletSetTxFee); - NODE_SET_METHOD(target, "walletImportKey", WalletImportKey); - NODE_SET_METHOD(target, "walletDumpWallet", WalletDumpWallet); - NODE_SET_METHOD(target, "walletImportWallet", WalletImportWallet); - NODE_SET_METHOD(target, "walletChangeLabel", WalletChangeLabel); - NODE_SET_METHOD(target, "walletDeleteAccount", WalletDeleteAccount); - NODE_SET_METHOD(target, "walletIsMine", WalletIsMine); - NODE_SET_METHOD(target, "walletRescan", WalletRescan); } NODE_MODULE(bitcoindjs, init)