use txIndex instead of coins to keep track of commited tx

This commit is contained in:
Miguel Freitas 2013-07-19 01:00:06 -03:00
parent 4652b9f01b
commit 311b1d7eaa
4 changed files with 30 additions and 105 deletions

View File

@ -521,27 +521,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
} }
{ {
// [MF] FIXME: check txIndex here instead of coins
CCoinsView dummy;
CCoinsViewCache view(dummy);
{
LOCK(cs);
CCoinsViewMemPool viewMemPool(*pcoinsTip, *this);
view.SetBackend(viewMemPool);
// do we already have it? // do we already have it?
if (view.HaveCoins(tx.GetUsernameHash())) if( pblocktree->HaveTxIndex(userhash) )
return false; return false;
// Bring the best block into scope
view.GetBestBlock();
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Continuously rate-limit free transactions // Continuously rate-limit free transactions
@ -716,31 +699,6 @@ bool GetTransaction(const uint256 &userhash, CTransaction &txOut, uint256 &hashB
return true; return true;
} }
} }
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
CCoinsViewCache &view = *pcoinsTip;
CCoins coins;
if (view.GetCoins(userhash, coins))
nHeight = coins.nHeight;
}
if (nHeight > 0)
pindexSlow = FindBlockByHeight(nHeight);
}
}
if (pindexSlow) {
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow)) {
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
if (tx.GetHash() == userhash) {
txOut = tx;
hashBlock = pindexSlow->GetBlockHash();
return true;
}
}
}
} }
return false; return false;
@ -1136,57 +1094,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
return error("DisconnectBlock() : block and undo data inconsistent"); return error("DisconnectBlock() : block and undo data inconsistent");
// undo transactions in reverse order // undo transactions in reverse order
// [MF] FIXME: remove from txIndex // [MF] just remove from txIndex, no more coins
for (int i = block.vtx.size() - 1; i >= 0; i--) { for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = block.vtx[i]; const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash();
// check that all outputs are available if( i > 0 && pblocktree->EraseTxIndex(tx.GetUsernameHash()) ) {
if (!view.HaveCoins(tx.GetUsernameHash())) { fClean = fClean && error("DisconnectBlock() : error erasing txIndex");
fClean = fClean && error("DisconnectBlock() : outputs still spent? database corrupted");
view.SetCoins(tx.GetUsernameHash(), CCoins());
}
CCoins &outs = view.GetCoins(tx.GetUsernameHash());
CCoins outsBlock = CCoins(tx, pindex->nHeight);
if (outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted");
// remove outputs
outs = CCoins();
// restore inputs
if (i > 0) { // not coinbases
const CTxUndo &txundo = blockUndo.vtxundo[i-1];
/*
if (txundo.vprevout.size() != tx.vin.size())
return error("DisconnectBlock() : transaction and undo data inconsistent");
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout;
const CTxInUndo &undo = txundo.vprevout[j];
CCoins coins;
view.GetCoins(out.hash, coins); // this can fail if the prevout was already entirely spent
if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent
if (!coins.IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction");
coins = CCoins();
coins.fCoinBase = undo.fCoinBase;
coins.nHeight = undo.nHeight;
coins.nVersion = undo.nVersion;
} else {
if (coins.IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction");
}
if (coins.IsAvailable(out.n))
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output");
if (coins.vout.size() < out.n+1)
coins.vout.resize(out.n+1);
coins.vout[out.n] = undo.txout;
if (!view.SetCoins(out.hash, coins))
return error("DisconnectBlock() : cannot restore coin inputs");
}
*/
} }
} }
@ -1245,10 +1158,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
// Do not allow blocks that contain transactions which 'overwrite' older transactions, // Do not allow blocks that contain transactions which 'overwrite' older transactions,
for (unsigned int i = 0; i < block.vtx.size(); i++) { for (unsigned int i = 0; i < block.vtx.size(); i++) {
// [MF] FIXME: check here for indexTx if( pblocktree->HaveTxIndex(block.vtx[i].GetUsernameHash()) )
uint256 hash = block.GetTxHash(i); return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
if (view.HaveCoins(block.vtx[i].GetUsernameHash()))
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction")); // [MF] FIXME: check here for indexTx (done above!)
//uint256 hash = block.GetTxHash(i);
//if (view.HaveCoins(block.vtx[i].GetUsernameHash()))
// return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
} }
CBlockUndo blockundo; CBlockUndo blockundo;
@ -1262,12 +1178,10 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
const CTransaction &tx = block.vtx[i]; const CTransaction &tx = block.vtx[i];
CTxUndo txundo; CTxUndo txundo;
//UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
UpdateCoins(tx, state, view, txundo, pindex->nHeight, tx.GetUsernameHash());
if (!tx.IsSpamMessage()) if (!tx.IsSpamMessage())
blockundo.vtxundo.push_back(txundo); blockundo.vtxundo.push_back(txundo);
vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); vPos.push_back(std::make_pair(tx.GetUsernameHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
} }
int64 nTime = GetTimeMicros() - nStart; int64 nTime = GetTimeMicros() - nStart;
@ -1876,7 +1790,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
for (unsigned int i = 0; i < block.vtx.size(); i++) for (unsigned int i = 0; i < block.vtx.size(); i++)
{ {
uint256 hash = block.vtx[i].GetHash(); uint256 hash = block.vtx[i].GetHash();
if (filter.IsRelevantAndUpdate(block.vtx[i], hash)) // [MF] unsure. force 0, use userhash for filter, hash for merkletree
if (i == 0 || filter.IsRelevantAndUpdate(block.vtx[i], block.vtx[i].GetUsernameHash()))
{ {
vMatch.push_back(true); vMatch.push_back(true);
vMatchedTxn.push_back(make_pair(i, block.vtx[i].GetUsernameHash())); vMatchedTxn.push_back(make_pair(i, block.vtx[i].GetUsernameHash()));
@ -2518,12 +2433,11 @@ bool static AlreadyHave(const CInv& inv)
LOCK(mempool.cs); LOCK(mempool.cs);
txInMap = mempool.exists(inv.hash); txInMap = mempool.exists(inv.hash);
} }
bool txInCoins = false; bool txInTxIndex = false;
if( !txInMap ) { if( !txInMap ) {
// [MF] FIXME: como converter inv.hash no usernamehash? txInTxIndex = pblocktree->HaveTxIndex(inv.hash);
txInCoins = pcoinsTip->HaveCoins(inv.hash);
} }
return txInMap || txInCoins; return txInMap || txInTxIndex;
} }
case MSG_BLOCK: case MSG_BLOCK:
return mapBlockIndex.count(inv.hash) || return mapBlockIndex.count(inv.hash) ||
@ -3684,7 +3598,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
continue; continue;
// This should never happen; all transactions in the memory are new // This should never happen; all transactions in the memory are new
if( view.HaveCoins(tx.GetUsernameHash()) ) { if( pblocktree->HaveTxIndex(tx.GetUsernameHash()) ) {
printf("ERROR: mempool transaction already exists\n"); printf("ERROR: mempool transaction already exists\n");
if (fDebug) assert("mempool transaction already exists" == 0); if (fDebug) assert("mempool transaction already exists" == 0);
} }

View File

@ -76,7 +76,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{ {
entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("txid", tx.GetUsernameHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("version", tx.nVersion));
//entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); //entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
Array vin; Array vin;

View File

@ -159,6 +159,15 @@ bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
return Read(make_pair('t', txid), pos); return Read(make_pair('t', txid), pos);
} }
bool CBlockTreeDB::HaveTxIndex(const uint256 &txid) {
CDiskTxPos pos;
return ReadTxIndex(txid, pos);
}
bool CBlockTreeDB::EraseTxIndex(const uint256 &txid) {
return Erase(make_pair('t', txid));
}
bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) { bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
CLevelDBBatch batch; CLevelDBBatch batch;
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++) for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)

View File

@ -44,6 +44,8 @@ public:
bool WriteReindexing(bool fReindex); bool WriteReindexing(bool fReindex);
bool ReadReindexing(bool &fReindex); bool ReadReindexing(bool &fReindex);
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
bool HaveTxIndex(const uint256 &txid);
bool EraseTxIndex(const uint256 &txid);
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list); bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool WriteFlag(const std::string &name, bool fValue); bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue); bool ReadFlag(const std::string &name, bool &fValue);