Browse Source

Added support for cryptonote header in functional test python code.

cn_mining
Jianping Wu 5 years ago
parent
commit
dea50be56b
  1. 73
      src/rpc/mining.cpp
  2. 3
      test/functional/test_framework/authproxy.py
  3. 13
      test/functional/test_framework/blocktools.py
  4. 102
      test/functional/test_framework/messages.py

73
src/rpc/mining.cpp

@ -632,6 +632,78 @@ static uint256 CryptoHashToUint256(const crypto::hash& hash) @@ -632,6 +632,78 @@ static uint256 CryptoHashToUint256(const crypto::hash& hash)
return uint256(prev_id);
}
UniValue submitblock_original(const JSONRPCRequest& request)
{
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
"submitblock \"hexdata\" ( \"dummy\" )\n"
"\nAttempts to submit new block to network.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments\n"
"1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
"2. \"dummy\" (optional) dummy value, for compatibility with BIP22. This value is ignored.\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
);
}
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock& block = *blockptr;
if (!DecodeHexBlk(block, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
}
uint256 hash = block.GetHash();
bool fBlockPresent = false;
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex *pindex = mi->second;
if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
return "duplicate";
}
if (pindex->nStatus & BLOCK_FAILED_MASK) {
return "duplicate-invalid";
}
// Otherwise, we might only have the header - process the block before returning
fBlockPresent = true;
}
}
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi != mapBlockIndex.end()) {
UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus());
}
}
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr);
UnregisterValidationInterface(&sc);
if (fBlockPresent) {
if (fAccepted && !sc.found) {
return "duplicate-inconclusive";
}
return "duplicate";
}
if (!sc.found) {
return "inconclusive";
}
return BIP22ValidationResult(sc.state);
}
// Cryptonote RPC call
UniValue submitblock(const JSONRPCRequest& request)
{
@ -947,6 +1019,7 @@ static const CRPCCommand commands[] = @@ -947,6 +1019,7 @@ static const CRPCCommand commands[] =
{ "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
{ "mining", "getblocktemplate", &getblocktemplate, {"reserve_size", "wallet_address"} },
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
{ "mining", "submitblock_original", &submitblock_original, {"hexdata","dummy"} },
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },

3
test/functional/test_framework/authproxy.py

@ -133,6 +133,9 @@ class AuthServiceProxy(): @@ -133,6 +133,9 @@ class AuthServiceProxy():
def __call__(self, *args, **argsn):
postdata = json.dumps(self.get_request(*args, **argsn), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
# Kevacoin: submitblock expects a cryptonote wrapper around the block,
# while submitblock_original is the original implementation.
postdata = postdata.replace('submitblock', 'submitblock_original')
response = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if response['error'] is not None:
raise JSONRPCException(response['error'])

13
test/functional/test_framework/blocktools.py

@ -35,6 +35,14 @@ def create_block(hashprev, coinbase, nTime=None): @@ -35,6 +35,14 @@ def create_block(hashprev, coinbase, nTime=None):
block.nBits = 0x207fffff # Will break after a difficulty adjustment...
block.vtx.append(coinbase)
block.hashMerkleRoot = block.calc_merkle_root()
# In kevacoin, nNonce is used to store the height of the block, which will
# be used in cn_slow_hash computation.
block.nNonce = coinbase.height
assert block.nNonce > 0
block.major_version = 10 # CN variant 4
block.timestamp = block.nTime
block.calc_sha256()
return block
@ -98,6 +106,11 @@ def create_coinbase(height, pubkey = None): @@ -98,6 +106,11 @@ def create_coinbase(height, pubkey = None):
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
coinbase.vout = [ coinbaseoutput ]
coinbase.calc_sha256()
# Kevacoin needs to know the height, because it is used as a parameter of
# cn_slow_hash.
coinbase.height = height
return coinbase
# Create a transaction.

102
test/functional/test_framework/messages.py

@ -100,6 +100,32 @@ def ser_uint256(u): @@ -100,6 +100,32 @@ def ser_uint256(u):
return rs
def deser_varint(f):
shift = 0
result = 0
while True:
i = ord(f.read(1))
result |= (i & 0x7f) << shift
shift += 7
if not (i & 0x80):
break
return result
def ser_varint(u):
buf = b''
while True:
towrite = u & 0x7f
u >>= 7
if u:
buf += bytes((towrite | 0x80, ))
else:
buf += bytes((towrite, ))
break
return buf
def uint256_from_str(s):
r = 0
t = struct.unpack("<IIIIIIII", s[:32])
@ -499,6 +525,17 @@ class CBlockHeader(): @@ -499,6 +525,17 @@ class CBlockHeader():
self.nBits = header.nBits
self.nNonce = header.nNonce
self.sha256 = header.sha256
# Cryptonote header
self.major_version = header.major_version
self.minor_version = header.minor_version
self.timestamp = header.timestamp
self.prev_id = header.prev_id
self.nonce = header.nonce
self.merkle_root = header.merkle_root
self.nTxes = header.nTxes
# End of cryptonote header
self.hash = header.hash
self.scrypt256 = header.scrypt256
self.calc_sha256()
@ -514,6 +551,16 @@ class CBlockHeader(): @@ -514,6 +551,16 @@ class CBlockHeader():
self.hash = None
self.scrypt256 = None
# Cryptonote header
self.major_version = 0
self.minor_version = 0
self.timestamp = 0
self.prev_id = None
self.nonce = 0
self.merkle_root = None
self.nTxes = 0
# End of cryptonote header
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
self.hashPrevBlock = deser_uint256(f)
@ -521,6 +568,17 @@ class CBlockHeader(): @@ -521,6 +568,17 @@ class CBlockHeader():
self.nTime = struct.unpack("<I", f.read(4))[0]
self.nBits = struct.unpack("<I", f.read(4))[0]
self.nNonce = struct.unpack("<I", f.read(4))[0]
# Cryptonote header
cnHeader = deser_string(f)
self.major_version = struct.unpack("<B", f.read(1))[0]
self.minor_version = struct.unpack("<B", f.read(1))[0]
self.timestamp = deser_varint(f)
self.prev_id = deser_uint256(f)
self.nonce = struct.unpack("<I", f.read(4))[0]
self.merkle_root = deser_uint256(f)
self.nTxes = struct.unpack("<B", f.read(1))[0]
self.sha256 = None
self.hash = None
self.scrypt256 = None
@ -533,7 +591,19 @@ class CBlockHeader(): @@ -533,7 +591,19 @@ class CBlockHeader():
r += struct.pack("<I", self.nTime)
r += struct.pack("<I", self.nBits)
r += struct.pack("<I", self.nNonce)
return r
# Cryptonote header
c = b""
c += struct.pack("<B", self.major_version)
c += struct.pack("<B", self.minor_version)
c += ser_varint(self.timestamp)
c += ser_uint256(self.prev_id)
c += struct.pack("<I", self.nonce)
c += ser_uint256(self.merkle_root)
c += struct.pack("<B", self.nTxes)
c = ser_string(c)
return r + c
def calc_sha256(self):
if self.sha256 is None:
@ -544,9 +614,31 @@ class CBlockHeader(): @@ -544,9 +614,31 @@ class CBlockHeader():
r += struct.pack("<I", self.nTime)
r += struct.pack("<I", self.nBits)
r += struct.pack("<I", self.nNonce)
self.sha256 = uint256_from_str(hash256(r))
self.hash = encode(hash256(r)[::-1], 'hex_codec').decode('ascii')
self.scrypt256 = uint256_from_str(pycryptonight.cn_slow_hash(r, 2))
# For kevacoin, self.sha256 doesn't actually store the sha256 value.
# It stores the cn_fast hash instead.
self.sha256_actual = uint256_from_str(hash256(r))
#self.hash = encode(hash256(r)[::-1], 'hex_codec').decode('ascii')
# Cryptonote cn hash
c = b""
c += struct.pack("<B", self.major_version)
c += struct.pack("<B", self.minor_version)
c += ser_varint(self.timestamp)
# prev_id is used to store sha256 value of the blockhash for Proof-of-Work
self.prev_id = self.sha256_actual
c += ser_uint256(self.prev_id)
c += struct.pack("<I", self.nonce)
# hardcoded merkle root.
self.merkle_root = uint256_from_str(bytes.fromhex("3cf6c3b6da3f4058853ee70369ee43d473aca91ae8fc8f44a645beb21c392d80"))
c += ser_uint256(self.merkle_root)
c += struct.pack("<B", self.nTxes)
# self.sha256 stores the cn_fast hash.
self.sha256 = uint256_from_str(pycryptonight.cn_fast_hash(c))
self.hash = encode(pycryptonight.cn_fast_hash(c)[::-1], 'hex_codec').decode('ascii')
# 4 is variant 4. nNonce is used to store block height.
self.scrypt256 = uint256_from_str(pycryptonight.cn_slow_hash(c, self.major_version - 6, 0, self.nNonce))
def rehash(self):
self.sha256 = None
@ -623,7 +715,7 @@ class CBlock(CBlockHeader): @@ -623,7 +715,7 @@ class CBlock(CBlockHeader):
self.rehash()
target = uint256_from_compact(self.nBits)
while self.scrypt256 > target:
self.nNonce += 1
self.nonce += 1
self.rehash()
def __repr__(self):

Loading…
Cancel
Save