rpc: cache aux block per scriptPubKey in createauxblock
- RPC caching source cherry-picked from: btccom@f4b613b2 - Adds addl test scenarios to createauxblock.py tests Allows pool operators to run multiple sub-pools with different target addresses from a single dogecoind instance. Without this enhancement, subsequent calls to createauxblock with differing addresses ignore the address given and instead just return the block containing the address that initially triggered generation of the cached block. This can quickly lead to unpredictable results as race scenarios between sub-pools come into play. Note that, like with getauxblock, the cache only resets on aux block creation, not submission, so submitauxblock will accept multiple submissions at the same height until createauxblock is called, resulting in chaintip forks. Co-Authored-By: leezhen <jasper.li@bitmain.com>
This commit is contained in:
parent
e90d4437a2
commit
2291b6a7cc
|
@ -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"])
|
||||
|
|
|
@ -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<CScriptID, CBlock*> 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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue