mirror of
https://github.com/twisterarmy/twister-core.git
synced 2025-01-11 07:17:53 +00:00
add support (untested) for key replacement
This commit is contained in:
parent
d1ec27e01a
commit
b6db2327e4
68
src/main.cpp
68
src/main.cpp
@ -483,8 +483,11 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
|
|||||||
|
|
||||||
{
|
{
|
||||||
// do we already have it?
|
// do we already have it?
|
||||||
if( pblocktree->HaveTxIndex(userhash) )
|
if( pblocktree->HaveTxIndex(userhash) &&
|
||||||
|
// duplicate should be discarded but replacement is allowed.
|
||||||
|
!verifyDuplicateOrReplacementTx(tx, false, true) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
|
||||||
@ -664,8 +667,40 @@ bool GetTransaction(const uint256 &userhash, CTransaction &txOut, uint256 &hashB
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool verifyDuplicateOrReplacementTx(CTransaction &tx, bool checkDuplicate, bool checkReplacement)
|
||||||
|
{
|
||||||
|
CTransaction oldTx;
|
||||||
|
uint256 hashBlock;
|
||||||
|
if( GetTransaction( tx.GetUsernameHash(), oldTx, hashBlock) ) {
|
||||||
|
if( checkDuplicate && oldTx.GetHash() == tx.GetHash() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector< vector<unsigned char> > vData;
|
||||||
|
if( checkReplacement && tx.pubKey.ExtractPushData(vData) && vData.size() >= 2 ) {
|
||||||
|
// possibly a key replacement. check if new key is signed by the old one.
|
||||||
|
|
||||||
|
// vData[0] is the (supposedly) new pub key
|
||||||
|
string strNewKey( (char *)vData[0].data(), vData[0].size() );
|
||||||
|
CHashWriter ss(SER_GETHASH, 0);
|
||||||
|
ss << strMessageMagic;
|
||||||
|
ss << strNewKey;
|
||||||
|
uint256 hashNewKey = ss.GetHash();
|
||||||
|
|
||||||
|
// vData[1] is (supposedly) the hash of the new key signed with the old one
|
||||||
|
CPubKey pubkeyRec;
|
||||||
|
vector< vector<unsigned char> > oldvData;
|
||||||
|
if (pubkeyRec.RecoverCompact(hashNewKey, vData[1]) &&
|
||||||
|
oldTx.pubKey.ExtractPushData(oldvData) &&
|
||||||
|
oldvData.size() >= 1 &&
|
||||||
|
pubkeyRec.GetID() == CPubKey(oldvData[0]).GetID()) {
|
||||||
|
// good signature. key replacement allowed.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1053,9 +1088,22 @@ 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,
|
||||||
|
// except if they are signed by the older one (key replacement)
|
||||||
for (unsigned int i = 1; i < block.vtx.size(); i++) {
|
for (unsigned int i = 1; i < block.vtx.size(); i++) {
|
||||||
if( pblocktree->HaveTxIndex(block.vtx[i].GetUsernameHash()) )
|
CTransaction &tx = block.vtx[i];
|
||||||
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
|
|
||||||
|
if( pblocktree->HaveTxIndex(block.vtx[i].GetUsernameHash()) ) {
|
||||||
|
/* We have index for this username, which is not allowed, except:
|
||||||
|
* 1) same transaction. this shouldn't happen but it does if twisterd terminates badly.
|
||||||
|
* explanation: TxIndex seems to get out-of-sync with block chain, so it may try to
|
||||||
|
* reconnect blocks which transactions are already written to the tx index.
|
||||||
|
* 2) possibly a key replacement. check if new key is signed by the old one.
|
||||||
|
*/
|
||||||
|
if( !verifyDuplicateOrReplacementTx(tx, true, true) ) {
|
||||||
|
// not the same, not replacement => error!
|
||||||
|
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CBlockUndo blockundo;
|
CBlockUndo blockundo;
|
||||||
@ -2335,9 +2383,17 @@ bool static AlreadyHave(const CInv& inv)
|
|||||||
txInMap = mempool.exists(inv.hash);
|
txInMap = mempool.exists(inv.hash);
|
||||||
}
|
}
|
||||||
bool txInTxIndex = false;
|
bool txInTxIndex = false;
|
||||||
|
/* [MF] checkme: because of key replacement, we better not check
|
||||||
|
* txIndex but rather only memory. "mempool" cmd is replied with
|
||||||
|
* "inv" cmd of the current txs in memory. if recipient decides he
|
||||||
|
* already has a given tx in txindex (by calling this function),
|
||||||
|
* he would never ask/receive the key replacement.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
if( !txInMap ) {
|
if( !txInMap ) {
|
||||||
txInTxIndex = pblocktree->HaveTxIndex(inv.hash);
|
txInTxIndex = pblocktree->HaveTxIndex(inv.hash);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return txInMap || txInTxIndex;
|
return txInMap || txInTxIndex;
|
||||||
}
|
}
|
||||||
case MSG_BLOCK:
|
case MSG_BLOCK:
|
||||||
@ -3534,8 +3590,10 @@ CBlockTemplate* CreateNewBlock(std::vector<unsigned char> &salt)
|
|||||||
|
|
||||||
// This should never happen; all transactions in the memory are new
|
// This should never happen; all transactions in the memory are new
|
||||||
if( pblocktree->HaveTxIndex(tx.GetUsernameHash()) ) {
|
if( pblocktree->HaveTxIndex(tx.GetUsernameHash()) ) {
|
||||||
printf("ERROR: mempool transaction already exists\n");
|
if( !verifyDuplicateOrReplacementTx(tx, false, true) ) {
|
||||||
if (fDebug) assert("mempool transaction already exists" == 0);
|
printf("ERROR: mempool transaction already exists\n");
|
||||||
|
if (fDebug) assert("mempool transaction already exists" == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size limits
|
// Size limits
|
||||||
|
@ -183,6 +183,8 @@ bool IsInitialBlockDownload();
|
|||||||
std::string GetWarnings(std::string strFor);
|
std::string GetWarnings(std::string strFor);
|
||||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||||
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
|
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
|
||||||
|
/** Verify duplicate or replacement transactions */
|
||||||
|
bool verifyDuplicateOrReplacementTx(CTransaction &tx, bool checkDuplicate, bool checkReplacement);
|
||||||
/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
|
/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
|
||||||
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
|
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
|
||||||
/** Find the best known block, and make it the tip of the block chain */
|
/** Find the best known block, and make it the tip of the block chain */
|
||||||
|
Loading…
Reference in New Issue
Block a user