Merge pull request #923 from blackjok3rtt/DICE_mempoolfix
Dice mempoolfix, needs more testing to be sure.
This commit is contained in:
@@ -276,6 +276,11 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
|
||||
abovei = belowi = -1;
|
||||
for (above=below=i=0; i<numunspents; i++)
|
||||
{
|
||||
// Filter to randomly pick utxo to avoid conflicts, and having multiple CC choose the same ones.
|
||||
//if ( numunspents > 500 ) {
|
||||
// if ( (rand() % 100) < 80 )
|
||||
// continue;
|
||||
//}
|
||||
if ( (atx_value= utxos[i].nValue) <= 0 )
|
||||
continue;
|
||||
if ( atx_value == value )
|
||||
|
||||
@@ -443,7 +443,6 @@ bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks)
|
||||
bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
|
||||
{
|
||||
uint256 txid,fundingtxid,vinfundingtxid,vinhentropy,vinproof,hashBlock,hash,proof,entropy; int64_t minbet,maxbet,maxodds,timeoutblocks,odds,winnings; uint64_t vinsbits,sbits,amount,inputs,outputs,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,iswin; uint8_t funcid; CScript fundingPubKey; CTransaction fundingTx,vinTx,vinofvinTx; char CCaddr[64];
|
||||
CBlockIndex block; int skipped = 0;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
@@ -542,19 +541,13 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
|
||||
//vin.3+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
|
||||
//vout.1: tag to owner address for entropy funds
|
||||
preventCCvouts = 1;
|
||||
CBlockIndex block;
|
||||
DiceAmounts(inputs,outputs,cp,eval,tx,sbits,fundingtxid);
|
||||
if ( IsCCInput(tx.vin[1].scriptSig) == 0 || IsCCInput(tx.vin[2].scriptSig) == 0 )
|
||||
return eval->Invalid("vin0 or vin1 normal vin for bet");
|
||||
else if ( tx.vin[1].prevout.hash != tx.vin[2].prevout.hash )
|
||||
return eval->Invalid("vin0 != vin1 prevout.hash for bet");
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 ) {
|
||||
char str[65],str2[65],str3[65];
|
||||
fprintf(stderr, "txid.%s tx.%s hashBlock.%s\n",uint256_str(str,txid),uint256_str(str2,tx.vin[1].prevout.hash),uint256_str(str3,hashBlock));
|
||||
//return eval->Invalid("always should find looking vin.0, but didnt for wlt");
|
||||
skipped = 1;
|
||||
} else if (hashBlock.IsNull() || !eval->GetBlock(hashBlock, block))
|
||||
return eval->Invalid(" TX not confirmed! always should find vin.0, but didnt for wlt");
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find looking vin.0, but didnt for wlt");
|
||||
else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[1].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' )
|
||||
return eval->Invalid("not betTx for vin0/1 for wlt");
|
||||
else if ( sbits != vinsbits || fundingtxid != vinfundingtxid )
|
||||
@@ -576,30 +569,27 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( skipped == 0 )
|
||||
//vout.0: funding CC change to entropy owner
|
||||
//vout.2: normal output to bettor's address
|
||||
//vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
|
||||
odds = vinTx.vout[2].nValue - txfee;
|
||||
if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
|
||||
else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
|
||||
return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
|
||||
else if ( tx.vout[2].nValue != (odds+1)*vinTx.vout[1].nValue )
|
||||
return eval->Invalid("vout[2] payut mismatch for win/timeout");
|
||||
else if ( inputs != (outputs + tx.vout[2].nValue) && inputs != (outputs + tx.vout[2].nValue+txfee) )
|
||||
{
|
||||
//vout.0: funding CC change to entropy owner
|
||||
//vout.2: normal output to bettor's address
|
||||
//vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
|
||||
odds = vinTx.vout[2].nValue - txfee;
|
||||
if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
|
||||
else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
|
||||
return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
|
||||
else if ( tx.vout[2].nValue != (odds+1)*vinTx.vout[1].nValue )
|
||||
return eval->Invalid("vout[2] payut mismatch for win/timeout");
|
||||
else if ( inputs != (outputs + tx.vout[2].nValue) && inputs != (outputs + tx.vout[2].nValue+txfee) )
|
||||
{
|
||||
fprintf(stderr,"inputs %.8f != outputs %.8f + %.8f\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN);
|
||||
return eval->Invalid("CC funds mismatch for win/timeout");
|
||||
}
|
||||
else if ( tx.vout[3].scriptPubKey != fundingPubKey )
|
||||
{
|
||||
if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a )
|
||||
return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout");
|
||||
}
|
||||
iswin = (funcid == 'W');
|
||||
fprintf(stderr,"inputs %.8f != outputs %.8f + %.8f\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN);
|
||||
return eval->Invalid("CC funds mismatch for win/timeout");
|
||||
}
|
||||
else if ( tx.vout[3].scriptPubKey != fundingPubKey )
|
||||
{
|
||||
if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a )
|
||||
return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout");
|
||||
}
|
||||
iswin = (funcid == 'W');
|
||||
}
|
||||
if ( iswin != 0 )
|
||||
{
|
||||
|
||||
54
src/main.cpp
54
src/main.cpp
@@ -92,6 +92,7 @@ unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA;
|
||||
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
|
||||
|
||||
CTxMemPool mempool(::minRelayTxFee);
|
||||
CTxMemPool tmpmempool(::minRelayTxFee);
|
||||
|
||||
struct COrphanTx {
|
||||
CTransaction tx;
|
||||
@@ -1309,7 +1310,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
|
||||
}
|
||||
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee)
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, bool fNullifiers)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (pfMissingInputs)
|
||||
@@ -1390,14 +1391,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
|
||||
if (fNullifiers == false)
|
||||
{
|
||||
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers)
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
|
||||
{
|
||||
if (pool.mapNullifiers.count(nf))
|
||||
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers)
|
||||
{
|
||||
fprintf(stderr,"pool.mapNullifiers.count\n");
|
||||
return false;
|
||||
if (pool.mapNullifiers.count(nf))
|
||||
{
|
||||
fprintf(stderr,"pool.mapNullifiers.count\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1450,12 +1454,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
}
|
||||
}
|
||||
// are the joinsplit's requirements met?
|
||||
if (!view.HaveJoinSplitRequirements(tx))
|
||||
if ( fNullifiers == true )
|
||||
{
|
||||
//fprintf(stderr,"accept failure.2\n");
|
||||
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
|
||||
if (!view.HaveJoinSplitRequirements(tx))
|
||||
{
|
||||
//fprintf(stderr,"accept failure.2\n");
|
||||
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
|
||||
}
|
||||
}
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
@@ -1697,7 +1703,7 @@ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlo
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check disk\n");
|
||||
|
||||
|
||||
if (fTxIndex) {
|
||||
CDiskTxPos postx;
|
||||
//fprintf(stderr,"ReadTxIndex\n");
|
||||
@@ -4247,6 +4253,17 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
||||
{
|
||||
CValidationState stateDummy; int32_t i,j,rejects=0,lastrejects=0;
|
||||
//fprintf(stderr,"put block's tx into mempool\n");
|
||||
// Copy the mempool to temporary mempool because there can be tx in local mempool that make the block invalid.
|
||||
LOCK(mempool.cs);
|
||||
BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) {
|
||||
const CTransaction &tx = e.GetTx();
|
||||
const uint256 &hash = tx.GetHash();
|
||||
tmpmempool.addUnchecked(hash,e,!IsInitialBlockDownload());
|
||||
fprintf(stderr, "added mempool tx to temp mempool\n");
|
||||
}
|
||||
// clear the mempool before importing all block txs to mempool.
|
||||
mempool.clear();
|
||||
// add all the txs in the block to the empty mempool.
|
||||
while ( 1 )
|
||||
{
|
||||
for (i=0; i<block.vtx.size(); i++)
|
||||
@@ -4295,6 +4312,21 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
||||
LogPrintf("CheckBlockHeader komodo_check_deposit error");
|
||||
return(false);
|
||||
}
|
||||
if ( ASSETCHAINS_CC != 0 ) // CC contracts might refer to transactions in the current block, from a CC spend within the same block and out of order
|
||||
{
|
||||
int invalidtxs = 0;
|
||||
BOOST_FOREACH(const CTxMemPoolEntry& e, tmpmempool.mapTx) {
|
||||
CTransaction tx = e.GetTx();
|
||||
CValidationState state; bool fMissingInputs,fOverrideFees = false;
|
||||
if (AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees,true) == false )
|
||||
invalidtxs++;
|
||||
else
|
||||
fprintf(stderr, "added mempool tx back to mempool\n");
|
||||
}
|
||||
fprintf(stderr, "number of invalid txs: %d\n",invalidtxs );
|
||||
// empty the temp mempool for next time.
|
||||
tmpmempool.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
18
src/main.h
18
src/main.h
@@ -180,11 +180,11 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
|
||||
/** Unregister a network node */
|
||||
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Process an incoming block. This only returns after the best known valid
|
||||
* block is made active. Note that it does not, however, guarantee that the
|
||||
* specific block passed to it has been checked for validity!
|
||||
*
|
||||
*
|
||||
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
|
||||
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
|
||||
* @param[in] pblock The block we want to process.
|
||||
@@ -267,7 +267,7 @@ void PruneAndFlush();
|
||||
|
||||
/** (try to) add transaction to memory pool **/
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
|
||||
bool* pfMissingInputs, bool fRejectAbsurdFee=false, bool fNullifiers=false);
|
||||
|
||||
|
||||
struct CNodeStateStats {
|
||||
@@ -640,7 +640,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
|
||||
/**
|
||||
* Check transaction inputs, and make sure any
|
||||
* pay-to-script-hash transactions are evaluating IsStandard scripts
|
||||
*
|
||||
*
|
||||
* Why bother? To avoid denial-of-service attacks; an attacker
|
||||
* can submit a standard HASH... OP_EQUAL transaction,
|
||||
* which will get accepted into blocks. The redemption
|
||||
@@ -649,14 +649,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
|
||||
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
|
||||
*/
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check for standard transaction types
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
||||
* @return number of sigops this transaction's outputs will produce when spent
|
||||
* @see CTransaction::FetchInputs
|
||||
@@ -665,7 +665,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
|
||||
|
||||
/**
|
||||
* Count ECDSA signature operations in pay-to-script-hash inputs.
|
||||
*
|
||||
*
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
* @return maximum number of sigops required to validate this transaction's inputs
|
||||
* @see CTransaction::FetchInputs
|
||||
@@ -732,9 +732,9 @@ bool IsExpiredTx(const CTransaction &tx, int nBlockHeight);
|
||||
*/
|
||||
bool CheckFinalTx(const CTransaction &tx, int flags = -1);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Closure representing one script verification
|
||||
* Note that this stores references to the spending transaction
|
||||
* Note that this stores references to the spending transaction
|
||||
*/
|
||||
class CScriptCheck
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user