Merge branch 'exp-btc09backports' into exp-mark11b
Conflicts: src/base58.h
This commit is contained in:
commit
07b32c2cb2
@ -3,7 +3,8 @@ TARGET = litecoin-qt
|
||||
macx:TARGET = "Litecoin-Qt"
|
||||
VERSION = 0.8.3
|
||||
INCLUDEPATH += src src/json src/qt
|
||||
QT += network
|
||||
QT += core gui network
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE
|
||||
CONFIG += no_include_pwd
|
||||
CONFIG += thread
|
||||
@ -212,6 +213,7 @@ HEADERS += src/qt/bitcoingui.h \
|
||||
src/leveldb.h \
|
||||
src/threadsafety.h \
|
||||
src/limitedmap.h \
|
||||
src/qt/macnotificationhandler.h \
|
||||
src/qt/splashscreen.h
|
||||
|
||||
SOURCES += src/qt/bitcoin.cpp \
|
||||
@ -314,6 +316,7 @@ DEFINES += BITCOIN_QT_TEST
|
||||
macx: CONFIG -= app_bundle
|
||||
}
|
||||
|
||||
# Todo: Remove this line when switching to Qt5, as that option was removed
|
||||
CODECFORTR = UTF-8
|
||||
|
||||
# for lrelease/lupdate
|
||||
@ -337,6 +340,7 @@ QMAKE_EXTRA_COMPILERS += TSQM
|
||||
OTHER_FILES += README.md \
|
||||
doc/*.rst \
|
||||
doc/*.txt \
|
||||
doc/*.md \
|
||||
src/qt/res/bitcoin-qt.rc \
|
||||
src/test/*.cpp \
|
||||
src/test/*.h \
|
||||
@ -394,9 +398,9 @@ win32:!contains(MINGW_THREAD_BUGFIX, 0) {
|
||||
DEFINES += _FILE_OFFSET_BITS=64
|
||||
}
|
||||
|
||||
macx:HEADERS += src/qt/macdockiconhandler.h
|
||||
macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm
|
||||
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
|
||||
macx:HEADERS += src/qt/macdockiconhandler.h src/qt/macnotificationhandler.h
|
||||
macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm src/qt/macnotificationhandler.mm
|
||||
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit -framework CoreServices
|
||||
macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0
|
||||
macx:ICON = src/qt/res/icons/litecoin.icns
|
||||
macx:QMAKE_CFLAGS_THREAD += -pthread
|
||||
|
||||
20
contrib/debian/README
Normal file
20
contrib/debian/README
Normal file
@ -0,0 +1,20 @@
|
||||
This directory contains files used to package bitcoind/bitcoin-qt
|
||||
for Debian-based Linux systems.
|
||||
|
||||
If you compile bitcoind/bitcoin-qt yourself, there are some
|
||||
useful files here:
|
||||
|
||||
bitcoin: URI support
|
||||
--------------------
|
||||
|
||||
bitcoin-qt.desktop (Gnome / Open Desktop)
|
||||
To install:
|
||||
sudo desktop-file-install bitcoin-qt.desktop
|
||||
sudo update-desktop-database
|
||||
|
||||
If you build yourself, you will either need to modify the paths in
|
||||
the .desktop file or copy or symlink your bitcoin-qt binary to /usr/bin
|
||||
and the ../../share/pixmaps/bitcoin128.png to /usr/share/pixmaps
|
||||
|
||||
bitcoin-qt.protocol (KDE)
|
||||
|
||||
@ -4,7 +4,7 @@ Name=Bitcoin
|
||||
Comment=Bitcoin P2P Cryptocurrency
|
||||
Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair
|
||||
Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi
|
||||
Exec=/usr/bin/bitcoin-qt
|
||||
Exec=/usr/bin/bitcoin-qt %u
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=/usr/share/pixmaps/bitcoin128.png
|
||||
|
||||
@ -31,5 +31,7 @@
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -144,9 +144,7 @@ bool CAlert::RelayTo(CNode* pnode) const
|
||||
|
||||
bool CAlert::CheckSignature() const
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey)))
|
||||
return error("CAlert::CheckSignature() : SetPubKey failed");
|
||||
CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey));
|
||||
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
|
||||
return error("CAlert::CheckSignature() : verify signature failed");
|
||||
|
||||
|
||||
@ -176,6 +176,19 @@ private:
|
||||
{}
|
||||
};
|
||||
|
||||
//
|
||||
// Functions for directly locking/unlocking memory objects.
|
||||
// Intended for non-dynamically allocated structures.
|
||||
//
|
||||
template<typename T> void LockObject(const T &t) {
|
||||
LockedPageManager::instance.LockRange((void*)(&t), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> void UnlockObject(const T &t) {
|
||||
OPENSSL_cleanse((void*)(&t), sizeof(T));
|
||||
LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T));
|
||||
}
|
||||
|
||||
//
|
||||
// Allocator that locks its contents from being paged
|
||||
// out of memory and clears its contents before deletion.
|
||||
|
||||
22
src/base58.h
22
src/base58.h
@ -404,21 +404,19 @@ public:
|
||||
PRIVKEY_ADDRESS_TEST = CBitcoinAddress::PUBKEY_ADDRESS_TEST + 128,
|
||||
};
|
||||
|
||||
void SetSecret(const CSecret& vchSecret, bool fCompressed)
|
||||
void SetKey(const CKey& vchSecret)
|
||||
{
|
||||
assert(vchSecret.size() == 32);
|
||||
SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, &vchSecret[0], vchSecret.size());
|
||||
if (fCompressed)
|
||||
assert(vchSecret.IsValid());
|
||||
SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, vchSecret.begin(), vchSecret.size());
|
||||
if (vchSecret.IsCompressed())
|
||||
vchData.push_back(1);
|
||||
}
|
||||
|
||||
CSecret GetSecret(bool &fCompressedOut)
|
||||
CKey GetKey()
|
||||
{
|
||||
CSecret vchSecret;
|
||||
vchSecret.resize(32);
|
||||
memcpy(&vchSecret[0], &vchData[0], 32);
|
||||
fCompressedOut = vchData.size() == 33;
|
||||
return vchSecret;
|
||||
CKey ret;
|
||||
ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
@ -449,9 +447,9 @@ public:
|
||||
return SetString(strSecret.c_str());
|
||||
}
|
||||
|
||||
CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
|
||||
CBitcoinSecret(const CKey& vchSecret)
|
||||
{
|
||||
SetSecret(vchSecret, fCompressed);
|
||||
SetKey(vchSecret);
|
||||
}
|
||||
|
||||
CBitcoinSecret()
|
||||
|
||||
@ -100,17 +100,17 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
|
||||
}
|
||||
|
||||
|
||||
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
|
||||
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
|
||||
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
|
||||
return false;
|
||||
return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
|
||||
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
|
||||
}
|
||||
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
|
||||
|
||||
@ -101,7 +101,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext);
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
|
||||
|
||||
#endif
|
||||
|
||||
@ -541,6 +541,8 @@ bool CAddrDB::Read(CAddrMan& addr)
|
||||
// use file size to size memory buffer
|
||||
int fileSize = GetFilesize(filein);
|
||||
int dataSize = fileSize - sizeof(uint256);
|
||||
//Don't try to resize to a negative number if file is small
|
||||
if ( dataSize < 0 ) dataSize = 0;
|
||||
vector<unsigned char> vchData;
|
||||
vchData.resize(dataSize);
|
||||
uint256 hashIn;
|
||||
|
||||
11
src/hash.h
11
src/hash.h
@ -105,15 +105,22 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
inline uint160 Hash160(const std::vector<unsigned char>& vch)
|
||||
template<typename T1>
|
||||
inline uint160 Hash160(const T1 pbegin, const T1 pend)
|
||||
{
|
||||
static unsigned char pblank[1];
|
||||
uint256 hash1;
|
||||
SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
|
||||
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
|
||||
uint160 hash2;
|
||||
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
|
||||
return hash2;
|
||||
}
|
||||
|
||||
inline uint160 Hash160(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
return Hash160(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
|
||||
|
||||
#endif
|
||||
|
||||
18
src/init.cpp
18
src/init.cpp
@ -531,7 +531,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
// Make sure enough file descriptors are available
|
||||
int nBind = std::max((int)mapArgs.count("-bind"), 1);
|
||||
nMaxConnections = GetArg("-maxconnections", 125);
|
||||
nMaxConnections = std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS), 0);
|
||||
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
|
||||
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
|
||||
if (nFD < MIN_CORE_FILEDESCRIPTORS)
|
||||
return InitError(_("Not enough file descriptors available."));
|
||||
@ -870,12 +870,23 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
break;
|
||||
}
|
||||
|
||||
// If the loaded chain has a wrong genesis, bail out immediately
|
||||
// (we're likely using a testnet datadir, or the other way around).
|
||||
if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL)
|
||||
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
|
||||
|
||||
// Initialize the block index (no-op if non-empty database was already loaded)
|
||||
if (!InitBlockIndex()) {
|
||||
strLoadError = _("Error initializing block database");
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for changed -txindex state
|
||||
if (fTxIndex != GetBoolArg("-txindex", false)) {
|
||||
strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
|
||||
break;
|
||||
}
|
||||
|
||||
uiInterface.InitMessage(_("Verifying blocks..."));
|
||||
if (!VerifyDB()) {
|
||||
strLoadError = _("Corrupted block database detected");
|
||||
@ -893,7 +904,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
// first suggest a reindex
|
||||
if (!fReset) {
|
||||
bool fRet = uiInterface.ThreadSafeMessageBox(
|
||||
strLoadError + ".\n" + _("Do you want to rebuild the block database now?"),
|
||||
strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"),
|
||||
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
|
||||
if (fRet) {
|
||||
fReindex = true;
|
||||
@ -907,9 +918,6 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
}
|
||||
}
|
||||
|
||||
if (mapArgs.count("-txindex") && fTxIndex != GetBoolArg("-txindex", false))
|
||||
return InitError(_("You need to rebuild the databases using -reindex to change -txindex"));
|
||||
|
||||
// as LoadBlockIndex can take several minutes, it's possible the user
|
||||
// requested to kill bitcoin-qt during the last operation. If so, exit.
|
||||
// As the program has not fully started yet, Shutdown() is possibly overkill.
|
||||
|
||||
492
src/key.cpp
492
src/key.cpp
@ -2,13 +2,16 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include "key.h"
|
||||
|
||||
|
||||
// anonymous namespace with local implementation code (OpenSSL interaction)
|
||||
namespace {
|
||||
|
||||
// Generate a private key from just the secret parameter
|
||||
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
|
||||
{
|
||||
@ -120,287 +123,274 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CKey::SetCompressedPubKey(bool fCompressed)
|
||||
{
|
||||
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
|
||||
fCompressedPubKey = true;
|
||||
}
|
||||
// RAII Wrapper around OpenSSL's EC_KEY
|
||||
class CECKey {
|
||||
private:
|
||||
EC_KEY *pkey;
|
||||
|
||||
void CKey::Reset()
|
||||
{
|
||||
fCompressedPubKey = false;
|
||||
if (pkey != NULL)
|
||||
public:
|
||||
CECKey() {
|
||||
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
assert(pkey != NULL);
|
||||
}
|
||||
|
||||
~CECKey() {
|
||||
EC_KEY_free(pkey);
|
||||
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if (pkey == NULL)
|
||||
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
|
||||
fSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
CKey::CKey()
|
||||
{
|
||||
pkey = NULL;
|
||||
Reset();
|
||||
}
|
||||
void GetSecretBytes(unsigned char vch[32]) const {
|
||||
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
|
||||
assert(bn);
|
||||
int nBytes = BN_num_bytes(bn);
|
||||
int n=BN_bn2bin(bn,&vch[32 - nBytes]);
|
||||
assert(n == nBytes);
|
||||
memset(vch, 0, 32 - nBytes);
|
||||
}
|
||||
|
||||
CKey::CKey(const CKey& b)
|
||||
{
|
||||
pkey = EC_KEY_dup(b.pkey);
|
||||
if (pkey == NULL)
|
||||
throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
|
||||
fSet = b.fSet;
|
||||
}
|
||||
void SetSecretBytes(const unsigned char vch[32]) {
|
||||
BIGNUM bn;
|
||||
BN_init(&bn);
|
||||
assert(BN_bin2bn(vch, 32, &bn));
|
||||
assert(EC_KEY_regenerate_key(pkey, &bn));
|
||||
BN_clear_free(&bn);
|
||||
}
|
||||
|
||||
CKey& CKey::operator=(const CKey& b)
|
||||
{
|
||||
if (!EC_KEY_copy(pkey, b.pkey))
|
||||
throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
|
||||
fSet = b.fSet;
|
||||
return (*this);
|
||||
}
|
||||
void GetPrivKey(CPrivKey &privkey, bool fCompressed) {
|
||||
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
|
||||
int nSize = i2d_ECPrivateKey(pkey, NULL);
|
||||
assert(nSize);
|
||||
privkey.resize(nSize);
|
||||
unsigned char* pbegin = &privkey[0];
|
||||
int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
|
||||
assert(nSize == nSize2);
|
||||
}
|
||||
|
||||
CKey::~CKey()
|
||||
{
|
||||
EC_KEY_free(pkey);
|
||||
}
|
||||
|
||||
bool CKey::IsNull() const
|
||||
{
|
||||
return !fSet;
|
||||
}
|
||||
|
||||
bool CKey::IsCompressed() const
|
||||
{
|
||||
return fCompressedPubKey;
|
||||
}
|
||||
|
||||
void CKey::MakeNewKey(bool fCompressed)
|
||||
{
|
||||
if (!EC_KEY_generate_key(pkey))
|
||||
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
|
||||
if (fCompressed)
|
||||
SetCompressedPubKey();
|
||||
fSet = true;
|
||||
}
|
||||
|
||||
bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
|
||||
{
|
||||
const unsigned char* pbegin = &vchPrivKey[0];
|
||||
if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
|
||||
{
|
||||
// In testing, d2i_ECPrivateKey can return true
|
||||
// but fill in pkey with a key that fails
|
||||
// EC_KEY_check_key, so:
|
||||
if (EC_KEY_check_key(pkey))
|
||||
{
|
||||
fSet = true;
|
||||
return true;
|
||||
bool SetPrivKey(const CPrivKey &privkey) {
|
||||
const unsigned char* pbegin = &privkey[0];
|
||||
if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
|
||||
// d2i_ECPrivateKey returns true if parsing succeeds.
|
||||
// This doesn't necessarily mean the key is valid.
|
||||
if (EC_KEY_check_key(pkey))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// If vchPrivKey data is bad d2i_ECPrivateKey() can
|
||||
// leave pkey in a state where calling EC_KEY_free()
|
||||
// crashes. To avoid that, set pkey to NULL and
|
||||
// leak the memory (a leak is better than a crash)
|
||||
pkey = NULL;
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
|
||||
{
|
||||
EC_KEY_free(pkey);
|
||||
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if (pkey == NULL)
|
||||
throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
|
||||
if (vchSecret.size() != 32)
|
||||
throw key_error("CKey::SetSecret() : secret must be 32 bytes");
|
||||
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
|
||||
if (bn == NULL)
|
||||
throw key_error("CKey::SetSecret() : BN_bin2bn failed");
|
||||
if (!EC_KEY_regenerate_key(pkey,bn))
|
||||
{
|
||||
BN_clear_free(bn);
|
||||
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
|
||||
void GetPubKey(CPubKey &pubkey, bool fCompressed) {
|
||||
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
|
||||
int nSize = i2o_ECPublicKey(pkey, NULL);
|
||||
assert(nSize);
|
||||
assert(nSize <= 65);
|
||||
unsigned char c[65];
|
||||
unsigned char *pbegin = c;
|
||||
int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
|
||||
assert(nSize == nSize2);
|
||||
pubkey.Set(&c[0], &c[nSize]);
|
||||
}
|
||||
BN_clear_free(bn);
|
||||
fSet = true;
|
||||
if (fCompressed || fCompressedPubKey)
|
||||
SetCompressedPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
CSecret CKey::GetSecret(bool &fCompressed) const
|
||||
{
|
||||
CSecret vchRet;
|
||||
vchRet.resize(32);
|
||||
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
|
||||
int nBytes = BN_num_bytes(bn);
|
||||
if (bn == NULL)
|
||||
throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
|
||||
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
|
||||
if (n != nBytes)
|
||||
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
|
||||
fCompressed = fCompressedPubKey;
|
||||
return vchRet;
|
||||
}
|
||||
bool SetPubKey(const CPubKey &pubkey) {
|
||||
const unsigned char* pbegin = pubkey.begin();
|
||||
return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size());
|
||||
}
|
||||
|
||||
CPrivKey CKey::GetPrivKey() const
|
||||
{
|
||||
int nSize = i2d_ECPrivateKey(pkey, NULL);
|
||||
if (!nSize)
|
||||
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
|
||||
CPrivKey vchPrivKey(nSize, 0);
|
||||
unsigned char* pbegin = &vchPrivKey[0];
|
||||
if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
|
||||
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
|
||||
return vchPrivKey;
|
||||
}
|
||||
|
||||
bool CKey::SetPubKey(const CPubKey& vchPubKey)
|
||||
{
|
||||
const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
|
||||
if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
|
||||
{
|
||||
fSet = true;
|
||||
if (vchPubKey.vchPubKey.size() == 33)
|
||||
SetCompressedPubKey();
|
||||
bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) {
|
||||
unsigned int nSize = ECDSA_size(pkey);
|
||||
vchSig.resize(nSize); // Make sure it is big enough
|
||||
assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey));
|
||||
vchSig.resize(nSize); // Shrink to fit actual size
|
||||
return true;
|
||||
}
|
||||
pkey = NULL;
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
CPubKey CKey::GetPubKey() const
|
||||
{
|
||||
int nSize = i2o_ECPublicKey(pkey, NULL);
|
||||
if (!nSize)
|
||||
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
|
||||
std::vector<unsigned char> vchPubKey(nSize, 0);
|
||||
unsigned char* pbegin = &vchPubKey[0];
|
||||
if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
|
||||
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
|
||||
return CPubKey(vchPubKey);
|
||||
}
|
||||
|
||||
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
unsigned int nSize = ECDSA_size(pkey);
|
||||
vchSig.resize(nSize); // Make sure it is big enough
|
||||
if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
|
||||
{
|
||||
vchSig.clear();
|
||||
return false;
|
||||
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
|
||||
// -1 = error, 0 = bad sig, 1 = good
|
||||
if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
|
||||
bool fOk = false;
|
||||
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
|
||||
if (sig==NULL)
|
||||
return false;
|
||||
memset(p64, 0, 64);
|
||||
int nBitsR = BN_num_bits(sig->r);
|
||||
int nBitsS = BN_num_bits(sig->s);
|
||||
if (nBitsR <= 256 && nBitsS <= 256) {
|
||||
CPubKey pubkey;
|
||||
GetPubKey(pubkey, true);
|
||||
for (int i=0; i<4; i++) {
|
||||
CECKey keyRec;
|
||||
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
|
||||
CPubKey pubkeyRec;
|
||||
keyRec.GetPubKey(pubkeyRec, true);
|
||||
if (pubkeyRec == pubkey) {
|
||||
rec = i;
|
||||
fOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fOk);
|
||||
BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
|
||||
BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
|
||||
}
|
||||
ECDSA_SIG_free(sig);
|
||||
return fOk;
|
||||
}
|
||||
|
||||
// reconstruct public key from a compact signature
|
||||
// This is only slightly more CPU intensive than just verifying it.
|
||||
// If this function succeeds, the recovered public key is guaranteed to be valid
|
||||
// (the signature is a valid signature of the given data for that key)
|
||||
bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
|
||||
{
|
||||
if (rec<0 || rec>=3)
|
||||
return false;
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
BN_bin2bn(&p64[0], 32, sig->r);
|
||||
BN_bin2bn(&p64[32], 32, sig->s);
|
||||
bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
}; // end of anonymous namespace
|
||||
|
||||
bool CKey::Check(const unsigned char *vch) {
|
||||
// Do not convert to OpenSSL's data structures for range-checking keys,
|
||||
// it's easy enough to do directly.
|
||||
static const unsigned char vchMax[32] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
|
||||
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
|
||||
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
|
||||
};
|
||||
bool fIsZero = true;
|
||||
for (int i=0; i<32 && fIsZero; i++)
|
||||
if (vch[i] != 0)
|
||||
fIsZero = false;
|
||||
if (fIsZero)
|
||||
return false;
|
||||
for (int i=0; i<32; i++) {
|
||||
if (vch[i] < vchMax[i])
|
||||
return true;
|
||||
if (vch[i] > vchMax[i])
|
||||
return false;
|
||||
}
|
||||
vchSig.resize(nSize); // Shrink to fit actual size
|
||||
return true;
|
||||
}
|
||||
|
||||
// create a compact signature (65 bytes), which allows reconstructing the used public key
|
||||
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
|
||||
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
|
||||
// 0x1D = second key with even y, 0x1E = second key with odd y
|
||||
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
bool fOk = false;
|
||||
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
|
||||
if (sig==NULL)
|
||||
return false;
|
||||
vchSig.clear();
|
||||
vchSig.resize(65,0);
|
||||
int nBitsR = BN_num_bits(sig->r);
|
||||
int nBitsS = BN_num_bits(sig->s);
|
||||
if (nBitsR <= 256 && nBitsS <= 256)
|
||||
{
|
||||
int nRecId = -1;
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
CKey keyRec;
|
||||
keyRec.fSet = true;
|
||||
if (fCompressedPubKey)
|
||||
keyRec.SetCompressedPubKey();
|
||||
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
|
||||
if (keyRec.GetPubKey() == this->GetPubKey())
|
||||
{
|
||||
nRecId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nRecId == -1)
|
||||
throw key_error("CKey::SignCompact() : unable to construct recoverable key");
|
||||
|
||||
vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
|
||||
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
|
||||
BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
|
||||
fOk = true;
|
||||
}
|
||||
ECDSA_SIG_free(sig);
|
||||
return fOk;
|
||||
void CKey::MakeNewKey(bool fCompressedIn) {
|
||||
do {
|
||||
RAND_bytes(vch, sizeof(vch));
|
||||
} while (!Check(vch));
|
||||
fValid = true;
|
||||
fCompressed = fCompressedIn;
|
||||
}
|
||||
|
||||
// reconstruct public key from a compact signature
|
||||
// This is only slightly more CPU intensive than just verifying it.
|
||||
// If this function succeeds, the recovered public key is guaranteed to be valid
|
||||
// (the signature is a valid signature of the given data for that key)
|
||||
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
|
||||
CECKey key;
|
||||
if (!key.SetPrivKey(privkey))
|
||||
return false;
|
||||
key.GetSecretBytes(vch);
|
||||
fCompressed = fCompressedIn;
|
||||
fValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
CPrivKey CKey::GetPrivKey() const {
|
||||
assert(fValid);
|
||||
CECKey key;
|
||||
key.SetSecretBytes(vch);
|
||||
CPrivKey privkey;
|
||||
key.GetPrivKey(privkey, fCompressed);
|
||||
return privkey;
|
||||
}
|
||||
|
||||
CPubKey CKey::GetPubKey() const {
|
||||
assert(fValid);
|
||||
CECKey key;
|
||||
key.SetSecretBytes(vch);
|
||||
CPubKey pubkey;
|
||||
key.GetPubKey(pubkey, fCompressed);
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
|
||||
if (!fValid)
|
||||
return false;
|
||||
CECKey key;
|
||||
key.SetSecretBytes(vch);
|
||||
return key.Sign(hash, vchSig);
|
||||
}
|
||||
|
||||
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
|
||||
if (!fValid)
|
||||
return false;
|
||||
CECKey key;
|
||||
key.SetSecretBytes(vch);
|
||||
vchSig.resize(65);
|
||||
int rec = -1;
|
||||
if (!key.SignCompact(hash, &vchSig[1], rec))
|
||||
return false;
|
||||
assert(rec != -1);
|
||||
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(*this))
|
||||
return false;
|
||||
if (!key.Verify(hash, vchSig))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
|
||||
if (vchSig.size() != 65)
|
||||
return false;
|
||||
int nV = vchSig[0];
|
||||
if (nV<27 || nV>=35)
|
||||
CECKey key;
|
||||
if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
|
||||
return false;
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
BN_bin2bn(&vchSig[1],32,sig->r);
|
||||
BN_bin2bn(&vchSig[33],32,sig->s);
|
||||
|
||||
EC_KEY_free(pkey);
|
||||
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if (nV >= 31)
|
||||
{
|
||||
SetCompressedPubKey();
|
||||
nV -= 4;
|
||||
}
|
||||
if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
|
||||
{
|
||||
fSet = true;
|
||||
ECDSA_SIG_free(sig);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
// -1 = error, 0 = bad sig, 1 = good
|
||||
if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
|
||||
return false;
|
||||
|
||||
key.GetPubKey(*this, (vchSig[0] - 27) & 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetCompactSignature(hash, vchSig))
|
||||
bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
if (GetPubKey() != key.GetPubKey())
|
||||
if (vchSig.size() != 65)
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
|
||||
return false;
|
||||
CPubKey pubkeyRec;
|
||||
key.GetPubKey(pubkeyRec, IsCompressed());
|
||||
if (*this != pubkeyRec)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKey::IsValid()
|
||||
{
|
||||
if (!fSet)
|
||||
bool CPubKey::IsFullyValid() const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
||||
if (!EC_KEY_check_key(pkey))
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(*this))
|
||||
return false;
|
||||
|
||||
bool fCompr;
|
||||
CSecret secret = GetSecret(fCompr);
|
||||
CKey key2;
|
||||
key2.SetSecret(secret, fCompr);
|
||||
return GetPubKey() == key2.GetPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::Decompress() {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(*this))
|
||||
return false;
|
||||
key.GetPubKey(*this, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
255
src/key.h
255
src/key.h
@ -1,11 +1,10 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef BITCOIN_KEY_H
|
||||
#define BITCOIN_KEY_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "allocators.h"
|
||||
@ -13,23 +12,6 @@
|
||||
#include "uint256.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include <openssl/ec.h> // for EC_KEY definition
|
||||
|
||||
// secp160k1
|
||||
// const unsigned int PRIVATE_KEY_SIZE = 192;
|
||||
// const unsigned int PUBLIC_KEY_SIZE = 41;
|
||||
// const unsigned int SIGNATURE_SIZE = 48;
|
||||
//
|
||||
// secp192k1
|
||||
// const unsigned int PRIVATE_KEY_SIZE = 222;
|
||||
// const unsigned int PUBLIC_KEY_SIZE = 49;
|
||||
// const unsigned int SIGNATURE_SIZE = 57;
|
||||
//
|
||||
// secp224k1
|
||||
// const unsigned int PRIVATE_KEY_SIZE = 250;
|
||||
// const unsigned int PUBLIC_KEY_SIZE = 57;
|
||||
// const unsigned int SIGNATURE_SIZE = 66;
|
||||
//
|
||||
// secp256k1:
|
||||
// const unsigned int PRIVATE_KEY_SIZE = 279;
|
||||
// const unsigned int PUBLIC_KEY_SIZE = 65;
|
||||
@ -38,12 +20,6 @@
|
||||
// see www.keylength.com
|
||||
// script supports up to 75 for single byte push
|
||||
|
||||
class key_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit key_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
/** A reference to a CKey: the Hash160 of its serialized public key */
|
||||
class CKeyID : public uint160
|
||||
{
|
||||
@ -63,99 +39,218 @@ public:
|
||||
/** An encapsulated public key. */
|
||||
class CPubKey {
|
||||
private:
|
||||
std::vector<unsigned char> vchPubKey;
|
||||
friend class CKey;
|
||||
// Just store the serialized data.
|
||||
// Its length can very cheaply be computed from the first byte.
|
||||
unsigned char vch[65];
|
||||
|
||||
// Compute the length of a pubkey with a given first byte.
|
||||
unsigned int static GetLen(unsigned char chHeader) {
|
||||
if (chHeader == 2 || chHeader == 3)
|
||||
return 33;
|
||||
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
|
||||
return 65;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set this key data to be invalid
|
||||
void Invalidate() {
|
||||
vch[0] = 0xFF;
|
||||
}
|
||||
|
||||
public:
|
||||
CPubKey() { }
|
||||
CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { }
|
||||
friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; }
|
||||
friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; }
|
||||
friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; }
|
||||
// Construct an invalid public key.
|
||||
CPubKey() {
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE(
|
||||
READWRITE(vchPubKey);
|
||||
)
|
||||
// Initialize a public key using begin/end iterators to byte data.
|
||||
template<typename T>
|
||||
void Set(const T pbegin, const T pend) {
|
||||
int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
|
||||
if (len && len == (pend-pbegin))
|
||||
memcpy(vch, (unsigned char*)&pbegin[0], len);
|
||||
else
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Construct a public key using begin/end iterators to byte data.
|
||||
template<typename T>
|
||||
CPubKey(const T pbegin, const T pend) {
|
||||
Set(pbegin, pend);
|
||||
}
|
||||
|
||||
// Construct a public key from a byte vector.
|
||||
CPubKey(const std::vector<unsigned char> &vch) {
|
||||
Set(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
// Simple read-only vector-like interface to the pubkey data.
|
||||
unsigned int size() const { return GetLen(vch[0]); }
|
||||
const unsigned char *begin() const { return vch; }
|
||||
const unsigned char *end() const { return vch+size(); }
|
||||
const unsigned char &operator[](unsigned int pos) const { return vch[pos]; }
|
||||
|
||||
// Comparator implementation.
|
||||
friend bool operator==(const CPubKey &a, const CPubKey &b) {
|
||||
return a.vch[0] == b.vch[0] &&
|
||||
memcmp(a.vch, b.vch, a.size()) == 0;
|
||||
}
|
||||
friend bool operator!=(const CPubKey &a, const CPubKey &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
friend bool operator<(const CPubKey &a, const CPubKey &b) {
|
||||
return a.vch[0] < b.vch[0] ||
|
||||
(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
|
||||
}
|
||||
|
||||
// Implement serialization, as if this was a byte vector.
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const {
|
||||
return size() + 1;
|
||||
}
|
||||
template<typename Stream> void Serialize(Stream &s, int nType, int nVersion) const {
|
||||
unsigned int len = size();
|
||||
::WriteCompactSize(s, len);
|
||||
s.write((char*)vch, len);
|
||||
}
|
||||
template<typename Stream> void Unserialize(Stream &s, int nType, int nVersion) {
|
||||
unsigned int len = ::ReadCompactSize(s);
|
||||
if (len <= 65) {
|
||||
s.read((char*)vch, len);
|
||||
} else {
|
||||
// invalid pubkey, skip available data
|
||||
char dummy;
|
||||
while (len--)
|
||||
s.read(&dummy, 1);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the KeyID of this public key (hash of its serialization)
|
||||
CKeyID GetID() const {
|
||||
return CKeyID(Hash160(vchPubKey));
|
||||
return CKeyID(Hash160(vch, vch+size()));
|
||||
}
|
||||
|
||||
// Get the 256-bit hash of this public key.
|
||||
uint256 GetHash() const {
|
||||
return Hash(vchPubKey.begin(), vchPubKey.end());
|
||||
return Hash(vch, vch+size());
|
||||
}
|
||||
|
||||
// just check syntactic correctness.
|
||||
bool IsValid() const {
|
||||
return vchPubKey.size() == 33 || vchPubKey.size() == 65;
|
||||
return size() > 0;
|
||||
}
|
||||
|
||||
// fully validate whether this is a valid public key (more expensive than IsValid())
|
||||
bool IsFullyValid() const;
|
||||
|
||||
// Check whether this is a compressed public key.
|
||||
bool IsCompressed() const {
|
||||
return vchPubKey.size() == 33;
|
||||
return size() == 33;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Raw() const {
|
||||
return vchPubKey;
|
||||
}
|
||||
// Verify a DER signature (~72 bytes).
|
||||
// If this public key is not fully valid, the return value will be false.
|
||||
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// Verify a compact signature (~65 bytes).
|
||||
// See CKey::SignCompact.
|
||||
bool VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// Recover a public key from a compact signature.
|
||||
bool RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
// Turn this public key into an uncompressed public key.
|
||||
bool Decompress();
|
||||
};
|
||||
|
||||
|
||||
// secure_allocator is defined in allocators.h
|
||||
// CPrivKey is a serialized private key, with all parameters included (279 bytes)
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||
// CSecret is a serialization of just the secret parameter (32 bytes)
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
|
||||
|
||||
/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */
|
||||
class CKey
|
||||
{
|
||||
protected:
|
||||
EC_KEY* pkey;
|
||||
bool fSet;
|
||||
bool fCompressedPubKey;
|
||||
/** An encapsulated private key. */
|
||||
class CKey {
|
||||
private:
|
||||
// Whether this private key is valid. We check for correctness when modifying the key
|
||||
// data, so fValid should always correspond to the actual state.
|
||||
bool fValid;
|
||||
|
||||
// Whether the public key corresponding to this private key is (to be) compressed.
|
||||
bool fCompressed;
|
||||
|
||||
// The actual byte data
|
||||
unsigned char vch[32];
|
||||
|
||||
// Check whether the 32-byte array pointed to be vch is valid keydata.
|
||||
bool static Check(const unsigned char *vch);
|
||||
public:
|
||||
void SetCompressedPubKey(bool fCompressed = true);
|
||||
|
||||
void Reset();
|
||||
// Construct an invalid private key.
|
||||
CKey() : fValid(false) {
|
||||
LockObject(vch);
|
||||
}
|
||||
|
||||
CKey();
|
||||
CKey(const CKey& b);
|
||||
// Copy constructor. This is necessary because of memlocking.
|
||||
CKey(const CKey &secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) {
|
||||
LockObject(vch);
|
||||
memcpy(vch, secret.vch, sizeof(vch));
|
||||
}
|
||||
|
||||
CKey& operator=(const CKey& b);
|
||||
// Destructor (again necessary because of memlocking).
|
||||
~CKey() {
|
||||
UnlockObject(vch);
|
||||
}
|
||||
|
||||
~CKey();
|
||||
// Initialize using begin and end iterators to byte data.
|
||||
template<typename T>
|
||||
void Set(const T pbegin, const T pend, bool fCompressedIn) {
|
||||
if (pend - pbegin != 32) {
|
||||
fValid = false;
|
||||
return;
|
||||
}
|
||||
if (Check(&pbegin[0])) {
|
||||
memcpy(vch, (unsigned char*)&pbegin[0], 32);
|
||||
fValid = true;
|
||||
fCompressed = fCompressedIn;
|
||||
} else {
|
||||
fValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNull() const;
|
||||
bool IsCompressed() const;
|
||||
// Simple read-only vector-like interface.
|
||||
unsigned int size() const { return (fValid ? 32 : 0); }
|
||||
const unsigned char *begin() const { return vch; }
|
||||
const unsigned char *end() const { return vch + size(); }
|
||||
|
||||
// Check whether this private key is valid.
|
||||
bool IsValid() const { return fValid; }
|
||||
|
||||
// Check whether the public key corresponding to this private key is (to be) compressed.
|
||||
bool IsCompressed() const { return fCompressed; }
|
||||
|
||||
// Initialize from a CPrivKey (serialized OpenSSL private key data).
|
||||
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed);
|
||||
|
||||
// Generate a new private key using a cryptographic PRNG.
|
||||
void MakeNewKey(bool fCompressed);
|
||||
bool SetPrivKey(const CPrivKey& vchPrivKey);
|
||||
bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
|
||||
CSecret GetSecret(bool &fCompressed) const;
|
||||
|
||||
// Convert the private key to a CPrivKey (serialized OpenSSL private key data).
|
||||
// This is expensive.
|
||||
CPrivKey GetPrivKey() const;
|
||||
bool SetPubKey(const CPubKey& vchPubKey);
|
||||
|
||||
// Compute the public key from a private key.
|
||||
// This is expensive.
|
||||
CPubKey GetPubKey() const;
|
||||
|
||||
bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);
|
||||
// Create a DER-serialized signature.
|
||||
bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// create a compact signature (65 bytes), which allows reconstructing the used public key
|
||||
// Create a compact signature (65 bytes), which allows reconstructing the used public key.
|
||||
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
|
||||
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
|
||||
// 0x1D = second key with even y, 0x1E = second key with odd y
|
||||
bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig);
|
||||
|
||||
// reconstruct public key from a compact signature
|
||||
// This is only slightly more CPU intensive than just verifying it.
|
||||
// If this function succeeds, the recovered public key is guaranteed to be valid
|
||||
// (the signature is a valid signature of the given data for that key)
|
||||
bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
// Verify a compact signature
|
||||
bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
bool IsValid();
|
||||
// 0x1D = second key with even y, 0x1E = second key with odd y,
|
||||
// add 0x04 for compressed keys.
|
||||
bool SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -15,61 +15,50 @@ bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddKey(const CKey& key)
|
||||
bool CKeyStore::AddKey(const CKey &key) {
|
||||
return AddKeyPubKey(key, key.GetPubKey());
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
|
||||
{
|
||||
bool fCompressed = false;
|
||||
CSecret secret = key.GetSecret(fCompressed);
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
|
||||
}
|
||||
LOCK(cs_KeyStore);
|
||||
mapKeys[pubkey.GetID()] = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
mapScripts[redeemScript.GetID()] = redeemScript;
|
||||
}
|
||||
LOCK(cs_KeyStore);
|
||||
mapScripts[redeemScript.GetID()] = redeemScript;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
|
||||
{
|
||||
bool result;
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
result = (mapScripts.count(hash) > 0);
|
||||
}
|
||||
return result;
|
||||
LOCK(cs_KeyStore);
|
||||
return mapScripts.count(hash) > 0;
|
||||
}
|
||||
|
||||
|
||||
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
ScriptMap::const_iterator mi = mapScripts.find(hash);
|
||||
if (mi != mapScripts.end())
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
ScriptMap::const_iterator mi = mapScripts.find(hash);
|
||||
if (mi != mapScripts.end())
|
||||
{
|
||||
redeemScriptOut = (*mi).second;
|
||||
return true;
|
||||
}
|
||||
redeemScriptOut = (*mi).second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetCrypted()
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (fUseCrypto)
|
||||
return true;
|
||||
if (!mapKeys.empty())
|
||||
return false;
|
||||
fUseCrypto = true;
|
||||
}
|
||||
LOCK(cs_KeyStore);
|
||||
if (fUseCrypto)
|
||||
return true;
|
||||
if (!mapKeys.empty())
|
||||
return false;
|
||||
fUseCrypto = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -99,14 +88,13 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
||||
CSecret vchSecret;
|
||||
CKeyingMaterial vchSecret;
|
||||
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
return false;
|
||||
if (vchSecret.size() != 32)
|
||||
return false;
|
||||
CKey key;
|
||||
key.SetPubKey(vchPubKey);
|
||||
key.SetSecret(vchSecret);
|
||||
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
if (key.GetPubKey() == vchPubKey)
|
||||
break;
|
||||
return false;
|
||||
@ -117,23 +105,22 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddKey(const CKey& key)
|
||||
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::AddKey(key);
|
||||
return CBasicKeyStore::AddKeyPubKey(key, pubkey);
|
||||
|
||||
if (IsLocked())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
CPubKey vchPubKey = key.GetPubKey();
|
||||
bool fCompressed;
|
||||
if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
|
||||
CKeyingMaterial vchSecret(key.begin(), key.end());
|
||||
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
|
||||
return false;
|
||||
|
||||
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
|
||||
if (!AddCryptedKey(pubkey, vchCryptedSecret))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -164,13 +151,12 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
|
||||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
||||
CSecret vchSecret;
|
||||
CKeyingMaterial vchSecret;
|
||||
if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
return false;
|
||||
if (vchSecret.size() != 32)
|
||||
return false;
|
||||
keyOut.SetPubKey(vchPubKey);
|
||||
keyOut.SetSecret(vchSecret);
|
||||
keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -204,13 +190,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
||||
fUseCrypto = true;
|
||||
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetSecret(mKey.second.first, mKey.second.second))
|
||||
return false;
|
||||
const CPubKey vchPubKey = key.GetPubKey();
|
||||
const CKey &key = mKey.second;
|
||||
CPubKey vchPubKey = key.GetPubKey();
|
||||
CKeyingMaterial vchSecret(key.begin(), key.end());
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
bool fCompressed;
|
||||
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
|
||||
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
|
||||
return false;
|
||||
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||
return false;
|
||||
|
||||
@ -21,7 +21,8 @@ public:
|
||||
virtual ~CKeyStore() {}
|
||||
|
||||
// Add a key to the store.
|
||||
virtual bool AddKey(const CKey& key) =0;
|
||||
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
|
||||
virtual bool AddKey(const CKey &key);
|
||||
|
||||
// Check whether a key corresponding to a given address is present in the store.
|
||||
virtual bool HaveKey(const CKeyID &address) const =0;
|
||||
@ -33,18 +34,9 @@ public:
|
||||
virtual bool AddCScript(const CScript& redeemScript) =0;
|
||||
virtual bool HaveCScript(const CScriptID &hash) const =0;
|
||||
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
|
||||
|
||||
virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
|
||||
{
|
||||
CKey key;
|
||||
if (!GetKey(address, key))
|
||||
return false;
|
||||
vchSecret = key.GetSecret(fCompressed);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
|
||||
typedef std::map<CKeyID, CKey> KeyMap;
|
||||
typedef std::map<CScriptID, CScript > ScriptMap;
|
||||
|
||||
/** Basic key store, that keeps keys in an address->secret map */
|
||||
@ -55,7 +47,7 @@ protected:
|
||||
ScriptMap mapScripts;
|
||||
|
||||
public:
|
||||
bool AddKey(const CKey& key);
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||
bool HaveKey(const CKeyID &address) const
|
||||
{
|
||||
bool result;
|
||||
@ -85,8 +77,7 @@ public:
|
||||
KeyMap::const_iterator mi = mapKeys.find(address);
|
||||
if (mi != mapKeys.end())
|
||||
{
|
||||
keyOut.Reset();
|
||||
keyOut.SetSecret((*mi).second.first, (*mi).second.second);
|
||||
keyOut = mi->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -146,7 +137,7 @@ public:
|
||||
bool Lock();
|
||||
|
||||
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKey(const CKey& key);
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||
bool HaveKey(const CKeyID &address) const
|
||||
{
|
||||
{
|
||||
|
||||
36
src/main.cpp
36
src/main.cpp
@ -367,37 +367,51 @@ bool CTxOut::IsDust() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CTransaction::IsStandard() const
|
||||
bool CTransaction::IsStandard(string& strReason) const
|
||||
{
|
||||
if (nVersion > CTransaction::CURRENT_VERSION)
|
||||
if (nVersion > CTransaction::CURRENT_VERSION) {
|
||||
strReason = "version";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsFinal())
|
||||
if (!IsFinal()) {
|
||||
strReason = "not-final";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extremely large transactions with lots of inputs can cost the network
|
||||
// almost as much to process as they cost the sender in fees, because
|
||||
// computing signature hashes is O(ninputs*txsize). Limiting transactions
|
||||
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
|
||||
unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
|
||||
if (sz >= MAX_STANDARD_TX_SIZE)
|
||||
if (sz >= MAX_STANDARD_TX_SIZE) {
|
||||
strReason = "tx-size";
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
{
|
||||
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
|
||||
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
|
||||
// ~65-byte public keys, plus a few script ops.
|
||||
if (txin.scriptSig.size() > 500)
|
||||
if (txin.scriptSig.size() > 500) {
|
||||
strReason = "scriptsig-size";
|
||||
return false;
|
||||
if (!txin.scriptSig.IsPushOnly())
|
||||
}
|
||||
if (!txin.scriptSig.IsPushOnly()) {
|
||||
strReason = "scriptsig-not-pushonly";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const CTxOut& txout, vout) {
|
||||
if (!::IsStandard(txout.scriptPubKey))
|
||||
if (!::IsStandard(txout.scriptPubKey)) {
|
||||
strReason = "scriptpubkey";
|
||||
return false;
|
||||
if (txout.IsDust())
|
||||
}
|
||||
if (txout.IsDust()) {
|
||||
strReason = "dust";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -660,8 +674,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
|
||||
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
|
||||
|
||||
// Rather not work on nonstandard transactions (unless -testnet)
|
||||
if (!fTestNet && !tx.IsStandard())
|
||||
return error("CTxMemPool::accept() : nonstandard transaction type");
|
||||
string strNonStd;
|
||||
if (!fTestNet && !tx.IsStandard(strNonStd))
|
||||
return error("CTxMemPool::accept() : nonstandard transaction (%s)",
|
||||
strNonStd.c_str());
|
||||
|
||||
// is it already in the memory pool?
|
||||
uint256 hash = tx.GetHash();
|
||||
|
||||
@ -563,7 +563,12 @@ public:
|
||||
/** Check for standard transaction types
|
||||
@return True if all outputs (scriptPubKeys) use only standard transaction forms
|
||||
*/
|
||||
bool IsStandard() const;
|
||||
bool IsStandard(std::string& strReason) const;
|
||||
bool IsStandard() const
|
||||
{
|
||||
std::string strReason;
|
||||
return IsStandard(strReason);
|
||||
}
|
||||
|
||||
/** Check for standard transaction types
|
||||
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
|
||||
@ -143,8 +143,13 @@ void AddressBookPage::setModel(AddressTableModel *model)
|
||||
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
// Set column widths
|
||||
#if QT_VERSION < 0x050000
|
||||
ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
|
||||
ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
|
||||
#else
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
|
||||
#endif
|
||||
|
||||
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
this, SLOT(selectionChanged()));
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
#include "splashscreen.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QTextCodec>
|
||||
#endif
|
||||
#include <QLocale>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
@ -118,9 +120,11 @@ int main(int argc, char *argv[])
|
||||
// Command-line options take precedence:
|
||||
ParseParameters(argc, argv);
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
// Internal string conversion is all UTF-8
|
||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
|
||||
#endif
|
||||
|
||||
Q_INIT_RESOURCE(bitcoin);
|
||||
QApplication app(argc, argv);
|
||||
@ -222,9 +226,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
try
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
// Regenerate startup link, to fix links to old versions
|
||||
// OSX: makes no sense on mac and might also scan/mount external (and sleeping) volumes (can take up some secs)
|
||||
if (GUIUtil::GetStartOnSystemStartup())
|
||||
GUIUtil::SetStartOnSystemStartup(true);
|
||||
#endif
|
||||
|
||||
boost::thread_group threadGroup;
|
||||
|
||||
|
||||
@ -44,7 +44,9 @@
|
||||
#include <QMovie>
|
||||
#include <QTimer>
|
||||
#include <QDragEnterEvent>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QUrl>
|
||||
#endif
|
||||
#include <QMimeData>
|
||||
#include <QStyle>
|
||||
#include <QSettings>
|
||||
|
||||
@ -205,6 +205,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Litecoin to complete"),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "Warning"),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the databases using -reindex to change -txindex"),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"),
|
||||
QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"),
|
||||
};
|
||||
|
||||
@ -13,8 +13,12 @@
|
||||
#include <QDoubleValidator>
|
||||
#include <QFont>
|
||||
#include <QLineEdit>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#else
|
||||
#include <QUrl>
|
||||
#include <QTextDocument> // For Qt::escape
|
||||
#endif
|
||||
#include <QTextDocument> // for Qt::mightBeRichText
|
||||
#include <QAbstractItemView>
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
@ -86,7 +90,13 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
||||
SendCoinsRecipient rv;
|
||||
rv.address = uri.path();
|
||||
rv.amount = 0;
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
QList<QPair<QString, QString> > items = uri.queryItems();
|
||||
#else
|
||||
QUrlQuery uriQuery(uri);
|
||||
QList<QPair<QString, QString> > items = uriQuery.queryItems();
|
||||
#endif
|
||||
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
|
||||
{
|
||||
bool fShouldReturnFalse = false;
|
||||
@ -139,7 +149,11 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
|
||||
|
||||
QString HtmlEscape(const QString& str, bool fMultiLine)
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
QString escaped = Qt::escape(str);
|
||||
#else
|
||||
QString escaped = str.toHtmlEscaped();
|
||||
#endif
|
||||
if(fMultiLine)
|
||||
{
|
||||
escaped = escaped.replace("\n", "<br>\n");
|
||||
@ -176,7 +190,11 @@ QString getSaveFileName(QWidget *parent, const QString &caption,
|
||||
QString myDir;
|
||||
if(dir.isEmpty()) // Default to user documents location
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
|
||||
#else
|
||||
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -408,10 +426,60 @@ bool SetStartOnSystemStartup(bool fAutoStart)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
||||
// TODO: OSX startup stuff; see:
|
||||
// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
|
||||
#elif defined(Q_OS_MAC)
|
||||
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
|
||||
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
|
||||
{
|
||||
// loop through the list of startup items and try to find the bitcoin app
|
||||
CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL);
|
||||
for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
|
||||
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
|
||||
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
|
||||
CFURLRef currentItemURL = NULL;
|
||||
LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL);
|
||||
if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
|
||||
// found
|
||||
CFRelease(currentItemURL);
|
||||
return item;
|
||||
}
|
||||
if(currentItemURL) {
|
||||
CFRelease(currentItemURL);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GetStartOnSystemStartup()
|
||||
{
|
||||
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
||||
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
|
||||
return !!foundItem; // return boolified object
|
||||
}
|
||||
|
||||
bool SetStartOnSystemStartup(bool fAutoStart)
|
||||
{
|
||||
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
||||
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
|
||||
|
||||
if(fAutoStart && !foundItem) {
|
||||
// add bitcoin app to startup item list
|
||||
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL);
|
||||
}
|
||||
else if(!fAutoStart && foundItem) {
|
||||
// remove item
|
||||
LSSharedFileListItemRemove(loginItems, foundItem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
||||
bool GetStartOnSystemStartup() { return false; }
|
||||
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
#include <QMenu>
|
||||
#include <QWidget>
|
||||
|
||||
extern void qt_mac_set_dock_menu(QMenu*);
|
||||
#include <QTemporaryFile>
|
||||
#include <QImageWriter>
|
||||
|
||||
#undef slots
|
||||
#include <Cocoa/Cocoa.h>
|
||||
@ -47,11 +47,12 @@ extern void qt_mac_set_dock_menu(QMenu*);
|
||||
MacDockIconHandler::MacDockIconHandler() : QObject()
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
|
||||
|
||||
this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
|
||||
this->m_dummyWidget = new QWidget();
|
||||
this->m_dockMenu = new QMenu(this->m_dummyWidget);
|
||||
qt_mac_set_dock_menu(this->m_dockMenu);
|
||||
this->setMainWindow(NULL);
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
@ -74,15 +75,29 @@ QMenu *MacDockIconHandler::dockMenu()
|
||||
void MacDockIconHandler::setIcon(const QIcon &icon)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSImage *image;
|
||||
NSImage *image = nil;
|
||||
if (icon.isNull())
|
||||
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
|
||||
else {
|
||||
// generate NSImage from QIcon and use this as dock icon.
|
||||
QSize size = icon.actualSize(QSize(128, 128));
|
||||
QPixmap pixmap = icon.pixmap(size);
|
||||
CGImageRef cgImage = pixmap.toMacCGImageRef();
|
||||
image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];
|
||||
CFRelease(cgImage);
|
||||
|
||||
// write temp file hack (could also be done through QIODevice [memory])
|
||||
QTemporaryFile notificationIconFile;
|
||||
if (!pixmap.isNull() && notificationIconFile.open()) {
|
||||
QImageWriter writer(¬ificationIconFile, "PNG");
|
||||
if (writer.write(pixmap.toImage())) {
|
||||
const char *cString = notificationIconFile.fileName().toUtf8().data();
|
||||
NSString *macString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
|
||||
image = [[NSImage alloc] initWithContentsOfFile:macString];
|
||||
}
|
||||
}
|
||||
|
||||
if(!image) {
|
||||
// if testnet image could not be created, load std. app icon
|
||||
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
|
||||
}
|
||||
}
|
||||
|
||||
[NSApp setApplicationIconImage:image];
|
||||
@ -100,8 +115,11 @@ MacDockIconHandler *MacDockIconHandler::instance()
|
||||
|
||||
void MacDockIconHandler::handleDockIconClickEvent()
|
||||
{
|
||||
this->mainWindow->activateWindow();
|
||||
this->mainWindow->show();
|
||||
if (this->mainWindow)
|
||||
{
|
||||
this->mainWindow->activateWindow();
|
||||
this->mainWindow->show();
|
||||
}
|
||||
|
||||
emit this->dockIconClicked();
|
||||
}
|
||||
|
||||
25
src/qt/macnotificationhandler.h
Normal file
25
src/qt/macnotificationhandler.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef MACNOTIFICATIONHANDLER_H
|
||||
#define MACNOTIFICATIONHANDLER_H
|
||||
#include <QObject>
|
||||
|
||||
/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl).
|
||||
*/
|
||||
class MacNotificationHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** shows a 10.8+ UserNotification in the UserNotificationCenter
|
||||
*/
|
||||
void showNotification(const QString &title, const QString &text);
|
||||
|
||||
/** executes AppleScript */
|
||||
void sendAppleScript(const QString &script);
|
||||
|
||||
/** check if OS can handle UserNotifications */
|
||||
bool hasUserNotificationCenterSupport(void);
|
||||
static MacNotificationHandler *instance();
|
||||
};
|
||||
|
||||
|
||||
#endif // MACNOTIFICATIONHANDLER_H
|
||||
65
src/qt/macnotificationhandler.mm
Normal file
65
src/qt/macnotificationhandler.mm
Normal file
@ -0,0 +1,65 @@
|
||||
#include "macnotificationhandler.h"
|
||||
|
||||
#undef slots
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
void MacNotificationHandler::showNotification(const QString &title, const QString &text)
|
||||
{
|
||||
// check if users OS has support for NSUserNotification
|
||||
if(this->hasUserNotificationCenterSupport()) {
|
||||
// okay, seems like 10.8+
|
||||
QByteArray utf8 = title.toUtf8();
|
||||
char* cString = (char *)utf8.constData();
|
||||
NSString *titleMac = [[NSString alloc] initWithUTF8String:cString];
|
||||
|
||||
utf8 = text.toUtf8();
|
||||
cString = (char *)utf8.constData();
|
||||
NSString *textMac = [[NSString alloc] initWithUTF8String:cString];
|
||||
|
||||
// do everything weak linked (because we will keep <10.8 compatibility)
|
||||
id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init];
|
||||
[userNotification performSelector:@selector(setTitle:) withObject:titleMac];
|
||||
[userNotification performSelector:@selector(setInformativeText:) withObject:textMac];
|
||||
|
||||
id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)];
|
||||
[notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification];
|
||||
|
||||
[titleMac release];
|
||||
[textMac release];
|
||||
[userNotification release];
|
||||
}
|
||||
}
|
||||
|
||||
// sendAppleScript just take a QString and executes it as apple script
|
||||
void MacNotificationHandler::sendAppleScript(const QString &script)
|
||||
{
|
||||
QByteArray utf8 = script.toUtf8();
|
||||
char* cString = (char *)utf8.constData();
|
||||
NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString];
|
||||
|
||||
NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple];
|
||||
NSDictionary *err = nil;
|
||||
[as executeAndReturnError:&err];
|
||||
[as release];
|
||||
[scriptApple release];
|
||||
}
|
||||
|
||||
bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
|
||||
{
|
||||
Class possibleClass = NSClassFromString(@"NSUserNotificationCenter");
|
||||
|
||||
// check if users OS has support for NSUserNotification
|
||||
if(possibleClass!=nil) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MacNotificationHandler *MacNotificationHandler::instance()
|
||||
{
|
||||
static MacNotificationHandler *s_instance = NULL;
|
||||
if (!s_instance)
|
||||
s_instance = new MacNotificationHandler();
|
||||
return s_instance;
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
|
||||
#include "macnotificationhandler.h"
|
||||
#endif
|
||||
|
||||
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
|
||||
@ -47,19 +47,25 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
// Check if Growl is installed (based on Qt's tray icon implementation)
|
||||
CFURLRef cfurl;
|
||||
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
|
||||
if (status != kLSApplicationNotFoundErr) {
|
||||
CFBundleRef bundle = CFBundleCreate(0, cfurl);
|
||||
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
|
||||
if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
|
||||
mode = Growl13;
|
||||
else
|
||||
mode = Growl12;
|
||||
// check if users OS has support for NSUserNotification
|
||||
if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
|
||||
mode = UserNotificationCenter;
|
||||
}
|
||||
else {
|
||||
// Check if Growl is installed (based on Qt's tray icon implementation)
|
||||
CFURLRef cfurl;
|
||||
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
|
||||
if (status != kLSApplicationNotFoundErr) {
|
||||
CFBundleRef bundle = CFBundleCreate(0, cfurl);
|
||||
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
|
||||
if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
|
||||
mode = Growl13;
|
||||
else
|
||||
mode = Growl12;
|
||||
}
|
||||
CFRelease(cfurl);
|
||||
CFRelease(bundle);
|
||||
}
|
||||
CFRelease(cfurl);
|
||||
CFRelease(bundle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te
|
||||
quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
|
||||
quotedText.replace("\\", "\\\\").replace("\"", "\\");
|
||||
QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
|
||||
qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0);
|
||||
MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
|
||||
}
|
||||
|
||||
void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
|
||||
// icon is not supported by the user notification center yet. OSX will use the app icon.
|
||||
MacNotificationHandler::instance()->showNotification(title, text);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
|
||||
@ -286,6 +298,9 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c
|
||||
notifySystray(cls, title, text, icon, millisTimeout);
|
||||
break;
|
||||
#ifdef Q_OS_MAC
|
||||
case UserNotificationCenter:
|
||||
notifyMacUserNotificationCenter(cls, title, text, icon);
|
||||
break;
|
||||
case Growl12:
|
||||
case Growl13:
|
||||
notifyGrowl(cls, title, text, icon);
|
||||
|
||||
@ -46,11 +46,12 @@ public slots:
|
||||
private:
|
||||
QWidget *parent;
|
||||
enum Mode {
|
||||
None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
|
||||
Freedesktop, /**< Use DBus org.freedesktop.Notifications */
|
||||
QSystemTray, /**< Use QSystemTray::showMessage */
|
||||
Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
|
||||
Growl13 /**< Use the Growl 1.3 notification system (Mac only) */
|
||||
None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
|
||||
Freedesktop, /**< Use DBus org.freedesktop.Notifications */
|
||||
QSystemTray, /**< Use QSystemTray::showMessage */
|
||||
Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
|
||||
Growl13, /**< Use the Growl 1.3 notification system (Mac only) */
|
||||
UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
|
||||
};
|
||||
QString programName;
|
||||
Mode mode;
|
||||
@ -63,6 +64,7 @@ private:
|
||||
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
|
||||
#ifdef Q_OS_MAC
|
||||
void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon);
|
||||
void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -45,7 +45,8 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
|
||||
|
||||
/* Window elements init */
|
||||
#ifdef Q_OS_MAC
|
||||
ui->tabWindow->setVisible(false);
|
||||
/* remove Window tab on Mac */
|
||||
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
|
||||
#endif
|
||||
|
||||
/* Display elements init */
|
||||
|
||||
@ -18,7 +18,9 @@
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QStringList>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QUrl>
|
||||
#endif
|
||||
|
||||
using namespace boost;
|
||||
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
#include "optionsmodel.h"
|
||||
|
||||
#include <QPixmap>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QUrl>
|
||||
#endif
|
||||
|
||||
#include <qrencode.h>
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
#include <QTime>
|
||||
#include <QThread>
|
||||
#include <QKeyEvent>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QUrl>
|
||||
#endif
|
||||
#include <QScrollBar>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
@ -93,7 +93,11 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
QStringList formatted;
|
||||
foreach(const SendCoinsRecipient &rcp, recipients)
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
|
||||
#else
|
||||
formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), rcp.label.toHtmlEscaped(), rcp.address));
|
||||
#endif
|
||||
}
|
||||
|
||||
fNewRecipientAllowed = false;
|
||||
|
||||
@ -218,8 +218,8 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
|
||||
ss << strMessageMagic;
|
||||
ss << ui->messageIn_VM->document()->toPlainText().toStdString();
|
||||
|
||||
CKey key;
|
||||
if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig))
|
||||
{
|
||||
ui->signatureIn_VM->setValid(false);
|
||||
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
|
||||
@ -227,7 +227,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr))
|
||||
if (!(CBitcoinAddress(pubkey.GetID()) == addr))
|
||||
{
|
||||
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
|
||||
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "util.h"
|
||||
|
||||
#include <QPainter>
|
||||
#undef loop /* ugh, remove this when the #define loop is gone from util.h */
|
||||
#include <QApplication>
|
||||
|
||||
SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) :
|
||||
|
||||
@ -176,7 +176,11 @@ void TransactionView::setModel(WalletModel *model)
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
|
||||
#if QT_VERSION < 0x050000
|
||||
transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
|
||||
#else
|
||||
transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
|
||||
#endif
|
||||
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,11 +8,9 @@
|
||||
#include "bitcoingui.h"
|
||||
#include "walletstack.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
WalletFrame::WalletFrame(BitcoinGUI *_gui) :
|
||||
QFrame(_gui),
|
||||
gui(_gui),
|
||||
|
||||
@ -17,8 +17,9 @@ class WalletStack;
|
||||
class WalletFrame : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WalletFrame(BitcoinGUI *_gui);
|
||||
explicit WalletFrame(BitcoinGUI *_gui = 0);
|
||||
~WalletFrame();
|
||||
|
||||
void setClientModel(ClientModel *clientModel);
|
||||
|
||||
@ -40,6 +40,7 @@ QT_END_NAMESPACE
|
||||
class WalletStack : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WalletStack(QWidget *parent = 0);
|
||||
~WalletStack();
|
||||
|
||||
@ -21,7 +21,11 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QAction>
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QDesktopServices>
|
||||
#else
|
||||
#include <QStandardPaths>
|
||||
#endif
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
|
||||
@ -232,7 +236,11 @@ void WalletView::encryptWallet(bool status)
|
||||
|
||||
void WalletView::backupWallet()
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
|
||||
#else
|
||||
QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
#endif
|
||||
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
|
||||
if (!filename.isEmpty()) {
|
||||
if (!walletModel->backupWallet(filename)) {
|
||||
|
||||
@ -54,20 +54,18 @@ Value importprivkey(const Array& params, bool fHelp)
|
||||
|
||||
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||
|
||||
CKey key;
|
||||
bool fCompressed;
|
||||
CSecret secret = vchSecret.GetSecret(fCompressed);
|
||||
key.SetSecret(secret, fCompressed);
|
||||
CKeyID vchAddress = key.GetPubKey().GetID();
|
||||
CKey key = vchSecret.GetKey();
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
CKeyID vchAddress = pubkey.GetID();
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
pwalletMain->MarkDirty();
|
||||
pwalletMain->SetAddressBookName(vchAddress, strLabel);
|
||||
|
||||
if (!pwalletMain->AddKey(key))
|
||||
if (!pwalletMain->AddKeyPubKey(key, pubkey))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||
|
||||
|
||||
if (fRescan) {
|
||||
pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
@ -91,9 +89,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
|
||||
CKeyID keyID;
|
||||
if (!address.GetKeyID(keyID))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
|
||||
CSecret vchSecret;
|
||||
bool fCompressed;
|
||||
if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
|
||||
CKey vchSecret;
|
||||
if (!pwalletMain->GetKey(keyID, vchSecret))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
|
||||
return CBitcoinSecret(vchSecret, fCompressed).ToString();
|
||||
return CBitcoinSecret(vchSecret).ToString();
|
||||
}
|
||||
|
||||
@ -407,10 +407,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
bool fGood = vchSecret.SetString(k.get_str());
|
||||
if (!fGood)
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||
CKey key;
|
||||
bool fCompressed;
|
||||
CSecret secret = vchSecret.GetSecret(fCompressed);
|
||||
key.SetSecret(secret, fCompressed);
|
||||
CKey key = vchSecret.GetKey();
|
||||
tempKeystore.AddKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,11 +393,11 @@ Value verifymessage(const Array& params, bool fHelp)
|
||||
ss << strMessageMagic;
|
||||
ss << strMessage;
|
||||
|
||||
CKey key;
|
||||
if (!key.SetCompactSignature(ss.GetHash(), vchSig))
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
|
||||
return false;
|
||||
|
||||
return (key.GetPubKey().GetID() == keyID);
|
||||
return (pubkey.GetID() == keyID);
|
||||
}
|
||||
|
||||
|
||||
@ -738,7 +738,7 @@ static CScript _createmultisig(const Array& params)
|
||||
throw runtime_error(
|
||||
strprintf("not enough keys supplied "
|
||||
"(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
|
||||
std::vector<CKey> pubkeys;
|
||||
std::vector<CPubKey> pubkeys;
|
||||
pubkeys.resize(keys.size());
|
||||
for (unsigned int i = 0; i < keys.size(); i++)
|
||||
{
|
||||
@ -756,16 +756,18 @@ static CScript _createmultisig(const Array& params)
|
||||
if (!pwalletMain->GetPubKey(keyID, vchPubKey))
|
||||
throw runtime_error(
|
||||
strprintf("no full public key for address %s",ks.c_str()));
|
||||
if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
|
||||
if (!vchPubKey.IsFullyValid())
|
||||
throw runtime_error(" Invalid public key: "+ks);
|
||||
pubkeys[i] = vchPubKey;
|
||||
}
|
||||
|
||||
// Case 2: hex public key
|
||||
else if (IsHex(ks))
|
||||
{
|
||||
CPubKey vchPubKey(ParseHex(ks));
|
||||
if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
|
||||
if (!vchPubKey.IsFullyValid())
|
||||
throw runtime_error(" Invalid public key: "+ks);
|
||||
pubkeys[i] = vchPubKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -830,6 +832,7 @@ struct tallyitem
|
||||
{
|
||||
int64 nAmount;
|
||||
int nConf;
|
||||
vector<uint256> txids;
|
||||
tallyitem()
|
||||
{
|
||||
nAmount = 0;
|
||||
@ -871,6 +874,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
||||
tallyitem& item = mapTally[address];
|
||||
item.nAmount += txout.nValue;
|
||||
item.nConf = min(item.nConf, nDepth);
|
||||
item.txids.push_back(wtx.GetHash());
|
||||
}
|
||||
}
|
||||
|
||||
@ -906,6 +910,15 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
||||
obj.push_back(Pair("account", strAccount));
|
||||
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
|
||||
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
|
||||
Array transactions;
|
||||
if (it != mapTally.end())
|
||||
{
|
||||
BOOST_FOREACH(const uint256& item, (*it).second.txids)
|
||||
{
|
||||
transactions.push_back(item.GetHex());
|
||||
}
|
||||
}
|
||||
obj.push_back(Pair("txids", transactions));
|
||||
ret.push_back(obj);
|
||||
}
|
||||
}
|
||||
@ -938,7 +951,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
|
||||
" \"address\" : receiving address\n"
|
||||
" \"account\" : the account of the receiving address\n"
|
||||
" \"amount\" : total amount received by the address\n"
|
||||
" \"confirmations\" : number of confirmations of the most recent transaction included");
|
||||
" \"confirmations\" : number of confirmations of the most recent transaction included\n"
|
||||
" \"txids\" : list of transactions with outputs to the address\n");
|
||||
|
||||
return ListReceived(params, false);
|
||||
}
|
||||
@ -1464,7 +1478,7 @@ public:
|
||||
CPubKey vchPubKey;
|
||||
pwalletMain->GetPubKey(keyID, vchPubKey);
|
||||
obj.push_back(Pair("isscript", false));
|
||||
obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
|
||||
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
|
||||
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ using namespace boost;
|
||||
#include "sync.h"
|
||||
#include "util.h"
|
||||
|
||||
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
|
||||
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
|
||||
|
||||
|
||||
|
||||
@ -1033,13 +1033,13 @@ class CSignatureCache
|
||||
{
|
||||
private:
|
||||
// sigdata_type is (signature hash, signature, public key):
|
||||
typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
|
||||
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
||||
std::set< sigdata_type> setValid;
|
||||
boost::shared_mutex cs_sigcache;
|
||||
|
||||
public:
|
||||
bool
|
||||
Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
|
||||
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
|
||||
|
||||
@ -1050,7 +1050,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
|
||||
void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||
{
|
||||
// DoS prevention: limit cache size to less than 10MB
|
||||
// (~200 bytes per cache entry times 50,000 entries)
|
||||
@ -1081,11 +1081,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
|
||||
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode,
|
||||
const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
|
||||
{
|
||||
static CSignatureCache signatureCache;
|
||||
|
||||
CPubKey pubkey(vchPubKey);
|
||||
if (!pubkey.IsValid())
|
||||
return false;
|
||||
|
||||
// Hash type is one byte tacked on to the end of the signature
|
||||
if (vchSig.empty())
|
||||
return false;
|
||||
@ -1097,18 +1101,14 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
|
||||
|
||||
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
|
||||
|
||||
if (signatureCache.Get(sighash, vchSig, vchPubKey))
|
||||
if (signatureCache.Get(sighash, vchSig, pubkey))
|
||||
return true;
|
||||
|
||||
CKey key;
|
||||
if (!key.SetPubKey(vchPubKey))
|
||||
return false;
|
||||
|
||||
if (!key.Verify(sighash, vchSig))
|
||||
if (!pubkey.Verify(sighash, vchSig))
|
||||
return false;
|
||||
|
||||
if (!(flags & SCRIPT_VERIFY_NOCACHE))
|
||||
signatureCache.Set(sighash, vchSig, vchPubKey);
|
||||
signatureCache.Set(sighash, vchSig, pubkey);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1770,13 +1770,13 @@ void CScript::SetDestination(const CTxDestination& dest)
|
||||
boost::apply_visitor(CScriptVisitor(this), dest);
|
||||
}
|
||||
|
||||
void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
|
||||
void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
*this << EncodeOP_N(nRequired);
|
||||
BOOST_FOREACH(const CKey& key, keys)
|
||||
*this << key.GetPubKey();
|
||||
BOOST_FOREACH(const CPubKey& key, keys)
|
||||
*this << key;
|
||||
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
}
|
||||
|
||||
@ -1801,20 +1801,17 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptCompressor::IsToPubKey(std::vector<unsigned char> &pubkey) const
|
||||
bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
|
||||
{
|
||||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
|
||||
&& (script[1] == 0x02 || script[1] == 0x03)) {
|
||||
pubkey.resize(33);
|
||||
memcpy(&pubkey[0], &script[1], 33);
|
||||
pubkey.Set(&script[1], &script[34]);
|
||||
return true;
|
||||
}
|
||||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
|
||||
&& script[1] == 0x04) {
|
||||
pubkey.resize(65);
|
||||
memcpy(&pubkey[0], &script[1], 65);
|
||||
CKey key;
|
||||
return (key.SetPubKey(CPubKey(pubkey))); // SetPubKey fails if this is not a valid public key, a case that would not be compressible
|
||||
pubkey.Set(&script[1], &script[66]);
|
||||
return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1835,7 +1832,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
|
||||
memcpy(&out[1], &scriptID, 20);
|
||||
return true;
|
||||
}
|
||||
std::vector<unsigned char> pubkey;
|
||||
CPubKey pubkey;
|
||||
if (IsToPubKey(pubkey)) {
|
||||
out.resize(33);
|
||||
memcpy(&out[1], &pubkey[1], 32);
|
||||
@ -1888,17 +1885,16 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
|
||||
return true;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
std::vector<unsigned char> vch(33, 0x00);
|
||||
unsigned char vch[33] = {};
|
||||
vch[0] = nSize - 2;
|
||||
memcpy(&vch[1], &in[0], 32);
|
||||
CKey key;
|
||||
if (!key.SetPubKey(CPubKey(vch)))
|
||||
CPubKey pubkey(&vch[0], &vch[33]);
|
||||
if (!pubkey.Decompress())
|
||||
return false;
|
||||
key.SetCompressedPubKey(false); // Decompress public key
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
assert(pubkey.size() == 65);
|
||||
script.resize(67);
|
||||
script[0] = 65;
|
||||
memcpy(&script[1], &pubkey.Raw()[0], 65);
|
||||
memcpy(&script[1], pubkey.begin(), 65);
|
||||
script[66] = OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
10
src/script.h
10
src/script.h
@ -348,8 +348,10 @@ public:
|
||||
|
||||
CScript& operator<<(const CPubKey& key)
|
||||
{
|
||||
std::vector<unsigned char> vchKey = key.Raw();
|
||||
return (*this) << vchKey;
|
||||
assert(key.size() < OP_PUSHDATA1);
|
||||
insert(end(), (unsigned char)key.size());
|
||||
insert(end(), key.begin(), key.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CBigNum& b)
|
||||
@ -548,7 +550,7 @@ public:
|
||||
|
||||
|
||||
void SetDestination(const CTxDestination& address);
|
||||
void SetMultisig(int nRequired, const std::vector<CKey>& keys);
|
||||
void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||
|
||||
|
||||
void PrintHex() const
|
||||
@ -619,7 +621,7 @@ protected:
|
||||
// form).
|
||||
bool IsToKeyID(CKeyID &hash) const;
|
||||
bool IsToScriptID(CScriptID &hash) const;
|
||||
bool IsToPubKey(std::vector<unsigned char> &pubkey) const;
|
||||
bool IsToPubKey(CPubKey &pubkey) const;
|
||||
|
||||
bool Compress(std::vector<unsigned char> &out) const;
|
||||
unsigned int GetSpecialSize(unsigned int nSize) const;
|
||||
|
||||
@ -133,9 +133,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
|
||||
// Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
|
||||
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
|
||||
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
|
||||
bool fCompressedOut = false;
|
||||
CSecret privkey = secret.GetSecret(fCompressedOut);
|
||||
BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest);
|
||||
CKey privkey = secret.GetKey();
|
||||
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
|
||||
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
|
||||
|
||||
// Private key must be invalid public key
|
||||
@ -187,8 +186,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
|
||||
if(isPrivkey)
|
||||
{
|
||||
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
|
||||
CKey key;
|
||||
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
|
||||
assert(key.IsValid());
|
||||
CBitcoinSecret secret;
|
||||
secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed);
|
||||
secret.SetKey(key);
|
||||
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
|
||||
}
|
||||
else
|
||||
|
||||
@ -73,14 +73,13 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
|
||||
CBitcoinSecret vchSecret;
|
||||
BOOST_CHECK(vchSecret.SetString(strSecret));
|
||||
|
||||
CKey key;
|
||||
bool fCompressed;
|
||||
CSecret secret = vchSecret.GetSecret(fCompressed);
|
||||
key.SetSecret(secret, fCompressed);
|
||||
CKey key = vchSecret.GetKey();
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
|
||||
|
||||
CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);
|
||||
filter.insert(key.GetPubKey().Raw());
|
||||
uint160 hash = key.GetPubKey().GetID();
|
||||
filter.insert(vchPubKey);
|
||||
uint160 hash = pubkey.GetID();
|
||||
filter.insert(vector<unsigned char>(hash.begin(), hash.end()));
|
||||
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
@ -26,8 +26,8 @@ static const string strAddressBad("LRjyUS2uuieEPkhZNdQz8hE5YycxVEqSXA");
|
||||
#ifdef KEY_TESTS_DUMPINFO
|
||||
void dumpKeyInfo(uint256 privkey)
|
||||
{
|
||||
CSecret secret;
|
||||
secret.resize(32);
|
||||
CKey key;
|
||||
key.resize(32);
|
||||
memcpy(&secret[0], &privkey, 32);
|
||||
vector<unsigned char> sec;
|
||||
sec.resize(32);
|
||||
@ -62,29 +62,24 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||
BOOST_CHECK( bsecret2C.SetString(strSecret2C));
|
||||
BOOST_CHECK(!baddress1.SetString(strAddressBad));
|
||||
|
||||
bool fCompressed;
|
||||
CSecret secret1 = bsecret1.GetSecret (fCompressed);
|
||||
BOOST_CHECK(fCompressed == false);
|
||||
CSecret secret2 = bsecret2.GetSecret (fCompressed);
|
||||
BOOST_CHECK(fCompressed == false);
|
||||
CSecret secret1C = bsecret1C.GetSecret(fCompressed);
|
||||
BOOST_CHECK(fCompressed == true);
|
||||
CSecret secret2C = bsecret2C.GetSecret(fCompressed);
|
||||
BOOST_CHECK(fCompressed == true);
|
||||
CKey key1 = bsecret1.GetKey();
|
||||
BOOST_CHECK(key1.IsCompressed() == false);
|
||||
CKey key2 = bsecret2.GetKey();
|
||||
BOOST_CHECK(key2.IsCompressed() == false);
|
||||
CKey key1C = bsecret1C.GetKey();
|
||||
BOOST_CHECK(key1C.IsCompressed() == true);
|
||||
CKey key2C = bsecret2C.GetKey();
|
||||
BOOST_CHECK(key1C.IsCompressed() == true);
|
||||
|
||||
BOOST_CHECK(secret1 == secret1C);
|
||||
BOOST_CHECK(secret2 == secret2C);
|
||||
CPubKey pubkey1 = key1. GetPubKey();
|
||||
CPubKey pubkey2 = key2. GetPubKey();
|
||||
CPubKey pubkey1C = key1C.GetPubKey();
|
||||
CPubKey pubkey2C = key2C.GetPubKey();
|
||||
|
||||
CKey key1, key2, key1C, key2C;
|
||||
key1.SetSecret(secret1, false);
|
||||
key2.SetSecret(secret2, false);
|
||||
key1C.SetSecret(secret1, true);
|
||||
key2C.SetSecret(secret2, true);
|
||||
|
||||
BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));
|
||||
BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
|
||||
BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
|
||||
BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
|
||||
BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
|
||||
|
||||
for (int n=0; n<16; n++)
|
||||
{
|
||||
@ -100,25 +95,25 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||
BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
|
||||
BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK( key1.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!key1.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( key1.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!key1.Verify(hashMsg, sign2C));
|
||||
BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK(!key2.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( key2.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!key2.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( key2.Verify(hashMsg, sign2C));
|
||||
BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK( key1C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!key1C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( key1C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!key1C.Verify(hashMsg, sign2C));
|
||||
BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
|
||||
|
||||
BOOST_CHECK(!key2C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( key2C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!key2C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( key2C.Verify(hashMsg, sign2C));
|
||||
BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
|
||||
BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
|
||||
BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
|
||||
BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
|
||||
|
||||
// compact signatures (with key recovery)
|
||||
|
||||
@ -129,18 +124,17 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||
BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
|
||||
BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
|
||||
|
||||
CKey rkey1, rkey2, rkey1C, rkey2C;
|
||||
CPubKey rkey1, rkey2, rkey1C, rkey2C;
|
||||
|
||||
BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1));
|
||||
BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2));
|
||||
BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C));
|
||||
BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C));
|
||||
BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
|
||||
BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
|
||||
BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
|
||||
BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
|
||||
|
||||
|
||||
BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey());
|
||||
BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey());
|
||||
BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey());
|
||||
BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey());
|
||||
BOOST_CHECK(rkey1 == pubkey1);
|
||||
BOOST_CHECK(rkey2 == pubkey2);
|
||||
BOOST_CHECK(rkey1C == pubkey1C);
|
||||
BOOST_CHECK(rkey2C == pubkey2C);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
|
||||
|
||||
CScript result;
|
||||
result << OP_0; // CHECKMULTISIG bug workaround
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
BOOST_FOREACH(const CKey &key, keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
|
||||
@ -79,6 +79,35 @@ static Value CallRPC(string args)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
{
|
||||
// Test RPC calls for various wallet statistics
|
||||
Value r;
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
|
||||
BOOST_CHECK(r.get_array().empty());
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
|
||||
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(rpc_rawparams)
|
||||
{
|
||||
// Test raw transaction API argument handling
|
||||
@ -88,14 +117,6 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
|
||||
BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
|
||||
BOOST_CHECK_THROW(r=CallRPC("listunspent 0 1 [] extra"), runtime_error);
|
||||
BOOST_CHECK(r.get_array().empty());
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
|
||||
|
||||
@ -145,19 +145,19 @@ BOOST_AUTO_TEST_CASE(set)
|
||||
// Test the CScript::Set* methods
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[4];
|
||||
std::vector<CKey> keys;
|
||||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keys.push_back(key[i]);
|
||||
keys.push_back(key[i].GetPubKey());
|
||||
}
|
||||
|
||||
CScript inner[4];
|
||||
inner[0].SetDestination(key[0].GetPubKey().GetID());
|
||||
inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
|
||||
inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
|
||||
inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
|
||||
inner[1].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
|
||||
inner[2].SetMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
|
||||
inner[3].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));
|
||||
|
||||
CScript outer[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
@ -248,12 +248,12 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
CCoinsViewCache coins(coinsDummy);
|
||||
CBasicKeyStore keystore;
|
||||
CKey key[3];
|
||||
vector<CKey> keys;
|
||||
vector<CPubKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keys.push_back(key[i]);
|
||||
keys.push_back(key[i].GetPubKey());
|
||||
}
|
||||
|
||||
CTransaction txFrom;
|
||||
|
||||
@ -211,7 +211,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
|
||||
// and vice-versa)
|
||||
//
|
||||
result << OP_0;
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
BOOST_FOREACH(const CKey &key, keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
@ -221,7 +221,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
|
||||
return result;
|
||||
}
|
||||
CScript
|
||||
sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
|
||||
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
|
||||
{
|
||||
std::vector<CKey> keys;
|
||||
keys.push_back(key);
|
||||
@ -333,11 +333,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
// Test the CombineSignatures function
|
||||
CBasicKeyStore keystore;
|
||||
vector<CKey> keys;
|
||||
vector<CPubKey> pubkeys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(i%2 == 1);
|
||||
keys.push_back(key);
|
||||
pubkeys.push_back(key.GetPubKey());
|
||||
keystore.AddKey(key);
|
||||
}
|
||||
|
||||
@ -390,7 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
|
||||
// Hardest case: Multisig 2-of-3
|
||||
scriptPubKey.SetMultisig(2, keys);
|
||||
scriptPubKey.SetMultisig(2, pubkeys);
|
||||
keystore.AddCScript(scriptPubKey);
|
||||
SignSignature(keystore, txFrom, txTo, 0);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
||||
|
||||
@ -37,12 +37,12 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
|
||||
scriptSig << OP_0 << Serialize(s1);
|
||||
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
|
||||
|
||||
std::vector<CKey> keys;
|
||||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey k;
|
||||
k.MakeNewKey(true);
|
||||
keys.push_back(k);
|
||||
keys.push_back(k.GetPubKey());
|
||||
}
|
||||
CScript s2;
|
||||
s2.SetMultisig(1, keys);
|
||||
|
||||
12
src/util.h
12
src/util.h
@ -13,8 +13,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#else
|
||||
typedef int pid_t; /* define for Windows compatibility */
|
||||
#endif
|
||||
#include <map>
|
||||
#include <list>
|
||||
@ -22,6 +20,7 @@ typedef int pid_t; /* define for Windows compatibility */
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@ -106,7 +105,11 @@ T* alignup(T* p)
|
||||
|
||||
inline void MilliSleep(int64 n)
|
||||
{
|
||||
#if BOOST_VERSION >= 105000
|
||||
// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50
|
||||
// until fixed in 1.52. Use the deprecated sleep method for the broken case.
|
||||
// See: https://svn.boost.org/trac/boost/ticket/7238
|
||||
|
||||
#if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200)
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
|
||||
#else
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(n));
|
||||
@ -300,7 +303,8 @@ std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
|
||||
template<typename T>
|
||||
inline std::string HexStr(const T& vch, bool fSpaces=false)
|
||||
{
|
||||
return HexStr(vch.begin(), vch.end(), fSpaces);
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ const std::string CLIENT_NAME("Satoshi");
|
||||
// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
|
||||
#ifdef GIT_ARCHIVE
|
||||
# define GIT_COMMIT_ID "$Format:%h$"
|
||||
# define GIT_COMMIT_DATE "$Format:%cD"
|
||||
# define GIT_COMMIT_DATE "$Format:%cD$"
|
||||
#endif
|
||||
|
||||
#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
|
||||
|
||||
@ -32,26 +32,28 @@ CPubKey CWallet::GenerateNewKey()
|
||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
||||
|
||||
RandAddSeedPerfmon();
|
||||
CKey key;
|
||||
key.MakeNewKey(fCompressed);
|
||||
CKey secret;
|
||||
secret.MakeNewKey(fCompressed);
|
||||
|
||||
// Compressed public keys were introduced in version 0.6.0
|
||||
if (fCompressed)
|
||||
SetMinVersion(FEATURE_COMPRPUBKEY);
|
||||
|
||||
if (!AddKey(key))
|
||||
CPubKey pubkey = secret.GetPubKey();
|
||||
if (!AddKeyPubKey(secret, pubkey))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
|
||||
return key.GetPubKey();
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
bool CWallet::AddKey(const CKey& key)
|
||||
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||
{
|
||||
if (!CCryptoKeyStore::AddKey(key))
|
||||
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
if (!IsCrypted())
|
||||
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
|
||||
if (!IsCrypted()) {
|
||||
return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -136,9 +136,9 @@ public:
|
||||
// Generate a new key
|
||||
CPubKey GenerateNewKey();
|
||||
// Adds a key to the store, and saves it to disk.
|
||||
bool AddKey(const CKey& key);
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||
// Adds a key to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
|
||||
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
|
||||
|
||||
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||
|
||||
|
||||
@ -262,52 +262,33 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
}
|
||||
else if (strType == "key" || strType == "wkey")
|
||||
{
|
||||
vector<unsigned char> vchPubKey;
|
||||
CPubKey vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
CKey key;
|
||||
if (strType == "key")
|
||||
if (!vchPubKey.IsValid())
|
||||
{
|
||||
CPrivKey pkey;
|
||||
ssValue >> pkey;
|
||||
key.SetPubKey(vchPubKey);
|
||||
if (!key.SetPrivKey(pkey))
|
||||
{
|
||||
strErr = "Error reading wallet database: CPrivKey corrupt";
|
||||
return false;
|
||||
}
|
||||
if (key.GetPubKey() != vchPubKey)
|
||||
{
|
||||
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
|
||||
return false;
|
||||
}
|
||||
if (!key.IsValid())
|
||||
{
|
||||
strErr = "Error reading wallet database: invalid CPrivKey";
|
||||
return false;
|
||||
}
|
||||
strErr = "Error reading wallet database: CPubKey corrupt";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CKey key;
|
||||
CPrivKey pkey;
|
||||
if (strType == "key")
|
||||
ssValue >> pkey;
|
||||
else {
|
||||
CWalletKey wkey;
|
||||
ssValue >> wkey;
|
||||
key.SetPubKey(vchPubKey);
|
||||
if (!key.SetPrivKey(wkey.vchPrivKey))
|
||||
{
|
||||
strErr = "Error reading wallet database: CPrivKey corrupt";
|
||||
return false;
|
||||
}
|
||||
if (key.GetPubKey() != vchPubKey)
|
||||
{
|
||||
strErr = "Error reading wallet database: CWalletKey pubkey inconsistency";
|
||||
return false;
|
||||
}
|
||||
if (!key.IsValid())
|
||||
{
|
||||
strErr = "Error reading wallet database: invalid CWalletKey";
|
||||
return false;
|
||||
}
|
||||
pkey = wkey.vchPrivKey;
|
||||
}
|
||||
if (!pwallet->LoadKey(key))
|
||||
if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed()))
|
||||
{
|
||||
strErr = "Error reading wallet database: CPrivKey corrupt";
|
||||
return false;
|
||||
}
|
||||
if (key.GetPubKey() != vchPubKey)
|
||||
{
|
||||
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
|
||||
return false;
|
||||
}
|
||||
if (!pwallet->LoadKey(key, vchPubKey))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadKey failed";
|
||||
return false;
|
||||
|
||||
@ -53,18 +53,18 @@ public:
|
||||
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false);
|
||||
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
|
||||
}
|
||||
|
||||
bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false))
|
||||
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
|
||||
return false;
|
||||
if (fEraseUnencryptedKey)
|
||||
{
|
||||
Erase(std::make_pair(std::string("key"), vchPubKey.Raw()));
|
||||
Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw()));
|
||||
Erase(std::make_pair(std::string("key"), vchPubKey));
|
||||
Erase(std::make_pair(std::string("wkey"), vchPubKey));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -101,7 +101,7 @@ public:
|
||||
bool WriteDefaultKey(const CPubKey& vchPubKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::string("defaultkey"), vchPubKey.Raw());
|
||||
return Write(std::string("defaultkey"), vchPubKey);
|
||||
}
|
||||
|
||||
bool ReadPool(int64 nPool, CKeyPool& keypool)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user