Permalink
Browse files

multi-colored wallets

Now coins of all colors can be kept in one wallet which would
select coins of relevant color when doing queries and operations.
(Currently selecting different color requires a restart, but that's
just user interface problem.)
Almost completely untested, I've only checked that GetBalance
returns correct value depending on color selected.
  • Loading branch information...
killerstorm committed Sep 7, 2012
1 parent 73b8747 commit cc062e447f626df3dbe2324c312080a619ebf811
Showing with 62 additions and 18 deletions.
  1. +0 −4 src/db.h
  2. +1 −1 src/init.cpp
  3. +9 −0 src/main.h
  4. +33 −8 src/wallet.cpp
  5. +19 −5 src/wallet.h
@@ -291,10 +291,6 @@ class CDB
};


#define COLOR_UNKNOWN -2
#define COLOR_MIXED -1
#define COLOR_DEFAULT 0

/** Access to the transaction database (blkindex.dat) */
class CTxDB : public CDB
{
@@ -651,7 +651,7 @@ bool AppInit2()
int wallet_color = GetArg("-walletcolor", 0);

pwalletMain = new CWallet(wallet_name);
pwalletMain->SetColor(wallet_color);
pwalletMain->SetCurrentColor(wallet_color);
int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
@@ -380,6 +380,15 @@ enum GetMinFee_mode
GMF_SEND,
};

typedef int txcolor_t;

enum TxColor
{
COLOR_UNKNOWN = -2,
COLOR_MIXED = -1,
COLOR_DEFAULT = 0
};

typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx;

/** The basic transaction that is broadcasted on the network and contained in
@@ -303,6 +303,7 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries,
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* wtx = &((*it).second);
if (!wtx->MatchesCurrentColor()) continue;
txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
}
acentries.clear();
@@ -431,6 +432,11 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
if (wtxIn.color != wtx.color)
{
wtx.color = wtxIn.color;
fUpdated = true;
}
fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
}

@@ -481,19 +487,22 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
bool CWallet::AddToWalletIfInvolvingMe(CTxDB& txdb, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
{
uint256 hash = tx.GetHash();

{
LOCK(cs_wallet);
bool fExisted = mapWallet.count(hash);

if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
int txcolor = tx.GetColor(txdb);

if (!((txcolor == color) || ((txcolor == COLOR_MIXED) && (color == 0))))
return false; // wrong color

CWalletTx wtx(this,tx);

// we do it manually since reading color requires txdb
// and transaction has no access to it
// (or rather, reading color via its own txdb causes deadlock)
txcolor_t color = tx.GetColor(txdb);
wtx.SetColor(color);

// Get merkle branch if transaction was found in a block
if (pblock)
wtx.SetMerkleBranch(pblock);
@@ -570,6 +579,15 @@ bool CWallet::IsChange(const CTxOut& txout) const
return false;
}

bool CWalletTx::MatchesCurrentColor(txcolor_t currentColor) const
{
return (color == currentColor)
|| ((currentColor == COLOR_DEFAULT) && (color == COLOR_MIXED))
|| (currentColor == COLOR_MIXED)
|| (currentColor == COLOR_UNKNOWN);

}

int64 CWalletTx::GetTxTime() const
{
int64 n = nTimeSmart;
@@ -936,7 +954,7 @@ int64 CWallet::GetBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsFinal() && pcoin->IsConfirmed())
if (pcoin->MatchesCurrentColor() && pcoin->IsFinal() && pcoin->IsConfirmed())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -952,7 +970,7 @@ int64 CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
if (pcoin->MatchesCurrentColor() && (!pcoin->IsFinal() || !pcoin->IsConfirmed()))
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -994,6 +1012,9 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;

if (!pcoin->MatchesCurrentColor())
continue;

for (unsigned int i = 0; i < pcoin->vout.size(); i++)
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0)
vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
@@ -1164,6 +1185,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
return false;

wtxNew.BindWallet(this);
wtxNew.SetColor(currentColor);

{
LOCK2(cs_main, cs_wallet);
@@ -1638,6 +1660,9 @@ std::map<CTxDestination, int64> CWallet::GetAddressBalances()
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;

if (!pcoin->MatchesCurrentColor())
continue;

int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
continue;
@@ -86,8 +86,7 @@ class CWallet : public CCryptoKeyStore

std::set<int64> setKeyPool;

int color;

txcolor_t currentColor;

typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@@ -100,7 +99,7 @@ class CWallet : public CCryptoKeyStore
fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
color = 0;
currentColor = COLOR_UNKNOWN;
}
CWallet(std::string strWalletFileIn)
{
@@ -110,7 +109,7 @@ class CWallet : public CCryptoKeyStore
fFileBacked = true;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
color = 0;
currentColor = COLOR_UNKNOWN;
}

std::map<uint256, CWalletTx> mapWallet;
@@ -293,7 +292,7 @@ class CWallet : public CCryptoKeyStore
// get the current wallet format (the oldest client version guaranteed to understand this wallet)
int GetVersion() { return nWalletVersion; }

void SetColor(int color) { this->color = color; }
void SetCurrentColor(int color) { this->currentColor = color; }

/** Address book entry changed.
* @note called with lock cs_wallet held.
@@ -373,6 +372,9 @@ class CWalletTx : public CMerkleTx
std::string strFromAccount;
std::vector<char> vfSpent; // which outputs are already spent
int64 nOrderPos; // position in ordered transaction list
txcolor_t color;



// memory only
mutable bool fDebitCached;
@@ -425,6 +427,7 @@ class CWalletTx : public CMerkleTx
nAvailableCreditCached = 0;
nChangeCached = 0;
nOrderPos = -1;
color = COLOR_UNKNOWN;
}

IMPLEMENT_SERIALIZE
@@ -437,6 +440,7 @@ class CWalletTx : public CMerkleTx
if (!fRead)
{
pthis->mapValue["fromaccount"] = pthis->strFromAccount;
pthis->mapValue["color"] = i64tostr(pthis->color);

std::string str;
BOOST_FOREACH(char f, vfSpent)
@@ -465,6 +469,7 @@ class CWalletTx : public CMerkleTx
if (fRead)
{
pthis->strFromAccount = pthis->mapValue["fromaccount"];
pthis->color = atoi64(pthis->mapValue["color"].c_str());

if (mapValue.count("spent"))
BOOST_FOREACH(char c, pthis->mapValue["spent"])
@@ -481,6 +486,7 @@ class CWalletTx : public CMerkleTx
pthis->mapValue.erase("version");
pthis->mapValue.erase("spent");
pthis->mapValue.erase("n");
pthis->mapValue.erase("color");
pthis->mapValue.erase("timesmart");
)

@@ -655,6 +661,14 @@ class CWalletTx : public CMerkleTx
return true;
}

void SetColor(txcolor_t color) { this->color = color; }
bool MatchesCurrentColor(txcolor_t currentColor) const;
bool MatchesCurrentColor() const
{
return MatchesCurrentColor(pwallet->currentColor);
}


bool WriteToDisk();

int64 GetTxTime() const;

0 comments on commit cc062e4

Please sign in to comment.