Rebase LBRY on top of Bitcoin 0.17 #263

Closed
lbrynaut wants to merge 18 commits from updated-rebase-0.17-deps into bitcoin-0.17
18 changed files with 8926 additions and 158 deletions
Showing only changes of commit 6dd2df3a0c - Show all commits

View file

@ -0,0 +1,277 @@
#!/usr/bin/env python3
import re
import subprocess as sp
import sys
import json
import urllib.request as req
import jsonschema
re_full = re.compile(r'(?P<name>^.*?$)(?P<desc>.*?)(^Argument.*?$(?P<args>.*?))?(^Result[^\n,]*?:\s*$(?P<resl>.*?))?(^Exampl.*?$(?P<exmp>.*))?', re.DOTALL | re.MULTILINE)
re_argline = re.compile(r'^("?)(?P<name>\w.*?)\1(\s*:.+?,?\s*)?\s+\((?P<type>.*?)\)\s*(?P<desc>.*?)\s*$', re.DOTALL)
def get_obj_from_dirty_text(full_object: str):
lines = full_object.splitlines()
lefts = []
i = 0
while i < len(lines):
idx = lines[i].find('(')
left = lines[i][0:idx].strip() if idx >= 0 else lines[i]
left = left.rstrip('.') # handling , ...
left = left.strip()
left = left.rstrip(',')
lefts.append(left)
while idx >= 0 and i < len(lines) - 1:
idx2 = len(re.match(r'^\s*', lines[i + 1]).group())
if idx2 > idx:
lines[i] += lines.pop(i + 1)[idx2 - 1:]
else:
break
i += 1
ret = None
try:
property_stack = []
object_stack = []
name_stack = []
last_name = None
for i in range(0, len(lines)):
left = lefts[i]
if not left:
continue
line = lines[i].strip()
arg_parsed = re_argline.fullmatch(line)
property_refined_type = 'object'
if arg_parsed is not None:
property_name, property_type, property_desc = arg_parsed.group('name', 'type', 'desc')
property_refined_type, property_required, property_child = get_type(property_type, None)
if property_refined_type is not 'array' and property_refined_type is not 'object':
property_stack[-1][property_name] = {
'type': property_refined_type,
'description': property_desc
}
else:
last_name = property_name
elif len(left) > 1:
match = re.match(r'^(\[)?"(?P<name>\w.*?)"(\])?.*', left)
last_name = match.group('name')
if match.group(1) is not None and match.group(3) is not None:
left = '['
property_refined_type = 'string'
if 'string' not in line:
raise NotImplementedError('Not implemented: ' + line)
if left.endswith('['):
object_stack.append({'type': 'array', 'items': {'type': property_refined_type}})
property_stack.append({})
name_stack.append(last_name)
elif left.endswith('{'):
object_stack.append({'type': 'object'})
property_stack.append({})
name_stack.append(last_name)
elif (left.endswith(']') and '[' not in left) or (left.endswith('}') and '{' not in left):
obj = object_stack.pop()
prop = property_stack.pop()
name = name_stack.pop()
if len(prop) > 0:
if 'items' in obj:
obj['items']['properties'] = prop
else:
obj['properties'] = prop
if len(property_stack) > 0:
if 'items' in object_stack[-1]:
object_stack[-1]['items']['type'] = obj['type']
if len(prop) > 0:
object_stack[-1]['items']['properties'] = prop
else:
if name is None:
raise RuntimeError('Not expected')
property_stack[-1][name] = obj
else:
ret = obj
if ret is not None:
if i + 1 < len(lines) - 1:
print('Ignoring this data (below the parsed object): ' + "\n".join(lines[i+1:]), file=sys.stderr)
return ret
except Exception as e:
print('Exception: ' + str(e), file=sys.stderr)
print('Unable to cope with: ' + '\n'.join(lines), file=sys.stderr)
return None
def get_type(arg_type: str, full_line: str):
if arg_type is None:
return 'string', True, None
required = 'required' in arg_type or 'optional' not in arg_type
arg_type = arg_type.lower()
if 'array' in arg_type:
return 'array', required, None
if 'numeric' in arg_type:
return 'number', required, None
if 'bool' in arg_type:
return 'boolean', required, None
if 'string' in arg_type:
return 'string', required, None
if 'object' in arg_type:
properties = get_obj_from_dirty_text(full_line) if full_line is not None else None
return 'object', required, properties
print('Unable to derive type from: ' + arg_type, file=sys.stderr)
return None, False, None
def get_default(arg_refined_type: str, arg_type: str):
if 'default=' in arg_type:
if 'number' in arg_refined_type:
return int(re.match('.*default=([^,)]+)', arg_type).group(1))
if 'string' in arg_refined_type:
return re.match('.*default=([^,)]+)', arg_type).group(1)
if 'boolean' in arg_refined_type:
if 'default=true' in arg_type:
return True
if 'default=false' in arg_type:
return False
raise NotImplementedError('Not implemented: ' + arg_type)
if 'array' in arg_type:
raise NotImplementedError('Not implemented: ' + arg_type)
return None
def parse_single_argument(line: str):
if line:
line = line.strip()
if not line or line.startswith('None'):
return None, None, False
arg_parsed = re_argline.fullmatch(line)
if arg_parsed is None:
if line.startswith('{') or line.startswith('['):
return get_obj_from_dirty_text(line), None, True
else:
print("Unparsable argument: " + line, file=sys.stderr)
descriptor = {
'type': 'array' if line.startswith('[') else 'object',
'description': line,
}
return descriptor, None, True
arg_name, arg_type, arg_desc = arg_parsed.group('name', 'type', 'desc')
if not arg_type:
raise NotImplementedError('Not implemented: ' + arg_type)
arg_refined_type, arg_required, arg_properties = get_type(arg_type, arg_desc)
if arg_properties is not None:
return arg_properties, arg_name, arg_required
arg_refined_default = get_default(arg_refined_type, arg_type)
arg_desc = re.sub('\s+', ' ', arg_desc.strip()) \
if arg_desc and arg_refined_type is not 'object' and arg_refined_type is not 'array' \
else arg_desc.strip() if arg_desc else ''
descriptor = {
'type': arg_refined_type,
'description': arg_desc,
}
if arg_refined_default is not None:
descriptor['default'] = arg_refined_default
return descriptor, arg_name, arg_required
def parse_params(args: str):
arguments = {}
requireds = []
if args:
for line in re.split('\s*\d+\.\s+', args, re.DOTALL):
descriptor, name, required = parse_single_argument(line)
if descriptor is None:
continue
if required:
requireds.append(name)
arguments[name] = descriptor
return arguments, requireds
def get_api(section_name: str, command: str, command_help: str):
parsed = re_full.fullmatch(command_help)
if parsed is None:
raise RuntimeError('Unable to resolve help format for ' + command)
name, desc, args, resl, exmp = parsed.group('name', 'desc', 'args', 'resl', 'exmp')
properties, required = parse_params(args)
result_descriptor, result_name, result_required = parse_single_argument(resl)
desc = re.sub('\s+', ' ', desc.strip()) if desc else name
example_array = exmp.splitlines() if exmp else []
ret = {
'summary': desc,
'description': example_array,
'tags': [section_name],
'params': {
'type': 'object',
'properties': properties,
'required': required
},
}
if result_descriptor is not None:
ret['result'] = result_descriptor
return ret
def write_api():
if len(sys.argv) < 2:
print("Missing required argument: <path to CLI tool>", file=sys.stderr)
sys.exit(1)
cli_tool = sys.argv[1]
result = sp.run([cli_tool, "help"], stdout=sp.PIPE, universal_newlines=True)
commands = result.stdout
sections = re.split('^==\s*(.*?)\s*==$', commands, flags=re.MULTILINE)
methods = {}
for section in sections:
if not section:
continue
lines = section.splitlines()
if len(lines) == 1:
section_name = lines[0]
continue
for command in sorted(lines[1:]):
if not command:
continue
command = command.split(' ')[0]
result = sp.run([cli_tool, "help", command], stdout=sp.PIPE, universal_newlines=True)
methods[command] = get_api(section_name, command, result.stdout)
version = sp.run([cli_tool, "--version"], stdout=sp.PIPE, universal_newlines=True)
wrapper = {
'$schema': 'https://rawgit.com/mzernetsch/jrgen/master/jrgen-spec.schema.json',
'jrgen': '1.1',
'jsonrpc': '1.0', # see https://github.com/bitcoin/bitcoin/pull/12435
'info': {
'title': 'lbrycrd RPC API',
'version': version.stdout.strip(),
'description': []
},
'definitions': {}, # for items used in $ref further down
'methods': methods,
}
schema = req.urlopen(wrapper['$schema']).read().decode('utf-8')
try:
jsonschema.validate(wrapper, schema)
except Exception as e:
print('From schema validation: ' + str(e), file=sys.stderr)
print(json.dumps(wrapper, indent=4))
if __name__ == '__main__':
write_api()

View file

@ -0,0 +1,129 @@
#!/usr/bin/env python3
import re
import subprocess as sp
import sys
import json
re_full = re.compile(r'(?P<name>^.*?$)(?P<desc>.*?)(^Argument.*?$(?P<args>.*?))?(^Result[^\n]*?:\s*$(?P<resl>.*?))?(^Exampl.*?$(?P<exmp>.*))?', re.DOTALL | re.MULTILINE)
re_argline = re.compile(r'^("?)(?P<name>.*?)\1\s+\((?P<type>.*?)\)\s*(?P<desc>.*)$', re.DOTALL)
def get_type(arg_type, full_line):
if arg_type is None:
return 'string'
arg_type = arg_type.lower()
if 'numeric' in arg_type:
return 'number'
if 'bool' in arg_type:
return 'boolean'
if 'string' in arg_type:
return 'string'
if 'object' in arg_type:
return 'object'
raise Exception('Not implemented: ' + arg_type)
def parse_params(args):
arguments = []
if args:
for line in re.split('\s*\d+\.\s+', args, re.DOTALL):
if not line or not line.strip() or line.strip().startswith('None'):
continue
arg_parsed = re_argline.fullmatch(line)
if arg_parsed is None:
raise Exception("Unparsable argument: " + line)
arg_name, arg_type, arg_desc = arg_parsed.group('name', 'type', 'desc')
if not arg_type:
raise Exception('Not implemented: ' + arg_type)
arg_required = 'required' in arg_type or 'optional' not in arg_type
arg_refined_type = get_type(arg_type, line)
arg_desc = re.sub('\s+', ' ', arg_desc.strip()) if arg_desc else []
arguments.append({
'name': arg_name,
'type': arg_refined_type,
'description': arg_desc,
'is_required': arg_required
})
return arguments
def process_examples(examples: str):
if not examples:
return []
examples = examples.strip()
splits = examples.split('\n')
result = []
inner = {}
for s in splits:
if not s:
continue
if '> curl' in s:
inner['curl'] = s.strip()
elif '> lbrycrd' in s:
inner['cli'] = s.strip()
else:
if 'title' in inner:
result.append(inner)
inner = {}
inner['title'] = s.strip()
result.append(inner)
return result
def get_api(section_name, command, command_help):
parsed = re_full.fullmatch(command_help)
if parsed is None:
raise Exception('Unable to resolve help format for ' + command)
name, desc, args, resl, exmp = parsed.group('name', 'desc', 'args', 'resl', 'exmp')
arguments = parse_params(args)
cmd_desc = re.sub('\s+', ' ', desc.strip()) if desc else ''
examp_desc = process_examples(exmp)
cmd_resl = resl.strip() if resl else None
ret = {
'name': command,
'namespace': section_name,
'description': cmd_desc,
'arguments': arguments,
'examples': examp_desc
}
if cmd_resl is not None:
ret['returns'] = cmd_resl
return ret
def write_api():
if len(sys.argv) < 2:
print("Missing required argument: <path to CLI tool>", file=sys.stderr)
sys.exit(1)
cli_tool = sys.argv[1]
result = sp.run([cli_tool, "help"], stdout=sp.PIPE, universal_newlines=True)
commands = result.stdout
sections = re.split('^==\s*(.*?)\s*==$', commands, flags=re.MULTILINE)
apis = []
for section in sections:
if not section:
continue
lines = section.splitlines()
if len(lines) == 1:
section_name = lines[0]
continue
for command in sorted(lines[1:]):
if not command:
continue
command = command.split(' ')[0]
result = sp.run([cli_tool, "help", command], stdout=sp.PIPE, universal_newlines=True)
apis.append(get_api(section_name, command, result.stdout))
print(json.dumps(apis, indent=4))
if __name__ == '__main__':
write_api()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -247,8 +247,8 @@ public:
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
// FIXME: adjust heights
consensus.BIP65Height = 1000000;
consensus.BIP66Height = 1000000;
consensus.BIP65Height = 1200000;
consensus.BIP66Height = 1200000;
consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 150;
consensus.nPowTargetSpacing = 150;

View file

@ -33,11 +33,11 @@ const CBaseChainParams& BaseParams()
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
return MakeUnique<CBaseChainParams>("", 9246);
return MakeUnique<CBaseChainParams>("", 9245);
else if (chain == CBaseChainParams::TESTNET)
return MakeUnique<CBaseChainParams>("testnet3", 19246);
return MakeUnique<CBaseChainParams>("testnet3", 19245);
else if (chain == CBaseChainParams::REGTEST)
return MakeUnique<CBaseChainParams>("regtest", 29246);
return MakeUnique<CBaseChainParams>("regtest", 29245);
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}

View file

@ -412,7 +412,7 @@ const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
{
nodeMapType::const_iterator itchildren = current->children.find(*itname);
if (itchildren == current->children.end())
return NULL;
return nullptr;
current = itchildren->second;
}
return current;
@ -692,7 +692,7 @@ bool CClaimTrie::update(nodeCacheType& cache, hashMapType& hashes, std::map<std:
{
if (!updateName(itcache->first, itcache->second))
{
LogPrintf("%s: Failed to update name for:%s\n", __func__, itcache->first);
LogPrintf("%s: Failed to update name for: %s\n", __func__, itcache->first);
return false;
}
}
@ -700,7 +700,7 @@ bool CClaimTrie::update(nodeCacheType& cache, hashMapType& hashes, std::map<std:
{
if (!updateHash(ithash->first, ithash->second))
{
LogPrintf("%s: Failed to update hash for:%s\n", __func__, ithash->first);
LogPrintf("%s: Failed to update hash for: %s\n", __func__, ithash->first);
return false;
}
}
@ -708,7 +708,7 @@ bool CClaimTrie::update(nodeCacheType& cache, hashMapType& hashes, std::map<std:
{
if (!updateTakeoverHeight(itheight->first, itheight->second))
{
LogPrintf("%s: Failed to update takeover height for:%s\n", __func__, itheight->first);
LogPrintf("%s: Failed to update takeover height for: %s\n", __func__, itheight->first);
return false;
}
}
@ -775,7 +775,7 @@ bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode
current = itchild->second;
}
}
assert(current != NULL);
assert(current != nullptr);
current->claims.swap(updatedNode->claims);
markNodeDirty(name, current);
for (nodeMapType::iterator itchild = current->children.begin(); itchild != current->children.end();)
@ -799,7 +799,7 @@ bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode
bool CClaimTrie::recursiveNullify(CClaimTrieNode* node, const std::string& name)
{
assert(node != NULL);
assert(node != nullptr);
for (nodeMapType::iterator itchild = node->children.begin(); itchild != node->children.end(); ++itchild)
{
std::stringstream nextName;
@ -808,7 +808,7 @@ bool CClaimTrie::recursiveNullify(CClaimTrieNode* node, const std::string& name)
return false;
}
node->children.clear();
markNodeDirty(name, NULL);
markNodeDirty(name, nullptr);
delete node;
return true;
}
@ -823,7 +823,7 @@ bool CClaimTrie::updateHash(const std::string& name, uint256& hash)
return false;
current = itchild->second;
}
assert(current != NULL);
assert(current != nullptr);
assert(!hash.IsNull());
current->hash = hash;
markNodeDirty(name, current);
@ -840,7 +840,7 @@ bool CClaimTrie::updateTakeoverHeight(const std::string& name, int nTakeoverHeig
return false;
current = itchild->second;
}
assert(current != NULL);
assert(current != nullptr);
current->nHeightOfLastTakeover = nTakeoverHeight;
markNodeDirty(name, current);
return true;
@ -961,7 +961,7 @@ void CClaimTrie::BatchWriteSupportExpirationQueueRows(CDBBatch& batch)
bool CClaimTrie::WriteToDisk()
{
CDBBatch batch(*const_cast<CDBWrapper*>(&db));
CDBBatch batch(db);
for (nodeCacheType::iterator itcache = dirtyNodes.begin(); itcache != dirtyNodes.end(); ++itcache)
BatchWriteNode(batch, itcache->first, itcache->second);
dirtyNodes.clear();
@ -1011,7 +1011,7 @@ bool CClaimTrie::ReadFromDisk(bool check)
LogPrintf("%s: Couldn't read the current height\n", __func__);
setExpirationTime(Params().GetConsensus().GetExpirationTime(nCurrentHeight-1));
boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator());
boost::scoped_ptr<CDBIterator> pcursor(db.NewIterator());
pcursor->SeekToFirst();
while (pcursor->Valid())
@ -1131,6 +1131,7 @@ bool CClaimTrieCacheBase::empty() const
return base->empty() && cache.empty();
}
// "position" has already been normalized if needed
CClaimTrieNode* CClaimTrieCacheBase::addNodeToCache(const std::string& position, CClaimTrieNode* original) const
{
// create a copy of the node in the cache, if new node, create empty node
@ -1155,13 +1156,12 @@ bool CClaimTrieCacheBase::getOriginalInfoForName(const std::string& name, CClaim
bool CClaimTrieCacheBase::insertClaimIntoTrie(const std::string& name, CClaimValue claim, bool fCheckTakeover) const
{
assert(base);
CClaimTrieNode* currentNode = getRoot();
nodeCacheType::iterator cachedNode;
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
{
std::string sCurrentSubstring(name.begin(), itCur);
std::string sNextSubstring(name.begin(), itCur + 1);
const std::string sCurrentSubstring(name.begin(), itCur);
const std::string sNextSubstring(name.begin(), itCur + 1);
cachedNode = cache.find(sNextSubstring);
if (cachedNode != cache.end())
@ -1194,7 +1194,7 @@ bool CClaimTrieCacheBase::insertClaimIntoTrie(const std::string& name, CClaimVal
{
currentNode = addNodeToCache(sCurrentSubstring, currentNode);
}
CClaimTrieNode* newNode = addNodeToCache(sNextSubstring, NULL);
CClaimTrieNode* newNode = addNodeToCache(sNextSubstring, nullptr);
currentNode->children[*itCur] = newNode;
currentNode = newNode;
}
@ -1241,7 +1241,6 @@ bool CClaimTrieCacheBase::insertClaimIntoTrie(const std::string& name, CClaimVal
bool CClaimTrieCacheBase::removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover) const
{
assert(base);
CClaimTrieNode* currentNode = getRoot();
nodeCacheType::iterator cachedNode;
assert(currentNode != nullptr); // If there is no root in either the trie or the cache, how can there be any names to remove?
@ -1272,7 +1271,7 @@ bool CClaimTrieCacheBase::removeClaimFromTrie(const std::string& name, const COu
else
currentNode = addNodeToCache(name, currentNode);
assert(currentNode != NULL);
assert(currentNode != nullptr);
if (currentNode->claims.empty())
{
LogPrintf("%s: Asked to remove claim from node without claims\n", __func__);
@ -1289,7 +1288,8 @@ bool CClaimTrieCacheBase::removeClaimFromTrie(const std::string& name, const COu
if (!success)
{
LogPrintf("%s: Removing a claim was unsuccessful. name = %s, txhash = %s, nOut = %d", __func__, name.c_str(), outPoint.hash.GetHex(), outPoint.n);
LogPrintf("%s: Removing a claim was unsuccessful. name = %s, txhash = %s, nOut = %d\n",
__func__, name.c_str(), outPoint.hash.GetHex(), outPoint.n);
return false;
}
@ -1305,6 +1305,7 @@ bool CClaimTrieCacheBase::removeClaimFromTrie(const std::string& name, const COu
return recursivePruneName(getRoot(), 0, name);
}
// sName has already been normalized if needed
bool CClaimTrieCacheBase::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned int nPos, const std::string& sName, bool* pfNullified) const
{
// Recursively prune leaf node(s) without any claims in it and store
@ -1316,7 +1317,7 @@ bool CClaimTrieCacheBase::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned
{
std::string sNextSubstring = sName.substr(0, nPos + 1);
unsigned char cNext = sName.at(nPos);
CClaimTrieNode* tnNext = NULL;
CClaimTrieNode* tnNext = nullptr;
nodeCacheType::iterator cachedNode = cache.find(sNextSubstring);
if (cachedNode != cache.end())
tnNext = cachedNode->second;
@ -1326,7 +1327,7 @@ bool CClaimTrieCacheBase::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned
if (childNode != tnCurrent->children.end())
tnNext = childNode->second;
}
if (tnNext == NULL)
if (tnNext == nullptr)
return false;
bool fChildNullified = false;
if (!recursivePruneName(tnNext, nPos + 1, sName, &fChildNullified))
@ -1502,7 +1503,7 @@ bool CClaimTrieCacheBase::removeClaimFromQueue(const std::string& name, const CO
}
if (itQueue != itQueueRow->second.end())
{
std::swap(claim, itQueue->second);
claim = itQueue->second;
itQueueNameRow->second.erase(itQueueName);
itQueueRow->second.erase(itQueue);
return true;
@ -1623,6 +1624,7 @@ bool CClaimTrieCacheBase::reorderTrieNode(const std::string& name, bool fCheckTa
// The node doesn't exist, so it can't be reordered.
return true;
}
currentNode = new CClaimTrieNode(*currentNode);
std::pair<nodeCacheType::iterator, bool> ret;
ret = cache.insert(std::pair<std::string, CClaimTrieNode*>(name, currentNode));
@ -1658,10 +1660,10 @@ bool CClaimTrieCacheBase::reorderTrieNode(const std::string& name, bool fCheckTa
return true;
}
// name has already been normalized if needed
bool CClaimTrieCacheBase::getSupportsForName(const std::string& name, supportMapEntryType& supports) const
{
supportMapType::iterator cachedNode;
cachedNode = supportCache.find(name);
const supportMapType::iterator cachedNode = supportCache.find(name);
if (cachedNode != supportCache.end())
{
supports = cachedNode->second;
@ -1932,8 +1934,6 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
std::vector<std::pair<std::string, int> >& takeoverHeightUndo)
{
// we don't actually modify the claimTrie here; that happens in flush
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
claimQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
if (itQueueRow != claimQueueCache.end())
{
@ -1987,6 +1987,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
expirationQueueType::iterator itExpirationRow = getExpirationQueueCacheRow(nCurrentHeight, false);
if (itExpirationRow != expirationQueueCache.end())
{
// for every claim expiring right now
for (expirationQueueRowType::iterator itEntry = itExpirationRow->second.begin(); itEntry != itExpirationRow->second.end(); ++itEntry)
{
CClaimValue claim;
@ -2226,13 +2227,12 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo)
{
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
nCurrentHeight--;
if (expireSupportUndo.begin() != expireSupportUndo.end())
{
expirationQueueType::iterator itSupportExpireRow = getSupportExpirationQueueCacheRow(nCurrentHeight, true);
for (supportQueueRowType::iterator itSupportExpireUndo = expireSupportUndo.begin(); itSupportExpireUndo != expireSupportUndo.end(); ++itSupportExpireUndo)
for (supportQueueRowType::reverse_iterator itSupportExpireUndo = expireSupportUndo.rbegin(); itSupportExpireUndo != expireSupportUndo.rend(); ++itSupportExpireUndo)
{
insertSupportIntoMap(itSupportExpireUndo->first, itSupportExpireUndo->second, false);
if (nCurrentHeight == itSupportExpireUndo->second.nHeight + base->nExpirationTime)
@ -2240,20 +2240,23 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
}
}
for (insertUndoType::iterator itSupportUndo = insertSupportUndo.begin(); itSupportUndo != insertSupportUndo.end(); ++itSupportUndo)
for (insertUndoType::reverse_iterator itSupportUndo = insertSupportUndo.rbegin(); itSupportUndo != insertSupportUndo.rend(); ++itSupportUndo)
{
supportQueueType::iterator itSupportRow = getSupportQueueCacheRow(itSupportUndo->nHeight, true);
CSupportValue support;
assert(removeSupportFromMap(itSupportUndo->name, itSupportUndo->outPoint, support, false));
if (itSupportUndo->nHeight >= 0)
{
// support.nValidHeight may have been changed if this was inserted before activation height
// due to a triggered takeover, change it back to original nValidAtHeight
support.nValidAtHeight = itSupportUndo->nHeight;
supportQueueType::iterator itSupportRow = getSupportQueueCacheRow(itSupportUndo->nHeight, true);
queueNameType::iterator itSupportNameRow = getSupportQueueCacheNameRow(itSupportUndo->name, true);
itSupportRow->second.push_back(std::make_pair(itSupportUndo->name, support));
itSupportNameRow->second.push_back(outPointHeightType(support.outPoint, support.nValidAtHeight));
}
}
if (expireUndo.begin() != expireUndo.end())
if (!expireUndo.empty())
{
expirationQueueType::iterator itExpireRow = getExpirationQueueCacheRow(nCurrentHeight, true);
for (claimQueueRowType::iterator itExpireUndo = expireUndo.begin(); itExpireUndo != expireUndo.end(); ++itExpireUndo)
@ -2265,20 +2268,27 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
}
}
for (insertUndoType::iterator itInsertUndo = insertUndo.begin(); itInsertUndo != insertUndo.end(); ++itInsertUndo)
for (insertUndoType::reverse_iterator itInsertUndo = insertUndo.rbegin(); itInsertUndo != insertUndo.rend(); ++itInsertUndo)
{
claimQueueType::iterator itQueueRow = getQueueCacheRow(itInsertUndo->nHeight, true);
CClaimValue claim;
assert(removeClaimFromTrie(itInsertUndo->name, itInsertUndo->outPoint, claim, false));
// claim.nValidHeight may have been changed if this was inserted before activation height
// due to a triggered takeover, change it back to original nValidAtHeight
if (itInsertUndo->nHeight >= 0) // aka it became valid at this height rather than being a rename/normalization
{
// valid height may have been changed if this was inserted because the winning claim was abandoned; reset it here:
claim.nValidAtHeight = itInsertUndo->nHeight;
queueNameType::iterator itQueueNameRow = getQueueCacheNameRow(itInsertUndo->name, true);
claimQueueType::iterator itQueueRow = getQueueCacheRow(itInsertUndo->nHeight, true);
itQueueRow->second.push_back(std::make_pair(itInsertUndo->name, claim));
queueNameType::iterator itQueueNameRow = getQueueCacheNameRow(itInsertUndo->name, true);
itQueueNameRow->second.push_back(outPointHeightType(itInsertUndo->outPoint, claim.nValidAtHeight));
}
else
{
// no present way to delete claim from the index by name (but we read after the deletion anyway)
claimsToDelete.insert(claim);
}
}
for (std::vector<std::pair<std::string, int> >::iterator itTakeoverHeightUndo = takeoverHeightUndo.begin(); itTakeoverHeightUndo != takeoverHeightUndo.end(); ++itTakeoverHeightUndo)
for (std::vector<std::pair<std::string, int> >::reverse_iterator itTakeoverHeightUndo = takeoverHeightUndo.rbegin(); itTakeoverHeightUndo != takeoverHeightUndo.rend(); ++itTakeoverHeightUndo)
{
cacheTakeoverHeights[itTakeoverHeightUndo->first] = itTakeoverHeightUndo->second;
}
@ -2295,7 +2305,7 @@ bool CClaimTrieCacheBase::finalizeDecrement() const
block_originals.clear();
for (nodeCacheType::const_iterator itCache = cache.begin(); itCache != cache.end(); ++itCache)
{
block_originals[itCache->first] = new CClaimTrieNode(*(itCache->second));
block_originals[itCache->first] = new CClaimTrieNode(*itCache->second);
}
return true;
}
@ -2355,7 +2365,7 @@ int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160&
uint256 CClaimTrieCacheBase::getBestBlock()
{
if (hashBlock.IsNull())
if (base != NULL)
if (base != nullptr)
hashBlock = base->hashBlock;
return hashBlock;
}
@ -2534,7 +2544,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, CClaimTriePro
valueHash = getValueHash(claim.outPoint, nHeightOfLastTakeover);
}
std::vector<std::pair<unsigned char, uint256> > children;
CClaimTrieNode* nextCurrent = NULL;
CClaimTrieNode* nextCurrent = nullptr;
for (nodeMapType::const_iterator itChildren = current->children.begin(); itChildren != current->children.end(); ++itChildren)
{
std::stringstream ss;

View file

@ -142,8 +142,6 @@ typedef std::vector<CSupportValue> supportMapEntryType;
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
typedef std::pair<std::string, CClaimTrieNode> namedNodeType;
class CClaimTrieNode
{
public:
@ -323,9 +321,10 @@ struct claimsForNameType
int nLastTakeoverHeight;
std::string name;
claimsForNameType(const std::vector<CClaimValue>& claims, const std::vector<CSupportValue>& supports,
claimsForNameType(std::vector<CClaimValue> claims, std::vector<CSupportValue> supports,
int nLastTakeoverHeight, const std::string& name)
: claims(claims), supports(supports), nLastTakeoverHeight(nLastTakeoverHeight), name(name) {}
: claims(std::move(claims)), supports(std::move(supports)),
nLastTakeoverHeight(nLastTakeoverHeight), name(name) {}
claimsForNameType(const claimsForNameType&) = default;
claimsForNameType(claimsForNameType&& other)
@ -335,6 +334,7 @@ struct claimsForNameType
nLastTakeoverHeight = other.nLastTakeoverHeight;
name = std::move(other.name);
}
claimsForNameType& operator=(const claimsForNameType&) = default;
claimsForNameType& operator=(claimsForNameType&& other)
{
@ -347,6 +347,8 @@ struct claimsForNameType
}
return *this;
}
virtual ~claimsForNameType() {}
};
class CClaimTrieCacheBase;
@ -381,7 +383,6 @@ public:
bool supportEmpty() const;
bool supportQueueEmpty() const;
bool expirationQueueEmpty() const;
bool supportExpirationQueueEmpty() const;
void setExpirationTime(int t);
@ -409,7 +410,8 @@ public:
int nCurrentHeight;
int nExpirationTime;
int nProportionalDelayFactor;
private:
private:
void clear(CClaimTrieNode* current);
const CClaimTrieNode* getNodeForName(const std::string& name) const;
@ -582,7 +584,7 @@ public:
CClaimTrieNode* getRoot() const
{
nodeCacheType::iterator iter = cache.find("");
const nodeCacheType::iterator iter = cache.find("");
return iter == cache.end() ? &(base->root) : iter->second;
}
@ -676,7 +678,6 @@ protected:
virtual int getDelayForName(const std::string& name, const uint160& claimId) const;
mutable nodeCacheType cache;
CClaimTrie* base;
mutable int nCurrentHeight; // Height of the block that is being worked on, which is
// one greater than the height of the chain's tip

View file

@ -205,6 +205,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insert
if (nCurrentHeight == Params().GetConsensus().nNormalizedNameForkHeight) {
std::cout << "RUNNING NORMALIZATION NOW" << std::endl;
// run the one-time upgrade of all names that need to change
// it modifies the (cache) trie as it goes, so we need to grab everything to be modified first

View file

@ -79,8 +79,11 @@ struct Params {
int nNormalizedNameForkHeight;
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
/** how long it took claims to expire before the hard fork */
int64_t nOriginalClaimExpirationTime;
/** how long it takes claims to expire after the hard fork */
int64_t nExtendedClaimExpirationTime;
/** blocks before the hard fork that changed the expiration time */
int64_t nExtendedClaimExpirationForkHeight;
int64_t GetExpirationTime(int64_t nHeight) const {
return nHeight < nExtendedClaimExpirationForkHeight ?

View file

@ -225,7 +225,7 @@ public:
~CDBWrapper();
CDBWrapper(const CDBWrapper&) = delete;
CDBWrapper& operator=(const CDBWrapper&) = delete;
/* CDBWrapper& operator=(const CDBWrapper&) = delete; */
template <typename K, typename V>
bool Read(const K& key, V& value) const

View file

@ -437,7 +437,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
{
CCoinsViewCache view(pcoinsTip.get());
const Coin& coin = view.AccessCoin(txin.prevout);
int nTxinHeight = coin.nHeight;
CScript scriptPubKey;
if (coin.out.IsNull()) {
auto it = std::find_if(txs.begin(), txs.end(), [&txin](const CTransactionRef& tx) {
@ -470,7 +469,7 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
}
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway))
if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), coin.nHeight, throwaway))
{
std::pair<std::string, uint160> entry(name, claimId);
spentClaims.push_back(entry);
@ -485,7 +484,7 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway))
if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coin.nHeight, throwaway))
{
LogPrintf("%s(): The support was not found in the trie or queue\n", __func__);
}
@ -518,7 +517,8 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
spentClaimsType::iterator itSpent;
for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent)
{
if (itSpent->first == name && itSpent->second == claimId)
if ((itSpent->first == name && itSpent->second == claimId) &&
(trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)))
break;
}
if (itSpent != spentClaims.end())

View file

@ -18,7 +18,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
if (pindexLast == nullptr)
return nProofOfWorkLimit;
if (params.fPowAllowMinDifficultyBlocks && pindexLast->nHeight >= 277299)
if (params.fPowAllowMinDifficultyBlocks &&
pindexLast->nHeight >= params.nAllowMinDiffMinHeight &&
pindexLast->nHeight < params.nAllowMinDiffMaxHeight)
{
// Special difficulty rule for testnet:
// If the new block's timestamp is twice the target block time
@ -29,12 +31,13 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2){
return nProofOfWorkLimit;
}
// Special difficulty rule for LBRY testnet killed at block 1100000.
}
// Go back the full period unless it's the first retarget after genesis.
int blockstogoback = params.DifficultyAdjustmentInterval()-1;
if ((pindexLast->nHeight+1) != params.DifficultyAdjustmentInterval())
blockstogoback = params.DifficultyAdjustmentInterval();
int blockstogoback = params.DifficultyAdjustmentInterval();
blockstogoback = std::min(blockstogoback, pindexLast->nHeight);
int nHeightFirst = pindexLast->nHeight - blockstogoback;
assert(nHeightFirst >= 0);

View file

@ -91,7 +91,7 @@ static UniValue getclaimsintrie(const JSONRPCRequest& request)
"Result: \n"
"[\n"
" {\n"
" \"name\" (string) the name claimed\n"
" \"normalized_name\" (string) the name of these claims (after normalization)\n"
" \"claims\": [ (array of object) the claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of the claim\n"
@ -100,6 +100,7 @@ static UniValue getclaimsintrie(const JSONRPCRequest& request)
" \"amount\" (numeric) txout amount\n"
" \"height\" (numeric) the height of the block in which this transaction is located\n"
" \"value\" (string) the value of this claim\n"
" \"name\" (string) the original name of this claim (before normalization)\n"
" }\n"
" ]\n"
" }\n"
@ -154,14 +155,18 @@ static UniValue getclaimsintrie(const JSONRPCRequest& request)
{
LogPrintf("%s: the specified txout of %s does not have an claim command\n", __func__, itClaims->outPoint.hash.GetHex());
}
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
claim.pushKV("value", sValue);
claim.pushKV("value", HexStr(vvchParams[1].begin(), vvchParams[1].end()));
}
std::string targetName;
CClaimValue targetClaim;
if (pclaimTrie->getClaimById(itClaims->claimId, targetName, targetClaim))
claim.push_back(Pair("name", targetName));
claims.push_back(claim);
}
UniValue nodeObj(UniValue::VOBJ);
nodeObj.pushKV("name", name);
nodeObj.pushKV("normalized_name", name);
nodeObj.pushKV("claims", claims);
nodes.push_back(nodeObj);
}
@ -249,7 +254,7 @@ static UniValue getclaimtrie(const JSONRPCRequest& request)
return ret;
}
static bool getValueForClaim(const CCoinsViewCache& coinsCache, const COutPoint& out, std::string& sValue)
static bool getValueForOutPoint(const CCoinsViewCache& coinsCache, const COutPoint& out, std::string& sValue)
{
const Coin& coin = coinsCache.AccessCoin(out);
if (coin.IsSpent())
@ -267,13 +272,15 @@ static bool getValueForClaim(const CCoinsViewCache& coinsCache, const COutPoint&
}
if (op == OP_CLAIM_NAME)
{
sValue = std::string(vvchParams[1].begin(), vvchParams[1].end());
sValue = HexStr(vvchParams[1].begin(), vvchParams[1].end());
return true;
}
else if (op == OP_UPDATE_CLAIM)
{
sValue = std::string(vvchParams[2].begin(), vvchParams[2].end());
}
sValue = HexStr(vvchParams[2].begin(), vvchParams[2].end());
return true;
}
return false;
}
@ -282,7 +289,7 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 2)
throw std::runtime_error(
"getvalueforname \"name\"\n"
"Return the value associated with a name, if one exists\n"
"Return the winning value associated with a name, if one exists\n"
"Arguments:\n"
"1. \"name\" (string) the name to look up\n"
"2. \"blockhash\" (string, optional) get the value\n"
@ -299,7 +306,8 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
"\"n\" (numeric) vout value\n"
"\"amount\" (numeric) txout amount\n"
"\"effective amount\" (numeric) txout amount plus amount from all supports associated with the claim\n"
"\"height\" (numeric) the height of the block in which this transaction is located\n");
"\"height\" (numeric) the height of the block in which this transaction is located\n"
"\"name\" (string) the original name of this claim (before normalization)\n");
LOCK(cs_main);
@ -319,7 +327,7 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
return ret; // they may have asked for a name that doesn't exist (which is not an error)
std::string sValue;
if (!getValueForClaim(coinsCache, claim.outPoint, sValue))
if (!getValueForOutPoint(coinsCache, claim.outPoint, sValue))
return ret;
const auto nEffectiveAmount = trieCache.getEffectiveAmountForClaim(name, claim.claimId);
@ -331,13 +339,19 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
ret.pushKV("amount", claim.nAmount);
ret.pushKV("effective amount", nEffectiveAmount);
ret.pushKV("height", claim.nHeight);
std::string targetName;
CClaimValue targetClaim;
if (pclaimTrie->getClaimById(claim.claimId, targetName, targetClaim))
ret.push_back(Pair("name", targetName));
return ret;
}
typedef std::pair<CClaimValue, std::vector<CSupportValue> > claimAndSupportsType;
typedef std::map<uint160, claimAndSupportsType> claimSupportMapType;
UniValue supportToJSON(const CSupportValue& support)
UniValue supportToJSON(const CCoinsViewCache& coinsCache, const CSupportValue& support)
{
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("txid", support.outPoint.hash.GetHex()));
@ -345,6 +359,9 @@ UniValue supportToJSON(const CSupportValue& support)
ret.push_back(Pair("nHeight", support.nHeight));
ret.push_back(Pair("nValidAtHeight", support.nValidAtHeight));
ret.push_back(Pair("nAmount", support.nAmount));
std::string value;
if (getValueForOutPoint(coinsCache, support.outPoint, value))
ret.push_back(Pair("value", value));
return ret;
}
@ -355,7 +372,7 @@ UniValue claimAndSupportsToJSON(const CCoinsViewCache& coinsCache, CAmount nEffe
UniValue supportObjs(UniValue::VARR);
for (const auto& support: supports)
supportObjs.push_back(supportToJSON(support));
supportObjs.push_back(supportToJSON(coinsCache, support));
UniValue result(UniValue::VOBJ);
result.pushKV("claimId", itClaimsAndSupports->first.GetHex());
@ -365,10 +382,16 @@ UniValue claimAndSupportsToJSON(const CCoinsViewCache& coinsCache, CAmount nEffe
result.pushKV("nValidAtHeight", claim.nValidAtHeight);
result.pushKV("nAmount", claim.nAmount);
std::string sValue;
if (getValueForClaim(coinsCache, claim.outPoint, sValue))
if (getValueForOutPoint(coinsCache, claim.outPoint, sValue))
result.pushKV("value", sValue);
result.pushKV("nEffectiveAmount", nEffectiveAmount);
result.pushKV("supports", supportObjs);
std::string targetName;
CClaimValue targetClaim;
if (pclaimTrie->getClaimById(claim.claimId, targetName, targetClaim))
result.push_back(Pair("name", targetName));
return result;
}
@ -389,6 +412,7 @@ UniValue getclaimsforname(const JSONRPCRequest& request)
"Result:\n"
"{\n"
" \"nLastTakeoverHeight\" (numeric) the last height at which ownership of the name changed\n"
" \"normalized_name\" (string) the name of these claims after normalization\n"
" \"claims\": [ (array of object) claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of this claim\n"
@ -397,7 +421,7 @@ UniValue getclaimsforname(const JSONRPCRequest& request)
" \"nHeight\" (numeric) the height at which the claim was included in the blockchain\n"
" \"nValidAtHeight\" (numeric) the height at which the claim became/becomes valid\n"
" \"nAmount\" (numeric) the amount of the claim\n"
" \"value\" (string) the value of the name, if it exists\n"
" \"value\" (string) the metadata of the claim\n"
" \"nEffectiveAmount\" (numeric) the total effective amount of the claim, taking into effect whether the claim or support has reached its nValidAtHeight\n"
" \"supports\" : [ (array of object) supports for this claim\n"
" \"txid\" (string) the txid of the support\n"
@ -405,6 +429,7 @@ UniValue getclaimsforname(const JSONRPCRequest& request)
" \"nHeight\" (numeric) the height at which the support was included in the blockchain\n"
" \"nValidAtHeight\" (numeric) the height at which the support became/becomes valid\n"
" \"nAmount\" (numeric) the amount of the support\n"
" \"value\" (string) the metadata of the support if any\n"
" ]\n"
" }\n"
" ],\n"
@ -446,13 +471,14 @@ UniValue getclaimsforname(const JSONRPCRequest& request)
{
claimSupportMapType::iterator itClaimAndSupports = claimSupportMap.find(itSupports->supportedClaimId);
if (itClaimAndSupports == claimSupportMap.end())
unmatchedSupports.push_back(supportToJSON(*itSupports));
unmatchedSupports.push_back(supportToJSON(coinsCache, *itSupports));
else
itClaimAndSupports->second.second.push_back(*itSupports);
}
UniValue result(UniValue::VOBJ);
result.pushKV("nLastTakeoverHeight", claimsForName.nLastTakeoverHeight);
result.pushKV("normalized_name", claimsForName.name);
for (claimSupportMapType::const_iterator itClaimsAndSupports = claimSupportMap.begin(); itClaimsAndSupports != claimSupportMap.end(); ++itClaimsAndSupports)
{
@ -476,8 +502,9 @@ UniValue getclaimbyid(const JSONRPCRequest& request)
"1. \"claimId\" (string) the claimId of this claim\n"
"Result:\n"
"{\n"
" \"name\" (string) the name of the claim\n"
" \"value\" (string) claim metadata\n"
" \"name\" (string) the original name of the claim (before normalization)\n"
" \"normalized_name\" (string) the name of this claim (after normalization)\n"
" \"value\" (string) metadata of the claim\n"
" \"claimId\" (string) the claimId of this claim\n"
" \"txid\" (string) the hash of the transaction which has successfully claimed this name\n"
" \"n\" (numeric) vout value\n"
@ -490,6 +517,7 @@ UniValue getclaimbyid(const JSONRPCRequest& request)
" \"height\" (numeric) the height at which the support was included in the blockchain\n"
" \"valid at height\" (numeric) the height at which the support is valid\n"
" \"amount\" (numeric) the amount of the support\n"
" \"value\" (string) the metadata of the support if any\n"
" ]\n"
" \"height\" (numeric) the height of the block in which this claim transaction is located\n"
" \"valid at height\" (numeric) the height at which the claim is valid\n"
@ -509,8 +537,10 @@ UniValue getclaimbyid(const JSONRPCRequest& request)
std::string sValue;
claim.pushKV("name", name);
if (trieCache.shouldNormalize())
claim.push_back(Pair("normalized_name", trieCache.normalizeClaimName(name, true)));
CCoinsViewCache coinsCache(pcoinsTip.get());
if (getValueForClaim(coinsCache, claimValue.outPoint, sValue))
if (getValueForOutPoint(coinsCache, claimValue.outPoint, sValue))
claim.pushKV("value", sValue);
claim.pushKV("claimId", claimValue.claimId.GetHex());
claim.pushKV("txid", claimValue.outPoint.hash.GetHex());
@ -525,6 +555,8 @@ UniValue getclaimbyid(const JSONRPCRequest& request)
supportEntry.pushKV("height", support.nHeight);
supportEntry.pushKV("valid at height", support.nValidAtHeight);
supportEntry.pushKV("amount", support.nAmount);
if (getValueForOutPoint(coinsCache, support.outPoint, sValue))
claim.pushKV("value", sValue);
supportList.pushKVs(supportEntry);
}
claim.pushKV("supports", supportList);
@ -614,6 +646,7 @@ UniValue getclaimsfortx(const JSONRPCRequest& request)
" \"nOut\" (numeric) the index of the claim or support in the transaction's list of outputs\n"
" \"claim type\" (string) 'claim' or 'support'\n"
" \"name\" (string) the name claimed or supported\n"
" \"claimId\" (string) if a claim, its ID\n"
" \"value\" (string) if a name claim, the value of the claim\n"
" \"supported txid\" (string) if a support, the txid of the supported claim\n"
" \"supported nout\" (numeric) if a support, the index of the supported claim in its transaction\n"
@ -653,22 +686,22 @@ UniValue getclaimsfortx(const JSONRPCRequest& request)
o.pushKV("name", sName);
if (op == OP_CLAIM_NAME)
{
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
uint160 claimId = ClaimIdHash(hash, i);
o.pushKV("claimId", claimId.GetHex());
o.pushKV("value", sValue);
o.pushKV("value", HexStr(vvchParams[1].begin(), vvchParams[1].end()));
}
else if (op == OP_UPDATE_CLAIM)
{
uint160 claimId(vvchParams[1]);
std::string sValue(vvchParams[2].begin(), vvchParams[2].end());
o.pushKV("claimId", claimId.GetHex());
o.pushKV("value", sValue);
o.pushKV("value", HexStr(vvchParams[2].begin(), vvchParams[2].end()));
}
else if (op == OP_SUPPORT_CLAIM)
{
uint160 supportedClaimId(vvchParams[1]);
o.pushKV("supported claimId", supportedClaimId.GetHex());
if (vvchParams.size() > 2)
o.pushKV("supported value", HexStr(vvchParams[2].begin(), vvchParams[2].end()));
}
if (nHeight > 0)
{
@ -850,6 +883,24 @@ UniValue getnameproof(const JSONRPCRequest& request)
return proofToJSON(proof);
}
UniValue checknormalization(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"checknormalization\n"
"Given an unnormalized name of a claim, return normalized version of it\n"
"Arguments:\n"
"1. \"name\" (string) the name to normalize\n"
"Result: \n"
"\"normalized\" (string) fully normalized name\n");
const bool force = true;
const std::string name = request.params[0].get_str();
CClaimTrieCache triecache(pclaimTrie);
return triecache.normalizeClaimName(name, force);
}
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
@ -862,7 +913,8 @@ static const CRPCCommand commands[] =
{ "Claimtrie", "gettotalvalueofclaims", &gettotalvalueofclaims, { "controlling_only" } },
{ "Claimtrie", "getclaimsfortx", &getclaimsfortx, { "txid" } },
{ "Claimtrie", "getnameproof", &getnameproof, { "name","blockhash"} },
{ "Claimtrie", "getclaimbyid", &getclaimbyid, {"claimId"} },
{ "Claimtrie", "getclaimbyid", &getclaimbyid, { "claimId" } },
{ "Claimtrie", "checknormalization", &checknormalization, { "name" }},
};
void RegisterClaimTrieRPCCommands(CRPCTable &tableRPC)

View file

@ -19,6 +19,8 @@ enum isminetype
ISMINE_NO = 0,
ISMINE_WATCH_ONLY = 1,
ISMINE_SPENDABLE = 2,
ISMINE_CLAIM = 4,
ISMINE_SUPPORT = 8,
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
};
/** used for bitflags of isminetype */

View file

@ -23,9 +23,10 @@
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtriebranching_tests, RegTestingSetup)
static ::CChainState g_chainstate;
static const boost::test_tools::predicate_result predicate_true(true);
static const boost::test_tools::predicate_result predicate_false(false);
@ -130,6 +131,7 @@ struct ClaimTrieChainFixture{
std::vector<int> marks;
int coinbase_txs_used;
int unique_block_counter;
int normalization_original;
unsigned int num_txs;
unsigned int num_txs_for_next_block;
@ -142,15 +144,16 @@ struct ClaimTrieChainFixture{
ClaimTrieChainFixture():
expirationForkHeight(Params().GetConsensus().nExtendedClaimExpirationForkHeight),
originalExpiration(Params().GetConsensus().nOriginalClaimExpirationTime),
extendedExpiration(Params().GetConsensus().nExtendedClaimExpirationTime)
extendedExpiration(Params().GetConsensus().nExtendedClaimExpirationTime),
unique_block_counter(0), normalization_original(-1)
{
fRequireStandard = false;
BOOST_CHECK_EQUAL(pclaimTrie->nCurrentHeight, chainActive.Height() + 1);
pclaimTrie->setExpirationTime(originalExpiration); // in case it was changed during the test
setNormalizationForkHeight(1000000); // Default should be dictated by Params()
num_txs_for_next_block = 0;
num_txs = 0;
coinbase_txs_used = 0;
unique_block_counter = 0;
// generate coinbases to spend
CreateCoinbases(40, coinbase_txs);
}
@ -158,6 +161,21 @@ struct ClaimTrieChainFixture{
~ClaimTrieChainFixture()
{
DecrementBlocks(chainActive.Height());
if (normalization_original >= 0)
{
const Consensus::Params& consensus = Params().GetConsensus();
const_cast<Consensus::Params&>(consensus).nNormalizedNameForkHeight = normalization_original;
}
pclaimTrie->setExpirationTime(originalExpiration); // in case it was changed during the test
}
void setNormalizationForkHeight(int targetMinusCurrent)
{
int target = chainActive.Height() + targetMinusCurrent;
const Consensus::Params& consensus = Params().GetConsensus();
if (normalization_original < 0)
normalization_original = consensus.nNormalizedNameForkHeight;
const_cast<Consensus::Params&>(consensus).nNormalizedNameForkHeight = target;
}
bool CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate)
@ -216,8 +234,8 @@ struct ClaimTrieChainFixture{
}
//spend a bid into some non claimtrie related unspent
CMutableTransaction Spend(const CTransaction &prev){
CMutableTransaction Spend(const CTransaction &prev)
{
uint32_t prevout = 0;
CMutableTransaction tx = BuildTransaction(prev, prevout);
tx.vout[0].scriptPubKey = CScript() << OP_TRUE;
@ -231,7 +249,6 @@ struct ClaimTrieChainFixture{
CMutableTransaction MakeClaim(const CTransaction& prev, std::string name, std::string value, CAmount quantity)
{
uint32_t prevout = 0;
CMutableTransaction tx = BuildTransaction(prev,prevout);
tx.vout[0].scriptPubKey = ClaimNameScript(name, value);
tx.vout[0].nValue = quantity;
@ -275,9 +292,8 @@ struct ClaimTrieChainFixture{
CTransaction GetCoinbase()
{
auto tx = coinbase_txs[coinbase_txs_used];
coinbase_txs_used++;
return tx;
assert(coinbase_txs_used + 1 < coinbase_txs.size());
return coinbase_txs[coinbase_txs_used++];
}
//create i blocks
@ -1087,6 +1103,504 @@ BOOST_AUTO_TEST_CASE(supports_fall_through)
BOOST_CHECK_EQUAL(is_best_claim("A", tx2), predicate_true); //tx2 support should be active now
}
/*
normalization
test normalization function indpendent from rest of the code
*/
BOOST_AUTO_TEST_CASE(normalization_only)
{
CClaimTrieCache ccache(pclaimTrie);
// basic ASCII casing tests
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TESt", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("tesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("test", true));
BOOST_CHECK_EQUAL("test this", ccache.normalizeClaimName("Test This", true));
// test invalid utf8 bytes are returned as is
BOOST_CHECK_EQUAL("\xFF", ccache.normalizeClaimName("\xFF", true));
BOOST_CHECK_EQUAL("\xC3\x28", ccache.normalizeClaimName("\xC3\x28", true));
// ohm sign unicode code point \x2126 should be transformed to equivalent
// unicode code point \x03C9 , greek small letter omega
BOOST_CHECK_EQUAL("\xCF\x89", ccache.normalizeClaimName("\xE2\x84\xA6", true));
// cyrillic capital ef code point \x0424 should be transformed to lower case
// \x0444
BOOST_CHECK_EQUAL("\xD1\x84", ccache.normalizeClaimName("\xD0\xA4", true));
// armenian capital ben code point \x0532 should be transformed to lower case
// \x0562
BOOST_CHECK_EQUAL("\xD5\xA2", ccache.normalizeClaimName("\xD4\xB2", true));
// japanese pbu code point \x3076 should be transformed by NFD decomposition
// into \x3075 and \x3099
BOOST_CHECK_EQUAL("\xE3\x81\xB5\xE3\x82\x99",
ccache.normalizeClaimName("\xE3\x81\xB6", true));
// hangul ggwalg unicode code point \xAF51 should be transformed by NFD
// decomposition into unicode code points \x1101 \x116A \x11B0
// source: http://unicode.org/L2/L2009/09052-tr47.html
BOOST_CHECK_EQUAL("\xE1\x84\x81\xE1\x85\xAA\xE1\x86\xB0",
ccache.normalizeClaimName("\xEA\xBD\x91", true));
}
/*
normalization
check claim name normalization before the fork
check claim name normalization after the fork
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_normalization)
{
ClaimTrieChainFixture fixture;
// check claim names are not normalized
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "normalizeTest", "one", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("normalizeTest", tx1), predicate_true);
fixture.DecrementBlocks(1);
BOOST_CHECK_EQUAL(pclaimTrie->getTotalNamesInTrie(), 0);
fixture.CommitTx(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("normalizeTest", tx1), predicate_true);
CMutableTransaction tx2a = fixture.MakeClaim(fixture.GetCoinbase(), "Normalizetest", "one_a", 2);
CMutableTransaction tx2 = fixture.MakeUpdate(tx2a, "Normalizetest", "one", ClaimIdHash(tx2a.GetHash(), 0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("normalizeTest", tx1), predicate_true);
BOOST_CHECK_EQUAL(is_best_claim("Normalizetest", tx2), predicate_true);
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("normalizeTest", tx1), predicate_true);
BOOST_CHECK_EQUAL(is_best_claim("Normalizetest", tx2), predicate_true);
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.IncrementBlocks(1, true);
// Post-fork, tx1 (the previous winning claim) assumes all name
// variants of what it originally was ...
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx1), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("normalizetest", 3), predicate_true);
CClaimValue val;
BOOST_CHECK_EQUAL(pclaimTrie->getInfoForName("normalizeTest", val), false);
// Check equivalence of normalized claim names
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx1), predicate_true); // collapsed tx2
fixture.IncrementBlocks(1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "NORMALIZETEST", "one", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx3), predicate_false);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "NoRmAlIzEtEsT", 2);
fixture.IncrementBlocks(1);
// Ensure that supports work for normalized claim names
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx1), predicate_true); // effective amount is 5
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("normalizetest", 5), predicate_true);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "foo", "bar", 1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "Foo", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("foo", tx4), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("FOO", 2), predicate_true);
CMutableTransaction u1 = fixture.MakeUpdate(tx4, "foo", "baz", ClaimIdHash(tx4.GetHash(), 0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("foo", u1), predicate_true);
CMutableTransaction u2 = fixture.MakeUpdate(tx1, "nOrmalIzEtEst", "two", ClaimIdHash(tx1.GetHash(), 0), 3);
fixture.IncrementBlocks(1);
CClaimValue tmpval;
pclaimTrie->getInfoForName("normalizetest", tmpval);
std::cout << "TX1 CLAIM: " << ClaimIdHash(tx1.GetHash(), 0) << std::endl;
std::cout << "TX3 CLAIM: " << ClaimIdHash(tx3.GetHash(), 0) << std::endl;
std::cout << "BEST CLAIM ID: " << HexStr(tmpval.claimId) << ", U2 CLAIM: " << ClaimIdHash(u2.GetHash(), 0) << std::endl;
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", u2), predicate_true);
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "Ame\u0301lie", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue nval1;
pclaimTrie->getInfoForName("amélie", nval1);
BOOST_CHECK_EQUAL(nval1.claimId, ClaimIdHash(tx5.GetHash(), 0));
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("amélie", 2), predicate_true);
// Check equivalence of normalized claim names
BOOST_CHECK_EQUAL(is_best_claim("amélie", tx5), predicate_true);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "あてはまる", "jn1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("あてはまる", tx7), predicate_true);
CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), "AÑEJO", "es1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("añejo", tx8), predicate_true);
// Rewind to 1 block before the fork and be sure that the fork is no longer active
fixture.DecrementBlocks();
// Now check that our old (non-normalized) claims are 'alive' again
BOOST_CHECK_EQUAL(is_best_claim("normalizeTest", tx1), predicate_true);
BOOST_CHECK_EQUAL(is_best_claim("Normalizetest", tx1), predicate_false); // no longer equivalent
BOOST_CHECK_EQUAL(is_best_claim("Normalizetest", tx2), predicate_true);
// Create new claim
CMutableTransaction tx9 = fixture.MakeClaim(fixture.GetCoinbase(), "blah", "blah", 1);
std::string invalidUtf8("\xFF\xFF");
CMutableTransaction tx10 = fixture.MakeClaim(fixture.GetCoinbase(), invalidUtf8, "blah", 1); // invalid UTF8
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx1), predicate_true); // collapsed tx2
BOOST_CHECK_EQUAL(is_best_claim(invalidUtf8, tx10), predicate_true);
// Rewind to 1 block before the fork and be sure that the fork is
// no longer active
fixture.DecrementBlocks(1);
BOOST_CHECK_EQUAL(is_best_claim("Normalizetest", tx2), predicate_true);
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK_EQUAL(is_best_claim("normalizetest", tx1), predicate_true); // collapsed tx2
}
BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
{
ClaimTrieChainFixture fixture;
std::string name = "Ame\u0301lie";
std::string name_upper = "Amélie";
std::string name_normd = "amélie"; // this accented e is not actually the same as the one above; this has been "normalized"
BOOST_CHECK(name != name_upper);
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "amilie", 2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name_upper, "amelie", 2);
fixture.MakeClaim(fixture.GetCoinbase(), "amelie1", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue lookupClaim;
std::string lookupName;
BOOST_CHECK(pclaimTrie->getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, lookupClaim));
CClaimValue nval1;
BOOST_CHECK(pclaimTrie->getInfoForName("amelie1", nval1));
// amélie is not found cause normalization still not appear
BOOST_CHECK(!pclaimTrie->getInfoForName(name_normd, nval1));
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.setNormalizationForkHeight(1);
int currentHeight = chainActive.Height();
fixture.IncrementBlocks(1);
// Ok normalization fix the name problem
BOOST_CHECK(pclaimTrie->getInfoForName(name_normd, nval1));
BOOST_CHECK(nval1.nHeight == currentHeight);
BOOST_CHECK(lookupClaim == nval1);
CCoinsViewCache coins(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
CBlockIndex* pindex = chainActive.Tip();
CBlock block;
int amelieValidHeight;
BOOST_CHECK(trieCache.shouldNormalize());
BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus()));
BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK);
BOOST_CHECK(!trieCache.shouldNormalize());
BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
BOOST_CHECK(!pclaimTrie->getInfoForName(name, nval1));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(trieCache.shouldNormalize());
// we cannot use getXXXForName cause the name will be normalized
struct CNameVerifierCallback : public CNodeCallback
{
const std::string& cmp;
CNameVerifierCallback(const std::string& cmp) : cmp(cmp) {}
void visit(const std::string& nodeName, const CClaimTrieNode* node)
{
BOOST_CHECK(nodeName != cmp);
}
};
CNameVerifierCallback callback(name);
trieCache.iterateTrie(callback);
}
BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
fixture.IncrementBlocks(2);
BOOST_CHECK(is_best_claim("A", tx2));
fixture.IncrementBlocks(3, true);
BOOST_CHECK(is_best_claim("a", tx3));
fixture.DecrementBlocks();
BOOST_CHECK(is_best_claim("A", tx2));
}
BOOST_AUTO_TEST_CASE(normalized_activations_fall_through)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
fixture.IncrementBlocks(3);
BOOST_CHECK(pclaimTrie->nProportionalDelayFactor == 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 4);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "2", 3);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "ab", "2", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("AB", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(is_best_claim("ab", tx2));
BOOST_CHECK(pclaimTrie->getClaimsForName("ab").size() == 4U);
fixture.DecrementBlocks(3);
fixture.Spend(tx1);
fixture.Spend(tx2);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("ab", tx3));
BOOST_CHECK(pclaimTrie->getClaimsForName("ab").size() == 2U);
fixture.DecrementBlocks(1);
BOOST_CHECK(is_best_claim("AB", tx1));
fixture.Spend(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("ab", tx2));
for (int i = 0; i < 7; i++)
{
fixture.IncrementBlocks(i, true); // well into normalized teritory
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "CD", "a", 1 + i);
fixture.IncrementBlocks(3);
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "Cd", "b", 2 + i);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "cD", "c", 3 + i);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("cd", tx5));
fixture.Spend(tx5);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("cd", tx7));
fixture.DecrementBlocks();
}
}
BOOST_AUTO_TEST_CASE(normalization_removal_test)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "3", 3);
CMutableTransaction sx1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "AB", 1);
CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1);
CClaimTrieCache cache(pclaimTrie);
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, pclaimTrie->nCurrentHeight);
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, pclaimTrie->nCurrentHeight);
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, pclaimTrie->nCurrentHeight);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), pclaimTrie->nCurrentHeight);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), pclaimTrie->nCurrentHeight);
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(cache.getClaimsForName("ab").claims.size() == 3U);
BOOST_CHECK(cache.getClaimsForName("ab").supports.size() == 2U);
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), pclaimTrie->nCurrentHeight));
BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), pclaimTrie->nCurrentHeight));
BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), pclaimTrie->nCurrentHeight));
BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), pclaimTrie->nCurrentHeight));
BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), pclaimTrie->nCurrentHeight));
BOOST_CHECK(cache.getClaimsForName("ab").claims.size() == 0U);
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_supports)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 3));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("a", 4));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("a", 5));
fixture.DecrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("a", 4));
fixture.DecrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 3));
fixture.DecrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
fixture.IncrementBlocks(5);
BOOST_CHECK(best_claim_effective_amount_equals("a", 3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_fail_on_spend)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
std::string sName1("testN");
std::string sName2("testn");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "1", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim(sName1, tx1));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "2", 2);
CMutableTransaction tx1s = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 2);
fixture.IncrementBlocks(2, true);
BOOST_CHECK(is_best_claim(sName2, tx1));
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
CMutableTransaction tx3s = fixture.Spend(tx1s);
fixture.IncrementBlocks(2);
BOOST_CHECK(is_best_claim(sName2, tx2));
fixture.DecrementBlocks();
BOOST_CHECK(is_best_claim(sName1, tx1));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_sort_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("A", tx2));
BOOST_CHECK(is_best_claim("a", tx3));
fixture.IncrementBlocks(1);
BOOST_CHECK(!is_best_claim("A", tx2));
BOOST_CHECK(is_best_claim("a", tx3));
BOOST_CHECK(pclaimTrie->getClaimsForName("a").size() == 3U);
fixture.DecrementBlocks(1);
BOOST_CHECK(is_best_claim("A", tx2));
BOOST_CHECK(is_best_claim("a", tx3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_expirations)
{
ClaimTrieChainFixture fixture;
pclaimTrie->setExpirationTime(3);
fixture.setNormalizationForkHeight(4);
// need to see that claims expiring on the frame when we normalize aren't kept
// need to see that supports expiring on the frame when we normalize aren't kept
// need to see that claims & supports carried through the normalization fork do expire
// and that they come back correctly when we roll backwards
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "B", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx2, "B", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(best_claim_effective_amount_equals("B", 2));
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "C", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx3, "C", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(best_claim_effective_amount_equals("C", 2));
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "D", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx4, "D", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(2);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(best_claim_effective_amount_equals("C", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(3);
BOOST_CHECK(!best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!best_claim_effective_amount_equals("d", 2)); // (not re-added)
}
/*
claim/support expiration for hard fork, but with checks for disk procedures
*/
@ -1106,8 +1620,8 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
// Reset to disk, increment past the fork height and make sure we get
// proper behavior
fixture.DecrementBlocks(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1,"test",1);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight -1);
@ -1117,10 +1631,10 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.extendedExpiration);
BOOST_CHECK_EQUAL(is_best_claim("test", tx1), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test",2), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test", 2), predicate_true);
fixture.IncrementBlocks(fixture.originalExpiration-1);
BOOST_CHECK_EQUAL(is_best_claim("test", tx1), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test",2), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test", 2), predicate_true);
fixture.DecrementBlocks(fixture.originalExpiration-1);
fixture.IncrementBlocks(fixture.extendedExpiration-1);
BOOST_CHECK_EQUAL(is_best_claim("test", tx1), predicate_false);
@ -1129,15 +1643,15 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
// increment past the fork height and make sure we get proper behavior
int height_of_update_before_expiration = 50;
fixture.DecrementBlocks(chainActive.Height() - fixture.expirationForkHeight + height_of_update_before_expiration+2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2,"test2",1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2", "one", 1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "test2", 1);
fixture.IncrementBlocks(1);
fixture.WriteClearReadClaimTrie();
CMutableTransaction u2 = fixture.MakeUpdate(tx2,"test2","two",ClaimIdHash(tx2.GetHash(),0),1);
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1);
// increment to fork
fixture.IncrementBlocks(fixture.expirationForkHeight - chainActive.Height());
BOOST_CHECK_EQUAL(is_best_claim("test2", u2), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test2",2), predicate_true);
BOOST_CHECK_EQUAL(best_claim_effective_amount_equals("test2", 2), predicate_true);
// increment to original expiration, should not be expired
fixture.IncrementBlocks(fixture.originalExpiration - height_of_update_before_expiration);
BOOST_CHECK_EQUAL(is_best_claim("test2", u2), predicate_true);
@ -1167,7 +1681,8 @@ BOOST_AUTO_TEST_CASE(insert_update_claim_test)
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash0);
CMutableTransaction tx1 = BuildTransaction(fixture.GetCoinbase());
tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME
tx1.vout[0].scriptPubKey = CScript()
<< OP_CLAIM_NAME
<< std::vector<unsigned char>(sName1.begin(), sName1.end())
<< std::vector<unsigned char>(sValue1.begin(), sValue1.end()) << OP_2DROP << OP_DROP << OP_TRUE;
uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0);

View file

@ -122,19 +122,19 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(!ntState.empty());
BOOST_CHECK(ntState.getMerkleHash() == hash1);
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1);
ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201));
BOOST_CHECK(ntState.getMerkleHash() == hash1);
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1);
ntState.insertClaimIntoTrie(std::string("tes"), CClaimValue(tx4OutPoint, hash160, 50, 100, 200));
BOOST_CHECK(ntState.getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2);
ntState.insertClaimIntoTrie(std::string("testtesttesttest"), CClaimValue(tx5OutPoint, hash160, 50, 100, 200));
ntState.removeClaimFromTrie(std::string("testtesttesttest"), tx5OutPoint, unused);
BOOST_CHECK(ntState.getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2);
ntState.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash2);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState1(pclaimTrie);
@ -143,52 +143,52 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState1.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused);
ntState1.removeClaimFromTrie(std::string("tes"), tx4OutPoint, unused);
BOOST_CHECK(ntState1.getMerkleHash() == hash0);
BOOST_CHECK_EQUAL(ntState1.getMerkleHash(), hash0);
CClaimTrieCacheTest ntState2(pclaimTrie);
ntState2.insertClaimIntoTrie(std::string("abab"), CClaimValue(tx6OutPoint, hash160, 50, 100, 200));
ntState2.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused);
BOOST_CHECK(ntState2.getMerkleHash() == hash3);
BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3);
ntState2.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash3);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash3);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState3(pclaimTrie);
ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200));
BOOST_CHECK(ntState3.getMerkleHash() == hash4);
BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4);
ntState3.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash4);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash4);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState4(pclaimTrie);
ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint, unused);
BOOST_CHECK(ntState4.getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2);
ntState4.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash2);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState5(pclaimTrie);
ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused);
BOOST_CHECK(ntState5.getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2);
ntState5.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash2);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState6(pclaimTrie);
ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201));
BOOST_CHECK(ntState6.getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2);
ntState6.flush();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash2);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash2);
BOOST_CHECK(pclaimTrie->checkConsistency());
CClaimTrieCacheTest ntState7(pclaimTrie);
@ -197,17 +197,17 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState7.removeClaimFromTrie(std::string("tes"), tx4OutPoint, unused);
ntState7.removeClaimFromTrie(std::string("test2"), tx2OutPoint, unused);
BOOST_CHECK(ntState7.getMerkleHash() == hash0);
BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0);
ntState7.flush();
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0);
BOOST_CHECK_EQUAL(pclaimTrie->getMerkleHash(), hash0);
BOOST_CHECK(pclaimTrie->checkConsistency());
}
BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
{
// test basic claim insertions and that get methods retreives information properly
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK_EQUAL(pclaimTrie->empty(), true);
CClaimTrieCacheTest ctc(pclaimTrie);
// create and insert claim
@ -223,14 +223,14 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
// try getClaimsForName, getEffectiveAmountForClaim, getInfoForName
claimsForNameType res = ctc.getClaimsForName("test");
BOOST_CHECK(res.claims.size() == 1);
BOOST_CHECK(res.claims[0] == claimVal);
BOOST_CHECK_EQUAL(res.claims.size(), 1);
BOOST_CHECK_EQUAL(res.claims[0], claimVal);
BOOST_CHECK_EQUAL(10, ctc.getEffectiveAmountForClaim("test", claimId));
CClaimValue claim;
BOOST_CHECK(ctc.getInfoForName("test", claim));
BOOST_CHECK(claim == claimVal);
BOOST_CHECK_EQUAL(ctc.getInfoForName("test", claim), true);
BOOST_CHECK_EQUAL(claim, claimVal);
// insert a support
CAmount supportAmount(10);
@ -285,7 +285,7 @@ BOOST_AUTO_TEST_CASE(recursive_prune_test)
BOOST_AUTO_TEST_CASE(iteratetrie_test)
{
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK_EQUAL(pclaimTrie->empty(), true);
CClaimTrieCacheTest ctc(pclaimTrie);
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@ -297,7 +297,8 @@ BOOST_AUTO_TEST_CASE(iteratetrie_test)
int count = 0;
struct TestCallBack : public CNodeCallback {
struct TestCallBack : public CNodeCallback
{
TestCallBack(int& count) : count(count)
{
}
@ -305,20 +306,20 @@ BOOST_AUTO_TEST_CASE(iteratetrie_test)
void visit(const std::string& name, const CClaimTrieNode* node)
{
count++;
if (name == "test") {
if (name == "test")
BOOST_CHECK_EQUAL(node->claims.size(), 1);
}
}
int& count;
} testCallback(count);
BOOST_CHECK(ctc.iterateTrie(testCallback));
BOOST_CHECK_EQUAL(ctc.iterateTrie(testCallback), true);
BOOST_CHECK_EQUAL(count, 5);
count = 3;
struct TestCallBack2 : public CNodeCallback {
struct TestCallBack2 : public CNodeCallback
{
TestCallBack2(int& count) : count(count)
{
}
@ -332,7 +333,7 @@ BOOST_AUTO_TEST_CASE(iteratetrie_test)
int& count;
} testCallback2(count);
BOOST_CHECK(!ctc.iterateTrie(testCallback2));
BOOST_CHECK_EQUAL(ctc.iterateTrie(testCallback2), false);
BOOST_CHECK_EQUAL(count, 0);
}

View file

@ -2187,7 +2187,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
spentClaimsType::iterator itSpent;
for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent)
{
if (itSpent->first == name && itSpent->second == claimId)
if ((itSpent->first == name && itSpent->second == claimId) &&
(trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)))
break;
}
if (itSpent != spentClaims.end())