Browse Source

mempool uses txhash again (instead of userhash). this is needed to fix key replacement.

using userhash in mempool was a bad idea, it creates incompatibilities with merkle tree code etc.
now we are back to standard bitcoin protocol regarding tx and inv commands, possibly filter as well.
miguelfreitas
Miguel Freitas 11 years ago
parent
commit
7e57fb2fe4
  1. 32
      src/main.cpp
  2. 10
      src/main.h
  3. 10
      src/net.cpp
  4. 4
      src/net.h
  5. 6
      src/rpcrawtransaction.cpp
  6. 2
      src/wallet.cpp

32
src/main.cpp

@ -474,16 +474,16 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
reason.c_str()); reason.c_str());
// is it already in the memory pool? // is it already in the memory pool?
uint256 userhash = tx.GetUsernameHash(); uint256 txhash = tx.GetHash();
{ {
LOCK(cs); LOCK(cs);
if (mapTx.count(userhash)) if (mapTx.count(txhash))
return false; return false;
} }
{ {
// do we already have it? // do we already have it?
if( pblocktree->HaveTxIndex(userhash) && if( pblocktree->HaveTxIndex(tx.GetUsernameHash()) &&
// duplicate should be discarded but replacement is allowed. // duplicate should be discarded but replacement is allowed.
!verifyDuplicateOrReplacementTx(tx, false, true) ) { !verifyDuplicateOrReplacementTx(tx, false, true) ) {
return false; return false;
@ -518,25 +518,25 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
// Store transaction in memory // Store transaction in memory
{ {
LOCK(cs); LOCK(cs);
addUnchecked(userhash, tx); // adds to mapTx addUnchecked(txhash, tx); // adds to mapTx
} }
///// are we sure this is ok when loading transactions or restoring block txes ///// are we sure this is ok when loading transactions or restoring block txes
SyncWithWallets(userhash, tx, NULL, true); SyncWithWallets(txhash, tx, NULL, true);
printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
userhash.ToString().c_str(), txhash.ToString().c_str(),
mapTx.size()); mapTx.size());
return true; return true;
} }
bool CTxMemPool::addUnchecked(const uint256& userhash, CTransaction &tx) bool CTxMemPool::addUnchecked(const uint256& txhash, CTransaction &tx)
{ {
// Add to memory pool without checking anything. Don't call this directly, // Add to memory pool without checking anything. Don't call this directly,
// call CTxMemPool::accept to properly check the transaction first. // call CTxMemPool::accept to properly check the transaction first.
{ {
mapTx[userhash] = tx; mapTx[txhash] = tx;
nTransactionsUpdated++; nTransactionsUpdated++;
} }
return true; return true;
@ -548,7 +548,7 @@ bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive)
// Remove transaction from memory pool // Remove transaction from memory pool
if( !tx.IsSpamMessage() ){ if( !tx.IsSpamMessage() ){
LOCK(cs); LOCK(cs);
uint256 hash = tx.GetUsernameHash(); uint256 hash = tx.GetHash();
if (mapTx.count(hash)) if (mapTx.count(hash))
{ {
mapTx.erase(hash); mapTx.erase(hash);
@ -636,12 +636,14 @@ bool GetTransaction(const uint256 &userhash, CTransaction &txOut, uint256 &hashB
{ {
LOCK(cs_main); LOCK(cs_main);
{ {
/* [MF] don't look in mempool anymore - userhash must be written to some block.
LOCK(mempool.cs); LOCK(mempool.cs);
if (mempool.exists(userhash)) if (mempool.exists(userhash)) // and btw mempool is not indexed by userhash anymore!
{ {
txOut = mempool.lookup(userhash); txOut = mempool.lookup(userhash);
return true; return true;
} }
*/
} }
if (fTxIndex) { if (fTxIndex) {
@ -1740,12 +1742,10 @@ 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();
// [MF] unsure. force 0, use userhash for filter, hash for merkletree if (i == 0 || filter.IsRelevantAndUpdate(block.vtx[i], hash))
// [MF] FIXME: this is most likely broken!
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, hash));
} }
else else
vMatch.push_back(false); vMatch.push_back(false);
@ -2388,6 +2388,7 @@ bool static AlreadyHave(const CInv& inv)
* "inv" cmd of the current txs in memory. if recipient decides he * "inv" cmd of the current txs in memory. if recipient decides he
* already has a given tx in txindex (by calling this function), * already has a given tx in txindex (by calling this function),
* he would never ask/receive the key replacement. * he would never ask/receive the key replacement.
* Besides: HaveTxIndex is userhash, mempool is txhash.
*/ */
/* /*
if( !txInMap ) { if( !txInMap ) {
@ -2447,7 +2448,6 @@ void static ProcessGetData(CNode* pfrom)
// Thus, the protocol spec specified allows for us to provide duplicate txn here, // Thus, the protocol spec specified allows for us to provide duplicate txn here,
// however we MUST always provide at least what the remote peer needs // however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType; typedef std::pair<unsigned int, uint256> PairType;
// [MF] check if vMatchedTxn is userhash
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
pfrom->PushMessage("tx", block.vtx[pair.first]); pfrom->PushMessage("tx", block.vtx[pair.first]);
@ -2863,7 +2863,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CTransaction tx; CTransaction tx;
vRecv >> tx; vRecv >> tx;
CInv inv(MSG_TX, tx.GetUsernameHash()); CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv); pfrom->AddInventoryKnown(inv);
// Truncate messages to the size of the tx in them // Truncate messages to the size of the tx in them

10
src/main.h

@ -1007,7 +1007,7 @@ class CTxMemPool
{ {
public: public:
mutable CCriticalSection cs; mutable CCriticalSection cs;
std::map<uint256, CTransaction> mapTx; // [MF] hash is now userhash std::map<uint256, CTransaction> mapTx; // [MF] hash is txhash again
bool accept(CValidationState &state, CTransaction &tx, bool fLimitFree, bool* pfMissingInputs); bool accept(CValidationState &state, CTransaction &tx, bool fLimitFree, bool* pfMissingInputs);
bool addUnchecked(const uint256& userhash, CTransaction &tx); bool addUnchecked(const uint256& userhash, CTransaction &tx);
@ -1021,14 +1021,14 @@ public:
return mapTx.size(); return mapTx.size();
} }
bool exists(uint256 userhash) bool exists(uint256 txhash)
{ {
return (mapTx.count(userhash) != 0); return (mapTx.count(txhash) != 0);
} }
CTransaction& lookup(uint256 userhash) CTransaction& lookup(uint256 txhash)
{ {
return mapTx[userhash]; return mapTx[txhash];
} }
}; };

10
src/net.cpp

@ -1792,17 +1792,17 @@ instance_of_cnetcleanup;
void RelayTransaction(const CTransaction& tx, const uint256& userhash) void RelayTransaction(const CTransaction& tx, const uint256& txhash)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000); ss.reserve(10000);
ss << tx; ss << tx;
RelayTransaction(tx, userhash, ss); RelayTransaction(tx, txhash, ss);
} }
void RelayTransaction(const CTransaction& tx, const uint256& userhash, const CDataStream& ss) void RelayTransaction(const CTransaction& tx, const uint256& txhash, const CDataStream& ss)
{ {
CInv inv(MSG_TX, userhash); CInv inv(MSG_TX, txhash);
{ {
LOCK(cs_mapRelay); LOCK(cs_mapRelay);
// Expire old relay messages // Expire old relay messages
@ -1824,7 +1824,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& userhash, const CDa
LOCK(pnode->cs_filter); LOCK(pnode->cs_filter);
if (pnode->pfilter) if (pnode->pfilter)
{ {
if (pnode->pfilter->IsRelevantAndUpdate(tx, userhash)) if (pnode->pfilter->IsRelevantAndUpdate(tx, txhash))
pnode->PushInventory(inv); pnode->PushInventory(inv);
} else } else
pnode->PushInventory(inv); pnode->PushInventory(inv);

4
src/net.h

@ -644,7 +644,7 @@ public:
class CTransaction; class CTransaction;
void RelayTransaction(const CTransaction& tx, const uint256& userhash); void RelayTransaction(const CTransaction& tx, const uint256& txhash);
void RelayTransaction(const CTransaction& tx, const uint256& userhash, const CDataStream& ss); void RelayTransaction(const CTransaction& tx, const uint256& txhash, const CDataStream& ss);
#endif #endif

6
src/rpcrawtransaction.cpp

@ -220,16 +220,16 @@ Value sendrawtransaction(const Array& params, bool fHelp)
catch (std::exception &e) { catch (std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
} }
uint256 hashTx = tx.GetUsernameHash(); uint256 hashTx = tx.GetHash();
bool fHave = false; bool fHave = false;
uint256 hashBlock; uint256 hashBlock;
CTransaction tx2; CTransaction tx2;
fHave = GetTransaction(hashTx, tx2, hashBlock); fHave = GetTransaction(tx.GetUsernameHash(), tx2, hashBlock);
// treat replacement as !fHave // treat replacement as !fHave
if( fHave && verifyDuplicateOrReplacementTx(tx, false, true) ) { if( fHave && verifyDuplicateOrReplacementTx(tx, false, true) ) {
printf("verifyDuplicateOrReplacementTx true\n"); printf("sendrawtransaction: is ReplacementTx true\n");
fHave = false; fHave = false;
} }

2
src/wallet.cpp

@ -675,7 +675,7 @@ void CWalletTx::RelayWalletTransaction()
if (!IsSpamMessage()) if (!IsSpamMessage())
{ {
if (GetDepthInMainChain() == 0) { if (GetDepthInMainChain() == 0) {
uint256 hash = GetUsernameHash(); uint256 hash = GetHash();
printf("Relaying wtx %s\n", hash.ToString().c_str()); printf("Relaying wtx %s\n", hash.ToString().c_str());
RelayTransaction((CTransaction)*this, hash); RelayTransaction((CTransaction)*this, hash);
} }

Loading…
Cancel
Save