diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 2bd97fa68..6fd3b47b3 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1807,6 +1807,9 @@ uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector &Notar int32_t staked_era; int8_t numSN; uint8_t staked_pubkeys[64][33]; staked_era = STAKED_era(timestamp); + // No point going further, no notaries can be paid. + if ( staked_era == 0 ) + return(0); numSN = numStakedNotaries(staked_pubkeys,staked_era); // resize coinbase vouts to number of notary nodes +1 for coinbase itself. txNew.vout.resize(NotarisationNotaries.size()+1); @@ -1821,11 +1824,11 @@ uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector &Notar memcpy(scriptbuf,script,len); if ( komodo_voutupdate(true,&isratification,0,scriptbuf,len,height,uint256(),1,1,&voutmask,&specialtx,¬arizedheight,0,1,0,timestamp) == -2 ) { - fprintf(stderr, "VALID NOTARIZATION ht.%i\n",notarizedheight); + fprintf(stderr, "notarypay found VALID NOTARIZATION ht.%i\n",notarizedheight); } else { - fprintf(stderr, "INVALID NOTARIZATION ht.%i\n",notarizedheight); + fprintf(stderr, "notarypay found INVALID NOTARIZATION ht.%i\n",notarizedheight); return(0); } } else return(0); @@ -1861,10 +1864,13 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) int32_t staked_era; int8_t numSN; uint8_t staked_pubkeys[64][33]; staked_era = STAKED_era(timestamp); + // No point going further, no notaries can be paid. + if ( staked_era == 0 ) + return(0); numSN = numStakedNotaries(staked_pubkeys,staked_era); uint8_t *script; int32_t scriptlen; - // Loop notarisation, and create the coinbase tx, with the same function the miner uses. + // Loop over the notarisation and extract the position of the participating notaries in the array of pukeys for this era. BOOST_FOREACH(const CTxIn& txin, pblock->vtx[1].vin) { uint256 hash; CTransaction tx1; @@ -1872,7 +1878,6 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) { for (int8_t i = 0; i < numSN; i++) { - //tx1.vout[txin.prevout.n].scriptPubKey script = (uint8_t *)&tx1.vout[txin.prevout.n].scriptPubKey[0]; scriptlen = (int32_t)tx1.vout[txin.prevout.n].scriptPubKey.size(); if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,staked_pubkeys[i],33) == 0 ) @@ -1891,19 +1896,22 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) int32_t scriptlen = (int32_t)pblock->vtx[1].vout[1].scriptPubKey.size(); if ( script[0] == OP_RETURN ) { + // Create the coinbase tx again, using the extracted data, this is the same function the miner uses, with the same data. + // This allows us to know exactly that the coinbase is correct. totalsats = komodo_notarypay(txNew, NotarisationNotaries, pblock->nTime, height, script, scriptlen); } else { fprintf(stderr, "vout 2 of notarisation is not OP_RETURN scriptlen.%i\n", scriptlen); - return(-1); + return(0); } } // if notarypay fails, because the notarisation is not valid, exit now as txNew was not created. + // This should never happen, as the notarisation is checked before this function is called. if ( totalsats == 0 ) { - fprintf(stderr, "notary pay RETURNED 0!\n"); + fprintf(stderr, "notary pay returned 0!\n"); return(0); } @@ -1913,11 +1921,10 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) // get the pay amount from the created tx. AmountToPay = txNew.vout[1].nValue; - //fprintf(stderr, "txNew.vout size = %li\n",txNew.vout.size()); // Check the created coinbase pays the correct notaries. BOOST_FOREACH(const CTxOut& txout, pblock->vtx[0].vout) { - // skip the coinbase + // skip the coinbase paid to the miner. if ( n == 0 ) { n++; @@ -1933,7 +1940,7 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) { matches++; total += txout.nValue; - fprintf(stderr, "matched.%i\n", NotarisationNotaries[n-1]); + fprintf(stderr, "MATCHED AmountPaid.%lu notaryid.%i\n",AmountToPay,NotarisationNotaries[n-1]); } else fprintf(stderr, "NOT MATCHED AmountPaid.%lu AmountToPay.%lu notaryid.%i\n", pblock->vtx[0].vout[n].nValue, AmountToPay, NotarisationNotaries[n-1]); } @@ -1941,7 +1948,7 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height) } if ( matches != 0 && matches == NotarisationNotaries.size() && totalsats == total ) { - fprintf(stderr, "VALIDATED.\n" ); + fprintf(stderr, "Validated coinbase matches notarisation in tx position 1.\n" ); return(totalsats); } return(0); @@ -2127,6 +2134,10 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) return(-1); } } + // Consensus rule to force miners to mine the notary coinbase payment happens in ConnectBlock + // the default daemon miner, checks the actual vins so the only way this will fail, is if someone changes the miner, + // and then creates txs to the crypto address meeting min sigs and puts it in tx position 1. + // If they go through this effort, the block will still fail at connect block, and will be auto purged by the temp file fix. if ( failed == 0 && ASSETCHAINS_NOTARY_PAY != 0 && pblock->vtx[0].vout.size() > 1 ) { // We check the full validation in ConnectBlock directly to get the amount for coinbase. So just approx here. @@ -2135,13 +2146,13 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) // Check the notarisation tx is to the crypto address. if ( !komodo_is_notarytx(pblock->vtx[1]) == 1 ) { - fprintf(stderr, "notarisation is not to crypto address.%i\n",height); + fprintf(stderr, "notarisation is not to crypto address ht.%i\n",height); return(-1); } // Check min sigs. if ( pblock->vtx[1].vin.size() < (num_notaries_STAKED[STAKED_era(pblock->nTime)]/5) ) { - fprintf(stderr, "block notarization does not meet minsigs .%i\n",height); + fprintf(stderr, "ht.%i does not meet minsigs.%i sigs.%li\n",height,(num_notaries_STAKED[STAKED_era(pblock->nTime)]/5),pblock->vtx[1].vin.size()); return(-1); } } diff --git a/src/main.cpp b/src/main.cpp index ec79fafbc..656cc0a96 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3267,6 +3267,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin auto verifier = libzcash::ProofVerifier::Strict(); auto disabledVerifier = libzcash::ProofVerifier::Disabled(); int32_t futureblock; + CAmount blockReward = 0; // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in if (!CheckBlock(&futureblock,pindex->GetHeight(),pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck) || futureblock != 0 ) { @@ -3280,6 +3281,34 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return false; fprintf(stderr,"grandfathered exception, until jan 15th 2019\n"); } + // Do this here before the block is moved to the main block files. + if ( ASSETCHAINS_NOTARY_PAY != 0 && pindex->GetHeight() != 0 ) + { + // do a full block scan to get notarisation position and to enforce 1 notarisation is in block only. + // if notarisation in the block, must be position 1 and the coinbase must pay notaries. + int notarisationTx = komodo_connectblock(true,pindex,*(CBlock *)&block); + // -1 means that more than 1 notarisation is in a block, or the notarisation is not in order. + if ( notarisationTx == -1 ) + return state.DoS(100, error("ConnectBlock(): Notarisation is not in TX position 1! Invalid Block!"), + REJECT_INVALID, "bad-notarization-position"); + // 1 means this block contains a valid notarisation + if ( notarisationTx == 1 ) + { + // Check if the notaries have been paid. + if ( block.vtx[0].vout.size() == 1 ) + return state.DoS(100, error("ConnectBlock(): Notaries have not been paid!"), + REJECT_INVALID, "bad-cb-amount"); + // calculate the notaries compensation and validate the amounts and pubkeys are correct. + uint64_t notarypaycheque = komodo_checknotarypay((CBlock *)&block,(int32_t)pindex->GetHeight()); + fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque); + if ( notarypaycheque > 0 ) + blockReward += notarypaycheque; + else + return state.DoS(100, error("ConnectBlock(): Notary pay validation failed!"), + REJECT_INVALID, "bad-cb-amount"); + } + } + // Move the block to the main block file, we need this to create the TxIndex in the following loop. if ( (pindex->nStatus & BLOCK_IN_TMPFILE) != 0 ) { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -3562,7 +3591,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - CAmount blockReward = nFees + GetBlockSubsidy(pindex->GetHeight(), chainparams.GetConsensus()) + sum; + blockReward += nFees + GetBlockSubsidy(pindex->GetHeight(), chainparams.GetConsensus()) + sum; if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 ) //ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && { uint64_t checktoshis; @@ -3574,33 +3603,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin fprintf(stderr,"checktoshis %.8f vs %.8f numvouts %d\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue),(int32_t)block.vtx[0].vout.size()); } } - bool sleepflag = false; - if ( ASSETCHAINS_NOTARY_PAY != 0 ) - { - // do a full block scan to get notarisation position and to enforce 1 notarisation is in block only. - // if notarisation in the block, must be position 1 and the coinbase must pay notaries. - int notarisationTx = komodo_connectblock(true,pindex,*(CBlock *)&block); - // -1 means that more than 1 notarisation is in a block, or the notarisation is not in order. - if ( notarisationTx == -1 ) - return state.DoS(100, error("ConnectBlock(): Notarisation is not in TX position 1! Invalid Block!"), - REJECT_INVALID, "bad-notarization-position"); - // 1 means this block contains a valid notarisation - if ( notarisationTx == 1 ) - { - // Check if the notaries have been paid. - if ( block.vtx[0].vout.size() == 1 ) - return state.DoS(100, error("ConnectBlock(): Notary has not been paid!"), - REJECT_INVALID, "bad-cb-amount"); - // calculate the notaries compensation and validate the amounts and pubkeys are correct. - uint64_t notarypaycheque = komodo_checknotarypay((CBlock *)&block,(int32_t)pindex->GetHeight()); - fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque); - if ( notarypaycheque > 0 ) - blockReward += notarypaycheque; - else - return state.DoS(100, error("ConnectBlock(): Notary pay Validation Failed!"), - REJECT_INVALID, "bad-cb-amount"); - } - } if (ASSETCHAINS_SYMBOL[0] != 0 && pindex->GetHeight() == 1 && block.vtx[0].GetValueOut() != blockReward) { return state.DoS(100, error("ConnectBlock(): coinbase for block 1 pays wrong amount (actual=%d vs correct=%d)", block.vtx[0].GetValueOut(), blockReward), @@ -3716,8 +3718,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin //FlushStateToDisk(); komodo_connectblock(false,pindex,*(CBlock *)&block); // dPoW state update. - if (sleepflag) - sleep(30); return true; }