From 4c6e22953ef8ae0764576993088ec83d729d18f8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 28 Jun 2011 23:45:22 +0200 Subject: [PATCH 1/5] Make CWalletTx::pwallet private --- src/db.cpp | 2 +- src/wallet.cpp | 6 +++--- src/wallet.h | 9 ++++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 9ac93b350..9b29e799e 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -810,7 +810,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) ssKey >> hash; CWalletTx& wtx = pwallet->mapWallet[hash]; ssValue >> wtx; - wtx.pwallet = pwallet; + wtx.BindWallet(pwallet); if (wtx.GetHash() != hash) printf("Error in wallet.dat, hash mismatch\n"); diff --git a/src/wallet.cpp b/src/wallet.cpp index 28babdb3e..c451186d9 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -232,7 +232,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Inserts only if not already there, returns tx inserted or tx found pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; - wtx.pwallet = this; + wtx.BindWallet(this); bool fInsertedNew = ret.second; if (fInsertedNew) wtx.nTimeReceived = GetAdjustedTime(); @@ -924,7 +924,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW if (vecSend.empty() || nValue < 0) return false; - wtxNew.pwallet = this; + wtxNew.BindWallet(this); CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_wallet) @@ -1062,7 +1062,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { CWalletTx &coin = mapWallet[txin.prevout.hash]; - coin.pwallet = this; + coin.BindWallet(this); coin.MarkSpent(txin.prevout.n); coin.WriteToDisk(); vWalletUpdated.push_back(coin.GetHash()); diff --git a/src/wallet.h b/src/wallet.h index ca7cf6731..e1c39a6f3 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -243,9 +243,10 @@ public: // class CWalletTx : public CMerkleTx { -public: +private: const CWallet* pwallet; +public: std::vector vtxPrev; std::map mapValue; std::vector > vOrderForm; @@ -389,6 +390,12 @@ public: fChangeCached = false; } + void BindWallet(CWallet *pwalletIn) + { + pwallet = pwalletIn; + MarkDirty(); + } + void MarkSpent(unsigned int nOut) { if (nOut >= vout.size()) From 93db3fceac1bfe274bc0fd906428a20e709e2da5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 11 Jul 2011 21:30:40 +0200 Subject: [PATCH 2/5] Add GetSecret() and GetKeys() to CKeyStore --- bitcoin-qt.pro | 1 + src/bitcoinrpc.cpp | 2 +- src/key.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++ src/key.h | 119 +-------------------------------------------- src/keystore.cpp | 12 ++--- src/keystore.h | 59 ++++++++++++++++++---- src/makefile.mingw | 1 + src/makefile.osx | 1 + src/makefile.unix | 1 + 9 files changed, 177 insertions(+), 136 deletions(-) create mode 100644 src/key.cpp diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 2b980ba86..0989fe8b0 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -148,6 +148,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/editaddressdialog.cpp \ src/qt/bitcoinaddressvalidator.cpp \ src/util.cpp \ + src/key.cpp \ src/script.cpp \ src/main.cpp \ src/init.cpp \ diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index bb8d8e2d7..17189040b 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -595,7 +595,7 @@ Value verifymessage(const Array& params, bool fHelp) if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) return false; - return (key.GetAddress() == addr); + return (CBitcoinAddress(key.GetPubKey()) == addr); } diff --git a/src/key.cpp b/src/key.cpp new file mode 100644 index 000000000..400b1887c --- /dev/null +++ b/src/key.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2011 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +// Generate a private key from just the secret parameter +int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) +{ + int ok = 0; + BN_CTX *ctx = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey) return 0; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + pub_key = EC_POINT_new(group); + + if (pub_key == NULL) + goto err; + + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + EC_KEY_set_private_key(eckey,priv_key); + EC_KEY_set_public_key(eckey,pub_key); + + ok = 1; + +err: + + if (pub_key) + EC_POINT_free(pub_key); + if (ctx != NULL) + BN_CTX_free(ctx); + + return(ok); +} + +// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields +// recid selects which key is recovered +// if check is nonzero, additional checks are performed +int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) +{ + if (!eckey) return 0; + + int ret = 0; + BN_CTX *ctx = NULL; + + BIGNUM *x = NULL; + BIGNUM *e = NULL; + BIGNUM *order = NULL; + BIGNUM *sor = NULL; + BIGNUM *eor = NULL; + BIGNUM *field = NULL; + EC_POINT *R = NULL; + EC_POINT *O = NULL; + EC_POINT *Q = NULL; + BIGNUM *rr = NULL; + BIGNUM *zero = NULL; + int n = 0; + int i = recid / 2; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } + x = BN_CTX_get(ctx); + if (!BN_copy(x, order)) { ret=-1; goto err; } + if (!BN_mul_word(x, i)) { ret=-1; goto err; } + if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } + field = BN_CTX_get(ctx); + if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } + if (BN_cmp(x, field) >= 0) { ret=0; goto err; } + if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } + if (check) + { + if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } + if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } + } + if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + n = EC_GROUP_get_degree(group); + e = BN_CTX_get(ctx); + if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } + if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); + zero = BN_CTX_get(ctx); + if (!BN_zero(zero)) { ret=-1; goto err; } + if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } + rr = BN_CTX_get(ctx); + if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } + sor = BN_CTX_get(ctx); + if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } + eor = BN_CTX_get(ctx); + if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } + if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } + if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } + + ret = 1; + +err: + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (R != NULL) EC_POINT_free(R); + if (O != NULL) EC_POINT_free(O); + if (Q != NULL) EC_POINT_free(Q); + return ret; +} diff --git a/src/key.h b/src/key.h index df5cfeb32..3f4b72d2d 100644 --- a/src/key.h +++ b/src/key.h @@ -14,7 +14,6 @@ #include "serialize.h" #include "uint256.h" -#include "base58.h" // secp160k1 // const unsigned int PRIVATE_KEY_SIZE = 192; @@ -39,116 +38,8 @@ // see www.keylength.com // script supports up to 75 for single byte push -// Generate a private key from just the secret parameter -int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) -{ - int ok = 0; - BN_CTX *ctx = NULL; - EC_POINT *pub_key = NULL; - - if (!eckey) return 0; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - - if ((ctx = BN_CTX_new()) == NULL) - goto err; - - pub_key = EC_POINT_new(group); - - if (pub_key == NULL) - goto err; - - if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) - goto err; - - EC_KEY_set_private_key(eckey,priv_key); - EC_KEY_set_public_key(eckey,pub_key); - - ok = 1; - -err: - - if (pub_key) - EC_POINT_free(pub_key); - if (ctx != NULL) - BN_CTX_free(ctx); - - return(ok); -} - -// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields -// recid selects which key is recovered -// if check is nonzero, additional checks are performed -int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) -{ - if (!eckey) return 0; - - int ret = 0; - BN_CTX *ctx = NULL; - - BIGNUM *x = NULL; - BIGNUM *e = NULL; - BIGNUM *order = NULL; - BIGNUM *sor = NULL; - BIGNUM *eor = NULL; - BIGNUM *field = NULL; - EC_POINT *R = NULL; - EC_POINT *O = NULL; - EC_POINT *Q = NULL; - BIGNUM *rr = NULL; - BIGNUM *zero = NULL; - int n = 0; - int i = recid / 2; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } - x = BN_CTX_get(ctx); - if (!BN_copy(x, order)) { ret=-1; goto err; } - if (!BN_mul_word(x, i)) { ret=-1; goto err; } - if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } - field = BN_CTX_get(ctx); - if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } - if (BN_cmp(x, field) >= 0) { ret=0; goto err; } - if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } - if (check) - { - if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } - if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } - } - if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - n = EC_GROUP_get_degree(group); - e = BN_CTX_get(ctx); - if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } - if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); - zero = BN_CTX_get(ctx); - if (!BN_zero(zero)) { ret=-1; goto err; } - if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } - rr = BN_CTX_get(ctx); - if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } - sor = BN_CTX_get(ctx); - if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } - eor = BN_CTX_get(ctx); - if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } - if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } - if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } - - ret = 1; - -err: - if (ctx) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } - if (R != NULL) EC_POINT_free(R); - if (O != NULL) EC_POINT_free(O); - if (Q != NULL) EC_POINT_free(Q); - return ret; -} +int extern EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key); +int extern ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check); class key_error : public std::runtime_error { @@ -381,12 +272,6 @@ public: return false; return true; } - - // Get the address corresponding to this key - CBitcoinAddress GetAddress() const - { - return CBitcoinAddress(GetPubKey()); - } }; #endif diff --git a/src/keystore.cpp b/src/keystore.cpp index 68f57e7e0..6cf557faf 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -29,7 +29,7 @@ bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector &vchPubKey, return true; } -bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const +bool CCryptoKeyStore::GetSecret(const CBitcoinAddress &address, CSecret& vchSecretOut) const { CRITICAL_BLOCK(cs_KeyStore) { if (!IsCrypted()) - return CBasicKeyStore::GetKey(address, keyOut); + return CBasicKeyStore::GetSecret(address, vchSecretOut); CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); if (mi != mapCryptedKeys.end()) { const std::vector &vchPubKey = (*mi).second.first; const std::vector &vchCryptedSecret = (*mi).second.second; - CSecret vchSecret; - if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret)) - return false; - keyOut.SetSecret(vchSecret); - return true; + return DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecretOut); } } return false; diff --git a/src/keystore.h b/src/keystore.h index 4d889146f..3b91de6fb 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -19,17 +19,28 @@ public: // Check whether a key corresponding to a given address is present in the store. virtual bool HaveKey(const CBitcoinAddress &address) const =0; - - // Retrieve a key corresponding to a given address from the store. - // Return true if succesful. - virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0; - - // Retrieve only the public key corresponding to a given address. - // This may succeed even if GetKey fails (e.g., encrypted wallets) + virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const + { + CSecret vchSecret; + if (!GetSecret(address, vchSecret)) + return false; + if (!keyOut.SetSecret(vchSecret)) + return false; + return true; + } + virtual void GetKeys(std::set &setAddress) const =0; virtual bool GetPubKey(const CBitcoinAddress &address, std::vector& vchPubKeyOut) const; // Generate a new key, and add it to the store virtual std::vector GenerateNewKey(); + virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const + { + CKey key; + if (!GetKey(address, key)) + return false; + vchSecret = key.GetSecret(); + return true; + } }; typedef std::map KeyMap; @@ -49,14 +60,27 @@ public: result = (mapKeys.count(address) > 0); return result; } - bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const + void GetKeys(std::set &setAddress) const + { + setAddress.clear(); + CRITICAL_BLOCK(cs_KeyStore) + { + KeyMap::const_iterator mi = mapKeys.begin(); + while (mi != mapKeys.end()) + { + setAddress.insert((*mi).first); + mi++; + } + } + } + bool GetSecret(const CBitcoinAddress &address, CSecret &vchSecret) const { CRITICAL_BLOCK(cs_KeyStore) { KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { - keyOut.SetSecret((*mi).second); + vchSecret = (*mi).second; return true; } } @@ -131,8 +155,23 @@ public: } return false; } - bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const; + bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const; bool GetPubKey(const CBitcoinAddress &address, std::vector& vchPubKeyOut) const; + void GetKeys(std::set &setAddress) const + { + if (!IsCrypted()) + { + CBasicKeyStore::GetKeys(setAddress); + return; + } + setAddress.clear(); + CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); + while (mi != mapCryptedKeys.end()) + { + setAddress.insert((*mi).first); + mi++; + } + } }; #endif diff --git a/src/makefile.mingw b/src/makefile.mingw index 2cb78d97e..ce3da062e 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -61,6 +61,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell OBJS= \ obj/checkpoints.o \ obj/crypter.o \ + obj/key.o \ obj/db.o \ obj/init.o \ obj/irc.o \ diff --git a/src/makefile.osx b/src/makefile.osx index de7188793..690e35a3e 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -72,6 +72,7 @@ HEADERS = \ OBJS= \ obj/checkpoints.o \ obj/crypter.o \ + obj/key.o \ obj/db.o \ obj/init.o \ obj/irc.o \ diff --git a/src/makefile.unix b/src/makefile.unix index 6c4819954..a8b6837c8 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -110,6 +110,7 @@ HEADERS = \ OBJS= \ obj/checkpoints.o \ obj/crypter.o \ + obj/key.o \ obj/db.o \ obj/init.o \ obj/irc.o \ From 15a8590ecf6610387502be14d26657cb154d6201 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 11 Jul 2011 21:48:09 +0200 Subject: [PATCH 3/5] CBitcoinSecret added (base58 encoded privkey) --- src/base58.h | 53 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/base58.h b/src/base58.h index cace423d6..113fa14a5 100644 --- a/src/base58.h +++ b/src/base58.h @@ -18,6 +18,7 @@ #include #include #include "bignum.h" +#include "key.h" static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -257,15 +258,14 @@ public: class CBitcoinAddress : public CBase58Data { public: - bool SetHash160(const uint160& hash160) + void SetHash160(const uint160& hash160) { SetData(fTestNet ? 111 : 0, &hash160, 20); - return true; } - bool SetPubKey(const std::vector& vchPubKey) + void SetPubKey(const std::vector& vchPubKey) { - return SetHash160(Hash160(vchPubKey)); + SetHash160(Hash160(vchPubKey)); } bool IsValid() const @@ -320,4 +320,49 @@ public: } }; +class CBitcoinSecret : public CBase58Data +{ +public: + void SetSecret(const CSecret& vchSecret) + { + SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size()); + } + + CSecret GetSecret() + { + CSecret vchSecret; + vchSecret.resize(vchData.size()); + memcpy(&vchSecret[0], &vchData[0], vchData.size()); + return vchSecret; + } + + bool IsValid() const + { + int nExpectedSize = 32; + bool fExpectTestNet = false; + switch(nVersion) + { + case 128: + break; + + case 239: + fExpectTestNet = true; + break; + + default: + return false; + } + return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; + } + + CBitcoinSecret(const CSecret& vchSecret) + { + SetSecret(vchSecret); + } + + CBitcoinSecret() + { + } +}; + #endif From 30ab2c9c46ce38197017ce6a6e13869617e692c7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 11 Jul 2011 21:49:45 +0200 Subject: [PATCH 4/5] Preparations for key import/export --- src/bitcoinrpc.cpp | 1 + src/main.cpp | 4 ++-- src/main.h | 10 ++++++++-- src/wallet.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- src/wallet.h | 5 ++++- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 17189040b..fcf2482ee 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef USE_SSL #include #include diff --git a/src/main.cpp b/src/main.cpp index a7871fcc1..3a4e86512 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -516,7 +516,7 @@ bool CTransaction::RemoveFromMemoryPool() -int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const { if (hashBlock == 0 || nIndex == -1) return 0; @@ -537,7 +537,7 @@ int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const fMerkleVerified = true; } - nHeightRet = pindex->nHeight; + pindexRet = pindex; return pindexBest->nHeight - pindex->nHeight + 1; } diff --git a/src/main.h b/src/main.h index 3870cee86..93528cdb2 100644 --- a/src/main.h +++ b/src/main.h @@ -695,8 +695,8 @@ public: int SetMerkleBranch(const CBlock* pblock=NULL); - int GetDepthInMainChain(int& nHeightRet) const; - int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); } + int GetDepthInMainChain(CBlockIndex* &pindexRet) const; + int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { return GetDepthInMainChain() > 0; } int GetBlocksToMaturity() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true); @@ -758,6 +758,7 @@ public: return !(a == b); } int GetDepthInMainChain() const; + }; @@ -1263,6 +1264,11 @@ public: Set((*mi).second); } + CBlockLocator(const std::vector& vHaveIn) + { + vHave = vHaveIn; + } + IMPLEMENT_SERIALIZE ( if (!(nType & SER_GETHASH)) diff --git a/src/wallet.cpp b/src/wallet.cpp index c451186d9..f9157e01d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -299,7 +299,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) { uint256 hash = tx.GetHash(); CRITICAL_BLOCK(cs_wallet) @@ -586,6 +586,15 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) return ret; } +int CWallet::ScanForWalletTransaction(const uint256& hashTx) +{ + CTransaction tx; + tx.ReadFromDisk(COutPoint(hashTx, 0)); + if (AddToWalletIfInvolvingMe(tx, NULL, true, true)) + return 1; + return 0; +} + void CWallet::ReacceptWalletTransactions() { CTxDB txdb("r"); @@ -1325,6 +1334,22 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) } } +int64 CWallet::AddReserveKey(const CKeyPool& keypool) +{ + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_wallet) + { + CWalletDB walletdb(strWalletFile); + + int64 nIndex = 1 + *(--setKeyPool.end()); + if (!walletdb.WritePool(nIndex, keypool)) + throw runtime_error("AddReserveKey() : writing added key failed"); + setKeyPool.insert(nIndex); + return nIndex; + } + return -1; +} + void CWallet::KeepKey(int64 nIndex) { // Remove from key pool @@ -1413,3 +1438,22 @@ void CReserveKey::ReturnKey() vchPubKey.clear(); } +void CWallet::GetAllReserveAddresses(set& setAddress) +{ + setAddress.clear(); + + CWalletDB walletdb(strWalletFile); + + CRITICAL_BLOCK(cs_main) + BOOST_FOREACH(const int64& id, setKeyPool) + { + CKeyPool keypool; + if (!walletdb.ReadPool(id, keypool)) + throw runtime_error("GetAllReserveKeyHashes() : read failed"); + CBitcoinAddress address(keypool.vchPubKey); + assert(!keypool.vchPubKey.empty()); + if (!HaveKey(address)) + throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); + setAddress.insert(address); + } +} diff --git a/src/wallet.h b/src/wallet.h index e1c39a6f3..95537be63 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -75,10 +75,11 @@ public: bool EncryptWallet(const SecureString& strWalletPassphrase); bool AddToWallet(const CWalletTx& wtxIn); - bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); + bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); bool EraseFromWallet(uint256 hash); void WalletUpdateSpent(const CTransaction& prevout); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); + int ScanForWalletTransaction(const uint256& hashTx); void ReacceptWalletTransactions(); void ResendWalletTransactions(); int64 GetBalance() const; @@ -92,11 +93,13 @@ public: bool NewKeyPool(); bool TopUpKeyPool(); + int64 AddReserveKey(const CKeyPool& keypool); void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); void KeepKey(int64 nIndex); void ReturnKey(int64 nIndex); bool GetKeyFromPool(std::vector &key, bool fAllowReuse=true); int64 GetOldestKeyPoolTime(); + void GetAllReserveAddresses(std::set& setAddress); bool IsMine(const CTxIn& txin) const; int64 GetDebit(const CTxIn& txin) const; From 95d888a6d1f659a5cb81124e0d97966b9de1f139 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 13 Jul 2011 11:56:38 +0200 Subject: [PATCH 5/5] Key import and export Introduces two new RPC calls: * dumpprivkey: retrieve the private key corresponding to an address * importprivkey: add a private key to your wallet The private key format is analoguous to the address format. It is a 51-character base58-encoded string, that includes a version number and a checksum. Includes patch by mhanne: * add optional account parameter for importprivkey, if omitted use default --- bitcoin-qt.pro | 1 + src/bitcoinrpc.cpp | 12 ++++-- src/makefile.mingw | 1 + src/makefile.osx | 1 + src/makefile.unix | 1 + src/rpcdump.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++ src/wallet.cpp | 10 +++++ src/wallet.h | 1 + 8 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/rpcdump.cpp diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 0989fe8b0..853f2faf9 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -174,6 +174,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactionview.cpp \ src/qt/walletmodel.cpp \ src/bitcoinrpc.cpp \ + src/rpcdump.cpp \ src/qt/overviewpage.cpp \ src/qt/csvmodelwriter.cpp \ src/crypter.cpp \ diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index fcf2482ee..e3378782c 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -9,6 +9,7 @@ #include "init.h" #undef printf #include +#include #include #include #include @@ -42,6 +43,8 @@ static std::string strRPCUserColonPass; static int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; +extern Value dumpprivkey(const Array& params, bool fHelp); +extern Value importprivkey(const Array& params, bool fHelp); Object JSONRPCError(int code, const string& message) { @@ -1599,7 +1602,6 @@ Value validateaddress(const Array& params, bool fHelp) return ret; } - Value getwork(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -1840,13 +1842,15 @@ pair pCallTable[] = make_pair("sendmany", &sendmany), make_pair("gettransaction", &gettransaction), make_pair("listtransactions", &listtransactions), - make_pair("signmessage", &signmessage), - make_pair("verifymessage", &verifymessage), + make_pair("signmessage", &signmessage), + make_pair("verifymessage", &verifymessage), make_pair("getwork", &getwork), make_pair("listaccounts", &listaccounts), make_pair("settxfee", &settxfee), make_pair("getmemorypool", &getmemorypool), - make_pair("listsinceblock", &listsinceblock), + make_pair("listsinceblock", &listsinceblock), + make_pair("dumpprivkey", &dumpprivkey), + make_pair("importprivkey", &importprivkey) }; map mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); diff --git a/src/makefile.mingw b/src/makefile.mingw index ce3da062e..ed718b89e 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -70,6 +70,7 @@ OBJS= \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ + obj/rpcdump.o \ obj/script.o \ obj/util.o \ obj/wallet.o diff --git a/src/makefile.osx b/src/makefile.osx index 690e35a3e..4b0b521a3 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -81,6 +81,7 @@ OBJS= \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ + obj/rpcdump.o \ obj/script.o \ obj/util.o \ obj/wallet.o diff --git a/src/makefile.unix b/src/makefile.unix index a8b6837c8..a436f968b 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -119,6 +119,7 @@ OBJS= \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ + obj/rpcdump.o \ obj/script.o \ obj/util.o \ obj/wallet.o diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp new file mode 100644 index 000000000..f3978fbce --- /dev/null +++ b/src/rpcdump.cpp @@ -0,0 +1,101 @@ +// Copyright (c) 2011 Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" +#include "init.h" // for pwalletMain +#include "bitcoinrpc.h" + +// #include +// #include +// #include +#include +// #ifdef USE_SSL +// #include +// typedef boost::asio::ssl::stream SSLStream; +// #endif +// #include +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_writer_template.h" +#include "json/json_spirit_utils.h" + +#define printf OutputDebugStringF + +// using namespace boost::asio; +using namespace json_spirit; +using namespace std; + +extern Object JSONRPCError(int code, const string& message); + +class CTxDump +{ +public: + CBlockIndex *pindex; + int64 nValue; + bool fSpent; + CWalletTx* ptx; + int nOut; + CTxDump(CWalletTx* ptx = NULL, int nOut = -1) + { + pindex = NULL; + nValue = 0; + fSpent = false; + this->ptx = ptx; + this->nOut = nOut; + } +}; + +Value importprivkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "importprivkey [label]\n" + "Adds a private key (as returned by dumpprivkey) to your wallet."); + + string strSecret = params[0].get_str(); + string strLabel = ""; + if (params.size() > 1) + strLabel = params[1].get_str(); + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(strSecret); + + if (!fGood) throw JSONRPCError(-5,"Invalid private key"); + + CKey key; + key.SetSecret(vchSecret.GetSecret()); + CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey()); + + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(pwalletMain->cs_wallet) + { + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBookName(vchAddress, strLabel); + + if (!pwalletMain->AddKey(key)) + throw JSONRPCError(-4,"Error adding key to wallet"); + + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); + } + + MainFrameRepaint(); + + return Value::null; +} + +Value dumpprivkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpprivkey \n" + "Reveals the private key corresponding to ."); + + string strAddress = params[0].get_str(); + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(-5, "Invalid bitcoin address"); + CSecret vchSecret; + if (!pwalletMain->GetSecret(address, vchSecret)) + throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known"); + return CBitcoinSecret(vchSecret).ToString(); +} diff --git a/src/wallet.cpp b/src/wallet.cpp index f9157e01d..87f5dfd65 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -224,6 +224,15 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) } } +void CWallet::MarkDirty() +{ + CRITICAL_BLOCK(cs_wallet) + { + BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + item.second.MarkDirty(); + } +} + bool CWallet::AddToWallet(const CWalletTx& wtxIn) { uint256 hash = wtxIn.GetHash(); @@ -1445,6 +1454,7 @@ void CWallet::GetAllReserveAddresses(set& setAddress) CWalletDB walletdb(strWalletFile); CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_wallet) BOOST_FOREACH(const int64& id, setKeyPool) { CKeyPool keypool; diff --git a/src/wallet.h b/src/wallet.h index 95537be63..78f055a60 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -74,6 +74,7 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); bool EraseFromWallet(uint256 hash);