diff --git a/qa/rpc-tests/createauxblock.py b/qa/rpc-tests/createauxblock.py index e4c02aea5..2c82c85ef 100644 --- a/qa/rpc-tests/createauxblock.py +++ b/qa/rpc-tests/createauxblock.py @@ -72,8 +72,7 @@ class CreateAuxBlockTest(BitcoinTestFramework): auxblock3 = self.nodes[0].createauxblock(dummy_addr2) # ... must give another block because the coinbase recipient differs ... - # TODO: Need to cache per address on createauxblock for this to work - # assert auxblock3["hash"] != auxblock["hash"] + assert auxblock3["hash"] != auxblock["hash"] # ... but must have retained the same parameterization otherwise assert_equal(auxblock["coinbasevalue"], auxblock3["coinbasevalue"]) @@ -133,8 +132,10 @@ class CreateAuxBlockTest(BitcoinTestFramework): # check the mined block and transaction self.check_mined_block(auxblock, apow, dummy_p2pkh_addr, Decimal("500000"), txid) - # Mine to a p2sh address + # Mine to a p2sh address while having multiple cached aux block templates + auxblock1 = self.nodes[0].createauxblock(dummy_p2pkh_addr) auxblock2 = self.nodes[0].createauxblock(dummy_p2sh_addr) + auxblock3 = self.nodes[0].createauxblock(dummy_addr2) reversedTarget = auxpow.reverseHex(auxblock2["target"]) apow = auxpow.computeAuxpowWithChainId(auxblock2["hash"], reversedTarget, "98", True) res = self.nodes[0].submitauxblock(auxblock2["hash"], apow) @@ -145,6 +146,30 @@ class CreateAuxBlockTest(BitcoinTestFramework): # check the mined block self.check_mined_block(auxblock2, apow, dummy_p2sh_addr, Decimal("500000")) + # Solve the first p2pkh template before requesting a new auxblock + # this succeeds but creates a chaintip fork + reversedTarget = auxpow.reverseHex(auxblock1["target"]) + apow = auxpow.computeAuxpowWithChainId(auxblock1["hash"], reversedTarget, "98", True) + res = self.nodes[0].submitauxblock(auxblock1["hash"], apow) + assert res + + chaintips = self.nodes[0].getchaintips() + tipsFound = 0; + for ct in chaintips: + if ct["hash"] in [ auxblock1["hash"], auxblock2["hash"] ]: + tipsFound += 1 + assert_equal(tipsFound, 2) + + # Solve the last p2pkh template after requesting a new auxblock - this fails + self.nodes[0].createauxblock(dummy_p2pkh_addr) + reversedTarget = auxpow.reverseHex(auxblock3["target"]) + apow = auxpow.computeAuxpowWithChainId(auxblock3["hash"], reversedTarget, "98", True) + try: + self.nodes[0].submitauxblock(auxblock3["hash"], apow) + raise AssertionError("Outdated blockhash accepted") + except JSONRPCException as exc: + assert_equal(exc.error["code"], -8) + def check_mined_block(self, auxblock, apow, addr, min_value, txid=None): # Call getblock and verify the auxpow field. data = self.nodes[1].getblock(auxblock["hash"]) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 08da3fa13..4e52734a9 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -1008,16 +1008,27 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey) static unsigned nTransactionsUpdatedLast; static const CBlockIndex* pindexPrev = nullptr; static uint64_t nStart; - static CBlock* pblock = nullptr; + static std::map curBlocks; static unsigned nExtraNonce = 0; // Dogecoin: Never mine witness tx const bool fMineWitnessTx = false; - // Update block + /* Search for cached blocks with given scriptPubKey and assign it to pBlock + * if we find a match. This allows for creating multiple aux templates with + * a single dogecoind instance, for example when a pool runs multiple sub- + * pools with different payout strategies. + */ + CBlock* pblock = nullptr; + CScriptID scriptID (scriptPubKey); + auto iter = curBlocks.find(scriptID); + if (iter != curBlocks.end()) pblock = iter->second; + { LOCK(cs_main); - if (pindexPrev != chainActive.Tip() + + // Update block + if (pblock == nullptr || pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)) { @@ -1026,6 +1037,7 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey) // Clear old blocks since they're obsolete now. mapNewBlock.clear(); vNewBlockTemplate.clear(); + curBlocks.clear(); pblock = nullptr; } @@ -1046,6 +1058,7 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey) // Save pblock = &newBlock->block; + curBlocks[scriptID] = pblock; mapNewBlock[pblock->GetHash()] = pblock; vNewBlockTemplate.push_back(std::move(newBlock)); }