add dump and import wallet methods.

This commit is contained in:
Christopher Jeffrey 2014-10-28 13:57:06 -07:00
parent a2283ae0cc
commit 349027d4b1
2 changed files with 347 additions and 1 deletions

View File

@ -751,6 +751,14 @@ Wallet.prototype.importKey = function(options) {
return bitcoindjs.walletImportKey(options || {});
};
Wallet.prototype.dump = function(options, callback) {
return bitcoindjs.walletDumpWallet(options || {}, callback);
};
Wallet.prototype.import = function(options, callback) {
return bitcoindjs.walletImportWallet(options || {}, callback);
};
Wallet = new Wallet;
/**

View File

@ -198,6 +198,8 @@ NAN_METHOD(WalletDumpPrivKey);
NAN_METHOD(WalletKeyPoolRefill);
NAN_METHOD(WalletSetTxFee);
NAN_METHOD(WalletImportKey);
NAN_METHOD(WalletDumpWallet);
NAN_METHOD(WalletImportWallet);
/**
* Node.js Internal Function Templates
@ -406,6 +408,26 @@ struct async_import_key_data {
Persistent<Function> callback;
};
/**
* async_import_wallet_data
*/
struct async_import_wallet_data {
std::string err_msg;
std::string path;
Persistent<Function> callback;
};
/**
* async_dump_wallet_data
*/
struct async_dump_wallet_data {
std::string err_msg;
std::string path;
Persistent<Function> callback;
};
/**
* Functions
*/
@ -3574,7 +3596,321 @@ async_import_key_after(uv_work_t *req) {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(Null())
Local<Value>::New(True())
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
/**
* WalletDumpWallet()
* bitcoindjs.walletDumpWallet(options, callback)
* Dump wallet to bitcoind plaintext format.
*/
NAN_METHOD(WalletDumpWallet) {
NanScope();
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();
Local<Object> options = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[1]);
String::Utf8Value path_(options->Get(NanNew<String>("path"))->ToString());
std::string path = std::string(*path_);
// Call to: EnsureWalletIsUnlocked()
if (pwalletMain->IsLocked()) {
return NanThrowError("Please enter the wallet passphrase with walletpassphrase first.");
}
data->path = path;
data->callback = Persistent<Function>::New(callback);
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());
}
static void
async_dump_wallet(uv_work_t *req) {
async_dump_wallet_data* data = static_cast<async_dump_wallet_data*>(req->data);
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<CKeyID, int64_t> mapKeyBirth;
std::set<CKeyID> setKeyPool;
pwalletMain->GetKeyBirthTimes(mapKeyBirth);
pwalletMain->GetAllReserveKeys(setKeyPool);
// sort time/key pairs
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
for (std::map<CKeyID, int64_t>::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 Bitcoin %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<std::pair<int64_t, CKeyID> >::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) {
NanScope();
async_dump_wallet_data* data = static_cast<async_dump_key_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(NanNew<String>(data->path))
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
/**
* WalletImportWallet()
* bitcoindjs.walletImportWallet(options, callback)
* Import bitcoind wallet from plaintext format.
*/
NAN_METHOD(WalletImportWallet) {
NanScope();
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();
Local<Object> options = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[1]);
String::Utf8Value path_(options->Get(NanNew<String>("path"))->ToString());
std::string path = std::string(*path_);
// Call to: EnsureWalletIsUnlocked()
if (pwalletMain->IsLocked()) {
return NanThrowError("Please enter the wallet passphrase with walletpassphrase first.");
}
data->path = path;
data->callback = Persistent<Function>::New(callback);
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());
}
static void
async_import_wallet(uv_work_t *req) {
async_import_wallet_data* data = static_cast<async_import_wallet_data*>(req->data);
std::string path = data->path;
ifstream file;
file.open(path.c_str(), std::ios::in | std::ios::ate);
if (!file.is_open()) {
return NanThrowError("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<std::string> 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) {
NanScope();
async_import_wallet_data* data = static_cast<async_import_key_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(NanNew<String>(data->path))
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
@ -3973,6 +4309,8 @@ init(Handle<Object> target) {
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_MODULE(bitcoindjs, init)