Skip to content

Commit

Permalink
Add link from old keyimage to new key image - allows us to do lookups…
Browse files Browse the repository at this point in the history
… on both
  • Loading branch information
SDCDev committed Feb 29, 2016
1 parent 023f622 commit ae7370e
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 48 deletions.
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ bool CTransaction::IsStandard() const

if (nVersion != ANON_TXN_VERSION
|| nRingSize < 1
|| nRingSize > (int)MAX_RING_SIZE
|| nRingSize > (Params().IsProtocolV3(pindexBest->nHeight) ? (int)MAX_RING_SIZE : (int)MAX_RING_SIZE_OLD)
|| txin.scriptSig.size() > sizeof(COutPoint) + 2 + (33 + 32 + 32) * nRingSize)
{
LogPrintf("IsStandard() anon txin failed.\n");
Expand Down Expand Up @@ -2243,7 +2243,7 @@ bool CTransaction::CheckAnonInputs(CTxDB& txdb, int64_t& nSumValue, bool& fInval
int64_t nCoinValue = -1;
int nRingSize = txin.ExtractRingSize();
if (nRingSize < 1
||nRingSize > (int)MAX_RING_SIZE)
||nRingSize > (Params().IsProtocolV3(pindexBest->nHeight) ? (int)MAX_RING_SIZE : (int)MAX_RING_SIZE_OLD))
{
LogPrintf("CheckAnonInputs(): Error input %d ringsize %d not in range [%d, %d].\n", i, nRingSize, MIN_RING_SIZE, MAX_RING_SIZE);
fInvalid = true; return false;
Expand Down
6 changes: 3 additions & 3 deletions src/ringsig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,15 @@ int getOldKeyImage(CPubKey &publicKey, ec_point &keyImage)
return 0;
}

static int hashToEC(const uint8_t *p, uint32_t len, BIGNUM *bnTmp, EC_POINT *ptRet)
static int hashToEC(const uint8_t *p, uint32_t len, BIGNUM *bnTmp, EC_POINT *ptRet, bool fNew=false)
{
// - bn(hash(data)) * (G + bn1)
uint256 pkHash = Hash(p, p + len);

if (!bnTmp || !BN_bin2bn(pkHash.begin(), EC_SECRET_SIZE, bnTmp))
return errorN(1, "%s: BN_bin2bn failed.", __func__);

if (!EC_POINT_mul(Params().IsProtocolV3(pindexBest->nHeight) ? ecGrpKi : ecGrp, ptRet, bnTmp, NULL, NULL, bnCtx))
if (!EC_POINT_mul(fNew || Params().IsProtocolV3(nBestHeight) ? ecGrpKi : ecGrp, ptRet, bnTmp, NULL, NULL, bnCtx))
return errorN(1, "%s: EC_POINT_mul failed.", __func__);

return 0;
Expand All @@ -256,7 +256,7 @@ int generateKeyImage(ec_point &publicKey, ec_secret secret, ec_point &keyImage)
&& (rv = errorN(1, "%s: EC_POINT_new failed.", __func__)))
goto End;

if (hashToEC(&publicKey[0], publicKey.size(), bnTmp, hG)
if (hashToEC(&publicKey[0], publicKey.size(), bnTmp, hG, true)
&& (rv = errorN(1, "%s: hashToEC failed.", __func__)))
goto End;

Expand Down
55 changes: 34 additions & 21 deletions src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,7 +1301,9 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)

int ret = 0;
int64_t nTimeFirstKeyTmp = nTimeFirstKey;
int nCurBestHeight = nBestHeight;

fReindexing = true;
// When scanning from a certain height, people could be interested in rebuilding stealth address and anonymous transaction cache.
if(pindexStart->nHeight > 1)
nTimeFirstKey = pindexStart->nTime;
Expand All @@ -1321,6 +1323,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)

CBlock block;
block.ReadFromDisk(pindex, true);
nBestHeight = pindex->nHeight;
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
uint256 hash = tx.GetHash();
Expand All @@ -1333,6 +1336,8 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)

// Reset nTimeFirstKey
nTimeFirstKey = nTimeFirstKeyTmp;
nBestHeight = nCurBestHeight;
fReindexing = false;

return ret;
}
Expand Down Expand Up @@ -2856,18 +2861,19 @@ static int GetBlockHeightFromHash(const uint256& blockHash)
return 0;
}

static int IsAnonCoinCompromised(CTxDB &txdb, CPubKey &pubKey, CAnonOutput &ao, ec_point &pkSpentImage)
static int IsAnonCoinCompromised(CTxDB *txdb, CPubKey &pubKey, CAnonOutput &ao, ec_point &vchSpentImage)
{
// check if its been compromised (signer known)
CKeyImageSpent kis;
ec_point pkImage;
bool fInMempool;

getOldKeyImage(pubKey, pkImage);

if (pkSpentImage == pkImage)
if (vchSpentImage == pkImage || GetKeyImage(txdb, pkImage, kis, fInMempool))
{
ao.nCompromised = 1;
txdb.WriteAnonOutput(pubKey, ao);
txdb->WriteAnonOutput(pubKey, ao);
if(fDebugRingSig)
LogPrintf("Spent key image, mark as compromised: %s\n", pubKey.GetID().ToString());
return 1;
Expand Down Expand Up @@ -2910,7 +2916,7 @@ bool CWallet::UpdateAnonTransaction(CTxDB *ptxdb, const CTransaction& tx, const
CTxIndex txindex;

const uint8_t *pPubkeys;
if (s.size() == 2 + EC_SECRET_SIZE + (EC_COMPRESSED_SIZE + EC_SECRET_SIZE) * nRingSize)
if (nRingSize > 1 && s.size() == 2 + EC_SECRET_SIZE + (EC_COMPRESSED_SIZE + EC_SECRET_SIZE) * nRingSize)
{
pPubkeys = &s[2 + EC_SECRET_SIZE + EC_SECRET_SIZE * nRingSize];
} else
Expand All @@ -2921,16 +2927,15 @@ bool CWallet::UpdateAnonTransaction(CTxDB *ptxdb, const CTransaction& tx, const
return error("%s: Input %d scriptSig too small.", __func__, i);

pkRingCoin = CPubKey(&pPubkeys[0 * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE);

if (!ptxdb->ReadAnonOutput(pkRingCoin, ao))
{
LogPrintf("UpdateAnonTransaction(): Error input %u AnonOutput %s not found.\n", i, pkRingCoin.GetID().ToString());
//LogPrintf("%s, %s\n", pkRingCoin.GetID().ToString(), CBitcoinAddress(pkRingCoin.GetID()).ToString());
return false;
};

int64_t nCoinValue = ao.nValue;


spentKeyImage.txnHash = txnHash;
spentKeyImage.inputNo = i;
spentKeyImage.nValue = nCoinValue;
Expand Down Expand Up @@ -3190,7 +3195,11 @@ bool CWallet::ProcessAnonTransaction(CWalletDB *pwdb, CTxDB *ptxdb, const CTrans


COwnedAnonOutput oao;
if (pwdb->ReadOwnedAnonOutput(vchImage, oao))
ec_point vchNewImage;
if (!pwdb->ReadOldOutputLink(vchImage, vchNewImage))
vchNewImage = vchImage;

if (pwdb->ReadOwnedAnonOutput(vchNewImage, oao))
{
if (fDebugRingSig)
LogPrintf("%s: input %d keyimage %s found in wallet (owned).\n", __func__, i, HexStr(vchImage).c_str());
Expand Down Expand Up @@ -3219,7 +3228,7 @@ bool CWallet::ProcessAnonTransaction(CWalletDB *pwdb, CTxDB *ptxdb, const CTrans
};

oao.fSpent = true;
if (!pwdb->WriteOwnedAnonOutput(vchImage, oao))
if (!pwdb->WriteOwnedAnonOutput(vchNewImage, oao))
{
return error("%s: Input %d WriteOwnedAnonOutput failed %s.", __func__, i, HexStr(vchImage).c_str());
};
Expand Down Expand Up @@ -3256,7 +3265,7 @@ bool CWallet::ProcessAnonTransaction(CWalletDB *pwdb, CTxDB *ptxdb, const CTrans
if (!ptxdb->ReadAnonOutput(pkRingCoin, ao))
return error("%s: Input %u AnonOutput %s not found, rsType: %d.", __func__, i, HexStr(pkRingCoin).c_str(), rsType);

if (IsAnonCoinCompromised(*ptxdb, pkRingCoin, ao, vchImage) and Params().IsProtocolV3(nBestHeight))
if (IsAnonCoinCompromised(ptxdb, pkRingCoin, ao, vchImage) and Params().IsProtocolV3(nBestHeight))
return error("%s: Found spent pubkey at index %u: AnonOutput: %s, rsType: %d.", __func__, i, HexStr(pkRingCoin).c_str(), rsType);

if (nCoinValue == -1)
Expand Down Expand Up @@ -3324,8 +3333,8 @@ bool CWallet::ProcessAnonTransaction(CWalletDB *pwdb, CTxDB *ptxdb, const CTrans

const CScript &s = txout.scriptPubKey;

CPubKey pkCoin = CPubKey(&s[2+1], EC_COMPRESSED_SIZE);
CKeyID ckCoinId = pkCoin.GetID();
CPubKey pkCoin = CPubKey(&s[2+1], EC_COMPRESSED_SIZE);
CKeyID ckCoinId = pkCoin.GetID();

COutPoint outpoint = COutPoint(tx.GetHash(), i);

Expand Down Expand Up @@ -3565,22 +3574,24 @@ bool CWallet::ProcessAnonTransaction(CWalletDB *pwdb, CTxDB *ptxdb, const CTrans

// -- store keyImage
ec_point pkImage;
ec_point pkOldImage;
getOldKeyImage(pkCoin, pkOldImage);
if (generateKeyImage(pkTestSpendR, sSpendR, pkImage) != 0)
{
LogPrintf("%s: generateKeyImage() failed.\n", __func__);
continue;
};
}

bool fSpentAOut = false;
bool fInMemPool;
CKeyImageSpent kis;
if (GetKeyImage(ptxdb, pkImage, kis, fInMemPool)
&& !fInMemPool) // shouldn't be possible for kis to be in mempool here
fSpentAOut = true;
bool fInMemPool;
bool fSpentAOut = false;
// shouldn't be possible for kis to be in mempool here
fSpentAOut = (GetKeyImage(ptxdb, pkImage, kis, fInMemPool));

COwnedAnonOutput oao(outpoint, fSpentAOut);

if (!pwdb->WriteOwnedAnonOutput(pkImage, oao)
||!pwdb->WriteOldOutputLink(pkOldImage, pkImage)
||!pwdb->WriteOwnedAnonOutputLink(pkCoin, pkImage))
{
LogPrintf("%s: WriteOwnedAnonOutput() failed.\n", __func__);
Expand Down Expand Up @@ -4201,7 +4212,7 @@ int CWallet::PickHidingOutputs(int64_t nValue, int nRingSize, CPubKey& pkCoin, i

if ((anonOutput.nBlockHeight > 0 && nBestHeight - anonOutput.nBlockHeight >= MIN_ANON_SPEND_DEPTH)
&& anonOutput.nValue == nValue
&& (Params().IsProtocolV3(nBestHeight) ? anonOutput.nCompromised == 0 : true))
&& anonOutput.nCompromised == 0)
try { vHideKeys.push_back(pkAo); } catch (std::exception& e)
{
LogPrintf("Error: PickHidingOutputs() vHideKeys.push_back threw: %s.\n", e.what());
Expand Down Expand Up @@ -5023,8 +5034,7 @@ bool CWallet::ExpandLockedAnonOutput(CWalletDB *pwdb, CKeyID &ckeyId, CLockedAno
bool fInMemPool;
CAnonOutput ao;
txdb.ReadAnonOutput(pkCoin, ao);
if (GetKeyImage(&txdb, pkImage, kis, fInMemPool)
&& !fInMemPool) // shouldn't be possible for kis to be in mempool here
if (GetKeyImage(&txdb, pkImage, kis, fInMemPool) && !fInMemPool) // shouldn't be possible for kis to be in mempool here
{
fSpentAOut = true;

Expand Down Expand Up @@ -5535,15 +5545,18 @@ bool CWallet::EraseAllAnonData()
uint32_t nLao = 0;
uint32_t nOao = 0;
uint32_t nOal = 0;
uint32_t nOol = 0;

LogPrintf("Erasing locked anon outputs.\n");
walletdb.EraseRange(std::string("lao"), nLao);
LogPrintf("Erasing owned anon outputs.\n");
walletdb.EraseRange(std::string("oao"), nOao);
LogPrintf("Erasing anon output links.\n");
walletdb.EraseRange(std::string("oal"), nOal);
LogPrintf("Erasing old output links.\n");
walletdb.EraseRange(std::string("ool"), nOol);

LogPrintf("EraseAllAnonData() Complete, %d %d %d %d %d, %15dms\n", nAo, nKi, nLao, nOao, nOal, GetTimeMillis() - nStart);
LogPrintf("EraseAllAnonData() Complete, %d %d %d %d %d %d, %15dms\n", nAo, nKi, nLao, nOao, nOal, nOol, GetTimeMillis() - nStart);
return true;
};

Expand Down
62 changes: 40 additions & 22 deletions src/walletdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ class CStealthKeyMetadata
{
// -- used to get secret for keys created by stealth transaction with wallet locked
public:
CStealthKeyMetadata() {};
CStealthKeyMetadata() {}

CStealthKeyMetadata(CPubKey pkEphem_, CPubKey pkScan_)
{
pkEphem = pkEphem_;
pkScan = pkScan_;
};
}

CPubKey pkEphem;
CPubKey pkScan;
Expand All @@ -124,14 +124,14 @@ class CLockedAnonOutput
// expand key for anon output received with wallet locked
// stored in walletdb, key is pubkey hash160
public:
CLockedAnonOutput() {};
CLockedAnonOutput() {}

CLockedAnonOutput(CPubKey pkEphem_, CPubKey pkScan_, COutPoint outpoint_)
{
pkEphem = pkEphem_;
pkScan = pkScan_;
outpoint = outpoint_;
};
}

CPubKey pkEphem;
CPubKey pkScan;
Expand All @@ -151,15 +151,15 @@ class COwnedAnonOutput
// stored in walletdb, key is keyimage
// TODO: store nValue?
public:
COwnedAnonOutput() {};
COwnedAnonOutput() {}

COwnedAnonOutput(COutPoint outpoint_, bool fSpent_)
{
outpoint = outpoint_;
fSpent = fSpent_;
};
}

std::vector<uint8_t> vchImage;
ec_point vchImage;
int64_t nValue;

COutPoint outpoint;
Expand Down Expand Up @@ -230,7 +230,7 @@ class CWalletDB : public CDB
if (ret != 0)
{
LogPrintf("CursorPut ret %d - %s\n", ret, DbEnv::strerror(ret));
};
}
// Clear memory in case it was a private key
memset(datValue.get_data(), 0, datValue.get_size());

Expand Down Expand Up @@ -259,53 +259,71 @@ class CWalletDB : public CDB
bool ReadLockedAnonOutput(const CKeyID& keyId, CLockedAnonOutput& lockedAo)
{
return Read(std::make_pair(std::string("lao"), keyId), lockedAo);
};
}

bool WriteLockedAnonOutput(const CKeyID& keyId, const CLockedAnonOutput& lockedAo)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("lao"), keyId), lockedAo, true);
};
}

bool EraseLockedAnonOutput(const CKeyID& keyId)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("lao"), keyId));
};
}

bool ReadOwnedAnonOutput(const std::vector<uint8_t>& vchImage, COwnedAnonOutput& ownAo)
bool ReadOwnedAnonOutput(const ec_point& vchImage, COwnedAnonOutput& ownAo)
{
return Read(std::make_pair(std::string("oao"), vchImage), ownAo);
};
}

bool WriteOwnedAnonOutput(const std::vector<uint8_t>& vchImage, const COwnedAnonOutput& ownAo)
bool WriteOwnedAnonOutput(const ec_point& vchImage, const COwnedAnonOutput& ownAo)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("oao"), vchImage), ownAo, true);
};
}

bool EraseOwnedAnonOutput(const std::vector<uint8_t>& vchImage)
bool EraseOwnedAnonOutput(const ec_point& vchImage)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("oao"), vchImage));
};
}

bool ReadOwnedAnonOutputLink(const CPubKey& pkCoin, std::vector<uint8_t>& vchImage)
bool ReadOwnedAnonOutputLink(const CPubKey& pkCoin, ec_point& vchImage)
{
return Read(std::make_pair(std::string("oal"), pkCoin), vchImage);
};
}

bool WriteOwnedAnonOutputLink(const CPubKey& pkCoin, const std::vector<uint8_t>& vchImage)
bool WriteOwnedAnonOutputLink(const CPubKey& pkCoin, const ec_point& vchImage)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("oal"), pkCoin), vchImage, true);
};
}

bool EraseOwnedAnonOutputLink(const CPubKey& pkCoin)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("oal"), pkCoin));
};
}

bool ReadOldOutputLink(const ec_point& pkImage, ec_point& vchImage)
{
return Read(std::make_pair(std::string("ool"), pkImage), vchImage);
}

bool WriteOldOutputLink(const ec_point& pkImage, const ec_point& vchImage)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("ool"), pkImage), vchImage, true);
}

bool EraseOldOutputLink(const ec_point& pkImage)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("ool"), pkImage));
}


bool WriteStealthKeyMeta(const CKeyID& keyId, const CStealthKeyMetadata& sxKeyMeta)
{
Expand Down

0 comments on commit ae7370e

Please sign in to comment.