...
 
Commits (11)
......@@ -53,3 +53,16 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
}
return false;
}
bool CBasicKeyStore::AddWatchOnly(const CTxDestination &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.insert(dest);
return true;
}
bool CBasicKeyStore::HaveWatchOnly(const CTxDestination &dest) const
{
LOCK(cs_KeyStore);
return setWatchOnly.count(dest) > 0;
}
......@@ -7,10 +7,21 @@
#include "key.h"
#include "sync.h"
#include "script.h" // for CNoDestination
#include <boost/signals2/signal.hpp>
#include <boost/variant.hpp>
class CScript;
/** A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
* * CKeyID: TX_PUBKEYHASH destination
* * CScriptID: TX_SCRIPTHASH destination
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
/** A virtual base class for key stores */
class CKeyStore
{
......@@ -34,10 +45,15 @@ 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;
// Support for Watch-only addresses
virtual bool AddWatchOnly(const CTxDestination &dest) =0;
virtual bool HaveWatchOnly(const CTxDestination &dest) const =0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CTxDestination> WatchOnlySet;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
......@@ -45,6 +61,7 @@ class CBasicKeyStore : public CKeyStore
protected:
KeyMap mapKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
......@@ -86,6 +103,9 @@ public:
virtual bool AddCScript(const CScript& redeemScript);
virtual bool HaveCScript(const CScriptID &hash) const;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
virtual bool AddWatchOnly(const CTxDestination &dest);
virtual bool HaveWatchOnly(const CTxDestination &dest) const;
};
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
......
# Copyright (c) 2009-2010 Satoshi Nakamoto
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
TARGET_PLATFORM:=i686
#TARGET_PLATFORM:=x86_64
DEPSDIR:=/home/michel/legacy/mxe/usr/i686-w64-mingw32.static
CC:=/home/michel/legacy/mxe/usr/bin/i686-w64-mingw32.static-gcc
CXX:=/home/michel/legacy/mxe/usr/bin/i686-w64-mingw32.static-g++
RANLIB=/home/michel/legacy/mxe/usr/bin/i686-w64-mingw32.static-ranlib
STRIP=/home/michel/legacy/mxe/usr/bin/i686-w64-mingw32.static-strip
USE_UPNP:=0
USE_WALLET:=1
INCLUDEPATHS= \
-I"$(CURDIR)" \
-I"$(CURDIR)"/obj \
-I"$(DEPSDIR)/include/" \
LIBPATHS= \
-L"$(DEPSDIR)/lib" \
LIBS= \
-l boost_system-mt \
-l boost_filesystem-mt \
-l boost_program_options-mt \
-l boost_thread_win32-mt \
-l boost_chrono-mt \
-l db_cxx \
-l ssl \
-l crypto \
-l z \
-l pthread \
DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE
DEBUGFLAGS=-g
CFLAGS=-O2 -msse2 -w -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -static-libgcc -static-libstdc++
ifndef USE_UPNP
override USE_UPNP = -
endif
ifneq (${USE_UPNP}, -)
LIBPATHS += -L"$(DEPSDIR)/miniupnpc"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DMINIUPNP_STATICLIB -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi
# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
HEADERS = $(wildcard *.h)
OBJS= \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/init.o \
obj/bitcoind.o \
obj/keystore.o \
obj/core.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
obj/rpcclient.o \
obj/rpcprotocol.o \
obj/rpcserver.o \
obj/rpcmisc.o \
obj/rpcnet.o \
obj/rpcblockchain.o \
obj/rpcrawtransaction.o \
obj/timedata.o \
obj/script.o \
obj/sync.o \
obj/txmempool.o \
obj/util.o \
obj/hash.o \
obj/noui.o \
obj/kernel.o \
obj/pbkdf2.o \
obj/scrypt.o \
obj/scrypt-x86.o \
obj/scrypt-x86_64.o \
obj/chainparams.o
ifeq (${USE_WALLET}, 1)
DEFS += -DENABLE_WALLET
OBJS += \
obj/db.o \
obj/miner.o \
obj/rpcdump.o \
obj/rpcmining.o \
obj/rpcwallet.o \
obj/wallet.o \
obj/walletdb.o
endif
all: blackcoind.exe
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers"
OBJS += obj/txdb-leveldb.o
leveldb/libleveldb.a:
@echo "Building LevelDB ..." && cd leveldb && CC=$(CC) CXX=$(CXX) TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && $(RANLIB) libleveldb.a && $(RANLIB) libmemenv.a && cd ..
obj/txdb-leveldb.o: leveldb/libleveldb.a
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp $(HEADERS)
$(CXX) -c $(CFLAGS) -o $@ $<
blackcoind.exe: $(OBJS:obj/%=obj/%)
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) -lshlwapi
$(STRIP) blackcoind.exe
obj/scrypt-x86.o: scrypt-x86.S
$(CXX) -c $(CFLAGS) -MMD -o $@ $<
obj/scrypt-x86_64.o: scrypt-x86_64.S
$(CXX) -c $(CFLAGS) -MMD -o $@ $<
clean:
-rm -f obj/*.o
-rm -f blackcoind.exe
-rm -f obj/build.h
cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) clean && cd ..
FORCE:
......@@ -46,7 +46,8 @@ qint64 WalletModel::getBalance(const CCoinControl *coinControl) const
std::vector<COutput> vCoins;
wallet->AvailableCoins(vCoins, true, coinControl);
BOOST_FOREACH(const COutput& out, vCoins)
nBalance += out.tx->vout[out.i].nValue;
if(out.fSpendable)
nBalance += out.tx->vout[out.i].nValue;
return nBalance;
}
......@@ -422,7 +423,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vOutputs.push_back(out);
}
}
......@@ -442,7 +443,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vCoins.push_back(out);
}
......@@ -453,11 +454,12 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
{
if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true);
}
CTxDestination address;
if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
continue;
mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
}
}
......
......@@ -152,6 +152,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransaction", 2 },
{ "keypoolrefill", 0 },
{ "importprivkey", 2 },
{ "importaddress", 2 },
{ "checkkernel", 0 },
{ "checkkernel", 1 },
{ "submitblock", 1 },
......
......@@ -157,6 +157,51 @@ Value importprivkey(const Array& params, bool fHelp)
return Value::null;
}
Value importaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
"importaddress <address> [label] [rescan=true]\n"
"Adds an address that can be watched as if it were in your wallet but cannot be used to spend.");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CTxDestination dest;
dest = address.Get();
string strLabel = "";
if (params.size() > 1)
strLabel = params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
if (params.size() > 2)
fRescan = params[2].get_bool();
{
LOCK2(cs_main, pwalletMain->cs_wallet);
// Don't throw error in case an address is already there
if (pwalletMain->HaveWatchOnly(dest))
return Value::null;
pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(dest, strLabel);
if (!pwalletMain->AddWatchOnly(dest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
if (fRescan)
{
pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
pwalletMain->ReacceptWalletTransactions();
}
}
return Value::null;
}
Value importwallet(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
......
......@@ -77,36 +77,45 @@ Value getinfo(const Array& params, bool fHelp)
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
private:
isminetype mine;
public:
DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
Object operator()(const CNoDestination &dest) const { return Object(); }
Object operator()(const CKeyID &keyID) const {
Object obj;
CPubKey vchPubKey;
pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("isscript", false));
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
if (mine == MINE_SPENDABLE) {
pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
return obj;
}
Object operator()(const CScriptID &scriptID) const {
Object obj;
obj.push_back(Pair("isscript", true));
CScript subscript;
pwalletMain->GetCScript(scriptID, subscript);
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
Array a;
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
if (mine == MINE_SPENDABLE) {
CScript subscript;
pwalletMain->GetCScript(scriptID, subscript);
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
Array a;
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
}
return obj;
}
};
......@@ -130,10 +139,11 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
ret.push_back(Pair("ismine", fMine));
if (fMine) {
Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
ret.push_back(Pair("ismine", mine != MINE_NO));
if (mine != MINE_NO) {
ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
ret.insert(ret.end(), detail.begin(), detail.end());
}
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
......@@ -169,10 +179,11 @@ Value validatepubkey(const Array& params, bool fHelp)
ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("iscompressed", isCompressed));
#ifdef ENABLE_WALLET
bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
ret.push_back(Pair("ismine", fMine));
if (fMine) {
Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
ret.push_back(Pair("ismine", mine != MINE_NO));
if (mine != MINE_NO) {
ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY));
Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
ret.insert(ret.end(), detail.begin(), detail.end());
}
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
......
......@@ -222,6 +222,7 @@ Value listunspent(const Array& params, bool fHelp)
}
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable));
results.push_back(entry);
}
......
......@@ -290,6 +290,7 @@ static const CRPCCommand vRPCCommands[] =
{ "dumpwallet", &dumpwallet, true, false, true },
{ "importprivkey", &importprivkey, false, false, true },
{ "importwallet", &importwallet, false, false, true },
{ "importaddress", &importaddress, false, false, true },
{ "listunspent", &listunspent, false, false, true },
{ "settxfee", &settxfee, false, false, true },
{ "getsubsidy", &getsubsidy, true, true, false },
......
......@@ -107,6 +107,7 @@ extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHel
extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendalert(const json_spirit::Array& params, bool fHelp);
......
......@@ -1531,36 +1531,57 @@ public:
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
{
return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest);
if (boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(dest))
return MINE_WATCH_ONLY;
return MINE_NO;
}
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
return MINE_WATCH_ONLY;
return MINE_NO;
}
CKeyID keyID;
switch (whichType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
return false;
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
return keystore.HaveKey(keyID);
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(keyID))
return MINE_WATCH_ONLY;
break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
return keystore.HaveKey(keyID);
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
if (keystore.HaveWatchOnly(keyID))
return MINE_WATCH_ONLY;
break;
case TX_SCRIPTHASH:
{
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript))
return false;
return IsMine(keystore, subscript);
if (keystore.GetCScript(scriptID, subscript)) {
isminetype ret = IsMine(keystore, subscript);
if (ret)
return ret;
}
if (keystore.HaveWatchOnly(scriptID))
return MINE_WATCH_ONLY;
break;
}
case TX_MULTISIG:
{
......@@ -1570,10 +1591,15 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
return HaveKeys(keys, keystore) == keys.size();
if (HaveKeys(keys, keystore) == keys.size())
return MINE_SPENDABLE;
break;
}
}
return false;
if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
return MINE_WATCH_ONLY;
return MINE_NO;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
......
......@@ -14,12 +14,13 @@
#include <boost/foreach.hpp>
#include <boost/variant.hpp>
#include "keystore.h"
#include "key.h"
#include "bignum.h"
#include "util.h"
typedef std::vector<unsigned char> valtype;
class CKeyStore;
class CTransaction;
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
......@@ -62,6 +63,14 @@ enum
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 6),
};
/** IsMine() return codes */
enum isminetype
{
MINE_NO = 0,
MINE_WATCH_ONLY = 1,
MINE_SPENDABLE = 2,
};
// Mandatory script verification flags that all new blocks must comply with for
// them to be valid. (but old blocks may not comply with)
//
......@@ -718,8 +727,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
isminetype IsMine(const CKeyStore& keystore, const CTxDestination &dest);
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
......
......@@ -36,7 +36,7 @@ static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int
wtx->fDebitCached = true;
wtx->nDebitCached = 1;
}
COutput output(wtx, nInput, nAge);
COutput output(wtx, nInput, nAge, true);
vCoins.push_back(output);
}
......
......@@ -140,6 +140,22 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return CCryptoKeyStore::AddCScript(redeemScript);
}
bool CWallet::AddWatchOnly(const CTxDestination &dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
nTimeFirstKey = 1; // No birthday information for watch-only keys.
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
}
bool CWallet::LoadWatchOnly(const CTxDestination &dest)
{
LogPrintf("Loaded %s!\n", CBitcoinAddress(dest).ToString().c_str());
return CCryptoKeyStore::AddWatchOnly(dest);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
......@@ -606,7 +622,7 @@ void CWallet::EraseFromWallet(const uint256 &hash)
}
bool CWallet::IsMine(const CTxIn &txin) const
isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
......@@ -615,11 +631,10 @@ bool CWallet::IsMine(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
if (IsMine(prev.vout[txin.prevout.n]))
return true;
return IsMine(prev.vout[txin.prevout.n]);
}
}
return false;
return MINE_NO;
}
int64_t CWallet::GetDebit(const CTxIn &txin) const
......@@ -1083,7 +1098,7 @@ int64_t CWallet::GetImmatureBalance() const
return nTotal;
}
// populate vCoins with vector of spendable COutputs
// populate vCoins with vector of available COutputs.
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
{
vCoins.clear();
......@@ -1110,11 +1125,12 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth < 0)
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue >= nMinimumInputValue &&
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
isminetype mine = IsMine(pcoin->vout[i]);
if (!(pcoin->IsSpent(i)) && mine != MINE_NO && pcoin->vout[i].nValue >= nMinimumInputValue &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
vCoins.push_back(COutput(pcoin, i, nDepth));
vCoins.push_back(COutput(pcoin, i, nDepth, mine & MINE_SPENDABLE));
}
}
}
}
......@@ -1139,9 +1155,11 @@ void CWallet::AvailableCoinsForStaking(vector<COutput>& vCoins) const
if (pcoin->GetBlocksToMaturity() > 0)
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue >= nMinimumInputValue)
vCoins.push_back(COutput(pcoin, i, nDepth));
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
isminetype mine = IsMine(pcoin->vout[i]);
if (!(pcoin->IsSpent(i)) && mine != MINE_NO && pcoin->vout[i].nValue >= nMinimumInputValue)
vCoins.push_back(COutput(pcoin, i, nDepth, mine & MINE_SPENDABLE));
}
}
}
}
......@@ -1233,8 +1251,11 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime,
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
BOOST_FOREACH(COutput output, vCoins)
BOOST_FOREACH(const COutput &output, vCoins)
{
if (!output.fSpendable)
continue;
const CWalletTx *pcoin = output.tx;
if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
......@@ -1331,6 +1352,8 @@ bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set<pai
{
BOOST_FOREACH(const COutput& out, vCoins)
{
if(!out.fSpendable)
continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
......@@ -1355,6 +1378,9 @@ bool CWallet::SelectCoinsForStaking(int64_t nTargetValue, set<pair<const CWallet
BOOST_FOREACH(COutput output, vCoins)
{
if (!output.fSpendable)
continue;
const CWalletTx *pcoin = output.tx;
int i = output.i;
......
......@@ -165,6 +165,11 @@ public:
bool AddCScript(const CScript& redeemScript);
bool LoadCScript(const CScript& redeemScript);
// Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CTxDestination &dest);
// Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CTxDestination &dest);
bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
......@@ -223,9 +228,9 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, int64_t> GetAddressBalances();
bool IsMine(const CTxIn& txin) const;
isminetype IsMine(const CTxIn& txin) const;
int64_t GetDebit(const CTxIn& txin) const;
bool IsMine(const CTxOut& txout) const
isminetype IsMine(const CTxOut& txout) const
{
return ::IsMine(*this, txout.scriptPubKey);
}
......@@ -727,10 +732,11 @@ public:
const CWalletTx *tx;
int i;
int nDepth;
bool fSpendable;
COutput(const CWalletTx *txIn, int iIn, int nDepthIn)
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
{
tx = txIn; i = iIn; nDepth = nDepthIn;
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
}
std::string ToString() const
......
......@@ -101,6 +101,12 @@ bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
bool CWalletDB::WriteWatchOnly(const CTxDestination &dest)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("watch"), CBitcoinAddress(dest).ToString()), '1');
}
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
......@@ -395,6 +401,19 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
wss.fAnyUnordered = true;
}
}
else if (strType == "watch")
{
std::string strAddress;
ssKey >> strAddress;
char fYes;
ssValue >> fYes;
if (fYes == '1')
pwallet->LoadWatchOnly(CBitcoinAddress(strAddress).Get());
// Watch-only addresses have no birthday information for now,
// so set the wallet birthday to the beginning of time.
pwallet->nTimeFirstKey = 1;
}
else if (strType == "key" || strType == "wkey")
{
CPubKey vchPubKey;
......
......@@ -7,6 +7,7 @@
#include "db.h"
#include "key.h"
#include "keystore.h"
#include <list>
#include <string>
......@@ -91,6 +92,8 @@ public:
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
bool WriteWatchOnly(const CTxDestination &dest);
bool WriteBestBlock(const CBlockLocator& locator);
bool ReadBestBlock(CBlockLocator& locator);
......