diff --git a/qa/rpc-tests/createauxblock.py b/qa/rpc-tests/createauxblock.py index d0dbbc1f9..f45c2040b 100644 --- a/qa/rpc-tests/createauxblock.py +++ b/qa/rpc-tests/createauxblock.py @@ -82,25 +82,39 @@ class CreateAuxBlockTest(BitcoinTestFramework): assert_equal(auxblock["chainid"], auxblock3["chainid"]) assert_equal(auxblock["target"], auxblock3["target"]) - # If we receive a new block, the template cache must be emptied. - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() - - auxblock4 = self.nodes[0].createauxblock(dummy_p2pkh_addr) - assert auxblock["hash"] != auxblock4["hash"] + # Invalid format for hash - fails before checking auxpow try: - self.nodes[0].submitauxblock(auxblock["hash"], "x") - raise AssertionError("invalid block hash accepted") + self.nodes[0].submitauxblock("00", "x") + raise AssertionError("malformed hash accepted") except JSONRPCException as exc: - assert_equal(exc.error["code"], -8) + assert_equal(exc.error['code'], -8) + assert("hash must be of length 64" in exc.error["message"]) # Invalid format for auxpow. try: - self.nodes[0].submitauxblock(auxblock4["hash"], "x") + self.nodes[0].submitauxblock(auxblock2['hash'], "x") raise AssertionError("malformed auxpow accepted") except JSONRPCException as exc: - assert_equal(exc.error["code"], -1) + assert_equal(exc.error['code'], -22) + assert("decode failed" in exc.error["message"]) + + # If we receive a new block, the old hash will be replaced. + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + auxblock2 = self.nodes[0].createauxblock(dummy_p2pkh_addr) + assert auxblock['hash'] != auxblock2['hash'] + apow = auxpow.computeAuxpowWithChainId(auxblock['hash'], auxpow.reverseHex(auxblock['target']), "98", True) + try: + self.nodes[0].submitauxblock(auxblock['hash'], apow) + raise AssertionError("invalid block hash accepted") + except JSONRPCException as exc: + assert_equal(exc.error['code'], -8) + assert("block hash unknown" in exc.error["message"]) + + # Auxpow doesn't match given hash + res = self.nodes[0].submitauxblock(auxblock2['hash'], apow) + assert not res # Invalidate the block again, send a transaction and query for the # auxblock to solve that contains the transaction. diff --git a/qa/rpc-tests/getauxblock.py b/qa/rpc-tests/getauxblock.py index 92296602a..0f34d4c45 100755 --- a/qa/rpc-tests/getauxblock.py +++ b/qa/rpc-tests/getauxblock.py @@ -51,24 +51,39 @@ class GetAuxBlockTest (BitcoinTestFramework): auxblock2 = self.nodes[0].getauxblock () assert_equal (auxblock2, auxblock) - # If we receive a new block, the old hash will be replaced. - self.sync_all () - self.nodes[1].generate (1) - self.sync_all () - auxblock2 = self.nodes[0].getauxblock () - assert auxblock['hash'] != auxblock2['hash'] + # Invalid format for hash - fails before checking auxpow try: - self.nodes[0].getauxblock (auxblock['hash'], "x") - raise AssertionError ("invalid block hash accepted") + self.nodes[0].getauxblock("00", "x") + raise AssertionError("malformed hash accepted") except JSONRPCException as exc: - assert_equal (exc.error['code'], -8) + assert_equal(exc.error['code'], -8) + assert("hash must be of length 64" in exc.error["message"]) # Invalid format for auxpow. try: - self.nodes[0].getauxblock (auxblock2['hash'], "x") - raise AssertionError ("malformed auxpow accepted") + self.nodes[0].getauxblock(auxblock2['hash'], "x") + raise AssertionError("malformed auxpow accepted") except JSONRPCException as exc: - assert_equal (exc.error['code'], -1) + assert_equal(exc.error['code'], -22) + assert("decode failed" in exc.error["message"]) + + # If we receive a new block, the old hash will be replaced. + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + auxblock2 = self.nodes[0].getauxblock() + assert auxblock['hash'] != auxblock2['hash'] + apow = auxpow.computeAuxpowWithChainId(auxblock['hash'], auxpow.reverseHex(auxblock['target']), "98", True) + try: + self.nodes[0].getauxblock(auxblock['hash'], apow) + raise AssertionError("invalid block hash accepted") + except JSONRPCException as exc: + assert_equal(exc.error['code'], -8) + assert("block hash unknown" in exc.error["message"]) + + # Auxpow doesn't match given hash + res = self.nodes[0].getauxblock(auxblock2['hash'], apow) + assert not res # Invalidate the block again, send a transaction and query for the # auxblock to solve that contains the transaction. diff --git a/src/core_io.h b/src/core_io.h index 2d63be5fc..b0e2d68a2 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -8,6 +8,7 @@ #include #include +class CAuxPow; class CBlock; class CScript; class CTransaction; @@ -20,6 +21,7 @@ CScript ParseScript(const std::string& s); std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false); bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); +bool DecodeAuxPow(CAuxPow& auxpow, const std::string& strHexAuxPow); uint256 ParseHashUV(const UniValue& v, const std::string& strName); uint256 ParseHashStr(const std::string&, const std::string& strName); std::vector ParseHexUV(const UniValue& v, const std::string& strName); diff --git a/src/core_read.cpp b/src/core_read.cpp index a8d667e3b..3ed4c4169 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -138,6 +138,24 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk) return true; } +bool DecodeAuxPow(CAuxPow& auxpow, const std::string& strHexAuxPow) +{ + if (!IsHex(strHexAuxPow)) + return false; + + std::vector auxData(ParseHex(strHexAuxPow)); + + CDataStream ssAuxPow(auxData, SER_NETWORK, PROTOCOL_VERSION); + try { + ssAuxPow >> auxpow; + } + catch (const std::exception&) { + return false; + } + + return true; +} + uint256 ParseHashUV(const UniValue& v, const std::string& strName) { std::string strHex; diff --git a/src/rpc/auxpow.cpp b/src/rpc/auxpow.cpp index 7d4914bae..828f1369b 100644 --- a/src/rpc/auxpow.cpp +++ b/src/rpc/auxpow.cpp @@ -12,6 +12,7 @@ #include "chainparams.h" #include "consensus/consensus.h" #include "consensus/params.h" +#include "core_io.h" #include "init.h" #include "miner.h" #include "net.h" @@ -139,25 +140,17 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey) return result; } -static UniValue AuxMiningSubmitBlock(const std::string& hashHex, const std::string& auxpowHex) +static UniValue AuxMiningSubmitBlock(const uint256 hash, const CAuxPow auxpow) { AuxMiningCheck(); LOCK(cs_auxpowrpc); - uint256 hash; - hash.SetHex(hashHex); - std::shared_ptr pblock; if (!auxBlockCache.Get(hash, pblock)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown"); } CBlock& block = *pblock; - - const std::vector vchAuxPow = ParseHex(auxpowHex); - CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION); - CAuxPow pow; - ss >> pow; - block.SetAuxpow(new CAuxPow(pow)); + block.SetAuxpow(new CAuxPow(auxpow)); assert(block.GetHash() == hash); submitblock_StateCatcher sc(block.GetHash()); @@ -222,10 +215,13 @@ UniValue submitauxblock(const JSONRPCRequest& request) + HelpExampleRpc("submitauxblock", "\"hash\" \"serialised auxpow\"") ); - std::string blockHashHex = request.params[0].get_str(); - std::string auxPowHex = request.params[1].get_str(); + const uint256 hash = ParseHashV(request.params[0], "hash"); + CAuxPow auxpow; + if (!DecodeAuxPow(auxpow, request.params[1].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "AuxPow decode failed"); + } - UniValue response = AuxMiningSubmitBlock(blockHashHex, auxPowHex); + UniValue response = AuxMiningSubmitBlock(hash, auxpow); return response.isNull(); } @@ -287,10 +283,13 @@ UniValue getauxblock(const JSONRPCRequest& request) /* Submit a block instead. */ assert(request.params.size() == 2); - std::string blockHashHex = request.params[0].get_str(); - std::string auxPowHex = request.params[1].get_str(); + const uint256 hash = ParseHashV(request.params[0], "hash"); + CAuxPow auxpow; + if (!DecodeAuxPow(auxpow, request.params[1].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "AuxPow decode failed"); + } - UniValue response = AuxMiningSubmitBlock(blockHashHex, auxPowHex); + UniValue response = AuxMiningSubmitBlock(hash, auxpow); if (response.isNull()) { coinbaseScript->KeepScript();