2018-08-06 15:40:20 -04:00
# include <claimtrie.h>
# include <coins.h>
# include <core_io.h>
2019-07-01 12:42:45 -06:00
# include <logging.h>
2018-08-06 15:40:20 -04:00
# include <nameclaim.h>
# include <rpc/server.h>
# include <shutdown.h>
# include <txdb.h>
# include <txmempool.h>
# include <univalue.h>
# include <validation.h>
2019-07-01 12:42:45 -06:00
# include <boost/locale.hpp>
# include <boost/locale/conversion.hpp>
2018-08-06 15:40:20 -04:00
# include <boost/thread.hpp>
# include <cmath>
uint160 ParseClaimtrieId ( const UniValue & v , const std : : string & strName )
{
static constexpr size_t claimIdHexLength = 40 ;
std : : string strHex ;
if ( v . isStr ( ) )
strHex = v . get_str ( ) ;
if ( ! IsHex ( strHex ) ) // Note: IsHex("") is false
throw JSONRPCError ( RPC_INVALID_PARAMETER , strName + " must be a 20-character hexadecimal string (not ' " + strHex + " ') " ) ;
if ( strHex . length ( ) ! = claimIdHexLength )
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " %s must be of length %d (not %d) " , strName, claimIdHexLength, strHex.length())) ;
uint160 result ;
result . SetHex ( strHex ) ;
return result ;
}
static CBlockIndex * BlockHashIndex ( const uint256 & blockHash )
{
AssertLockHeld ( cs_main ) ;
if ( mapBlockIndex . count ( blockHash ) = = 0 )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
CBlockIndex * pblockIndex = mapBlockIndex [ blockHash ] ;
if ( ! chainActive . Contains ( pblockIndex ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Block not in main chain " ) ;
return pblockIndex ;
}
# define MAX_RPC_BLOCK_DECREMENTS 500
extern CChainState g_chainstate ;
void RollBackTo ( const CBlockIndex * targetIndex , CCoinsViewCache & coinsCache , CClaimTrieCache & trieCache )
{
AssertLockHeld ( cs_main ) ;
const CBlockIndex * activeIndex = chainActive . Tip ( ) ;
if ( activeIndex - > nHeight > ( targetIndex - > nHeight + MAX_RPC_BLOCK_DECREMENTS ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Block is too deep " ) ;
const size_t currentMemoryUsage = pcoinsTip - > DynamicMemoryUsage ( ) ;
for ( ; activeIndex & & activeIndex ! = targetIndex ; activeIndex = activeIndex - > pprev ) {
boost : : this_thread : : interruption_point ( ) ;
CBlock block ;
if ( ! ReadBlockFromDisk ( block , activeIndex , Params ( ) . GetConsensus ( ) ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , strprintf ( " Failed to read %s " , activeIndex - > ToString ( ) ) ) ;
if ( coinsCache . DynamicMemoryUsage ( ) + currentMemoryUsage > nCoinCacheUsage )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Out of memory, you may want to increase dbcache size " ) ;
if ( ShutdownRequested ( ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Shutdown requested " ) ;
if ( g_chainstate . DisconnectBlock ( block , activeIndex , coinsCache , trieCache ) ! = DisconnectResult : : DISCONNECT_OK )
throw JSONRPCError ( RPC_INTERNAL_ERROR , strprintf ( " Failed to disconnect %s " , block . ToString ( ) ) ) ;
}
}
2019-07-01 12:42:45 -06:00
std : : string escapeNonUtf8 ( const std : : string & name )
{
using namespace boost : : locale : : conv ;
try {
return to_utf < char > ( name , " UTF-8 " , stop ) ;
} catch ( const conversion_error & ) {
std : : string result ;
result . reserve ( name . size ( ) * 2 ) ;
for ( uint8_t ch : name ) {
if ( ch < 0x08 | | ( ch > = 0x0e & & ch < = 0x1f ) | | ch > = 0x7f )
result + = tfm : : format ( " \\ u%04x " , ch ) ;
else if ( ch = = 0x08 ) result + = " \\ b " ;
else if ( ch = = 0x09 ) result + = " \\ t " ;
else if ( ch = = 0x0a ) result + = " \\ n " ;
else if ( ch = = 0x0c ) result + = " \\ f " ;
else if ( ch = = 0x0d ) result + = " \\ r " ;
else if ( ch = = 0x22 ) result + = " \\ \" " ;
else if ( ch = = 0x5c ) result + = " \\ \\ " ;
else result + = ch ;
}
return result ;
}
}
static bool getValueForOutPoint ( const CCoinsViewCache & coinsCache , const COutPoint & out , std : : string & sValue )
{
const Coin & coin = coinsCache . AccessCoin ( out ) ;
if ( coin . IsSpent ( ) )
{
return false ;
}
int op ;
std : : vector < std : : vector < unsigned char > > vvchParams ;
if ( ! DecodeClaimScript ( coin . out . scriptPubKey , op , vvchParams ) )
{
return false ;
}
if ( op = = OP_CLAIM_NAME )
{
sValue = HexStr ( vvchParams [ 1 ] . begin ( ) , vvchParams [ 1 ] . end ( ) ) ;
return true ;
}
if ( vvchParams . size ( ) > 2 ) // both UPDATE and SUPPORT
{
sValue = HexStr ( vvchParams [ 2 ] . begin ( ) , vvchParams [ 2 ] . end ( ) ) ;
return true ;
}
return false ;
}
bool validParams ( const UniValue & params , uint8_t required , uint8_t optional )
{
auto count = params . size ( ) ;
return count = = required | | count = = required + optional ;
}
2018-08-06 15:40:20 -04:00
static UniValue getclaimsintrie ( const JSONRPCRequest & request )
{
if ( request . fHelp | | request . params . size ( ) > 1 )
throw std : : runtime_error (
" getclaimsintrie \n "
2019-07-18 14:35:18 -06:00
" Return all claims in the name trie. Deprecated. \n "
2018-08-06 15:40:20 -04:00
" Arguments: \n "
" 1. \" blockhash \" (string, optional) get claims in the trie \n "
" at the block specified \n "
" by this block hash. \n "
" If none is given, \n "
" the latest active \n "
" block will be used. \n "
" Result: \n "
" [ \n "
" { \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 "
" \" txid \" (string) the txid of the claim \n "
" \" n \" (numeric) the vout value of the claim \n "
" \" 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 "
" ] \n " ) ;
2019-07-18 14:35:18 -06:00
if ( ! IsDeprecatedRPCEnabled ( " getclaimsintrie " ) ) {
const auto msg = " getclaimsintrie is deprecated and will be removed in v0.18. To use this command, start with -deprecatedrpc=getclaimsintrie " ;
if ( request . fHelp ) {
throw std : : runtime_error ( msg ) ;
}
throw JSONRPCError ( RPC_METHOD_DEPRECATED , msg ) ;
}
2019-08-01 18:35:58 -06:00
UniValue ret ( UniValue : : VARR ) ;
uint256 rootHash ;
2018-08-06 15:40:20 -04:00
LOCK ( cs_main ) ;
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
CClaimTrieCache trieCache ( pclaimTrie ) ;
if ( ! request . params . empty ( ) ) {
2019-08-01 18:35:58 -06:00
CBlockIndex * blockIndex = BlockHashIndex ( ParseHashV ( request . params [ 0 ] , " blockhash (optional parameter 1) " ) ) ;
2018-08-06 15:40:20 -04:00
RollBackTo ( blockIndex , coinsCache , trieCache ) ;
}
2019-08-01 18:35:58 -06:00
rootHash = trieCache . getMerkleHash ( ) ;
2018-08-06 15:40:20 -04:00
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode rootNode ;
if ( ! pclaimTrie - > find ( rootHash , rootNode ) )
return ret ;
pclaimTrie - > recurseAllHashedNodes ( " " , rootNode , [ & ret , & trieCache , & coinsCache ] ( const std : : string & name ,
const CClaimTrieDataNode & node ) {
2019-07-01 12:42:45 -06:00
if ( ShutdownRequested ( ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Shutdown requested " ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
boost : : this_thread : : interruption_point ( ) ;
2019-08-01 18:35:58 -06:00
if ( node . data . empty ( ) )
return ;
2019-07-01 12:42:45 -06:00
UniValue claims ( UniValue : : VARR ) ;
2019-08-01 18:35:58 -06:00
for ( auto itClaims = node . data . claims . cbegin ( ) ; itClaims ! = node . data . claims . cend ( ) ; + + itClaims ) {
2019-07-01 12:42:45 -06:00
UniValue claim ( UniValue : : VOBJ ) ;
claim . pushKV ( " claimId " , itClaims - > claimId . GetHex ( ) ) ;
claim . pushKV ( " txid " , itClaims - > outPoint . hash . GetHex ( ) ) ;
2019-08-01 18:35:58 -06:00
claim . pushKV ( " n " , ( int ) itClaims - > outPoint . n ) ;
2019-07-01 12:42:45 -06:00
claim . pushKV ( " amount " , ValueFromAmount ( itClaims - > nAmount ) ) ;
claim . pushKV ( " height " , itClaims - > nHeight ) ;
2019-08-01 18:35:58 -06:00
const Coin & coin = coinsCache . AccessCoin ( itClaims - > outPoint ) ;
if ( coin . IsSpent ( ) ) {
LogPrintf ( " %s: the specified txout of %s appears to have been spent \n " , __func__ ,
itClaims - > outPoint . hash . GetHex ( ) ) ;
2019-07-01 12:42:45 -06:00
claim . pushKV ( " error " , " Txout spent " ) ;
2019-08-01 18:35:58 -06:00
} else {
2019-07-01 12:42:45 -06:00
int op ;
std : : vector < std : : vector < unsigned char > > vvchParams ;
2019-08-01 18:35:58 -06:00
if ( ! DecodeClaimScript ( coin . out . scriptPubKey , op , vvchParams ) ) {
LogPrintf ( " %s: the specified txout of %s does not have an claim command \n " , __func__ ,
itClaims - > outPoint . hash . GetHex ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
claim . pushKV ( " value " , HexStr ( vvchParams [ 1 ] . begin ( ) , vvchParams [ 1 ] . end ( ) ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
std : : string targetName ;
CClaimValue targetClaim ;
if ( trieCache . getClaimById ( itClaims - > claimId , targetName , targetClaim ) )
claim . push_back ( Pair ( " name " , escapeNonUtf8 ( targetName ) ) ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
claims . push_back ( claim ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
UniValue nodeObj ( UniValue : : VOBJ ) ;
2019-08-01 18:35:58 -06:00
nodeObj . pushKV ( " normalized_name " , escapeNonUtf8 ( name ) ) ;
2019-07-01 12:42:45 -06:00
nodeObj . pushKV ( " claims " , claims ) ;
ret . push_back ( nodeObj ) ;
2019-08-01 18:35:58 -06:00
} ) ;
2018-08-06 15:40:20 -04:00
return ret ;
}
static UniValue getclaimtrie ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
throw JSONRPCError ( RPC_METHOD_DEPRECATED , " getclaimtrie was removed in v0.17. \n "
" Clients should use getnamesintrie. " ) ;
}
static UniValue getnamesintrie ( const JSONRPCRequest & request )
{
if ( request . fHelp | | ! validParams ( request . params , 0 , 1 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
2019-07-01 12:42:45 -06:00
" getnamesintrie \n "
" Return all claim names in the trie. \n "
2018-08-06 15:40:20 -04:00
" Arguments: \n "
2019-07-01 12:42:45 -06:00
" 1. \" blockhash \" (string, optional) get claims in the trie \n "
2018-08-06 15:40:20 -04:00
" at the block specified \n "
" by this block hash. \n "
" If none is given, \n "
" the latest active \n "
" block will be used. \n "
" Result: \n "
2019-07-01 12:42:45 -06:00
" \" names \" (array) all names in the trie that have claims \n " ) ;
2018-08-06 15:40:20 -04:00
2019-08-01 18:35:58 -06:00
uint256 rootHash ;
{
LOCK ( cs_main ) ;
2018-08-06 15:40:20 -04:00
2019-08-01 18:35:58 -06:00
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
CClaimTrieCache trieCache ( pclaimTrie ) ;
2018-08-06 15:40:20 -04:00
2019-08-01 18:35:58 -06:00
if ( ! request . params . empty ( ) ) {
CBlockIndex * blockIndex = BlockHashIndex ( ParseHashV ( request . params [ 0 ] , " blockhash (optional parameter 1) " ) ) ;
RollBackTo ( blockIndex , coinsCache , trieCache ) ;
}
rootHash = trieCache . getMerkleHash ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
UniValue ret ( UniValue : : VARR ) ;
2018-08-06 15:40:20 -04:00
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode rootNode ;
if ( ! pclaimTrie - > find ( rootHash , rootNode ) )
return ret ;
pclaimTrie - > recurseAllHashedNodes ( " " , rootNode , [ & ret ] ( const std : : string & name , const CClaimTrieDataNode & node ) {
if ( ! node . data . empty ( ) )
ret . push_back ( escapeNonUtf8 ( name ) ) ;
2019-07-01 12:42:45 -06:00
if ( ShutdownRequested ( ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Shutdown requested " ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
boost : : this_thread : : interruption_point ( ) ;
2019-08-01 18:35:58 -06:00
} ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
return ret ;
}
2018-08-06 15:40:20 -04:00
static UniValue getvalueforname ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 1 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" getvalueforname \" name \" \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 "
" associated with the name \n "
" at the block specified \n "
" by this block hash. \n "
" If none is given, \n "
" the latest active \n "
" block will be used. \n "
" Result: \n "
" \" value \" (string) the value of the name, if it exists \n "
" \" claimId \" (string) the claimId for this name claim \n "
" \" txid \" (string) the hash of the transaction which successfully claimed the name \n "
" \" 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 "
" \" name \" (string) the original name of this claim (before normalization) \n " ) ;
LOCK ( cs_main ) ;
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
CClaimTrieCache trieCache ( pclaimTrie ) ;
if ( request . params . size ( ) > 1 ) {
CBlockIndex * blockIndex = BlockHashIndex ( ParseHashV ( request . params [ 1 ] , " blockhash (optional parameter 2) " ) ) ;
RollBackTo ( blockIndex , coinsCache , trieCache ) ;
}
const auto & name = request . params [ 0 ] . get_str ( ) ;
UniValue ret ( UniValue : : VOBJ ) ;
CClaimValue claim ;
if ( ! trieCache . getInfoForName ( name , claim ) )
return ret ; // they may have asked for a name that doesn't exist (which is not an error)
std : : string sValue ;
if ( ! getValueForOutPoint ( coinsCache , claim . outPoint , sValue ) )
return ret ;
const auto nEffectiveAmount = trieCache . getEffectiveAmountForClaim ( name , claim . claimId ) ;
ret . pushKV ( " value " , sValue ) ;
ret . pushKV ( " claimId " , claim . claimId . GetHex ( ) ) ;
ret . pushKV ( " txid " , claim . outPoint . hash . GetHex ( ) ) ;
ret . pushKV ( " n " , ( int ) claim . outPoint . n ) ;
ret . pushKV ( " amount " , claim . nAmount ) ;
ret . pushKV ( " effective amount " , nEffectiveAmount ) ;
ret . pushKV ( " height " , claim . nHeight ) ;
std : : string targetName ;
CClaimValue targetClaim ;
2019-07-01 12:42:45 -06:00
if ( trieCache . getClaimById ( claim . claimId , targetName , targetClaim ) )
ret . pushKV ( " name " , escapeNonUtf8 ( targetName ) ) ;
2018-08-06 15:40:20 -04:00
return ret ;
}
typedef std : : pair < CClaimValue , std : : vector < CSupportValue > > claimAndSupportsType ;
typedef std : : map < uint160 , claimAndSupportsType > claimSupportMapType ;
UniValue supportToJSON ( const CCoinsViewCache & coinsCache , const CSupportValue & support )
{
UniValue ret ( UniValue : : VOBJ ) ;
2019-07-01 12:42:45 -06:00
ret . pushKV ( " txid " , support . outPoint . hash . GetHex ( ) ) ;
ret . pushKV ( " n " , ( int ) support . outPoint . n ) ;
ret . pushKV ( " nHeight " , support . nHeight ) ;
ret . pushKV ( " nValidAtHeight " , support . nValidAtHeight ) ;
ret . pushKV ( " nAmount " , support . nAmount ) ;
2018-08-06 15:40:20 -04:00
std : : string value ;
if ( getValueForOutPoint ( coinsCache , support . outPoint , value ) )
2019-07-01 12:42:45 -06:00
ret . pushKV ( " value " , value ) ;
2018-08-06 15:40:20 -04:00
return ret ;
}
2019-07-01 12:42:45 -06:00
UniValue claimAndSupportsToJSON ( const CClaimTrieCache & trieCache , const CCoinsViewCache & coinsCache , CAmount nEffectiveAmount , claimSupportMapType : : const_iterator itClaimsAndSupports )
2018-08-06 15:40:20 -04:00
{
const CClaimValue & claim = itClaimsAndSupports - > second . first ;
const std : : vector < CSupportValue > & supports = itClaimsAndSupports - > second . second ;
UniValue supportObjs ( UniValue : : VARR ) ;
for ( const auto & support : supports )
supportObjs . push_back ( supportToJSON ( coinsCache , support ) ) ;
UniValue result ( UniValue : : VOBJ ) ;
result . pushKV ( " claimId " , itClaimsAndSupports - > first . GetHex ( ) ) ;
result . pushKV ( " txid " , claim . outPoint . hash . GetHex ( ) ) ;
result . pushKV ( " n " , ( int ) claim . outPoint . n ) ;
result . pushKV ( " nHeight " , claim . nHeight ) ;
result . pushKV ( " nValidAtHeight " , claim . nValidAtHeight ) ;
result . pushKV ( " nAmount " , claim . nAmount ) ;
std : : string sValue ;
if ( getValueForOutPoint ( coinsCache , claim . outPoint , sValue ) )
result . pushKV ( " value " , sValue ) ;
result . pushKV ( " nEffectiveAmount " , nEffectiveAmount ) ;
result . pushKV ( " supports " , supportObjs ) ;
std : : string targetName ;
CClaimValue targetClaim ;
2019-07-01 12:42:45 -06:00
if ( trieCache . getClaimById ( claim . claimId , targetName , targetClaim ) )
result . pushKV ( " name " , escapeNonUtf8 ( targetName ) ) ;
2018-08-06 15:40:20 -04:00
return result ;
}
UniValue getclaimsforname ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 1 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" getclaimsforname \n "
" Return all claims and supports for a name \n "
" Arguments: \n "
" 1. \" name \" (string) the name for which to get claims and supports \n "
" 2. \" blockhash \" (string, optional) get claims for name \n "
" at the block specified \n "
" by this block hash. \n "
" If none is given, \n "
" the latest active \n "
" block will be used. \n "
" 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 "
" \" txid \" (string) the txid of this claim \n "
" \" n \" (numeric) the index of the claim in the transaction's list of outputs \n "
" \" 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 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 "
" \" n \" (numeric) the index of the support in the transaction's list of outputs \n "
" \" 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 "
" \" name \" (string) the original name of this claim before normalization \n "
" } \n "
" ], \n "
" \" supports without claims \" : [ (array of object) supports that did not match a claim for this name \n "
" { \n "
" \" txid \" (string) the txid of the support \n "
" \" n \" (numeric) the index of the support in the transaction's list of outputs \n "
" \" 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 "
" } \n "
" ] \n "
" } \n " ) ;
LOCK ( cs_main ) ;
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
CClaimTrieCache trieCache ( pclaimTrie ) ;
if ( request . params . size ( ) > 1 ) {
CBlockIndex * blockIndex = BlockHashIndex ( ParseHashV ( request . params [ 1 ] , " blockhash (optional parameter 2) " ) ) ;
RollBackTo ( blockIndex , coinsCache , trieCache ) ;
}
std : : string name = request . params [ 0 ] . get_str ( ) ;
2019-07-01 12:42:45 -06:00
auto claimsForName = trieCache . getClaimsForName ( name ) ;
2018-08-06 15:40:20 -04:00
UniValue claimObjs ( UniValue : : VARR ) ;
claimSupportMapType claimSupportMap ;
UniValue unmatchedSupports ( UniValue : : VARR ) ;
2019-07-01 12:40:18 -06:00
for ( auto itClaims = claimsForName . claims . begin ( ) ; itClaims ! = claimsForName . claims . end ( ) ; + + itClaims )
2018-08-06 15:40:20 -04:00
{
claimAndSupportsType claimAndSupports = std : : make_pair ( * itClaims , std : : vector < CSupportValue > ( ) ) ;
2019-07-01 12:40:18 -06:00
claimSupportMap . emplace ( itClaims - > claimId , claimAndSupports ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:40:18 -06:00
for ( auto itSupports = claimsForName . supports . begin ( ) ; itSupports ! = claimsForName . supports . end ( ) ; + + itSupports )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:40:18 -06:00
auto itClaimAndSupports = claimSupportMap . find ( itSupports - > supportedClaimId ) ;
2018-08-06 15:40:20 -04:00
if ( itClaimAndSupports = = claimSupportMap . end ( ) )
unmatchedSupports . push_back ( supportToJSON ( coinsCache , * itSupports ) ) ;
else
itClaimAndSupports - > second . second . push_back ( * itSupports ) ;
}
UniValue result ( UniValue : : VOBJ ) ;
result . pushKV ( " nLastTakeoverHeight " , claimsForName . nLastTakeoverHeight ) ;
2019-07-01 12:42:45 -06:00
result . pushKV ( " normalized_name " , escapeNonUtf8 ( claimsForName . name ) ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:40:18 -06:00
for ( auto itClaims = claimsForName . claims . begin ( ) ; itClaims ! = claimsForName . claims . end ( ) ; + + itClaims )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:40:18 -06:00
auto itClaimsAndSupports = claimSupportMap . find ( itClaims - > claimId ) ;
2018-08-06 15:40:20 -04:00
const auto nEffectiveAmount = trieCache . getEffectiveAmountForClaim ( claimsForName , itClaimsAndSupports - > first ) ;
2019-07-01 12:42:45 -06:00
UniValue claimObj = claimAndSupportsToJSON ( trieCache , coinsCache , nEffectiveAmount , itClaimsAndSupports ) ;
2018-08-06 15:40:20 -04:00
claimObjs . push_back ( claimObj ) ;
}
result . pushKV ( " claims " , claimObjs ) ;
result . pushKV ( " supports without claims " , unmatchedSupports ) ;
return result ;
}
UniValue getclaimbyid ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 0 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" getclaimbyid \n "
" Get a claim by claim id \n "
" Arguments: \n "
" 1. \" claimId \" (string) the claimId of this claim \n "
" Result: \n "
" { \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 "
" \" amount \" (numeric) txout value \n "
" \" effective amount \" (numeric) txout amount plus amount from all supports associated with the claim \n "
" \" supports \" (array of object) supports for this claim \n "
" [ \n "
" \" txid \" (string) the txid of the support \n "
" \" n \" (numeric) the index of the support in the transaction's list of outputs \n "
" \" 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 "
" } \n " ) ;
LOCK ( cs_main ) ;
2019-07-01 12:42:45 -06:00
CClaimTrieCache trieCache ( pclaimTrie ) ;
2018-08-06 15:40:20 -04:00
uint160 claimId = ParseClaimtrieId ( request . params [ 0 ] , " Claim-id (parameter 1) " ) ;
UniValue claim ( UniValue : : VOBJ ) ;
std : : string name ;
CClaimValue claimValue ;
2019-07-01 12:42:45 -06:00
trieCache . getClaimById ( claimId , name , claimValue ) ;
2018-08-06 15:40:20 -04:00
if ( claimValue . claimId = = claimId )
{
std : : vector < CSupportValue > supports ;
CAmount effectiveAmount = trieCache . getEffectiveAmountForClaim ( name , claimValue . claimId , & supports ) ;
std : : string sValue ;
2019-07-01 12:42:45 -06:00
claim . pushKV ( " name " , escapeNonUtf8 ( name ) ) ;
2018-08-06 15:40:20 -04:00
if ( trieCache . shouldNormalize ( ) )
2019-07-01 12:42:45 -06:00
claim . pushKV ( " normalized_name " , escapeNonUtf8 ( trieCache . normalizeClaimName ( name , true ) ) ) ;
2018-08-06 15:40:20 -04:00
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
if ( getValueForOutPoint ( coinsCache , claimValue . outPoint , sValue ) )
claim . pushKV ( " value " , sValue ) ;
claim . pushKV ( " claimId " , claimValue . claimId . GetHex ( ) ) ;
claim . pushKV ( " txid " , claimValue . outPoint . hash . GetHex ( ) ) ;
claim . pushKV ( " n " , ( int ) claimValue . outPoint . n ) ;
claim . pushKV ( " amount " , claimValue . nAmount ) ;
claim . pushKV ( " effective amount " , effectiveAmount ) ;
UniValue supportList ( UniValue : : VARR ) ;
for ( const CSupportValue & support : supports ) {
UniValue supportEntry ( UniValue : : VOBJ ) ;
supportEntry . pushKV ( " txid " , support . outPoint . hash . GetHex ( ) ) ;
supportEntry . pushKV ( " n " , ( int ) support . outPoint . n ) ;
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 ) ;
claim . pushKV ( " height " , claimValue . nHeight ) ;
claim . pushKV ( " valid at height " , claimValue . nValidAtHeight ) ;
}
return claim ;
}
UniValue gettotalclaimednames ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 0 , 0 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" gettotalclaimednames \n "
" Return the total number of names that have been \n "
" successfully claimed, and therefore exist in the trie \n "
" Arguments: \n "
" Result: \n "
" \" total names \" (numeric) the total number of \n "
" names in the trie \n "
) ;
LOCK ( cs_main ) ;
2019-08-01 18:35:58 -06:00
auto num_names = pclaimTrie - > getTotalNamesInTrie ( ) ;
2018-08-06 15:40:20 -04:00
return int ( num_names ) ;
}
UniValue gettotalclaims ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 0 , 0 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" gettotalclaims \n "
" Return the total number of active claims in the trie \n "
" Arguments: \n "
" Result: \n "
" \" total claims \" (numeric) the total number \n "
" of active claims \n "
) ;
LOCK ( cs_main ) ;
2019-08-01 18:35:58 -06:00
auto num_claims = pclaimTrie - > getTotalClaimsInTrie ( ) ;
2018-08-06 15:40:20 -04:00
return int ( num_claims ) ;
}
UniValue gettotalvalueofclaims ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 0 , 1 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" gettotalvalueofclaims \n "
" Return the total value of the claims in the trie \n "
" Arguments: \n "
" 1. \" controlling_only \" (boolean) only include the value \n "
" of controlling claims \n "
" Result: \n "
" \" total value \" (numeric) the total value of the \n "
" claims in the trie \n "
) ;
LOCK ( cs_main ) ;
bool controlling_only = false ;
if ( request . params . size ( ) = = 1 )
controlling_only = request . params [ 0 ] . get_bool ( ) ;
2019-08-01 18:35:58 -06:00
auto total_amount = pclaimTrie - > getTotalValueOfClaimsInTrie ( controlling_only ) ;
2018-08-06 15:40:20 -04:00
return ValueFromAmount ( total_amount ) ;
}
UniValue getclaimsfortx ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 0 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" getclaimsfortx \n "
" Return any claims or supports found in a transaction \n "
" Arguments: \n "
" 1. \" txid \" (string) the txid of the transaction to check for unspent claims \n "
" Result: \n "
" [ \n "
" { \n "
" \" 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 "
" \" depth \" (numeric) the depth of the transaction in the main chain \n "
" \" in claim trie \" (boolean) if a name claim, whether the claim is active, i.e. has made it into the trie \n "
" \" is controlling \" (boolean) if a name claim, whether the claim is the current controlling claim for the name \n "
" \" in support map \" (boolean) if a support, whether the support is active, i.e. has made it into the support map \n "
" \" in queue \" (boolean) whether the claim is in a queue waiting to be inserted into the trie or support map \n "
" \" blocks to valid \" (numeric) if in a queue, the number of blocks until it's inserted into the trie or support map \n "
" } \n "
" ] \n "
) ;
LOCK ( cs_main ) ;
uint256 hash = ParseHashV ( request . params [ 0 ] , " txid (parameter 1) " ) ;
UniValue ret ( UniValue : : VARR ) ;
int op ;
std : : vector < std : : vector < unsigned char > > vvchParams ;
2019-07-01 12:42:45 -06:00
CClaimTrieCache trieCache ( pclaimTrie ) ;
2018-08-06 15:40:20 -04:00
CCoinsViewCache view ( pcoinsTip . get ( ) ) ;
const Coin & coin = AccessByTxid ( view , hash ) ;
std : : vector < CTxOut > txouts { coin . out } ;
int nHeight = coin . nHeight ;
for ( unsigned int i = 0 ; i < txouts . size ( ) ; + + i )
{
if ( ! txouts [ i ] . IsNull ( ) )
{
vvchParams . clear ( ) ;
const CTxOut & txout = txouts [ i ] ;
UniValue o ( UniValue : : VOBJ ) ;
if ( DecodeClaimScript ( txout . scriptPubKey , op , vvchParams ) )
{
o . pushKV ( " nOut " , static_cast < int64_t > ( i ) ) ;
std : : string sName ( vvchParams [ 0 ] . begin ( ) , vvchParams [ 0 ] . end ( ) ) ;
2019-07-01 12:42:45 -06:00
o . pushKV ( " name " , escapeNonUtf8 ( sName ) ) ;
2018-08-06 15:40:20 -04:00
if ( op = = OP_CLAIM_NAME )
{
uint160 claimId = ClaimIdHash ( hash , i ) ;
o . pushKV ( " claimId " , claimId . GetHex ( ) ) ;
o . pushKV ( " value " , HexStr ( vvchParams [ 1 ] . begin ( ) , vvchParams [ 1 ] . end ( ) ) ) ;
}
else if ( op = = OP_UPDATE_CLAIM )
{
uint160 claimId ( vvchParams [ 1 ] ) ;
o . pushKV ( " claimId " , claimId . GetHex ( ) ) ;
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 )
{
o . pushKV ( " depth " , chainActive . Height ( ) - nHeight ) ;
if ( op = = OP_CLAIM_NAME | | op = = OP_UPDATE_CLAIM )
{
2019-07-01 12:42:45 -06:00
bool inClaimTrie = trieCache . haveClaim ( sName , COutPoint ( hash , i ) ) ;
2018-08-06 15:40:20 -04:00
o . pushKV ( " in claim trie " , inClaimTrie ) ;
if ( inClaimTrie )
{
CClaimValue claim ;
2019-07-01 12:42:45 -06:00
if ( ! trieCache . getInfoForName ( sName , claim ) )
2018-08-06 15:40:20 -04:00
{
LogPrintf ( " HaveClaim was true but getInfoForName returned false. " ) ;
}
o . pushKV ( " is controlling " , ( claim . outPoint . hash = = hash & & claim . outPoint . n = = i ) ) ;
}
else
{
int nValidAtHeight ;
2019-07-01 12:42:45 -06:00
if ( trieCache . haveClaimInQueue ( sName , COutPoint ( hash , i ) , nValidAtHeight ) )
2018-08-06 15:40:20 -04:00
{
o . pushKV ( " in queue " , true ) ;
o . pushKV ( " blocks to valid " , nValidAtHeight - chainActive . Height ( ) ) ;
}
else
{
o . pushKV ( " in queue " , false ) ;
}
}
}
else if ( op = = OP_SUPPORT_CLAIM )
{
2019-07-01 12:42:45 -06:00
bool inSupportMap = trieCache . haveSupport ( sName , COutPoint ( hash , i ) ) ;
2018-08-06 15:40:20 -04:00
o . pushKV ( " in support map " , inSupportMap ) ;
if ( ! inSupportMap )
{
int nValidAtHeight ;
2019-07-01 12:42:45 -06:00
if ( trieCache . haveSupportInQueue ( sName , COutPoint ( hash , i ) , nValidAtHeight ) )
2018-08-06 15:40:20 -04:00
{
o . pushKV ( " in queue " , true ) ;
o . pushKV ( " blocks to valid " , nValidAtHeight - chainActive . Height ( ) ) ;
}
else
{
o . pushKV ( " in queue " , false ) ;
}
}
}
}
else
{
o . pushKV ( " depth " , 0 ) ;
if ( op = = OP_CLAIM_NAME | | op = = OP_UPDATE_CLAIM )
{
o . pushKV ( " in claim trie " , false ) ;
}
else if ( op = = OP_SUPPORT_CLAIM )
{
o . pushKV ( " in support map " , false ) ;
}
o . pushKV ( " in queue " , false ) ;
}
ret . push_back ( o ) ;
}
}
}
return ret ;
}
UniValue proofToJSON ( const CClaimTrieProof & proof )
{
UniValue result ( UniValue : : VOBJ ) ;
UniValue nodes ( UniValue : : VARR ) ;
for ( std : : vector < CClaimTrieProofNode > : : const_iterator itNode = proof . nodes . begin ( ) ; itNode ! = proof . nodes . end ( ) ; + + itNode )
{
UniValue node ( UniValue : : VOBJ ) ;
UniValue children ( UniValue : : VARR ) ;
for ( std : : vector < std : : pair < unsigned char , uint256 > > : : const_iterator itChildren = itNode - > children . begin ( ) ; itChildren ! = itNode - > children . end ( ) ; + + itChildren )
{
UniValue child ( UniValue : : VOBJ ) ;
child . pushKV ( " character " , itChildren - > first ) ;
if ( ! itChildren - > second . IsNull ( ) )
{
child . pushKV ( " nodeHash " , itChildren - > second . GetHex ( ) ) ;
}
children . push_back ( child ) ;
}
node . pushKV ( " children " , children ) ;
if ( itNode - > hasValue & & ! itNode - > valHash . IsNull ( ) )
{
node . pushKV ( " valueHash " , itNode - > valHash . GetHex ( ) ) ;
}
nodes . push_back ( node ) ;
}
result . pushKV ( " nodes " , nodes ) ;
if ( proof . hasValue )
{
result . pushKV ( " txhash " , proof . outPoint . hash . GetHex ( ) ) ;
result . pushKV ( " nOut " , ( int ) proof . outPoint . n ) ;
result . pushKV ( " last takeover height " , ( int ) proof . nHeightOfLastTakeover ) ;
}
return result ;
}
UniValue getnameproof ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 1 ) )
2018-08-06 15:40:20 -04:00
throw std : : runtime_error (
" getnameproof \n "
" Return the cryptographic proof that a name maps to a value \n "
" or doesn't. \n "
" Arguments: \n "
" 1. \" name \" (string) the name to get a proof for \n "
" 2. \" blockhash \" (string, optional) the hash of the block \n "
" which is the basis \n "
" of the proof. If \n "
" none is given, \n "
" the latest block \n "
" will be used. \n "
" Result: \n "
" { \n "
" \" nodes \" : [ (array of object) full nodes (i.e. \n "
" those which lead to \n "
" the requested name) \n "
" \" children \" : [ (array of object) the children of \n "
" this node \n "
" \" child \" : { (object) a child node, either leaf or \n "
" reference to a full node \n "
" \" character \" : \" char \" (string) the character which \n "
" leads from the parent \n "
" to this child node \n "
" \" nodeHash \" : \" hash \" (string, if exists) the hash of \n "
" the node if \n "
" this is a \n "
" leaf node \n "
" } \n "
" ] \n "
" \" valueHash \" (string, if exists) the hash of this \n "
" node's value, if \n "
" it has one. If \n "
" this is the \n "
" requested name \n "
" this will not \n "
" exist whether \n "
" the node has a \n "
" value or not \n "
" ] \n "
" \" txhash \" : \" hash \" (string, if exists) the txid of the \n "
" claim which controls \n "
" this name, if there \n "
" is one. \n "
" \" nOut \" : n, (numeric) the nOut of the claim which \n "
" controls this name, if there \n "
" is one. \n "
" \" last takeover height \" (numeric) the most recent height at \n "
" which the value of a name \n "
" changed other than through \n "
" an update to the winning \n "
" bid \n "
" } \n "
" } \n " ) ;
LOCK ( cs_main ) ;
CCoinsViewCache coinsCache ( pcoinsTip . get ( ) ) ;
CClaimTrieCache trieCache ( pclaimTrie ) ;
if ( request . params . size ( ) = = 2 ) {
CBlockIndex * pblockIndex = BlockHashIndex ( ParseHashV ( request . params [ 1 ] , " blockhash (optional parameter 2) " ) ) ;
RollBackTo ( pblockIndex , coinsCache , trieCache ) ;
}
CClaimTrieProof proof ;
std : : string name = request . params [ 0 ] . get_str ( ) ;
if ( ! trieCache . getProofForName ( name , proof ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Failed to generate proof " ) ;
return proofToJSON ( proof ) ;
}
UniValue checknormalization ( const JSONRPCRequest & request )
{
2019-07-01 12:42:45 -06:00
if ( request . fHelp | | ! validParams ( request . params , 1 , 0 ) )
2018-08-06 15:40:20 -04:00
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
// --------------------- ------------------------ ----------------------- ----------
{ " Claimtrie " , " getclaimsintrie " , & getclaimsintrie , { " blockhash " } } ,
2019-07-01 12:42:45 -06:00
{ " Claimtrie " , " getnamesintrie " , & getnamesintrie , { " blockhash " } } ,
2019-07-18 14:35:18 -06:00
{ " hidden " , " getclaimtrie " , & getclaimtrie , { } } ,
2018-08-06 15:40:20 -04:00
{ " Claimtrie " , " getvalueforname " , & getvalueforname , { " name " , " blockhash " } } ,
{ " Claimtrie " , " getclaimsforname " , & getclaimsforname , { " name " , " blockhash " } } ,
{ " Claimtrie " , " gettotalclaimednames " , & gettotalclaimednames , { " " } } ,
{ " Claimtrie " , " gettotalclaims " , & gettotalclaims , { " " } } ,
{ " Claimtrie " , " gettotalvalueofclaims " , & gettotalvalueofclaims , { " controlling_only " } } ,
{ " Claimtrie " , " getclaimsfortx " , & getclaimsfortx , { " txid " } } ,
{ " Claimtrie " , " getnameproof " , & getnameproof , { " name " , " blockhash " } } ,
{ " Claimtrie " , " getclaimbyid " , & getclaimbyid , { " claimId " } } ,
{ " Claimtrie " , " checknormalization " , & checknormalization , { " name " } } ,
} ;
void RegisterClaimTrieRPCCommands ( CRPCTable & tableRPC )
{
for ( unsigned int vcidx = 0 ; vcidx < ARRAYLEN ( commands ) ; vcidx + + )
tableRPC . appendCommand ( commands [ vcidx ] . name , & commands [ vcidx ] ) ;
}