mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-01-31 10:30:52 +00:00
rpc: parse auxpow submissions early and safely
- Add core_io function DecodeAuxPow implementing a save means to
parse a hex encoded auxpow string into a CAuxPow instance
- Parse both the hash and the hex in the receiving methods, and
return meaningful errors when they fail.
1. Providing a malformed hash now returns RPC_INVALID_PARAMETER
(-8) instead of the generic -1
2. Providing a malformed auxpow hex now returns
RPC_DESERIALIZATION_ERROR (-22) instead of the generic -1
This commit is contained in:
parent
04e932789d
commit
a8e8726ebf
@ -82,25 +82,39 @@ class CreateAuxBlockTest(BitcoinTestFramework):
|
|||||||
assert_equal(auxblock["chainid"], auxblock3["chainid"])
|
assert_equal(auxblock["chainid"], auxblock3["chainid"])
|
||||||
assert_equal(auxblock["target"], auxblock3["target"])
|
assert_equal(auxblock["target"], auxblock3["target"])
|
||||||
|
|
||||||
# If we receive a new block, the template cache must be emptied.
|
# Invalid format for hash - fails before checking auxpow
|
||||||
self.sync_all()
|
|
||||||
self.nodes[1].generate(1)
|
|
||||||
self.sync_all()
|
|
||||||
|
|
||||||
auxblock4 = self.nodes[0].createauxblock(dummy_p2pkh_addr)
|
|
||||||
assert auxblock["hash"] != auxblock4["hash"]
|
|
||||||
try:
|
try:
|
||||||
self.nodes[0].submitauxblock(auxblock["hash"], "x")
|
self.nodes[0].submitauxblock("00", "x")
|
||||||
raise AssertionError("invalid block hash accepted")
|
raise AssertionError("malformed hash accepted")
|
||||||
except JSONRPCException as exc:
|
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.
|
# Invalid format for auxpow.
|
||||||
try:
|
try:
|
||||||
self.nodes[0].submitauxblock(auxblock4["hash"], "x")
|
self.nodes[0].submitauxblock(auxblock2['hash'], "x")
|
||||||
raise AssertionError("malformed auxpow accepted")
|
raise AssertionError("malformed auxpow accepted")
|
||||||
except JSONRPCException as exc:
|
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
|
# Invalidate the block again, send a transaction and query for the
|
||||||
# auxblock to solve that contains the transaction.
|
# auxblock to solve that contains the transaction.
|
||||||
|
|||||||
@ -51,24 +51,39 @@ class GetAuxBlockTest (BitcoinTestFramework):
|
|||||||
auxblock2 = self.nodes[0].getauxblock ()
|
auxblock2 = self.nodes[0].getauxblock ()
|
||||||
assert_equal (auxblock2, auxblock)
|
assert_equal (auxblock2, auxblock)
|
||||||
|
|
||||||
# If we receive a new block, the old hash will be replaced.
|
# Invalid format for hash - fails before checking auxpow
|
||||||
self.sync_all ()
|
|
||||||
self.nodes[1].generate (1)
|
|
||||||
self.sync_all ()
|
|
||||||
auxblock2 = self.nodes[0].getauxblock ()
|
|
||||||
assert auxblock['hash'] != auxblock2['hash']
|
|
||||||
try:
|
try:
|
||||||
self.nodes[0].getauxblock (auxblock['hash'], "x")
|
self.nodes[0].getauxblock("00", "x")
|
||||||
raise AssertionError ("invalid block hash accepted")
|
raise AssertionError("malformed hash accepted")
|
||||||
except JSONRPCException as exc:
|
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.
|
# Invalid format for auxpow.
|
||||||
try:
|
try:
|
||||||
self.nodes[0].getauxblock (auxblock2['hash'], "x")
|
self.nodes[0].getauxblock(auxblock2['hash'], "x")
|
||||||
raise AssertionError ("malformed auxpow accepted")
|
raise AssertionError("malformed auxpow accepted")
|
||||||
except JSONRPCException as exc:
|
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
|
# Invalidate the block again, send a transaction and query for the
|
||||||
# auxblock to solve that contains the transaction.
|
# auxblock to solve that contains the transaction.
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class CAuxPow;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CScript;
|
class CScript;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
@ -20,6 +21,7 @@ CScript ParseScript(const std::string& s);
|
|||||||
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
|
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
|
||||||
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
|
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
|
||||||
bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
|
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 ParseHashUV(const UniValue& v, const std::string& strName);
|
||||||
uint256 ParseHashStr(const std::string&, const std::string& strName);
|
uint256 ParseHashStr(const std::string&, const std::string& strName);
|
||||||
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
|
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
|
||||||
|
|||||||
@ -138,6 +138,24 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DecodeAuxPow(CAuxPow& auxpow, const std::string& strHexAuxPow)
|
||||||
|
{
|
||||||
|
if (!IsHex(strHexAuxPow))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::vector<unsigned char> 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)
|
uint256 ParseHashUV(const UniValue& v, const std::string& strName)
|
||||||
{
|
{
|
||||||
std::string strHex;
|
std::string strHex;
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
#include "consensus/params.h"
|
#include "consensus/params.h"
|
||||||
|
#include "core_io.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
@ -139,25 +140,17 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniValue AuxMiningSubmitBlock(const std::string& hashHex, const std::string& auxpowHex)
|
static UniValue AuxMiningSubmitBlock(const uint256 hash, const CAuxPow auxpow)
|
||||||
{
|
{
|
||||||
AuxMiningCheck();
|
AuxMiningCheck();
|
||||||
LOCK(cs_auxpowrpc);
|
LOCK(cs_auxpowrpc);
|
||||||
|
|
||||||
uint256 hash;
|
|
||||||
hash.SetHex(hashHex);
|
|
||||||
|
|
||||||
std::shared_ptr<CBlock> pblock;
|
std::shared_ptr<CBlock> pblock;
|
||||||
if (!auxBlockCache.Get(hash, pblock)) {
|
if (!auxBlockCache.Get(hash, pblock)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
|
||||||
}
|
}
|
||||||
CBlock& block = *pblock;
|
CBlock& block = *pblock;
|
||||||
|
block.SetAuxpow(new CAuxPow(auxpow));
|
||||||
const std::vector<unsigned char> vchAuxPow = ParseHex(auxpowHex);
|
|
||||||
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
|
|
||||||
CAuxPow pow;
|
|
||||||
ss >> pow;
|
|
||||||
block.SetAuxpow(new CAuxPow(pow));
|
|
||||||
assert(block.GetHash() == hash);
|
assert(block.GetHash() == hash);
|
||||||
|
|
||||||
submitblock_StateCatcher sc(block.GetHash());
|
submitblock_StateCatcher sc(block.GetHash());
|
||||||
@ -222,10 +215,13 @@ UniValue submitauxblock(const JSONRPCRequest& request)
|
|||||||
+ HelpExampleRpc("submitauxblock", "\"hash\" \"serialised auxpow\"")
|
+ HelpExampleRpc("submitauxblock", "\"hash\" \"serialised auxpow\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string blockHashHex = request.params[0].get_str();
|
const uint256 hash = ParseHashV(request.params[0], "hash");
|
||||||
std::string auxPowHex = request.params[1].get_str();
|
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();
|
return response.isNull();
|
||||||
}
|
}
|
||||||
@ -287,10 +283,13 @@ UniValue getauxblock(const JSONRPCRequest& request)
|
|||||||
/* Submit a block instead. */
|
/* Submit a block instead. */
|
||||||
assert(request.params.size() == 2);
|
assert(request.params.size() == 2);
|
||||||
|
|
||||||
std::string blockHashHex = request.params[0].get_str();
|
const uint256 hash = ParseHashV(request.params[0], "hash");
|
||||||
std::string auxPowHex = request.params[1].get_str();
|
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()) {
|
if (response.isNull()) {
|
||||||
coinbaseScript->KeepScript();
|
coinbaseScript->KeepScript();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user