2012-08-21 17:03:38 +02:00
// Copyright (c) 2010 Satoshi Nakamoto
2021-12-12 14:38:12 +01:00
// Copyright (c) 2009-2019 The Bitcoin Core developers
2021-04-20 21:33:02 +02:00
// Copyright (c) 2014-2021 The Dash Core developers
2014-11-20 03:19:29 +01:00
// Distributed under the MIT software license, see the accompanying
2012-08-21 17:03:38 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2020-03-19 23:46:56 +01:00
# include <rpc/blockchain.h>
# include <amount.h>
2021-08-12 09:04:28 +02:00
# include <blockfilter.h>
2018-01-15 22:23:44 +01:00
# include <chain.h>
2020-03-19 23:46:56 +01:00
# include <chainparams.h>
# include <coins.h>
2020-12-15 17:22:23 +01:00
# include <node/coinstats.h>
2020-03-19 23:46:56 +01:00
# include <core_io.h>
# include <consensus/validation.h>
2021-08-12 09:04:28 +02:00
# include <index/blockfilterindex.h>
2018-01-15 22:23:44 +01:00
# include <key_io.h>
2021-05-25 12:48:04 +02:00
# include <index/txindex.h>
2020-03-19 23:46:56 +01:00
# include <policy/feerate.h>
# include <policy/policy.h>
# include <primitives/transaction.h>
# include <rpc/server.h>
2018-11-13 18:34:43 +01:00
# include <rpc/util.h>
2021-07-20 17:59:35 +02:00
# include <script/descriptor.h>
2020-03-19 23:46:56 +01:00
# include <streams.h>
# include <sync.h>
# include <txmempool.h>
2021-06-27 08:33:13 +02:00
# include <util/strencodings.h>
2021-06-25 08:07:28 +02:00
# include <util/validation.h>
2018-11-13 18:34:43 +01:00
# include <util/system.h>
# include <validation.h>
2018-01-18 14:26:21 +01:00
# include <validationinterface.h>
2021-09-03 00:36:11 +02:00
# include <versionbitsinfo.h>
2020-03-19 23:46:56 +01:00
# include <warnings.h>
# include <evo/specialtx.h>
# include <evo/cbtx.h>
2021-10-02 19:32:24 +02:00
# include <llmq/chainlocks.h>
# include <llmq/instantsend.h>
2019-01-22 14:21:06 +01:00
2018-01-15 22:23:44 +01:00
# include <assert.h>
2013-04-13 07:13:08 +02:00
# include <stdint.h>
2015-09-04 16:11:34 +02:00
# include <univalue.h>
2012-08-21 17:03:38 +02:00
2016-04-15 16:36:39 +02:00
# include <boost/thread/thread.hpp> // boost::thread::interrupt
2016-09-09 08:33:26 +02:00
# include <mutex>
# include <condition_variable>
2021-04-16 05:41:16 +02:00
# include <merkleblock.h>
2012-08-21 17:03:38 +02:00
2016-09-09 08:33:26 +02:00
struct CUpdatedBlock
{
uint256 hash ;
int height ;
} ;
2021-06-04 21:26:33 +02:00
static Mutex cs_blockchange ;
2016-09-09 08:33:26 +02:00
static std : : condition_variable cond_blockchange ;
2021-06-09 14:06:31 +02:00
static CUpdatedBlock latestblock GUARDED_BY ( cs_blockchange ) ;
2016-09-09 08:33:26 +02:00
2015-05-18 14:02:18 +02:00
extern void TxToJSON ( const CTransaction & tx , const uint256 hashBlock , UniValue & entry ) ;
2013-01-04 22:51:00 +01:00
2018-06-05 20:30:40 +02:00
/* Calculate the difficulty for a given block index.
Merge #11748: [Tests] Adding unit tests for GetDifficulty in blockchain.cpp.
3e1ee31 [Tests] Adding unit tests for GetDifficulty in blockchain.cpp. (sean)
Pull request description:
blockchain.cpp has low unit test coverage. This commit is intended
to start improving its code coverage to reasonable levels. One or more
follow up commits will complete the task that this commit is starting
(though the usefulness of this commit is not dependent upon later
commits).
Note that these tests were not written based upon a specification of how
GetDifficulty *should* work, but rather how it actually *does* work. As
a result, if there are any bugs in the current GetDifficulty
implementation, these unit tests serve to lock them in rather than
expose them.
-- Why has blockchain.cpp been modified if this is a unit testing change?
Since the existing GetDifficulty function relies on a global variable,
chainActive, it was not suitable for unit testing purposes. Both the
existing GetDifficulty function and the unit tests now call through to
a new, more modular version of GetDifficulty that can work on any chain,
not just chainActive.
-- Why does blockchain_tests.cpp directly include blockchain.cpp instead
of blockchain.h?
While the new GetDifficulty function's signature is arguably better than
the old one's, it still isn't great, and doesn't seem to warrant inclusion
as part of the blockchain.h API, especially since only test code is
directly using it. If a better way of exposing the new GetDifficulty
function to unit tests exists, please mention it and the commit will be
updated accordingly.
-- Why is the test fixture named blockchain_difficulty_tests rather than
blockchain_tests?
The Bitcoin Core policy for naming unit test files is to match the the
file under test ("blockchain" becomes "blockchain_tests"). While this
commit complies with that, blockchain.cpp is a massive file, such that
having all of the unit tests in one file will tend towards disorder.
Since there will be a lot more tests added to this file, the intention
is to divide up different types of tests into different test fixtures
within the same file.
Tree-SHA512: a7dda9c2a9414d4819b4d2911f5637891dc19cecbecfc1463846161d2a78793151927a5ab911c69a5d3013f7668e75a1d78a65667cb9d83910cda439cbe84d62
2017-12-23 11:15:18 +01:00
*/
2018-06-05 20:30:40 +02:00
double GetDifficulty ( const CBlockIndex * blockindex )
2012-08-21 17:03:38 +02:00
{
2019-01-04 12:30:36 +01:00
assert ( blockindex ) ;
2012-08-21 17:03:38 +02:00
int nShift = ( blockindex - > nBits > > 24 ) & 0xff ;
double dDiff =
( double ) 0x0000ffff / ( double ) ( blockindex - > nBits & 0x00ffffff ) ;
while ( nShift < 29 )
{
dDiff * = 256.0 ;
nShift + + ;
}
while ( nShift > 29 )
{
dDiff / = 256.0 ;
nShift - - ;
}
return dDiff ;
}
2019-01-04 12:30:36 +01:00
static int ComputeNextBlockAndDepth ( const CBlockIndex * tip , const CBlockIndex * blockindex , const CBlockIndex * & next )
{
next = tip - > GetAncestor ( blockindex - > nHeight + 1 ) ;
if ( next & & next - > pprev = = blockindex ) {
return tip - > nHeight - blockindex - > nHeight + 1 ;
}
next = nullptr ;
return blockindex = = tip ? 1 : - 1 ;
}
UniValue blockheaderToJSON ( const CBlockIndex * tip , const CBlockIndex * blockindex )
2015-06-05 21:37:17 +02:00
{
UniValue result ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
result . pushKV ( " hash " , blockindex - > GetBlockHash ( ) . GetHex ( ) ) ;
2019-01-04 12:30:36 +01:00
const CBlockIndex * pnext ;
int confirmations = ComputeNextBlockAndDepth ( tip , blockindex , pnext ) ;
2020-06-18 11:17:23 +02:00
result . pushKV ( " confirmations " , confirmations ) ;
result . pushKV ( " height " , blockindex - > nHeight ) ;
result . pushKV ( " version " , blockindex - > nVersion ) ;
result . pushKV ( " versionHex " , strprintf ( " %08x " , blockindex - > nVersion ) ) ;
result . pushKV ( " merkleroot " , blockindex - > hashMerkleRoot . GetHex ( ) ) ;
result . pushKV ( " time " , ( int64_t ) blockindex - > nTime ) ;
result . pushKV ( " mediantime " , ( int64_t ) blockindex - > GetMedianTimePast ( ) ) ;
result . pushKV ( " nonce " , ( uint64_t ) blockindex - > nNonce ) ;
result . pushKV ( " bits " , strprintf ( " %08x " , blockindex - > nBits ) ) ;
result . pushKV ( " difficulty " , GetDifficulty ( blockindex ) ) ;
result . pushKV ( " chainwork " , blockindex - > nChainWork . GetHex ( ) ) ;
result . pushKV ( " nTx " , ( uint64_t ) blockindex - > nTx ) ;
2012-08-21 17:03:38 +02:00
2015-06-05 21:37:17 +02:00
if ( blockindex - > pprev )
2020-06-18 11:17:23 +02:00
result . pushKV ( " previousblockhash " , blockindex - > pprev - > GetBlockHash ( ) . GetHex ( ) ) ;
2015-06-05 21:37:17 +02:00
if ( pnext )
2020-06-18 11:17:23 +02:00
result . pushKV ( " nextblockhash " , pnext - > GetBlockHash ( ) . GetHex ( ) ) ;
2019-01-22 14:21:06 +01:00
2020-06-18 11:17:23 +02:00
result . pushKV ( " chainlock " , llmq : : chainLocksHandler - > HasChainLock ( blockindex - > nHeight , blockindex - > GetBlockHash ( ) ) ) ;
2019-01-22 14:21:06 +01:00
2015-06-05 21:37:17 +02:00
return result ;
}
2019-01-04 12:30:36 +01:00
UniValue blockToJSON ( const CBlock & block , const CBlockIndex * tip , const CBlockIndex * blockindex , bool txDetails )
2012-08-21 17:03:38 +02:00
{
2015-05-10 14:48:35 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
result . pushKV ( " hash " , blockindex - > GetBlockHash ( ) . GetHex ( ) ) ;
2019-01-04 12:30:36 +01:00
const CBlockIndex * pnext ;
int confirmations = ComputeNextBlockAndDepth ( tip , blockindex , pnext ) ;
2020-06-18 11:17:23 +02:00
result . pushKV ( " confirmations " , confirmations ) ;
result . pushKV ( " size " , ( int ) : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION ) ) ;
result . pushKV ( " height " , blockindex - > nHeight ) ;
result . pushKV ( " version " , block . nVersion ) ;
result . pushKV ( " versionHex " , strprintf ( " %08x " , block . nVersion ) ) ;
result . pushKV ( " merkleroot " , block . hashMerkleRoot . GetHex ( ) ) ;
2019-08-28 09:53:20 +02:00
bool chainLock = llmq : : chainLocksHandler - > HasChainLock ( blockindex - > nHeight , blockindex - > GetBlockHash ( ) ) ;
2015-05-10 14:48:35 +02:00
UniValue txs ( UniValue : : VARR ) ;
2016-11-21 10:51:32 +01:00
for ( const auto & tx : block . vtx )
2014-11-28 20:32:52 +01:00
{
if ( txDetails )
{
2015-05-10 14:48:35 +02:00
UniValue objTx ( UniValue : : VOBJ ) ;
2020-01-22 11:36:22 +01:00
TxToUniv ( * tx , uint256 ( ) , objTx , true ) ;
2019-08-28 09:53:20 +02:00
bool fLocked = llmq : : quorumInstantSendManager - > IsLocked ( tx - > GetHash ( ) ) ;
2020-06-18 11:17:23 +02:00
objTx . pushKV ( " instantlock " , fLocked | | chainLock ) ;
objTx . pushKV ( " instantlock_internal " , fLocked ) ;
2014-11-28 20:32:52 +01:00
txs . push_back ( objTx ) ;
}
else
2016-11-21 10:51:32 +01:00
txs . push_back ( tx - > GetHash ( ) . GetHex ( ) ) ;
2014-11-28 20:32:52 +01:00
}
2020-06-18 11:17:23 +02:00
result . pushKV ( " tx " , txs ) ;
2018-04-09 10:35:43 +02:00
if ( ! block . vtx [ 0 ] - > vExtraPayload . empty ( ) ) {
CCbTx cbTx ;
if ( GetTxPayload ( block . vtx [ 0 ] - > vExtraPayload , cbTx ) ) {
UniValue cbTxObj ;
cbTx . ToJson ( cbTxObj ) ;
2020-06-18 11:17:23 +02:00
result . pushKV ( " cbTx " , cbTxObj ) ;
2018-04-09 10:35:43 +02:00
}
}
2020-06-18 11:17:23 +02:00
result . pushKV ( " time " , block . GetBlockTime ( ) ) ;
result . pushKV ( " mediantime " , ( int64_t ) blockindex - > GetMedianTimePast ( ) ) ;
result . pushKV ( " nonce " , ( uint64_t ) block . nNonce ) ;
result . pushKV ( " bits " , strprintf ( " %08x " , block . nBits ) ) ;
result . pushKV ( " difficulty " , GetDifficulty ( blockindex ) ) ;
result . pushKV ( " chainwork " , blockindex - > nChainWork . GetHex ( ) ) ;
result . pushKV ( " nTx " , ( uint64_t ) blockindex - > nTx ) ;
2012-08-21 17:03:38 +02:00
if ( blockindex - > pprev )
2020-06-18 11:17:23 +02:00
result . pushKV ( " previousblockhash " , blockindex - > pprev - > GetBlockHash ( ) . GetHex ( ) ) ;
2013-05-12 15:50:22 +02:00
if ( pnext )
2020-06-18 11:17:23 +02:00
result . pushKV ( " nextblockhash " , pnext - > GetBlockHash ( ) . GetHex ( ) ) ;
2019-01-22 14:21:06 +01:00
2020-06-18 11:17:23 +02:00
result . pushKV ( " chainlock " , chainLock ) ;
2019-01-22 14:21:06 +01:00
2012-08-21 17:03:38 +02:00
return result ;
}
2018-05-04 22:42:39 +02:00
static UniValue getblockcount ( const JSONRPCRequest & request )
2012-08-21 17:03:38 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockcount " ,
2019-07-03 14:49:07 +02:00
" \n Returns the height of the most-work fully-validated chain. \n "
" The genesis block has height 0. \n " ,
2019-01-29 15:55:37 +01:00
{ } ,
RPCResult {
2013-10-29 12:29:44 +01:00
" n (numeric) The current block count \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getblockcount " , " " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " getblockcount " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2021-10-16 12:54:22 +02:00
return : : ChainActive ( ) . Height ( ) ;
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue getbestblockhash ( const JSONRPCRequest & request )
2013-07-03 17:02:29 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getbestblockhash " ,
2019-07-03 14:49:07 +02:00
" \n Returns the hash of the best (tip) block in the most-work fully-validated chain. \n " ,
2019-01-29 15:55:37 +01:00
{ } ,
RPCResult {
2018-10-10 05:59:20 +02:00
" \" hex \" (string) the block hash, hex-encoded \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getbestblockhash " , " " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " getbestblockhash " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2013-07-03 17:02:29 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2021-10-16 12:54:22 +02:00
return : : ChainActive ( ) . Tip ( ) - > GetBlockHash ( ) . GetHex ( ) ;
2013-07-03 17:02:29 +02:00
}
2012-08-21 17:03:38 +02:00
2018-05-04 22:42:39 +02:00
static UniValue getbestchainlock ( const JSONRPCRequest & request )
2019-09-23 20:36:55 +02:00
{
if ( request . fHelp | | request . params . size ( ) ! = 0 )
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getbestchainlock " ,
" \n Returns information about the best chainlock. Throws an error if there is no known chainlock yet. " ,
2021-11-05 19:47:35 +01:00
{ } ,
RPCResult {
" { \n "
" \" blockhash \" : \" hash \" , (string) The block hash hex-encoded \n "
" \" height \" : n, (numeric) The block height or index \n "
" \" signature \" : \" hash \" , (string) The chainlock's BLS signature. \n "
" \" known_block \" : true|false (boolean) True if the block is known by our node \n "
" } \n "
} ,
RPCExamples {
HelpExampleCli ( " getbestchainlock " , " " )
+ HelpExampleRpc ( " getbestchainlock " , " " )
} ,
} . ToString ( ) ) ;
2019-09-23 20:36:55 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2020-05-14 22:10:58 +02:00
2019-09-23 20:36:55 +02:00
llmq : : CChainLockSig clsig = llmq : : chainLocksHandler - > GetBestChainLock ( ) ;
if ( clsig . IsNull ( ) ) {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Unable to find any chainlock " ) ;
}
2020-06-18 11:17:23 +02:00
result . pushKV ( " blockhash " , clsig . blockHash . GetHex ( ) ) ;
result . pushKV ( " height " , clsig . nHeight ) ;
2020-09-18 13:07:52 +02:00
result . pushKV ( " signature " , clsig . sig . ToString ( ) ) ;
2019-09-23 20:36:55 +02:00
LOCK ( cs_main ) ;
2021-10-16 19:42:59 +02:00
result . pushKV ( " known_block " , : : BlockIndex ( ) . count ( clsig . blockHash ) > 0 ) ;
2019-09-23 20:36:55 +02:00
return result ;
}
2016-09-09 08:33:26 +02:00
void RPCNotifyBlockChange ( bool ibd , const CBlockIndex * pindex )
{
if ( pindex ) {
2021-06-09 14:06:31 +02:00
LOCK ( cs_blockchange ) ;
2016-09-09 08:33:26 +02:00
latestblock . hash = pindex - > GetBlockHash ( ) ;
latestblock . height = pindex - > nHeight ;
}
2017-05-23 19:07:29 +02:00
cond_blockchange . notify_all ( ) ;
2016-09-09 08:33:26 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue waitfornewblock ( const JSONRPCRequest & request )
2016-09-09 08:33:26 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) > 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " waitfornewblock " ,
" \n Waits for a specific new block and returns useful info about it. \n "
" \n Returns the current block on timeout or exit. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " timeout " , RPCArg : : Type : : NUM , /* default */ " 0 " , " Time in milliseconds to wait for a response. 0 indicates no timeout. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2016-09-09 08:33:26 +02:00
" { (json object) \n "
" \" hash \" : { (string) The blockhash \n "
" \" height \" : { (int) Block height \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " waitfornewblock " , " 1000 " )
2016-09-09 08:33:26 +02:00
+ HelpExampleRpc ( " waitfornewblock " , " 1000 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-09-09 08:33:26 +02:00
int timeout = 0 ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 0 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
timeout = request . params [ 0 ] . get_int ( ) ;
2016-09-09 08:33:26 +02:00
CUpdatedBlock block ;
{
2017-11-08 21:28:35 +01:00
WAIT_LOCK ( cs_blockchange , lock ) ;
2016-09-09 08:33:26 +02:00
block = latestblock ;
if ( timeout )
2021-06-09 14:06:31 +02:00
cond_blockchange . wait_for ( lock , std : : chrono : : milliseconds ( timeout ) , [ & block ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . height ! = block . height | | latestblock . hash ! = block . hash | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
else
2021-06-09 14:06:31 +02:00
cond_blockchange . wait ( lock , [ & block ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . height ! = block . height | | latestblock . hash ! = block . hash | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
block = latestblock ;
}
UniValue ret ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " hash " , block . hash . GetHex ( ) ) ;
ret . pushKV ( " height " , block . height ) ;
2016-09-09 08:33:26 +02:00
return ret ;
}
2018-05-04 22:42:39 +02:00
static UniValue waitforblock ( const JSONRPCRequest & request )
2016-09-09 08:33:26 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " waitforblock " ,
" \n Waits for a specific new block and returns useful info about it. \n "
" \n Returns the current block on timeout or exit. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " Block hash to wait for. " } ,
{ " timeout " , RPCArg : : Type : : NUM , /* default */ " 0 " , " Time in milliseconds to wait for a response. 0 indicates no timeout. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2016-09-09 08:33:26 +02:00
" { (json object) \n "
" \" hash \" : { (string) The blockhash \n "
" \" height \" : { (int) Block height \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
Merge #18398: rpc: fix broken RPCExamples for waitforblock(height)
ef35604c9c88e7800e9be106b791b1c0fa8b310a rpc: fix broken RPCExamples for waitforblock(height) (Sebastian Falbesoner)
Pull request description:
This PR fixes several broken RPCExamples from the "blockchain" category:
- `HelpExampleCli` for `waitforblock` (disturbing comma between arguments)
- `HelpExampleCli` for `waitforblockheight` (disturbing comma between arguments)
- `HelpExampleRpc` for `waitforblockheight` (disturbing quotation marks around integer argument)
Note that the CLI example for `waitforblockheight` would also work with the first argument in quotation marks (in contrast to the RPC example), but I removed them as well as they are not needed.
Outputs for the non-working examples in the master branch:
```
$ ./bitcoin-cli waitforblock "0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862", 1000
error code: -8
error message:
blockhash must be of length 64 (not 65, for '0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862,')
```
```
$ ./bitcoin-cli waitforblockheight "100", 1000
error: Error parsing JSON:100,
```
```
$ curl --user __cookie__ --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "waitforblockheight", "params": ["100", 1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
Enter host password for user '__cookie__':
{"result":null,"error":{"code":-1,"message":"JSON value is not an integer as expected"},"id":"curltest"}
```
Outputs for the fixed examples in the PR branch:
```
$ ./bitcoin-cli waitforblock "0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862" 1000
{
"hash": "0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080",
"height": 622416
}
```
```
$ ./bitcoin-cli waitforblockheight 100 1000
{
"hash": "0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080",
"height": 622416
}
```
```
$ curl --user __cookie__ --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "waitforblockheight", "params": [100, 1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
Enter host password for user '__cookie__':
{"result":{"hash":"0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080","height":622416},"error":null,"id":"curltest"}
```
ACKs for top commit:
fanquake:
ACK ef35604c9c88e7800e9be106b791b1c0fa8b310a
Tree-SHA512: b98c6681d1aa24b3ee3ef4ef450cb630082a9f8695af18f3b6d418e5b0b1e472b787ccf6397cd719b4d5fe0082ea5f1d0ca553c1cc56066ee2d288be34c601e3
2020-03-27 08:06:52 +01:00
HelpExampleCli ( " waitforblock " , " \" 0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862 \" 1000 " )
2016-09-09 08:33:26 +02:00
+ HelpExampleRpc ( " waitforblock " , " \" 0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862 \" , 1000 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-09-09 08:33:26 +02:00
int timeout = 0 ;
2016-10-19 15:01:33 +02:00
uint256 hash = uint256S ( request . params [ 0 ] . get_str ( ) ) ;
2016-09-09 08:33:26 +02:00
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
timeout = request . params [ 1 ] . get_int ( ) ;
2016-09-09 08:33:26 +02:00
CUpdatedBlock block ;
{
2017-11-08 21:28:35 +01:00
WAIT_LOCK ( cs_blockchange , lock ) ;
2016-09-09 08:33:26 +02:00
if ( timeout )
2021-06-09 14:06:31 +02:00
cond_blockchange . wait_for ( lock , std : : chrono : : milliseconds ( timeout ) , [ & hash ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . hash = = hash | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
else
2021-06-09 14:06:31 +02:00
cond_blockchange . wait ( lock , [ & hash ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . hash = = hash | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
block = latestblock ;
}
UniValue ret ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " hash " , block . hash . GetHex ( ) ) ;
ret . pushKV ( " height " , block . height ) ;
2016-09-09 08:33:26 +02:00
return ret ;
}
2018-05-04 22:42:39 +02:00
static UniValue waitforblockheight ( const JSONRPCRequest & request )
2016-09-09 08:33:26 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " waitforblockheight " ,
" \n Waits for (at least) block height and returns the height and hash \n "
" of the current tip. \n "
" \n Returns the current block on timeout or exit. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " height " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " Block height to wait for. " } ,
{ " timeout " , RPCArg : : Type : : NUM , /* default */ " 0 " , " Time in milliseconds to wait for a response. 0 indicates no timeout. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2016-09-09 08:33:26 +02:00
" { (json object) \n "
" \" hash \" : { (string) The blockhash \n "
" \" height \" : { (int) Block height \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
Merge #18398: rpc: fix broken RPCExamples for waitforblock(height)
ef35604c9c88e7800e9be106b791b1c0fa8b310a rpc: fix broken RPCExamples for waitforblock(height) (Sebastian Falbesoner)
Pull request description:
This PR fixes several broken RPCExamples from the "blockchain" category:
- `HelpExampleCli` for `waitforblock` (disturbing comma between arguments)
- `HelpExampleCli` for `waitforblockheight` (disturbing comma between arguments)
- `HelpExampleRpc` for `waitforblockheight` (disturbing quotation marks around integer argument)
Note that the CLI example for `waitforblockheight` would also work with the first argument in quotation marks (in contrast to the RPC example), but I removed them as well as they are not needed.
Outputs for the non-working examples in the master branch:
```
$ ./bitcoin-cli waitforblock "0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862", 1000
error code: -8
error message:
blockhash must be of length 64 (not 65, for '0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862,')
```
```
$ ./bitcoin-cli waitforblockheight "100", 1000
error: Error parsing JSON:100,
```
```
$ curl --user __cookie__ --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "waitforblockheight", "params": ["100", 1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
Enter host password for user '__cookie__':
{"result":null,"error":{"code":-1,"message":"JSON value is not an integer as expected"},"id":"curltest"}
```
Outputs for the fixed examples in the PR branch:
```
$ ./bitcoin-cli waitforblock "0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862" 1000
{
"hash": "0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080",
"height": 622416
}
```
```
$ ./bitcoin-cli waitforblockheight 100 1000
{
"hash": "0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080",
"height": 622416
}
```
```
$ curl --user __cookie__ --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "waitforblockheight", "params": [100, 1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
Enter host password for user '__cookie__':
{"result":{"hash":"0000000000000000000910ae4d56120e0ddd55c0552e80ed12dba147abc68080","height":622416},"error":null,"id":"curltest"}
```
ACKs for top commit:
fanquake:
ACK ef35604c9c88e7800e9be106b791b1c0fa8b310a
Tree-SHA512: b98c6681d1aa24b3ee3ef4ef450cb630082a9f8695af18f3b6d418e5b0b1e472b787ccf6397cd719b4d5fe0082ea5f1d0ca553c1cc56066ee2d288be34c601e3
2020-03-27 08:06:52 +01:00
HelpExampleCli ( " waitforblockheight " , " 100 1000 " )
+ HelpExampleRpc ( " waitforblockheight " , " 100, 1000 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-09-09 08:33:26 +02:00
int timeout = 0 ;
2016-10-19 15:01:33 +02:00
int height = request . params [ 0 ] . get_int ( ) ;
2016-09-09 08:33:26 +02:00
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
timeout = request . params [ 1 ] . get_int ( ) ;
2016-09-09 08:33:26 +02:00
CUpdatedBlock block ;
{
2017-11-08 21:28:35 +01:00
WAIT_LOCK ( cs_blockchange , lock ) ;
2016-09-09 08:33:26 +02:00
if ( timeout )
2021-06-09 14:06:31 +02:00
cond_blockchange . wait_for ( lock , std : : chrono : : milliseconds ( timeout ) , [ & height ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . height > = height | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
else
2021-06-09 14:06:31 +02:00
cond_blockchange . wait ( lock , [ & height ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( cs_blockchange ) { return latestblock . height > = height | | ! IsRPCRunning ( ) ; } ) ;
2016-09-09 08:33:26 +02:00
block = latestblock ;
}
2021-06-09 14:06:31 +02:00
// TODO: Backport g_utxosetscan and associated logic from #16127
2016-09-09 08:33:26 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " hash " , block . hash . GetHex ( ) ) ;
ret . pushKV ( " height " , block . height ) ;
2016-09-09 08:33:26 +02:00
return ret ;
}
2018-05-04 22:42:39 +02:00
static UniValue syncwithvalidationinterfacequeue ( const JSONRPCRequest & request )
2018-01-18 14:26:21 +01:00
{
if ( request . fHelp | | request . params . size ( ) > 0 ) {
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " syncwithvalidationinterfacequeue " ,
2019-01-29 15:55:37 +01:00
" \n Waits for the validation interface queue to catch up on everything that was there when we entered this function. \n " ,
{ } ,
RPCResults { } ,
RPCExamples {
HelpExampleCli ( " syncwithvalidationinterfacequeue " , " " )
2018-01-18 14:26:21 +01:00
+ HelpExampleRpc ( " syncwithvalidationinterfacequeue " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2018-01-18 14:26:21 +01:00
}
SyncWithValidationInterfaceQueue ( ) ;
return NullUniValue ;
}
2018-05-04 22:42:39 +02:00
static UniValue getdifficulty ( const JSONRPCRequest & request )
2012-08-21 17:03:38 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getdifficulty " ,
2019-01-29 15:55:37 +01:00
" \n Returns the proof-of-work difficulty as a multiple of the minimum difficulty. \n " ,
{ } ,
RPCResult {
2013-10-29 12:29:44 +01:00
" n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty. \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getdifficulty " , " " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " getdifficulty " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2021-10-16 12:54:22 +02:00
return GetDifficulty ( : : ChainActive ( ) . Tip ( ) ) ;
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static std : : string EntryDescriptionString ( )
2016-06-09 16:04:34 +02:00
{
2019-03-26 17:56:08 +01:00
return " \" vsize \" : n, (numeric) virtual transaction size. This can be different from actual serialized size for high-sigop transactions. \n "
" \" size \" : n, (numeric) (DEPRECATED) same as vsize. Only returned if dashd is started with -deprecatedrpc=size \n "
" size will be completely removed in v0.20. \n "
2020-12-16 09:54:56 +01:00
" \" fee \" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED) \n "
" \" modifiedfee \" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED) \n "
2018-04-30 00:09:47 +02:00
" \" time \" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT \n "
" \" height \" : n, (numeric) block height when transaction entered pool \n "
" \" descendantcount \" : n, (numeric) number of in-mempool descendant transactions (including this one) \n "
" \" descendantsize \" : n, (numeric) size of in-mempool descendants (including this one) \n "
2020-12-16 09:54:56 +01:00
" \" descendantfees \" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) (DEPRECATED) \n "
2018-04-30 00:09:47 +02:00
" \" ancestorcount \" : n, (numeric) number of in-mempool ancestor transactions (including this one) \n "
" \" ancestorsize \" : n, (numeric) size of in-mempool ancestors (including this one) \n "
2020-12-16 09:54:56 +01:00
" \" ancestorfees \" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) (DEPRECATED) \n "
2018-04-26 12:34:31 +02:00
" \" fees \" : { \n "
" \" base \" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " \n "
" \" modified \" : n, (numeric) transaction fee with fee deltas used for mining priority in " + CURRENCY_UNIT + " \n "
" \" ancestor \" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) in " + CURRENCY_UNIT + " \n "
2018-04-30 10:49:56 +02:00
" \" descendant \" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) in " + CURRENCY_UNIT + " \n "
2018-04-26 12:34:31 +02:00
" } \n "
2018-04-30 00:09:47 +02:00
" \" depends \" : [ (array) unconfirmed transactions used as inputs for this transaction \n "
" \" transactionid \" , (string) parent transaction id \n "
" ... ], \n "
2018-03-06 22:14:44 +01:00
" \" spentby \" : [ (array) unconfirmed transactions spending outputs from this transaction \n "
" \" transactionid \" , (string) child transaction id \n "
2020-06-18 20:52:05 +02:00
" ... ] \n "
2020-06-13 20:18:31 +02:00
" \" instantlock \" : true|false (boolean) True if this transaction was locked via InstantSend \n " ;
2016-06-09 16:04:34 +02:00
}
2019-02-23 17:04:20 +01:00
static void entryToJSON ( const CTxMemPool & pool , UniValue & info , const CTxMemPoolEntry & e ) EXCLUSIVE_LOCKS_REQUIRED ( pool . cs )
2016-06-09 16:04:34 +02:00
{
2019-02-23 17:04:20 +01:00
AssertLockHeld ( pool . cs ) ;
2016-06-09 16:04:34 +02:00
2018-04-26 12:34:31 +02:00
UniValue fees ( UniValue : : VOBJ ) ;
fees . pushKV ( " base " , ValueFromAmount ( e . GetFee ( ) ) ) ;
fees . pushKV ( " modified " , ValueFromAmount ( e . GetModifiedFee ( ) ) ) ;
fees . pushKV ( " ancestor " , ValueFromAmount ( e . GetModFeesWithAncestors ( ) ) ) ;
fees . pushKV ( " descendant " , ValueFromAmount ( e . GetModFeesWithDescendants ( ) ) ) ;
info . pushKV ( " fees " , fees ) ;
2019-03-26 17:56:08 +01:00
info . pushKV ( " vsize " , ( int ) e . GetTxSize ( ) ) ;
if ( IsDeprecatedRPCEnabled ( " size " ) ) info . pushKV ( " size " , ( int ) e . GetTxSize ( ) ) ;
2020-06-18 11:17:23 +02:00
info . pushKV ( " fee " , ValueFromAmount ( e . GetFee ( ) ) ) ;
info . pushKV ( " modifiedfee " , ValueFromAmount ( e . GetModifiedFee ( ) ) ) ;
info . pushKV ( " time " , e . GetTime ( ) ) ;
info . pushKV ( " height " , ( int ) e . GetHeight ( ) ) ;
info . pushKV ( " descendantcount " , e . GetCountWithDescendants ( ) ) ;
info . pushKV ( " descendantsize " , e . GetSizeWithDescendants ( ) ) ;
info . pushKV ( " descendantfees " , e . GetModFeesWithDescendants ( ) ) ;
info . pushKV ( " ancestorcount " , e . GetCountWithAncestors ( ) ) ;
info . pushKV ( " ancestorsize " , e . GetSizeWithAncestors ( ) ) ;
info . pushKV ( " ancestorfees " , e . GetModFeesWithAncestors ( ) ) ;
2016-06-09 16:04:34 +02:00
const CTransaction & tx = e . GetTx ( ) ;
2017-03-09 08:14:27 +01:00
std : : set < std : : string > setDepends ;
2019-07-05 09:06:28 +02:00
for ( const CTxIn & txin : tx . vin )
2016-06-09 16:04:34 +02:00
{
2019-02-23 17:04:20 +01:00
if ( pool . exists ( txin . prevout . hash ) )
2016-06-09 16:04:34 +02:00
setDepends . insert ( txin . prevout . hash . ToString ( ) ) ;
}
UniValue depends ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( const std : : string & dep : setDepends )
2016-06-09 16:04:34 +02:00
{
depends . push_back ( dep ) ;
}
2020-06-18 11:17:23 +02:00
info . pushKV ( " depends " , depends ) ;
2018-03-06 22:14:44 +01:00
UniValue spent ( UniValue : : VARR ) ;
2019-02-23 17:04:20 +01:00
const CTxMemPool : : txiter & it = pool . mapTx . find ( tx . GetHash ( ) ) ;
const CTxMemPool : : setEntries & setChildren = pool . GetMemPoolChildren ( it ) ;
2018-09-04 15:36:09 +02:00
for ( CTxMemPool : : txiter childiter : setChildren ) {
2018-03-06 22:14:44 +01:00
spent . push_back ( childiter - > GetTx ( ) . GetHash ( ) . ToString ( ) ) ;
}
2020-06-18 11:17:23 +02:00
info . pushKV ( " spentby " , spent ) ;
info . pushKV ( " instantlock " , llmq : : quorumInstantSendManager - > IsLocked ( tx . GetHash ( ) ) ) ;
2016-06-09 16:04:34 +02:00
}
2019-02-23 17:04:20 +01:00
UniValue MempoolToJSON ( const CTxMemPool & pool , bool verbose )
2012-08-21 17:03:38 +02:00
{
2019-02-23 17:04:20 +01:00
if ( verbose ) {
LOCK ( pool . cs ) ;
2015-05-10 14:48:35 +02:00
UniValue o ( UniValue : : VOBJ ) ;
2019-02-23 17:04:20 +01:00
for ( const CTxMemPoolEntry & e : pool . mapTx ) {
2015-06-24 10:32:20 +02:00
const uint256 & hash = e . GetTx ( ) . GetHash ( ) ;
2015-05-10 14:48:35 +02:00
UniValue info ( UniValue : : VOBJ ) ;
2019-02-23 17:04:20 +01:00
entryToJSON ( pool , info , e ) ;
2019-05-15 17:32:23 +02:00
// Mempool has unique entries so there is no advantage in using
// UniValue::pushKV, which checks if the key already exists in O(N).
// UniValue::__pushKV is used instead which currently is O(1).
o . __pushKV ( hash . ToString ( ) , info ) ;
2013-11-11 08:35:14 +01:00
}
return o ;
2019-02-23 17:04:20 +01:00
} else {
2017-03-09 08:14:27 +01:00
std : : vector < uint256 > vtxid ;
2019-02-23 17:04:20 +01:00
pool . queryHashes ( vtxid ) ;
2012-08-21 17:03:38 +02:00
2015-05-10 14:48:35 +02:00
UniValue a ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( const uint256 & hash : vtxid )
2013-11-11 08:35:14 +01:00
a . push_back ( hash . ToString ( ) ) ;
return a ;
}
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue getrawmempool ( const JSONRPCRequest & request )
2012-08-21 17:03:38 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) > 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getrawmempool " ,
2018-12-05 17:02:57 +01:00
" \n Returns all transaction ids in memory pool as a json array of string transaction ids. \n "
" \n Hint: use getmempoolentry to fetch a specific transaction from the mempool. \n " ,
2021-10-11 23:55:23 +02:00
{
2019-02-13 00:42:50 +01:00
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " false " , " True for a json object, false for array of transaction ids " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbose = false " ,
2013-11-11 08:35:14 +01:00
" [ (json array of string) \n "
2013-10-29 12:29:44 +01:00
" \" transactionid \" (string) The transaction id \n "
" ,... \n "
" ] \n "
2013-11-11 08:35:14 +01:00
" \n Result: (for verbose = true): \n "
" { (json object) \n "
" \" transactionid \" : { (json object) \n "
2016-06-09 16:04:34 +02:00
+ EntryDescriptionString ( )
+ " }, ... \n "
2015-08-06 19:38:19 +02:00
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getrawmempool " , " true " )
2013-11-11 08:35:14 +01:00
+ HelpExampleRpc ( " getrawmempool " , " true " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2013-11-11 08:35:14 +01:00
bool fVerbose = false ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 0 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fVerbose = request . params [ 0 ] . get_bool ( ) ;
2012-08-21 17:03:38 +02:00
2019-02-23 17:04:20 +01:00
return MempoolToJSON ( : : mempool , fVerbose ) ;
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue getmempoolancestors ( const JSONRPCRequest & request )
2016-06-09 16:04:34 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 ) {
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getmempoolancestors " ,
" \n If txid is in the mempool, returns all in-mempool ancestors. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id (must be in mempool) " } ,
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " false " , " True for a json object, false for array of transaction ids " } ,
2019-01-29 15:55:37 +01:00
} ,
{
RPCResult { " for verbose = false " ,
2016-06-09 16:04:34 +02:00
" [ (json array of strings) \n "
" \" transactionid \" (string) The transaction id of an in-mempool ancestor transaction \n "
" ,... \n "
" ] \n "
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbose = true " ,
2016-06-09 16:04:34 +02:00
" { (json object) \n "
" \" transactionid \" : { (json object) \n "
+ EntryDescriptionString ( )
+ " }, ... \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getmempoolancestors " , " \" mytxid \" " )
2016-06-09 16:04:34 +02:00
+ HelpExampleRpc ( " getmempoolancestors " , " \" mytxid \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-06-09 16:04:34 +02:00
}
bool fVerbose = false ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fVerbose = request . params [ 1 ] . get_bool ( ) ;
2016-06-09 16:04:34 +02:00
2016-10-19 15:01:33 +02:00
uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2016-06-09 16:04:34 +02:00
LOCK ( mempool . cs ) ;
CTxMemPool : : txiter it = mempool . mapTx . find ( hash ) ;
if ( it = = mempool . mapTx . end ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Transaction not in mempool " ) ;
}
CTxMemPool : : setEntries setAncestors ;
uint64_t noLimit = std : : numeric_limits < uint64_t > : : max ( ) ;
std : : string dummy ;
mempool . CalculateMemPoolAncestors ( * it , setAncestors , noLimit , noLimit , noLimit , noLimit , dummy , false ) ;
if ( ! fVerbose ) {
UniValue o ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( CTxMemPool : : txiter ancestorIt : setAncestors ) {
2016-06-09 16:04:34 +02:00
o . push_back ( ancestorIt - > GetTx ( ) . GetHash ( ) . ToString ( ) ) ;
}
return o ;
} else {
UniValue o ( UniValue : : VOBJ ) ;
2019-07-05 09:06:28 +02:00
for ( CTxMemPool : : txiter ancestorIt : setAncestors ) {
2016-06-09 16:04:34 +02:00
const CTxMemPoolEntry & e = * ancestorIt ;
2016-09-27 13:25:42 +02:00
const uint256 & _hash = e . GetTx ( ) . GetHash ( ) ;
2016-06-09 16:04:34 +02:00
UniValue info ( UniValue : : VOBJ ) ;
2019-02-23 17:04:20 +01:00
entryToJSON ( : : mempool , info , e ) ;
2020-06-18 11:17:23 +02:00
o . pushKV ( _hash . ToString ( ) , info ) ;
2016-06-09 16:04:34 +02:00
}
return o ;
}
}
2018-05-04 22:42:39 +02:00
static UniValue getmempooldescendants ( const JSONRPCRequest & request )
2016-06-09 16:04:34 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 ) {
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getmempooldescendants " ,
" \n If txid is in the mempool, returns all in-mempool descendants. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id (must be in mempool) " } ,
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " false " , " True for a json object, false for array of transaction ids " } ,
2019-01-29 15:55:37 +01:00
} ,
{
RPCResult { " for verbose = false " ,
2016-06-09 16:04:34 +02:00
" [ (json array of strings) \n "
" \" transactionid \" (string) The transaction id of an in-mempool descendant transaction \n "
" ,... \n "
" ] \n "
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbose = true " ,
2016-06-09 16:04:34 +02:00
" { (json object) \n "
" \" transactionid \" : { (json object) \n "
+ EntryDescriptionString ( )
+ " }, ... \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getmempooldescendants " , " \" mytxid \" " )
2016-06-09 16:04:34 +02:00
+ HelpExampleRpc ( " getmempooldescendants " , " \" mytxid \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-06-09 16:04:34 +02:00
}
bool fVerbose = false ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fVerbose = request . params [ 1 ] . get_bool ( ) ;
2016-06-09 16:04:34 +02:00
2016-10-19 15:01:33 +02:00
uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2016-06-09 16:04:34 +02:00
LOCK ( mempool . cs ) ;
CTxMemPool : : txiter it = mempool . mapTx . find ( hash ) ;
if ( it = = mempool . mapTx . end ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Transaction not in mempool " ) ;
}
CTxMemPool : : setEntries setDescendants ;
mempool . CalculateDescendants ( it , setDescendants ) ;
// CTxMemPool::CalculateDescendants will include the given tx
setDescendants . erase ( it ) ;
if ( ! fVerbose ) {
UniValue o ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( CTxMemPool : : txiter descendantIt : setDescendants ) {
2016-06-09 16:04:34 +02:00
o . push_back ( descendantIt - > GetTx ( ) . GetHash ( ) . ToString ( ) ) ;
}
return o ;
} else {
UniValue o ( UniValue : : VOBJ ) ;
2019-07-05 09:06:28 +02:00
for ( CTxMemPool : : txiter descendantIt : setDescendants ) {
2016-06-09 16:04:34 +02:00
const CTxMemPoolEntry & e = * descendantIt ;
2016-09-27 13:25:42 +02:00
const uint256 & _hash = e . GetTx ( ) . GetHash ( ) ;
2016-06-09 16:04:34 +02:00
UniValue info ( UniValue : : VOBJ ) ;
2019-02-23 17:04:20 +01:00
entryToJSON ( : : mempool , info , e ) ;
2020-06-18 11:17:23 +02:00
o . pushKV ( _hash . ToString ( ) , info ) ;
2016-06-09 16:04:34 +02:00
}
return o ;
}
}
2018-05-04 22:42:39 +02:00
static UniValue getmempoolentry ( const JSONRPCRequest & request )
2016-06-09 16:04:34 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 ) {
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getmempoolentry " ,
" \n Returns mempool data for given transaction \n " ,
{
2019-02-13 00:42:50 +01:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id (must be in mempool) " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2016-06-09 16:04:34 +02:00
" { (json object) \n "
+ EntryDescriptionString ( )
+ " } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getmempoolentry " , " \" mytxid \" " )
2016-06-09 16:04:34 +02:00
+ HelpExampleRpc ( " getmempoolentry " , " \" mytxid \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-06-09 16:04:34 +02:00
}
2016-10-19 15:01:33 +02:00
uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2016-06-09 16:04:34 +02:00
LOCK ( mempool . cs ) ;
CTxMemPool : : txiter it = mempool . mapTx . find ( hash ) ;
if ( it = = mempool . mapTx . end ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Transaction not in mempool " ) ;
}
const CTxMemPoolEntry & e = * it ;
UniValue info ( UniValue : : VOBJ ) ;
2019-02-23 17:04:20 +01:00
entryToJSON ( : : mempool , info , e ) ;
2016-06-09 16:04:34 +02:00
return info ;
}
2018-05-04 22:42:39 +02:00
static UniValue getblockhashes ( const JSONRPCRequest & request )
2016-03-22 23:11:04 +01:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 2 )
2017-03-09 08:10:09 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockhashes " ,
" \n Returns array of hashes of blocks within the timestamp range provided. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " high " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The newer block timestamp " } ,
{ " low " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The older block timestamp " } ,
} ,
RPCResult {
" [ \n "
" \" hash \" (string) The block hash \n "
" ] \n "
} ,
RPCExamples {
HelpExampleCli ( " getblockhashes " , " 1231614698 1231024505 " )
+ HelpExampleRpc ( " getblockhashes " , " 1231614698, 1231024505 " )
} ,
} . ToString ( ) ) ;
2016-03-22 23:11:04 +01:00
2016-10-19 15:01:33 +02:00
unsigned int high = request . params [ 0 ] . get_int ( ) ;
unsigned int low = request . params [ 1 ] . get_int ( ) ;
2016-03-22 23:11:04 +01:00
std : : vector < uint256 > blockHashes ;
if ( ! GetTimestampIndex ( high , low , blockHashes ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for block hashes " ) ;
}
UniValue result ( UniValue : : VARR ) ;
for ( std : : vector < uint256 > : : const_iterator it = blockHashes . begin ( ) ; it ! = blockHashes . end ( ) ; it + + ) {
result . push_back ( it - > GetHex ( ) ) ;
}
return result ;
}
2018-05-04 22:42:39 +02:00
static UniValue getblockhash ( const JSONRPCRequest & request )
2012-08-21 17:03:38 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockhash " ,
" \n Returns hash of block in best-block-chain at height provided. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " height " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The height index " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2013-10-29 12:29:44 +01:00
" \" hash \" (string) The block hash \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getblockhash " , " 1000 " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " getblockhash " , " 1000 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2016-10-19 15:01:33 +02:00
int nHeight = request . params [ 0 ] . get_int ( ) ;
2021-10-16 12:54:22 +02:00
if ( nHeight < 0 | | nHeight > : : ChainActive ( ) . Height ( ) )
2014-10-24 15:43:40 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Block height out of range " ) ;
2012-08-21 17:03:38 +02:00
2021-10-16 12:54:22 +02:00
CBlockIndex * pblockindex = : : ChainActive ( ) [ nHeight ] ;
2013-10-10 23:07:44 +02:00
return pblockindex - > GetBlockHash ( ) . GetHex ( ) ;
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue getblockheader ( const JSONRPCRequest & request )
2012-08-21 17:03:38 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockheader " ,
" \n If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'. \n "
" If verbose is true, returns an Object with information about blockheader <hash>. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The block hash " } ,
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " true " , " true for a json object, false for the hex-encoded data " } ,
2019-01-29 15:55:37 +01:00
} ,
{
RPCResult { " for verbose = true " ,
2013-10-29 12:29:44 +01:00
" { \n "
" \" hash \" : \" hash \" , (string) the block hash (same as provided) \n "
2014-08-28 17:14:22 +02:00
" \" confirmations \" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain \n "
2013-10-29 12:29:44 +01:00
" \" height \" : n, (numeric) The block height or index \n "
" \" version \" : n, (numeric) The block version \n "
2016-04-05 15:48:49 +02:00
" \" versionHex \" : \" 00000000 \" , (string) The block version formatted in hexadecimal \n "
2013-10-29 12:29:44 +01:00
" \" merkleroot \" : \" xxxx \" , (string) The merkle root \n "
" \" time \" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) \n "
2015-11-13 22:57:10 +01:00
" \" mediantime \" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) \n "
2013-10-29 12:29:44 +01:00
" \" nonce \" : n, (numeric) The nonce \n "
" \" bits \" : \" 1d00ffff \" , (string) The bits \n "
" \" difficulty \" : x.xxx, (numeric) The difficulty \n "
2017-12-05 23:17:45 +01:00
" \" chainwork \" : \" 0000...1f3 \" (string) Expected number of hashes required to produce the current chain (in hex) \n "
2018-06-14 19:38:19 +02:00
" \" nTx \" : n, (numeric) The number of transactions in the block. \n "
2013-10-29 12:29:44 +01:00
" \" previousblockhash \" : \" hash \" , (string) The hash of the previous block \n "
2015-12-09 18:01:34 +01:00
" \" nextblockhash \" : \" hash \" , (string) The hash of the next block \n "
2013-10-29 12:29:44 +01:00
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbose=false " ,
2013-10-29 12:29:44 +01:00
" \" data \" (string) A string that is serialized, hex-encoded data for block 'hash'. \n "
2019-01-29 15:55:37 +01:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getblockheader " , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 \" " )
2015-06-05 21:37:17 +02:00
+ HelpExampleRpc ( " getblockheader " , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2015-06-05 21:37:17 +02:00
uint256 hash ( uint256S ( strHash ) ) ;
2012-08-21 17:03:38 +02:00
2013-06-07 07:23:30 +02:00
bool fVerbose = true ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fVerbose = request . params [ 1 ] . get_bool ( ) ;
2013-06-07 07:23:30 +02:00
2019-01-08 13:53:20 +01:00
const CBlockIndex * pblockindex ;
const CBlockIndex * tip ;
{
LOCK ( cs_main ) ;
pblockindex = LookupBlockIndex ( hash ) ;
2021-10-16 12:54:22 +02:00
tip = : : ChainActive ( ) . Tip ( ) ;
2019-01-08 13:53:20 +01:00
}
2018-03-13 19:04:28 +01:00
if ( ! pblockindex ) {
2012-10-04 09:34:44 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-03-13 19:04:28 +01:00
}
2014-07-10 02:37:27 +02:00
2013-06-07 07:23:30 +02:00
if ( ! fVerbose )
{
CDataStream ssBlock ( SER_NETWORK , PROTOCOL_VERSION ) ;
2015-06-05 21:37:17 +02:00
ssBlock < < pblockindex - > GetBlockHeader ( ) ;
2021-05-18 19:17:10 +02:00
std : : string strHex = HexStr ( ssBlock ) ;
2013-06-07 07:23:30 +02:00
return strHex ;
}
2021-08-24 21:21:39 +02:00
return blockheaderToJSON ( tip , pblockindex ) ;
2012-08-21 17:03:38 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue getblockheaders ( const JSONRPCRequest & request )
2016-06-20 21:53:20 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 3 )
2017-03-09 08:10:09 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockheaders " ,
" \n Returns an array of items with information about <count> blockheaders starting from <hash>. \n "
" \n If verbose is false, each item is a string that is serialized, hex-encoded data for a single blockheader. \n "
" If verbose is true, each item is an Object with information about a single blockheader. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " hash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The block hash " } ,
{ " count " , RPCArg : : Type : : NUM , /* default */ strprintf ( " %s " , MAX_HEADERS_RESULTS ) , " " } ,
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " true " , " true for a json object, false for the hex-encoded data " } ,
} ,
RPCResults {
{ " for verbose = true " ,
2016-06-20 21:53:20 +02:00
" [ { \n "
" \" hash \" : \" hash \" , (string) The block hash \n "
" \" confirmations \" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain \n "
" \" height \" : n, (numeric) The block height or index \n "
" \" version \" : n, (numeric) The block version \n "
" \" merkleroot \" : \" xxxx \" , (string) The merkle root \n "
" \" time \" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) \n "
" \" mediantime \" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) \n "
" \" nonce \" : n, (numeric) The nonce \n "
" \" bits \" : \" 1d00ffff \" , (string) The bits \n "
" \" difficulty \" : x.xxx, (numeric) The difficulty \n "
2017-12-05 23:17:45 +01:00
" \" chainwork \" : \" 0000...1f3 \" (string) Expected number of hashes required to produce the current chain (in hex) \n "
2016-06-20 21:53:20 +02:00
" \" previousblockhash \" : \" hash \" , (string) The hash of the previous block \n "
" \" nextblockhash \" : \" hash \" , (string) The hash of the next block \n "
" }, { \n "
" ... \n "
" }, \n "
" ... \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} , { " for verbose=false " ,
2016-06-20 21:53:20 +02:00
" [ \n "
" \" data \" , (string) A string that is serialized, hex-encoded data for block header. \n "
" ... \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} } ,
RPCExamples {
HelpExampleCli ( " getblockheaders " , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 \" 2000 " )
2016-06-20 21:53:20 +02:00
+ HelpExampleRpc ( " getblockheaders " , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 \" 2000 " )
2021-11-05 19:47:35 +01:00
} ,
} . ToString ( ) ) ;
2016-06-20 21:53:20 +02:00
LOCK ( cs_main ) ;
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2016-06-20 21:53:20 +02:00
uint256 hash ( uint256S ( strHash ) ) ;
2021-10-16 19:42:59 +02:00
if ( : : BlockIndex ( ) . count ( hash ) = = 0 )
2016-06-20 21:53:20 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
int nCount = MAX_HEADERS_RESULTS ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
nCount = request . params [ 1 ] . get_int ( ) ;
2016-06-20 21:53:20 +02:00
if ( nCount < = 0 | | nCount > ( int ) MAX_HEADERS_RESULTS )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Count is out of range " ) ;
bool fVerbose = true ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 2 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fVerbose = request . params [ 2 ] . get_bool ( ) ;
2016-06-20 21:53:20 +02:00
2021-10-16 19:42:59 +02:00
CBlockIndex * pblockindex = : : BlockIndex ( ) [ hash ] ;
2016-06-20 21:53:20 +02:00
UniValue arrHeaders ( UniValue : : VARR ) ;
if ( ! fVerbose )
{
2021-10-16 12:54:22 +02:00
for ( ; pblockindex ; pblockindex = : : ChainActive ( ) . Next ( pblockindex ) )
2016-06-20 21:53:20 +02:00
{
CDataStream ssBlock ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssBlock < < pblockindex - > GetBlockHeader ( ) ;
2021-05-18 19:17:10 +02:00
std : : string strHex = HexStr ( ssBlock ) ;
2016-06-20 21:53:20 +02:00
arrHeaders . push_back ( strHex ) ;
if ( - - nCount < = 0 )
break ;
}
return arrHeaders ;
}
2021-10-16 12:54:22 +02:00
for ( ; pblockindex ; pblockindex = : : ChainActive ( ) . Next ( pblockindex ) )
2016-06-20 21:53:20 +02:00
{
2021-10-16 12:54:22 +02:00
arrHeaders . push_back ( blockheaderToJSON ( : : ChainActive ( ) . Tip ( ) , pblockindex ) ) ;
2016-06-20 21:53:20 +02:00
if ( - - nCount < = 0 )
break ;
}
return arrHeaders ;
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
static CBlock GetBlockChecked ( const CBlockIndex * pblockindex )
{
CBlock block ;
2018-06-08 13:31:24 +02:00
if ( IsBlockPruned ( pblockindex ) ) {
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
throw JSONRPCError ( RPC_MISC_ERROR , " Block not available (pruned data) " ) ;
}
if ( ! ReadBlockFromDisk ( block , pblockindex , Params ( ) . GetConsensus ( ) ) ) {
// Block not found on disk. This could be because we have the block
// header in our index but don't have the block (for example if a
// non-whitelisted node sends us an unrequested long chain of valid
// blocks, we add the headers to our index, but don't accept the
// block).
throw JSONRPCError ( RPC_MISC_ERROR , " Block not found on disk " ) ;
}
return block ;
}
2018-05-04 22:42:39 +02:00
static UniValue getmerkleblocks ( const JSONRPCRequest & request )
2019-05-21 15:36:13 +02:00
{
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 3 )
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getmerkleblocks " ,
" \n Returns an array of hex-encoded merkleblocks for <count> blocks starting from <hash> which match <filter>. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " filter " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The hex-encoded bloom filter " } ,
{ " hash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The block hash " } ,
{ " count " , RPCArg : : Type : : NUM , /* default */ strprintf ( " %s " , MAX_HEADERS_RESULTS ) , " " } ,
} ,
RPCResult {
2019-05-21 15:36:13 +02:00
" [ \n "
" \" data \" , (string) A string that is serialized, hex-encoded data for a merkleblock. \n "
" ... \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getmerkleblocks " , " \" 2303028005802040100040000008008400048141010000f8400420800080025004000004130000000000000001 \" \" 00000000007e1432d2af52e8463278bf556b55cf5049262f25634557e2e91202 \" 2000 " )
2019-05-21 15:36:13 +02:00
+ HelpExampleRpc ( " getmerkleblocks " , " \" 2303028005802040100040000008008400048141010000f8400420800080025004000004130000000000000001 \" \" 00000000007e1432d2af52e8463278bf556b55cf5049262f25634557e2e91202 \" 2000 " )
2021-11-05 19:47:35 +01:00
} ,
} . ToString ( ) ) ;
2019-05-21 15:36:13 +02:00
LOCK ( cs_main ) ;
CBloomFilter filter ;
std : : string strFilter = request . params [ 0 ] . get_str ( ) ;
CDataStream ssBloomFilter ( ParseHex ( strFilter ) , SER_NETWORK , PROTOCOL_VERSION ) ;
ssBloomFilter > > filter ;
if ( ! filter . IsWithinSizeConstraints ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Filter is not within size constraints " ) ;
}
filter . UpdateEmptyFull ( ) ;
std : : string strHash = request . params [ 1 ] . get_str ( ) ;
uint256 hash ( uint256S ( strHash ) ) ;
2021-10-16 19:42:59 +02:00
if ( : : BlockIndex ( ) . count ( hash ) = = 0 ) {
2019-05-21 15:36:13 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
}
int nCount = MAX_HEADERS_RESULTS ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 2 ] . isNull ( ) )
2019-05-21 15:36:13 +02:00
nCount = request . params [ 2 ] . get_int ( ) ;
if ( nCount < = 0 | | nCount > ( int ) MAX_HEADERS_RESULTS ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Count is out of range " ) ;
}
2021-10-16 19:42:59 +02:00
CBlockIndex * pblockindex = : : BlockIndex ( ) [ hash ] ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
CBlock block = GetBlockChecked ( pblockindex ) ;
2019-05-21 15:36:13 +02:00
UniValue arrMerkleBlocks ( UniValue : : VARR ) ;
2021-10-16 12:54:22 +02:00
for ( ; pblockindex ; pblockindex = : : ChainActive ( ) . Next ( pblockindex ) )
2019-05-21 15:36:13 +02:00
{
2019-06-13 11:04:07 +02:00
if ( - - nCount < 0 ) {
break ;
}
2019-05-21 15:36:13 +02:00
if ( ! ReadBlockFromDisk ( block , pblockindex , Params ( ) . GetConsensus ( ) ) ) {
// this shouldn't happen, we already checked pruning case earlier
throw JSONRPCError ( RPC_MISC_ERROR , " Block not found on disk " ) ;
}
2019-06-13 11:04:07 +02:00
CMerkleBlock merkleblock ( block , filter ) ;
if ( merkleblock . vMatchedTxn . empty ( ) ) {
// ignore blocks that do not match the filter
continue ;
}
2019-05-21 15:36:13 +02:00
CDataStream ssMerkleBlock ( SER_NETWORK , PROTOCOL_VERSION ) ;
2019-06-13 11:04:07 +02:00
ssMerkleBlock < < merkleblock ;
2019-05-21 15:36:13 +02:00
std : : string strHex = HexStr ( ssMerkleBlock ) ;
arrMerkleBlocks . push_back ( strHex ) ;
}
return arrMerkleBlocks ;
}
2018-05-04 22:42:39 +02:00
static UniValue getblock ( const JSONRPCRequest & request )
2015-03-23 18:36:16 +01:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblock " ,
" \n If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'. \n "
" If verbosity is 1, returns an Object with information about block <hash>. \n "
" If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The block hash " } ,
{ " verbosity " , RPCArg : : Type : : NUM , /* default */ " 1 " , " 0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data " } ,
2019-01-29 15:55:37 +01:00
} ,
{
RPCResult { " for verbosity = 0 " ,
2018-12-03 16:49:21 +01:00
" \" data \" (string) A string that is serialized, hex-encoded data for block 'hash'. \n "
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbosity = 1 " ,
2013-10-29 12:29:44 +01:00
" { \n "
" \" hash \" : \" hash \" , (string) the block hash (same as provided) \n "
2014-08-28 17:14:22 +02:00
" \" confirmations \" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain \n "
2013-10-29 12:29:44 +01:00
" \" size \" : n, (numeric) The block size \n "
" \" height \" : n, (numeric) The block height or index \n "
" \" version \" : n, (numeric) The block version \n "
2016-04-05 15:48:49 +02:00
" \" versionHex \" : \" 00000000 \" , (string) The block version formatted in hexadecimal \n "
2013-10-29 12:29:44 +01:00
" \" merkleroot \" : \" xxxx \" , (string) The merkle root \n "
" \" tx \" : [ (array of string) The transaction ids \n "
" \" transactionid \" (string) The transaction id \n "
" ,... \n "
" ], \n "
2019-03-30 15:55:04 +01:00
" \" cbTx \" : { (json object) The coinbase special transaction \n "
" \" version \" (numeric) The coinbase special transaction version \n "
" \" height \" (numeric) The block height \n "
" \" merkleRootMNList \" : \" xxxx \" , (string) The merkle root of the masternode list \n "
2019-10-03 15:42:24 +02:00
" \" merkleRootQuorums \" : \" xxxx \" , (string) The merkle root of the quorum list \n "
2019-03-30 15:55:04 +01:00
" }, \n "
2013-10-29 12:29:44 +01:00
" \" time \" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) \n "
2015-11-13 22:57:10 +01:00
" \" mediantime \" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) \n "
2013-10-29 12:29:44 +01:00
" \" nonce \" : n, (numeric) The nonce \n "
" \" bits \" : \" 1d00ffff \" , (string) The bits \n "
" \" difficulty \" : x.xxx, (numeric) The difficulty \n "
2015-12-18 20:07:48 +01:00
" \" chainwork \" : \" xxxx \" , (string) Expected number of hashes required to produce the chain up to this block (in hex) \n "
2018-06-14 19:38:19 +02:00
" \" nTx \" : n, (numeric) The number of transactions in the block. \n "
2013-10-29 12:29:44 +01:00
" \" previousblockhash \" : \" hash \" , (string) The hash of the previous block \n "
" \" nextblockhash \" : \" hash \" (string) The hash of the next block \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCResult { " for verbosity = 2 " ,
2018-12-03 16:49:21 +01:00
" { \n "
" ..., Same output as verbosity = 1. \n "
" \" tx \" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \" tx \" result. \n "
" ,... \n "
" ], \n "
" ,... Same output as verbosity = 1. \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getblock " , " \" 00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2 \" " )
2016-02-02 16:28:56 +01:00
+ HelpExampleRpc ( " getblock " , " \" 00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2 \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2015-03-23 18:36:16 +01:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2014-12-16 14:50:05 +01:00
uint256 hash ( uint256S ( strHash ) ) ;
2015-03-23 18:36:16 +01:00
2018-12-03 16:49:21 +01:00
int verbosity = 1 ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) ) {
2018-12-03 16:49:21 +01:00
if ( request . params [ 1 ] . isNum ( ) )
verbosity = request . params [ 1 ] . get_int ( ) ;
else
verbosity = request . params [ 1 ] . get_bool ( ) ? 1 : 0 ;
}
2015-03-23 18:36:16 +01:00
2018-03-13 19:04:28 +01:00
const CBlockIndex * pblockindex = LookupBlockIndex ( hash ) ;
if ( ! pblockindex ) {
2015-03-23 18:36:16 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-03-13 19:04:28 +01:00
}
2015-03-23 18:36:16 +01:00
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
const CBlock block = GetBlockChecked ( pblockindex ) ;
2015-03-23 18:36:16 +01:00
2018-12-03 16:49:21 +01:00
if ( verbosity < = 0 )
2015-03-23 18:36:16 +01:00
{
CDataStream ssBlock ( SER_NETWORK , PROTOCOL_VERSION ) ;
2013-06-07 07:23:30 +02:00
ssBlock < < block ;
2021-05-18 19:17:10 +02:00
std : : string strHex = HexStr ( ssBlock ) ;
2015-03-23 18:36:16 +01:00
return strHex ;
}
2021-10-16 12:54:22 +02:00
return blockToJSON ( block , : : ChainActive ( ) . Tip ( ) , pblockindex , verbosity > = 2 ) ;
2015-03-23 18:36:16 +01:00
}
2018-05-04 22:42:39 +02:00
static UniValue pruneblockchain ( const JSONRPCRequest & request )
2017-01-11 14:16:11 +01:00
{
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " pruneblockchain " , " " ,
{
2019-02-13 00:42:50 +01:00
{ " height " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The block height to prune up to. May be set to a discrete height, or a unix timestamp \n "
2018-12-05 17:02:57 +01:00
" to prune blocks whose block time is at least 2 hours older than the provided timestamp. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2017-01-12 11:49:48 +01:00
" n (numeric) Height of the last block pruned. \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " pruneblockchain " , " 1000 " )
+ HelpExampleRpc ( " pruneblockchain " , " 1000 " )
} ,
} . ToString ( ) ) ;
2017-01-11 14:16:11 +01:00
if ( ! fPruneMode )
2017-03-09 10:02:13 +01:00
throw JSONRPCError ( RPC_MISC_ERROR , " Cannot prune blocks because node is not in prune mode. " ) ;
2017-01-11 14:16:11 +01:00
LOCK ( cs_main ) ;
int heightParam = request . params [ 0 ] . get_int ( ) ;
if ( heightParam < 0 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Negative block height. " ) ;
// Height value more than a billion is too high to be a block height, and
// too low to be a block time (corresponds to timestamp from Sep 2001).
if ( heightParam > 1000000000 ) {
2017-02-17 12:44:35 +01:00
// Add a 2 hour buffer to include blocks which might have had old timestamps
2019-04-19 17:59:56 +02:00
CBlockIndex * pindex = : : ChainActive ( ) . FindEarliestAtLeast ( heightParam - TIMESTAMP_WINDOW , 0 ) ;
2017-01-11 14:16:11 +01:00
if ( ! pindex ) {
2017-03-09 10:02:13 +01:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Could not find block with at least the specified timestamp. " ) ;
2017-01-11 14:16:11 +01:00
}
heightParam = pindex - > nHeight ;
}
unsigned int height = ( unsigned int ) heightParam ;
2021-10-16 12:54:22 +02:00
unsigned int chainHeight = ( unsigned int ) : : ChainActive ( ) . Height ( ) ;
2017-01-11 14:16:11 +01:00
if ( chainHeight < Params ( ) . PruneAfterHeight ( ) )
2017-03-09 10:02:13 +01:00
throw JSONRPCError ( RPC_MISC_ERROR , " Blockchain is too short for pruning. " ) ;
2017-01-11 14:16:11 +01:00
else if ( height > chainHeight )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Blockchain is shorter than the attempted prune height. " ) ;
2017-01-12 11:49:48 +01:00
else if ( height > chainHeight - MIN_BLOCKS_TO_KEEP ) {
2018-05-02 15:56:30 +02:00
LogPrint ( BCLog : : RPC , " Attempt to prune blocks close to the tip. Retaining the minimum number of blocks. \n " ) ;
2017-01-12 11:49:48 +01:00
height = chainHeight - MIN_BLOCKS_TO_KEEP ;
}
2017-01-11 14:16:11 +01:00
PruneBlockFilesManual ( height ) ;
2019-06-13 13:34:05 +02:00
const CBlockIndex * block = : : ChainActive ( ) . Tip ( ) ;
assert ( block ) ;
while ( block - > pprev & & ( block - > pprev - > nStatus & BLOCK_HAVE_DATA ) ) {
block = block - > pprev ;
}
return uint64_t ( block - > nHeight ) ;
2017-01-11 14:16:11 +01:00
}
2018-05-04 22:42:39 +02:00
static UniValue gettxoutsetinfo ( const JSONRPCRequest & request )
2012-09-25 23:04:54 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " gettxoutsetinfo " ,
" \n Returns statistics about the unspent transaction output set. \n "
" Note this call may take some time. \n " ,
2019-01-29 15:55:37 +01:00
{ } ,
RPCResult {
2013-10-29 12:29:44 +01:00
" { \n "
" \" height \" :n, (numeric) The current block height (index) \n "
2018-05-07 22:49:07 +02:00
" \" bestblock \" : \" hex \" , (string) The hash of the block at the tip of the chain \n "
" \" transactions \" : n, (numeric) The number of transactions with unspent outputs \n "
2018-03-01 14:18:46 +01:00
" \" txouts \" : n, (numeric) The number of unspent transaction outputs \n "
2017-06-06 11:26:28 +02:00
" \" bogosize \" : n, (numeric) A meaningless metric for UTXO set size \n "
" \" hash_serialized_2 \" : \" hash \" , (string) The serialized hash \n "
2017-06-02 00:47:58 +02:00
" \" disk_size \" : n, (numeric) The estimated size of the chainstate on disk \n "
2013-10-29 12:29:44 +01:00
" \" total_amount \" : x.xxx (numeric) The total amount \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " gettxoutsetinfo " , " " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " gettxoutsetinfo " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-09-25 23:04:54 +02:00
2015-05-10 14:48:35 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2012-09-25 23:04:54 +02:00
CCoinsStats stats ;
2021-10-09 16:14:44 +02:00
: : ChainstateActive ( ) . ForceFlushStateToDisk ( ) ;
2019-07-24 17:45:04 +02:00
CCoinsView * coins_view = WITH_LOCK ( cs_main , return & ChainstateActive ( ) . CoinsDB ( ) ) ;
if ( GetUTXOStats ( coins_view , stats ) ) {
2020-06-18 11:17:23 +02:00
ret . pushKV ( " height " , ( int64_t ) stats . nHeight ) ;
ret . pushKV ( " bestblock " , stats . hashBlock . GetHex ( ) ) ;
ret . pushKV ( " transactions " , ( int64_t ) stats . nTransactions ) ;
ret . pushKV ( " txouts " , ( int64_t ) stats . nTransactionOutputs ) ;
ret . pushKV ( " bogosize " , ( int64_t ) stats . nBogoSize ) ;
ret . pushKV ( " hash_serialized_2 " , stats . hashSerialized . GetHex ( ) ) ;
ret . pushKV ( " disk_size " , stats . nDiskSize ) ;
ret . pushKV ( " total_amount " , ValueFromAmount ( stats . nTotalAmount ) ) ;
2016-09-29 07:59:22 +02:00
} else {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Unable to read UTXO set " ) ;
2012-09-25 23:04:54 +02:00
}
return ret ;
}
2012-08-21 17:03:38 +02:00
2018-05-04 22:42:39 +02:00
static UniValue gettxout ( const JSONRPCRequest & request )
2012-09-25 23:04:54 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 3 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " gettxout " ,
" \n Returns details about an unspent transaction output. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " txid " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The transaction id " } ,
{ " n " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " vout number " } ,
{ " include_mempool " , RPCArg : : Type : : BOOL , /* default */ " true " , " Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2013-10-29 12:29:44 +01:00
" { \n "
2018-05-07 22:49:07 +02:00
" \" bestblock \" : \" hash \" , (string) The hash of the block at the tip of the chain \n "
2013-10-29 12:29:44 +01:00
" \" confirmations \" : n, (numeric) The number of confirmations \n "
2015-08-01 21:15:23 +02:00
" \" value \" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + " \n "
2013-10-29 12:29:44 +01:00
" \" scriptPubKey \" : { (json object) \n "
" \" asm \" : \" code \" , (string) \n "
" \" hex \" : \" hex \" , (string) \n "
" \" reqSigs \" : n, (numeric) Number of required signatures \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg pubkeyhash \n "
2015-03-19 15:15:08 +01:00
" \" addresses \" : [ (array of string) array of dash addresses \n "
2018-01-18 17:07:17 +01:00
" \" address \" (string) dash address \n "
2013-10-29 12:29:44 +01:00
" ,... \n "
" ] \n "
" }, \n "
" \" coinbase \" : true|false (boolean) Coinbase or not \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
2013-10-29 12:29:44 +01:00
" \n Get unspent transactions \n "
+ HelpExampleCli ( " listunspent " , " " ) +
" \n View the details \n "
+ HelpExampleCli ( " gettxout " , " \" txid \" 1 " ) +
2018-10-10 05:59:20 +02:00
" \n As a JSON-RPC call \n "
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " gettxout " , " \" txid \" , 1 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2012-08-21 17:03:38 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2015-05-10 14:48:35 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2012-09-25 23:04:54 +02:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2014-12-16 14:50:05 +01:00
uint256 hash ( uint256S ( strHash ) ) ;
2016-10-19 15:01:33 +02:00
int n = request . params [ 1 ] . get_int ( ) ;
2017-06-02 00:47:58 +02:00
COutPoint out ( hash , n ) ;
2012-09-25 23:04:54 +02:00
bool fMempool = true ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 2 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
fMempool = request . params [ 2 ] . get_bool ( ) ;
2012-09-25 23:04:54 +02:00
2017-06-02 00:47:58 +02:00
Coin coin ;
2019-07-24 17:45:04 +02:00
CCoinsViewCache * coins_view = & : : ChainstateActive ( ) . CoinsTip ( ) ;
2012-09-25 23:04:54 +02:00
if ( fMempool ) {
LOCK ( mempool . cs ) ;
2019-07-24 17:45:04 +02:00
CCoinsViewMemPool view ( coins_view , mempool ) ;
2017-06-28 20:15:45 +02:00
if ( ! view . GetCoin ( out , coin ) | | mempool . isSpent ( out ) ) {
2014-08-20 21:15:16 +02:00
return NullUniValue ;
2017-06-02 00:47:58 +02:00
}
2012-09-25 23:04:54 +02:00
} else {
2019-07-24 17:45:04 +02:00
if ( ! coins_view - > GetCoin ( out , coin ) ) {
2014-08-20 21:15:16 +02:00
return NullUniValue ;
2017-06-02 00:47:58 +02:00
}
2012-09-25 23:04:54 +02:00
}
2019-07-24 17:45:04 +02:00
const CBlockIndex * pindex = LookupBlockIndex ( coins_view - > GetBestBlock ( ) ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " bestblock " , pindex - > GetBlockHash ( ) . GetHex ( ) ) ;
2017-06-02 00:47:58 +02:00
if ( coin . nHeight = = MEMPOOL_HEIGHT ) {
2020-06-18 11:17:23 +02:00
ret . pushKV ( " confirmations " , 0 ) ;
2017-06-02 00:47:58 +02:00
} else {
2020-06-18 11:17:23 +02:00
ret . pushKV ( " confirmations " , ( int64_t ) ( pindex - > nHeight - coin . nHeight + 1 ) ) ;
2017-06-02 00:47:58 +02:00
}
2020-06-18 11:17:23 +02:00
ret . pushKV ( " value " , ValueFromAmount ( coin . out . nValue ) ) ;
2015-05-10 14:48:35 +02:00
UniValue o ( UniValue : : VOBJ ) ;
2019-06-11 13:42:17 +02:00
ScriptPubKeyToUniv ( coin . out . scriptPubKey , o , true ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " scriptPubKey " , o ) ;
ret . pushKV ( " coinbase " , ( bool ) coin . fCoinBase ) ;
2012-09-25 23:04:54 +02:00
return ret ;
}
2012-08-21 17:03:38 +02:00
2018-05-04 22:42:39 +02:00
static UniValue verifychain ( const JSONRPCRequest & request )
2013-06-19 17:53:02 +02:00
{
2019-06-24 18:44:27 +02:00
int nCheckLevel = gArgs . GetArg ( " -checklevel " , DEFAULT_CHECKLEVEL ) ;
int nCheckDepth = gArgs . GetArg ( " -checkblocks " , DEFAULT_CHECKBLOCKS ) ;
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " verifychain " ,
" \n Verifies blockchain database. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " checklevel " , RPCArg : : Type : : NUM , /* default */ strprintf ( " %d, range=0-4 " , nCheckLevel ) , " How thorough the block verification is. " } ,
{ " nblocks " , RPCArg : : Type : : NUM , /* default */ strprintf ( " %d, 0=all " , nCheckDepth ) , " The number of blocks to check. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2013-10-29 12:29:44 +01:00
" true|false (boolean) Verified or not \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " verifychain " , " " )
2013-10-29 12:29:44 +01:00
+ HelpExampleRpc ( " verifychain " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2013-06-19 17:53:02 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 0 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
nCheckLevel = request . params [ 0 ] . get_int ( ) ;
2019-08-08 17:57:08 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
nCheckDepth = request . params [ 1 ] . get_int ( ) ;
2013-06-19 17:53:02 +02:00
2019-07-24 17:45:04 +02:00
return CVerifyDB ( ) . VerifyDB (
Params ( ) , & : : ChainstateActive ( ) . CoinsTip ( ) , nCheckLevel , nCheckDepth ) ;
2013-06-19 17:53:02 +02:00
}
2012-08-21 17:03:38 +02:00
2015-06-27 08:03:34 +02:00
/** Implementation of IsSuperMajority with better feedback */
2019-01-04 12:30:36 +01:00
static UniValue SoftForkMajorityDesc ( int version , const CBlockIndex * pindex , const Consensus : : Params & consensusParams )
2015-06-27 08:03:34 +02:00
{
2016-08-04 11:55:25 +02:00
UniValue rv ( UniValue : : VOBJ ) ;
bool activated = false ;
switch ( version )
2015-06-27 08:03:34 +02:00
{
2016-08-04 11:55:25 +02:00
case 2 :
activated = pindex - > nHeight > = consensusParams . BIP34Height ;
break ;
case 3 :
activated = pindex - > nHeight > = consensusParams . BIP66Height ;
break ;
case 4 :
activated = pindex - > nHeight > = consensusParams . BIP65Height ;
break ;
2015-06-27 08:03:34 +02:00
}
2020-06-18 11:17:23 +02:00
rv . pushKV ( " status " , activated ) ;
2015-06-27 08:03:34 +02:00
return rv ;
}
2019-01-04 12:30:36 +01:00
static UniValue SoftForkDesc ( const std : : string & name , int version , const CBlockIndex * pindex , const Consensus : : Params & consensusParams )
2015-06-27 08:03:34 +02:00
{
UniValue rv ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
rv . pushKV ( " id " , name ) ;
rv . pushKV ( " version " , version ) ;
rv . pushKV ( " reject " , SoftForkMajorityDesc ( version , pindex , consensusParams ) ) ;
2015-06-27 08:03:34 +02:00
return rv ;
2013-06-19 17:53:02 +02:00
}
2012-08-21 17:03:38 +02:00
2016-04-14 12:14:24 +02:00
static UniValue BIP9SoftForkDesc ( const Consensus : : Params & consensusParams , Consensus : : DeploymentPos id )
2016-03-03 21:00:03 +01:00
{
UniValue rv ( UniValue : : VOBJ ) ;
2016-04-05 15:48:49 +02:00
const ThresholdState thresholdState = VersionBitsTipState ( consensusParams , id ) ;
switch ( thresholdState ) {
2020-06-18 11:17:23 +02:00
case ThresholdState : : DEFINED : rv . pushKV ( " status " , " defined " ) ; break ;
case ThresholdState : : STARTED : rv . pushKV ( " status " , " started " ) ; break ;
case ThresholdState : : LOCKED_IN : rv . pushKV ( " status " , " locked_in " ) ; break ;
case ThresholdState : : ACTIVE : rv . pushKV ( " status " , " active " ) ; break ;
case ThresholdState : : FAILED : rv . pushKV ( " status " , " failed " ) ; break ;
2016-03-03 21:00:03 +01:00
}
2020-06-09 05:44:04 +02:00
if ( ThresholdState : : STARTED = = thresholdState )
2016-04-05 15:48:49 +02:00
{
2020-06-18 11:17:23 +02:00
rv . pushKV ( " bit " , consensusParams . vDeployments [ id ] . bit ) ;
2016-04-05 15:48:49 +02:00
}
2019-09-27 14:49:18 +02:00
rv . pushKV ( " start_time " , consensusParams . vDeployments [ id ] . nStartTime ) ;
2020-06-18 11:17:23 +02:00
rv . pushKV ( " timeout " , consensusParams . vDeployments [ id ] . nTimeout ) ;
rv . pushKV ( " since " , VersionBitsTipStateSinceHeight ( consensusParams , id ) ) ;
2020-06-09 05:44:04 +02:00
if ( ThresholdState : : STARTED = = thresholdState )
2017-05-23 19:07:29 +02:00
{
UniValue statsUV ( UniValue : : VOBJ ) ;
BIP9Stats statsStruct = VersionBitsTipStatistics ( consensusParams , id ) ;
2020-06-18 11:17:23 +02:00
statsUV . pushKV ( " period " , statsStruct . period ) ;
statsUV . pushKV ( " threshold " , statsStruct . threshold ) ;
statsUV . pushKV ( " elapsed " , statsStruct . elapsed ) ;
statsUV . pushKV ( " count " , statsStruct . count ) ;
statsUV . pushKV ( " possible " , statsStruct . possible ) ;
rv . pushKV ( " statistics " , statsUV ) ;
2017-05-23 19:07:29 +02:00
}
2016-03-03 21:00:03 +01:00
return rv ;
}
2018-05-04 22:42:39 +02:00
static void BIP9SoftForkDescPushBack ( UniValue & bip9_softforks , const Consensus : : Params & consensusParams , Consensus : : DeploymentPos id )
2016-06-27 16:07:14 +02:00
{
// Deployments with timeout value of 0 are hidden.
// A timeout value of 0 guarantees a softfork will never be activated.
// This is used when softfork codes are merged without specifying the deployment schedule.
if ( consensusParams . vDeployments [ id ] . nTimeout > 0 )
2020-06-18 11:17:23 +02:00
bip9_softforks . pushKV ( VersionBitsDeploymentInfo [ id ] . name , BIP9SoftForkDesc ( consensusParams , id ) ) ;
2016-06-27 16:07:14 +02:00
}
2016-10-19 15:01:33 +02:00
UniValue getblockchaininfo ( const JSONRPCRequest & request )
2014-05-05 13:22:28 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockchaininfo " ,
2019-01-29 15:55:37 +01:00
" Returns an object containing various state info regarding blockchain processing. \n " ,
{ } ,
RPCResult {
2014-05-05 13:22:28 +02:00
" { \n "
2020-11-19 20:44:33 +01:00
" \" chain \" : \" xxxx \" , (string) current network name as defined in BIP70 (main, test, regtest) and \n "
" devnet or devnet-<name> for \" -devnet \" and \" -devnet=<name> \" respectively \n "
2019-07-03 14:49:07 +02:00
" \" blocks \" : xxxxxx, (numeric) the height of the most-work fully-validated chain. The genesis block has height 0 \n "
2017-11-10 21:48:00 +01:00
" \" headers \" : xxxxxx, (numeric) the current number of headers we have validated \n "
" \" bestblockhash \" : \" ... \" , (string) the hash of the currently best block \n "
" \" difficulty \" : xxxxxx, (numeric) the current difficulty \n "
" \" mediantime \" : xxxxxx, (numeric) median time for the current best block \n "
2014-05-05 13:22:28 +02:00
" \" verificationprogress \" : xxxx, (numeric) estimate of verification progress [0..1] \n "
2017-11-10 21:48:00 +01:00
" \" initialblockdownload \" : xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode. \n "
" \" chainwork \" : \" xxxx \" (string) total amount of work in active chain, in hexadecimal \n "
" \" size_on_disk \" : xxxxxx, (numeric) the estimated size of the block and undo files on disk \n "
" \" pruned \" : xx, (boolean) if the blocks are subject to pruning \n "
" \" pruneheight \" : xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled) \n "
" \" automatic_pruning \" : xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled) \n "
2017-10-09 16:53:12 +02:00
" \" prune_target_size \" : xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled) \n "
2017-11-10 21:48:00 +01:00
" \" softforks \" : [ (array) status of softforks in progress \n "
2015-06-27 08:03:34 +02:00
" { \n "
2017-11-10 21:48:00 +01:00
" \" id \" : \" xxxx \" , (string) name of softfork \n "
" \" version \" : xx, (numeric) block version \n "
" \" reject \" : { (object) progress toward rejecting pre-softfork blocks \n "
" \" status \" : xx, (boolean) true if threshold reached \n "
2015-06-27 08:03:34 +02:00
" }, \n "
" }, ... \n "
2016-03-03 21:00:03 +01:00
" ], \n "
2017-11-10 21:48:00 +01:00
" \" bip9_softforks \" : { (object) status of BIP9 softforks in progress \n "
" \" xxxx \" : { (string) name of the softfork \n "
" \" status \" : \" xxxx \" , (string) one of \" defined \" , \" started \" , \" locked_in \" , \" active \" , \" failed \" \n "
" \" bit \" : xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \" started \" status) \n "
2019-09-27 14:49:18 +02:00
" \" start_time \" : xx, (numeric) the minimum median time past of a block at which the bit gains its meaning \n "
2017-11-10 21:48:00 +01:00
" \" timeout \" : xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in \n "
" \" since \" : xx, (numeric) height of the first block to which the status applies \n "
" \" statistics \" : { (object) numeric statistics about BIP9 signalling for a softfork (only for \" started \" status) \n "
" \" period \" : xx, (numeric) the length in blocks of the BIP9 signalling period \n "
" \" threshold \" : xx, (numeric) the number of blocks with the version bit set required to activate the feature \n "
" \" elapsed \" : xx, (numeric) the number of blocks elapsed since the beginning of the current period \n "
" \" count \" : xx, (numeric) the number of blocks with the version bit set in the current period \n "
" \" possible \" : xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n "
2017-05-23 19:07:29 +02:00
" } \n "
2016-03-03 21:00:03 +01:00
" } \n "
2016-04-14 12:14:24 +02:00
" } \n "
2017-11-10 21:48:00 +01:00
" \" warnings \" : \" ... \" , (string) any network and blockchain warnings. \n "
2014-05-05 13:22:28 +02:00
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getblockchaininfo " , " " )
2014-05-05 13:22:28 +02:00
+ HelpExampleRpc ( " getblockchaininfo " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2014-05-05 13:22:28 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2020-11-19 20:44:33 +01:00
std : : string strChainName = gArgs . IsArgSet ( " -devnet " ) ? gArgs . GetDevNetName ( ) : Params ( ) . NetworkIDString ( ) ;
2021-10-16 12:54:22 +02:00
const CBlockIndex * tip = : : ChainActive ( ) . Tip ( ) ;
2015-05-10 14:48:35 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
2020-11-19 20:44:33 +01:00
obj . pushKV ( " chain " , strChainName ) ;
2021-10-16 12:54:22 +02:00
obj . pushKV ( " blocks " , ( int ) : : ChainActive ( ) . Height ( ) ) ;
2020-06-18 11:17:23 +02:00
obj . pushKV ( " headers " , pindexBestHeader ? pindexBestHeader - > nHeight : - 1 ) ;
2019-01-04 12:30:36 +01:00
obj . pushKV ( " bestblockhash " , tip - > GetBlockHash ( ) . GetHex ( ) ) ;
obj . pushKV ( " difficulty " , ( double ) GetDifficulty ( tip ) ) ;
obj . pushKV ( " mediantime " , ( int64_t ) tip - > GetMedianTimePast ( ) ) ;
obj . pushKV ( " verificationprogress " , GuessVerificationProgress ( Params ( ) . TxData ( ) , tip ) ) ;
2021-10-09 16:14:44 +02:00
obj . pushKV ( " initialblockdownload " , : : ChainstateActive ( ) . IsInitialBlockDownload ( ) ) ;
2019-01-04 12:30:36 +01:00
obj . pushKV ( " chainwork " , tip - > nChainWork . GetHex ( ) ) ;
2020-06-18 11:17:23 +02:00
obj . pushKV ( " size_on_disk " , CalculateCurrentUsage ( ) ) ;
obj . pushKV ( " pruned " , fPruneMode ) ;
2017-10-09 16:53:12 +02:00
if ( fPruneMode ) {
2019-01-04 12:30:36 +01:00
const CBlockIndex * block = tip ;
2017-10-09 16:53:12 +02:00
assert ( block ) ;
while ( block - > pprev & & ( block - > pprev - > nStatus & BLOCK_HAVE_DATA ) ) {
block = block - > pprev ;
}
2020-06-18 11:17:23 +02:00
obj . pushKV ( " pruneheight " , block - > nHeight ) ;
2017-10-09 16:53:12 +02:00
// if 0, execution bypasses the whole if block.
bool automatic_pruning = ( gArgs . GetArg ( " -prune " , 0 ) ! = 1 ) ;
2020-06-18 11:17:23 +02:00
obj . pushKV ( " automatic_pruning " , automatic_pruning ) ;
2017-10-09 16:53:12 +02:00
if ( automatic_pruning ) {
2020-06-18 11:17:23 +02:00
obj . pushKV ( " prune_target_size " , nPruneTarget ) ;
2017-10-09 16:53:12 +02:00
}
}
2015-06-27 08:03:34 +02:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
UniValue softforks ( UniValue : : VARR ) ;
2016-04-14 12:14:24 +02:00
UniValue bip9_softforks ( UniValue : : VOBJ ) ;
2019-11-13 19:17:00 +01:00
// sorted by activation block
2015-06-27 08:03:34 +02:00
softforks . push_back ( SoftForkDesc ( " bip34 " , 2 , tip , consensusParams ) ) ;
softforks . push_back ( SoftForkDesc ( " bip66 " , 3 , tip , consensusParams ) ) ;
2015-09-27 20:32:10 +02:00
softforks . push_back ( SoftForkDesc ( " bip65 " , 4 , tip , consensusParams ) ) ;
2017-11-30 18:19:21 +01:00
for ( int pos = Consensus : : DEPLOYMENT_CSV ; pos ! = Consensus : : MAX_VERSION_BITS_DEPLOYMENTS ; + + pos ) {
BIP9SoftForkDescPushBack ( bip9_softforks , consensusParams , static_cast < Consensus : : DeploymentPos > ( pos ) ) ;
}
2020-06-18 11:17:23 +02:00
obj . pushKV ( " softforks " , softforks ) ;
obj . pushKV ( " bip9_softforks " , bip9_softforks ) ;
2015-06-27 08:03:34 +02:00
2020-06-18 11:17:23 +02:00
obj . pushKV ( " warnings " , GetWarnings ( " statusbar " ) ) ;
2014-05-05 13:22:28 +02:00
return obj ;
}
2014-08-03 18:12:19 +02:00
2014-11-20 03:19:29 +01:00
/** Comparison function for sorting the getchaintips heads. */
2014-08-03 18:12:19 +02:00
struct CompareBlocksByHeight
{
bool operator ( ) ( const CBlockIndex * a , const CBlockIndex * b ) const
{
/* Make sure that unequal blocks with the same height do not compare
2014-10-31 09:36:30 +01:00
equal . Use the pointers themselves to make a distinction . */
2014-08-03 18:12:19 +02:00
if ( a - > nHeight ! = b - > nHeight )
return ( a - > nHeight > b - > nHeight ) ;
return a < b ;
}
} ;
2018-05-04 22:42:39 +02:00
static UniValue getchaintips ( const JSONRPCRequest & request )
2014-08-03 18:12:19 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) > 2 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getchaintips " ,
" Return information about all known tips in the block tree, "
" including the main chain as well as orphaned branches. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " count " , RPCArg : : Type : : NUM , /* default */ " " , " only show this much of latest tips " } ,
{ " branchlen " , RPCArg : : Type : : NUM , /* default */ " " , " only show tips that have equal or greater length of branch " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2014-08-03 18:12:19 +02:00
" [ \n "
" { \n "
2016-12-30 17:38:53 +01:00
" \" height \" : xxxx, (numeric) height of the chain tip \n "
" \" hash \" : \" xxxx \" , (string) block hash of the tip \n "
" \" difficulty \" : x.xxx, (numeric) The difficulty \n "
" \" chainwork \" : \" 0000...1f3 \" (string) Expected number of hashes required to produce the current chain (in hex) \n "
" \" branchlen \" : 0 (numeric) zero for main chain \n "
2018-04-18 13:50:52 +02:00
" \" forkpoint \" : \" xxxx \" , (string) same as \" hash \" for the main chain \n "
2016-12-30 17:38:53 +01:00
" \" status \" : \" active \" (string) \" active \" for the main chain \n "
2014-08-03 18:12:19 +02:00
" }, \n "
" { \n "
" \" height \" : xxxx, \n "
" \" hash \" : \" xxxx \" , \n "
2016-12-30 17:38:53 +01:00
" \" difficulty \" : x.xxx, \n "
" \" chainwork \" : \" 0000...1f3 \" \n "
" \" branchlen \" : 1 (numeric) length of branch connecting the tip to the main chain \n "
2018-04-18 13:50:52 +02:00
" \" forkpoint \" : \" xxxx \" , (string) block hash of the last common block between this tip and the main chain \n "
2016-12-30 17:38:53 +01:00
" \" status \" : \" xxxx \" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid) \n "
2014-08-03 18:12:19 +02:00
" } \n "
" ] \n "
2014-12-01 20:48:50 +01:00
" Possible values for status: \n "
" 1. \" invalid \" This branch contains at least one invalid block \n "
" 2. \" headers-only \" Not all blocks for this branch are available, but the headers are valid \n "
" 3. \" valid-headers \" All blocks are available for this branch, but they were never fully validated \n "
" 4. \" valid-fork \" This branch is not part of the active chain, but is fully validated \n "
" 5. \" active \" This is the tip of the active main chain, which is certainly valid \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getchaintips " , " " )
2014-08-03 18:12:19 +02:00
+ HelpExampleRpc ( " getchaintips " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2014-08-03 18:12:19 +02:00
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2016-04-19 10:44:44 +02:00
/*
2021-10-16 12:54:22 +02:00
* Idea : the set of chain tips is : : ChainActive ( ) . tip , plus orphan blocks which do not have another orphan building off of them .
2016-04-19 10:44:44 +02:00
* Algorithm :
2021-10-16 19:42:59 +02:00
* - Make one pass through g_blockman . m_block_index , picking out the orphan blocks , and also storing a set of the orphan block ' s pprev pointers .
2016-04-19 10:44:44 +02:00
* - Iterate through the orphan blocks . If the block isn ' t pointed to by another orphan , it is a chain tip .
2021-10-16 12:54:22 +02:00
* - add : : ChainActive ( ) . Tip ( )
2016-04-19 10:44:44 +02:00
*/
2014-08-03 18:12:19 +02:00
std : : set < const CBlockIndex * , CompareBlocksByHeight > setTips ;
2016-04-19 10:44:44 +02:00
std : : set < const CBlockIndex * > setOrphans ;
std : : set < const CBlockIndex * > setPrevs ;
2021-10-16 19:42:59 +02:00
for ( const std : : pair < const uint256 , CBlockIndex * > & item : : : BlockIndex ( ) )
2014-08-03 18:12:19 +02:00
{
2021-10-16 12:54:22 +02:00
if ( ! : : ChainActive ( ) . Contains ( item . second ) ) {
2016-04-19 10:44:44 +02:00
setOrphans . insert ( item . second ) ;
setPrevs . insert ( item . second - > pprev ) ;
}
}
for ( std : : set < const CBlockIndex * > : : iterator it = setOrphans . begin ( ) ; it ! = setOrphans . end ( ) ; + + it )
{
if ( setPrevs . erase ( * it ) = = 0 ) {
setTips . insert ( * it ) ;
}
2014-08-03 18:12:19 +02:00
}
2014-11-27 10:46:55 +01:00
// Always report the currently active tip.
2021-10-16 12:54:22 +02:00
setTips . insert ( : : ChainActive ( ) . Tip ( ) ) ;
2014-11-27 10:46:55 +01:00
2016-03-15 01:48:08 +01:00
int nBranchMin = - 1 ;
int nCountMax = INT_MAX ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 0 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
nCountMax = request . params [ 0 ] . get_int ( ) ;
2016-03-15 01:48:08 +01:00
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 1 ] . isNull ( ) )
2016-10-19 15:01:33 +02:00
nBranchMin = request . params [ 1 ] . get_int ( ) ;
2016-03-15 01:48:08 +01:00
2014-08-03 18:12:19 +02:00
/* Construct the output array. */
2015-05-10 14:48:35 +02:00
UniValue res ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( const CBlockIndex * block : setTips )
2014-08-03 18:12:19 +02:00
{
2021-10-16 12:54:22 +02:00
const CBlockIndex * pindexFork = : : ChainActive ( ) . FindFork ( block ) ;
2018-04-18 13:50:52 +02:00
const int branchLen = block - > nHeight - pindexFork - > nHeight ;
2016-03-15 01:48:08 +01:00
if ( branchLen < nBranchMin ) continue ;
if ( nCountMax - - < 1 ) break ;
2015-05-10 14:48:35 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
obj . pushKV ( " height " , block - > nHeight ) ;
obj . pushKV ( " hash " , block - > phashBlock - > GetHex ( ) ) ;
obj . pushKV ( " difficulty " , GetDifficulty ( block ) ) ;
obj . pushKV ( " chainwork " , block - > nChainWork . GetHex ( ) ) ;
obj . pushKV ( " branchlen " , branchLen ) ;
obj . pushKV ( " forkpoint " , pindexFork - > phashBlock - > GetHex ( ) ) ;
2014-08-03 18:12:19 +02:00
2017-03-09 08:14:27 +01:00
std : : string status ;
2021-10-16 12:54:22 +02:00
if ( : : ChainActive ( ) . Contains ( block ) ) {
2014-11-27 10:46:55 +01:00
// This block is part of the currently active chain.
status = " active " ;
} else if ( block - > nStatus & BLOCK_FAILED_MASK ) {
// This block or one of its ancestors is invalid.
status = " invalid " ;
2021-01-16 20:47:13 +01:00
} else if ( block - > nStatus & BLOCK_CONFLICT_CHAINLOCK ) {
// This block or one of its ancestors is conflicting with ChainLocks.
status = " conflicting " ;
2018-12-07 14:02:30 +01:00
} else if ( ! block - > HaveTxsDownloaded ( ) ) {
2014-11-27 10:46:55 +01:00
// This block cannot be connected because full block data for it or one of its parents is missing.
status = " headers-only " ;
} else if ( block - > IsValid ( BLOCK_VALID_SCRIPTS ) ) {
// This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
status = " valid-fork " ;
} else if ( block - > IsValid ( BLOCK_VALID_TREE ) ) {
// The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
status = " valid-headers " ;
} else {
// No clue.
status = " unknown " ;
}
2020-06-18 11:17:23 +02:00
obj . pushKV ( " status " , status ) ;
2014-11-27 10:46:55 +01:00
2014-08-03 18:12:19 +02:00
res . push_back ( obj ) ;
}
return res ;
}
2014-08-07 05:58:19 +02:00
2019-02-23 17:04:20 +01:00
UniValue MempoolInfoToJSON ( const CTxMemPool & pool )
2015-08-06 19:38:19 +02:00
{
2021-11-08 18:20:39 +01:00
// Make sure this call is atomic in the pool.
LOCK ( pool . cs ) ;
2015-08-06 19:38:19 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2019-05-01 16:06:11 +02:00
ret . pushKV ( " loaded " , pool . IsLoaded ( ) ) ;
2019-02-23 17:04:20 +01:00
ret . pushKV ( " size " , ( int64_t ) pool . size ( ) ) ;
ret . pushKV ( " bytes " , ( int64_t ) pool . GetTotalTxSize ( ) ) ;
ret . pushKV ( " usage " , ( int64_t ) pool . DynamicMemoryUsage ( ) ) ;
2019-06-24 18:44:27 +02:00
size_t maxmempool = gArgs . GetArg ( " -maxmempool " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " maxmempool " , ( int64_t ) maxmempool ) ;
2019-02-23 17:04:20 +01:00
ret . pushKV ( " mempoolminfee " , ValueFromAmount ( std : : max ( pool . GetMinFee ( maxmempool ) , : : minRelayTxFee ) . GetFeePerK ( ) ) ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " minrelaytxfee " , ValueFromAmount ( : : minRelayTxFee . GetFeePerK ( ) ) ) ;
ret . pushKV ( " instantsendlocks " , ( int64_t ) llmq : : quorumInstantSendManager - > GetInstantSendLockCount ( ) ) ;
2015-08-06 19:38:19 +02:00
return ret ;
}
2018-05-04 22:42:39 +02:00
static UniValue getmempoolinfo ( const JSONRPCRequest & request )
2014-08-07 05:58:19 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 0 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getmempoolinfo " ,
2019-01-29 15:55:37 +01:00
" \n Returns details on the active state of the TX memory pool. \n " ,
{ } ,
RPCResult {
2014-08-07 05:58:19 +02:00
" { \n "
2019-05-01 16:06:11 +02:00
" \" loaded \" : true|false (boolean) True if the mempool is fully loaded \n "
2015-11-27 16:53:29 +01:00
" \" size \" : xxxxx, (numeric) Current tx count \n "
" \" bytes \" : xxxxx, (numeric) Sum of all tx sizes \n "
" \" usage \" : xxxxx, (numeric) Total memory usage for the mempool \n "
" \" maxmempool \" : xxxxx, (numeric) Maximum memory usage for the mempool \n "
2018-01-04 09:22:40 +01:00
" \" mempoolminfee \" : xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + " /kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee \n "
" \" minrelaytxfee \" : xxxxx (numeric) Current minimum relay fee for transactions \n "
2020-06-13 20:18:31 +02:00
" \" instantsendlocks \" : xxxxx, (numeric) Number of unconfirmed instant send locks \n "
2014-08-07 05:58:19 +02:00
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getmempoolinfo " , " " )
2014-08-07 05:58:19 +02:00
+ HelpExampleRpc ( " getmempoolinfo " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2014-08-07 05:58:19 +02:00
2019-02-23 17:04:20 +01:00
return MempoolInfoToJSON ( : : mempool ) ;
2014-08-07 05:58:19 +02:00
}
2018-05-04 22:42:39 +02:00
static UniValue preciousblock ( const JSONRPCRequest & request )
2016-10-18 21:35:27 +02:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " preciousblock " ,
" \n Treats a block as if it were received before others with the same work. \n "
" \n A later preciousblock call can override the effect of an earlier one. \n "
" \n The effects of preciousblock are not retained across restarts. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " the hash of the block to mark as precious " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResults { } ,
RPCExamples {
HelpExampleCli ( " preciousblock " , " \" blockhash \" " )
2016-10-18 21:35:27 +02:00
+ HelpExampleRpc ( " preciousblock " , " \" blockhash \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2016-10-18 21:35:27 +02:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2016-10-18 21:35:27 +02:00
uint256 hash ( uint256S ( strHash ) ) ;
CBlockIndex * pblockindex ;
{
LOCK ( cs_main ) ;
2018-03-13 19:04:28 +01:00
pblockindex = LookupBlockIndex ( hash ) ;
if ( ! pblockindex ) {
2016-10-18 21:35:27 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-03-13 19:04:28 +01:00
}
2016-10-18 21:35:27 +02:00
}
CValidationState state ;
PreciousBlock ( state , Params ( ) , pblockindex ) ;
if ( ! state . IsValid ( ) ) {
2018-02-15 16:35:12 +01:00
throw JSONRPCError ( RPC_DATABASE_ERROR , FormatStateMessage ( state ) ) ;
2016-10-18 21:35:27 +02:00
}
return NullUniValue ;
}
2018-05-04 22:42:39 +02:00
static UniValue invalidateblock ( const JSONRPCRequest & request )
2014-11-19 09:39:42 +01:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " invalidateblock " ,
" \n Permanently marks a block as invalid, as if it violated a consensus rule. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " the hash of the block to mark as invalid " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResults { } ,
RPCExamples {
HelpExampleCli ( " invalidateblock " , " \" blockhash \" " )
2014-11-19 09:39:42 +01:00
+ HelpExampleRpc ( " invalidateblock " , " \" blockhash \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2014-11-19 09:39:42 +01:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2014-12-16 14:50:05 +01:00
uint256 hash ( uint256S ( strHash ) ) ;
2014-11-19 09:39:42 +01:00
CValidationState state ;
Merge #15402: Granular invalidateblock and RewindBlockIndex
519b0bc5dc5155b6f7e2362c2105552bb7618ad0 Make last disconnected block BLOCK_FAILED_VALID, even when aborted (Pieter Wuille)
8d220417cd7bc34464e28a4861a885193ec091c2 Optimization: don't add txn back to mempool after 10 invalidates (Pieter Wuille)
9ce9c37004440d6a329874dbf66b51666d497dcb Prevent callback overruns in InvalidateBlock and RewindBlockIndex (Pieter Wuille)
9bb32eb571a846b66ed3bac493f55cee11a3a1b9 Release cs_main during InvalidateBlock iterations (Pieter Wuille)
9b1ff5c742dec0a6e0d6aab29b0bb771ad6d8135 Call InvalidateBlock without cs_main held (Pieter Wuille)
241b2c74ac8c4c3000e778554da1271e3f293e5d Make RewindBlockIndex interruptible (Pieter Wuille)
880ce7d46b51835c00d77a366ec28f54a05239df Call RewindBlockIndex without cs_main held (Pieter Wuille)
436f7d735f1c37e77d42ff59d4cbb1bd76d5fcfb Release cs_main during RewindBlockIndex operation (Pieter Wuille)
1d342875c21b5d0a17cf4d176063bb14b35b657e Merge the disconnection and erasing loops in RewindBlockIndex (Pieter Wuille)
32b2696ab4b079db736074b57bbc24deaee0b3d9 Move erasure of non-active blocks to a separate loop in RewindBlockIndex (Pieter Wuille)
9d6dcc52c6cb0cdcda220fddccaabb0ffd40068d Abstract EraseBlockData out of RewindBlockIndex (Pieter Wuille)
Pull request description:
This PR makes a number of improvements to the InvalidateBlock (`invalidateblock` RPC) and RewindBlockIndex functions, primarily around breaking up their long-term cs_main holding. In addition:
* They're made safely interruptible (`bitcoind` can be shutdown, and no progress in either will be lost, though if incomplete, `invalidateblock` won't continue after restart and will need to be called again)
* The validation queue is prevented from overflowing (meaning `invalidateblock` on a very old block will not drive bitcoind OOM) (see #14289).
* `invalidateblock` won't bother to move transactions back into the mempool after 10 blocks (optimization).
This is not an optimal solution, as we're relying on the scheduler call sites to make sure the scheduler doesn't overflow. Ideally, the scheduler would guarantee this directly, but that needs a few further changes (moving the signal emissions out of cs_main) to prevent deadlocks.
I have manually tested the `invalidateblock` changes (including interrupting, and running with -checkblockindex and -checkmempool), but haven't tried the rewinding (which is probably becoming increasingly unnecessary, as very few pre-0.13.1 nodes remain that would care to upgrade).
Tree-SHA512: 692e42758bd3d3efc2eb701984a8cb5db25fbeee32e7575df0183a00d0c2c30fdf72ce64c7625c32ad8c8bdc56313da72a7471658faeb0d39eefe39c4b8b8474
2019-03-07 17:39:54 +01:00
CBlockIndex * pblockindex ;
2014-11-19 09:39:42 +01:00
{
LOCK ( cs_main ) ;
Merge #15402: Granular invalidateblock and RewindBlockIndex
519b0bc5dc5155b6f7e2362c2105552bb7618ad0 Make last disconnected block BLOCK_FAILED_VALID, even when aborted (Pieter Wuille)
8d220417cd7bc34464e28a4861a885193ec091c2 Optimization: don't add txn back to mempool after 10 invalidates (Pieter Wuille)
9ce9c37004440d6a329874dbf66b51666d497dcb Prevent callback overruns in InvalidateBlock and RewindBlockIndex (Pieter Wuille)
9bb32eb571a846b66ed3bac493f55cee11a3a1b9 Release cs_main during InvalidateBlock iterations (Pieter Wuille)
9b1ff5c742dec0a6e0d6aab29b0bb771ad6d8135 Call InvalidateBlock without cs_main held (Pieter Wuille)
241b2c74ac8c4c3000e778554da1271e3f293e5d Make RewindBlockIndex interruptible (Pieter Wuille)
880ce7d46b51835c00d77a366ec28f54a05239df Call RewindBlockIndex without cs_main held (Pieter Wuille)
436f7d735f1c37e77d42ff59d4cbb1bd76d5fcfb Release cs_main during RewindBlockIndex operation (Pieter Wuille)
1d342875c21b5d0a17cf4d176063bb14b35b657e Merge the disconnection and erasing loops in RewindBlockIndex (Pieter Wuille)
32b2696ab4b079db736074b57bbc24deaee0b3d9 Move erasure of non-active blocks to a separate loop in RewindBlockIndex (Pieter Wuille)
9d6dcc52c6cb0cdcda220fddccaabb0ffd40068d Abstract EraseBlockData out of RewindBlockIndex (Pieter Wuille)
Pull request description:
This PR makes a number of improvements to the InvalidateBlock (`invalidateblock` RPC) and RewindBlockIndex functions, primarily around breaking up their long-term cs_main holding. In addition:
* They're made safely interruptible (`bitcoind` can be shutdown, and no progress in either will be lost, though if incomplete, `invalidateblock` won't continue after restart and will need to be called again)
* The validation queue is prevented from overflowing (meaning `invalidateblock` on a very old block will not drive bitcoind OOM) (see #14289).
* `invalidateblock` won't bother to move transactions back into the mempool after 10 blocks (optimization).
This is not an optimal solution, as we're relying on the scheduler call sites to make sure the scheduler doesn't overflow. Ideally, the scheduler would guarantee this directly, but that needs a few further changes (moving the signal emissions out of cs_main) to prevent deadlocks.
I have manually tested the `invalidateblock` changes (including interrupting, and running with -checkblockindex and -checkmempool), but haven't tried the rewinding (which is probably becoming increasingly unnecessary, as very few pre-0.13.1 nodes remain that would care to upgrade).
Tree-SHA512: 692e42758bd3d3efc2eb701984a8cb5db25fbeee32e7575df0183a00d0c2c30fdf72ce64c7625c32ad8c8bdc56313da72a7471658faeb0d39eefe39c4b8b8474
2019-03-07 17:39:54 +01:00
pblockindex = LookupBlockIndex ( hash ) ;
2018-03-13 19:04:28 +01:00
if ( ! pblockindex ) {
2014-11-19 09:39:42 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-03-13 19:04:28 +01:00
}
2014-11-19 09:39:42 +01:00
}
Merge #15402: Granular invalidateblock and RewindBlockIndex
519b0bc5dc5155b6f7e2362c2105552bb7618ad0 Make last disconnected block BLOCK_FAILED_VALID, even when aborted (Pieter Wuille)
8d220417cd7bc34464e28a4861a885193ec091c2 Optimization: don't add txn back to mempool after 10 invalidates (Pieter Wuille)
9ce9c37004440d6a329874dbf66b51666d497dcb Prevent callback overruns in InvalidateBlock and RewindBlockIndex (Pieter Wuille)
9bb32eb571a846b66ed3bac493f55cee11a3a1b9 Release cs_main during InvalidateBlock iterations (Pieter Wuille)
9b1ff5c742dec0a6e0d6aab29b0bb771ad6d8135 Call InvalidateBlock without cs_main held (Pieter Wuille)
241b2c74ac8c4c3000e778554da1271e3f293e5d Make RewindBlockIndex interruptible (Pieter Wuille)
880ce7d46b51835c00d77a366ec28f54a05239df Call RewindBlockIndex without cs_main held (Pieter Wuille)
436f7d735f1c37e77d42ff59d4cbb1bd76d5fcfb Release cs_main during RewindBlockIndex operation (Pieter Wuille)
1d342875c21b5d0a17cf4d176063bb14b35b657e Merge the disconnection and erasing loops in RewindBlockIndex (Pieter Wuille)
32b2696ab4b079db736074b57bbc24deaee0b3d9 Move erasure of non-active blocks to a separate loop in RewindBlockIndex (Pieter Wuille)
9d6dcc52c6cb0cdcda220fddccaabb0ffd40068d Abstract EraseBlockData out of RewindBlockIndex (Pieter Wuille)
Pull request description:
This PR makes a number of improvements to the InvalidateBlock (`invalidateblock` RPC) and RewindBlockIndex functions, primarily around breaking up their long-term cs_main holding. In addition:
* They're made safely interruptible (`bitcoind` can be shutdown, and no progress in either will be lost, though if incomplete, `invalidateblock` won't continue after restart and will need to be called again)
* The validation queue is prevented from overflowing (meaning `invalidateblock` on a very old block will not drive bitcoind OOM) (see #14289).
* `invalidateblock` won't bother to move transactions back into the mempool after 10 blocks (optimization).
This is not an optimal solution, as we're relying on the scheduler call sites to make sure the scheduler doesn't overflow. Ideally, the scheduler would guarantee this directly, but that needs a few further changes (moving the signal emissions out of cs_main) to prevent deadlocks.
I have manually tested the `invalidateblock` changes (including interrupting, and running with -checkblockindex and -checkmempool), but haven't tried the rewinding (which is probably becoming increasingly unnecessary, as very few pre-0.13.1 nodes remain that would care to upgrade).
Tree-SHA512: 692e42758bd3d3efc2eb701984a8cb5db25fbeee32e7575df0183a00d0c2c30fdf72ce64c7625c32ad8c8bdc56313da72a7471658faeb0d39eefe39c4b8b8474
2019-03-07 17:39:54 +01:00
InvalidateBlock ( state , Params ( ) , pblockindex ) ;
2014-11-19 09:39:42 +01:00
if ( state . IsValid ( ) ) {
2016-12-05 08:07:22 +01:00
ActivateBestChain ( state , Params ( ) ) ;
2014-11-19 09:39:42 +01:00
}
if ( ! state . IsValid ( ) ) {
2018-02-15 16:35:12 +01:00
throw JSONRPCError ( RPC_DATABASE_ERROR , FormatStateMessage ( state ) ) ;
2014-11-19 09:39:42 +01:00
}
2015-05-10 13:35:44 +02:00
return NullUniValue ;
2014-11-19 09:39:42 +01:00
}
2018-05-04 22:42:39 +02:00
static UniValue reconsiderblock ( const JSONRPCRequest & request )
2014-11-19 09:39:42 +01:00
{
2016-10-19 15:01:33 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-03-09 08:14:27 +01:00
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " reconsiderblock " ,
2019-01-07 15:44:12 +01:00
" \n Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation. \n "
2021-10-11 23:55:23 +02:00
" This can be used to undo the effects of invalidateblock. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " the hash of the block to reconsider " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResults { } ,
RPCExamples {
HelpExampleCli ( " reconsiderblock " , " \" blockhash \" " )
2014-11-19 09:39:42 +01:00
+ HelpExampleRpc ( " reconsiderblock " , " \" blockhash \" " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2014-11-19 09:39:42 +01:00
2016-10-19 15:01:33 +02:00
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
2014-12-16 14:50:05 +01:00
uint256 hash ( uint256S ( strHash ) ) ;
2014-11-19 09:39:42 +01:00
{
LOCK ( cs_main ) ;
2018-03-13 19:04:28 +01:00
CBlockIndex * pblockindex = LookupBlockIndex ( hash ) ;
if ( ! pblockindex ) {
2014-11-19 09:39:42 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-03-13 19:04:28 +01:00
}
2014-11-19 09:39:42 +01:00
2016-05-10 12:43:19 +02:00
ResetBlockFailureFlags ( pblockindex ) ;
2014-11-19 09:39:42 +01:00
}
2016-05-10 12:43:19 +02:00
CValidationState state ;
2016-12-05 08:07:22 +01:00
ActivateBestChain ( state , Params ( ) ) ;
2014-11-19 09:39:42 +01:00
if ( ! state . IsValid ( ) ) {
2018-02-15 16:35:12 +01:00
throw JSONRPCError ( RPC_DATABASE_ERROR , FormatStateMessage ( state ) ) ;
2014-11-19 09:39:42 +01:00
}
2015-05-10 13:35:44 +02:00
return NullUniValue ;
2014-11-19 09:39:42 +01:00
}
2016-03-31 10:55:06 +02:00
2018-05-04 22:42:39 +02:00
static UniValue getchaintxstats ( const JSONRPCRequest & request )
2017-05-03 08:14:50 +02:00
{
if ( request . fHelp | | request . params . size ( ) > 2 )
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getchaintxstats " ,
" \n Compute statistics about the total number and rate of transactions in the chain. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " nblocks " , RPCArg : : Type : : NUM , /* default */ " one month " , " Size of the window in number of blocks " } ,
{ " blockhash " , RPCArg : : Type : : STR_HEX , /* default */ " chain tip " , " The hash of the block that ends the window. " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2017-05-03 08:14:50 +02:00
" { \n "
2018-02-02 17:57:01 +01:00
" \" time \" : xxxxx, (numeric) The timestamp for the final block in the window in UNIX format. \n "
" \" txcount \" : xxxxx, (numeric) The total number of transactions in the chain up to that point. \n "
" \" window_final_block_hash \" : \" ... \" , (string) The hash of the final block in the window. \n "
2019-08-29 16:41:29 +02:00
" \" window_final_block_height \" : xxxxx, (numeric) The height of the final block in the window. \n "
2018-02-02 17:57:01 +01:00
" \" window_block_count \" : xxxxx, (numeric) Size of the window in number of blocks. \n "
" \" window_tx_count \" : xxxxx, (numeric) The number of transactions in the window. Only returned if \" window_block_count \" is > 0. \n "
" \" window_interval \" : xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \" window_block_count \" is > 0. \n "
" \" txrate \" : x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \" window_interval \" is > 0. \n "
2017-05-03 08:14:50 +02:00
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getchaintxstats " , " " )
2017-05-03 08:14:50 +02:00
+ HelpExampleRpc ( " getchaintxstats " , " 2016 " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2017-05-03 08:14:50 +02:00
const CBlockIndex * pindex ;
int blockcount = 30 * 24 * 60 * 60 / Params ( ) . GetConsensus ( ) . nPowTargetSpacing ; // By default: 1 month
2018-02-26 16:35:56 +01:00
if ( request . params [ 1 ] . isNull ( ) ) {
2017-05-03 08:14:50 +02:00
LOCK ( cs_main ) ;
2021-10-16 12:54:22 +02:00
pindex = : : ChainActive ( ) . Tip ( ) ;
2018-02-26 16:35:56 +01:00
} else {
uint256 hash = uint256S ( request . params [ 1 ] . get_str ( ) ) ;
LOCK ( cs_main ) ;
2018-03-13 19:04:28 +01:00
pindex = LookupBlockIndex ( hash ) ;
if ( ! pindex ) {
2018-02-26 16:35:56 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
}
2021-10-16 12:54:22 +02:00
if ( ! : : ChainActive ( ) . Contains ( pindex ) ) {
2018-02-26 16:35:56 +01:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Block is not in main chain " ) ;
2017-05-03 08:14:50 +02:00
}
}
2020-01-05 11:17:40 +01:00
2017-09-06 23:53:55 +02:00
assert ( pindex ! = nullptr ) ;
2017-05-03 08:14:50 +02:00
2017-10-02 15:21:26 +02:00
if ( request . params [ 0 ] . isNull ( ) ) {
blockcount = std : : max ( 0 , std : : min ( blockcount , pindex - > nHeight - 1 ) ) ;
} else {
blockcount = request . params [ 0 ] . get_int ( ) ;
if ( blockcount < 0 | | ( blockcount > 0 & & blockcount > = pindex - > nHeight ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid block count: should be between 0 and the block's height - 1 " ) ;
}
2017-05-03 08:14:50 +02:00
}
const CBlockIndex * pindexPast = pindex - > GetAncestor ( pindex - > nHeight - blockcount ) ;
int nTimeDiff = pindex - > GetMedianTimePast ( ) - pindexPast - > GetMedianTimePast ( ) ;
int nTxDiff = pindex - > nChainTx - pindexPast - > nChainTx ;
UniValue ret ( UniValue : : VOBJ ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " time " , ( int64_t ) pindex - > nTime ) ;
ret . pushKV ( " txcount " , ( int64_t ) pindex - > nChainTx ) ;
ret . pushKV ( " window_final_block_hash " , pindex - > GetBlockHash ( ) . GetHex ( ) ) ;
2019-08-29 16:41:29 +02:00
ret . pushKV ( " window_final_block_height " , pindex - > nHeight ) ;
2020-06-18 11:17:23 +02:00
ret . pushKV ( " window_block_count " , blockcount ) ;
2017-10-02 15:21:26 +02:00
if ( blockcount > 0 ) {
2020-06-18 11:17:23 +02:00
ret . pushKV ( " window_tx_count " , nTxDiff ) ;
ret . pushKV ( " window_interval " , nTimeDiff ) ;
2017-10-02 15:21:26 +02:00
if ( nTimeDiff > 0 ) {
2020-06-18 11:17:23 +02:00
ret . pushKV ( " txrate " , ( ( double ) nTxDiff ) / nTimeDiff ) ;
2017-10-02 15:21:26 +02:00
}
}
2017-05-03 08:14:50 +02:00
return ret ;
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
template < typename T >
static T CalculateTruncatedMedian ( std : : vector < T > & scores )
{
size_t size = scores . size ( ) ;
if ( size = = 0 ) {
return 0 ;
}
std : : sort ( scores . begin ( ) , scores . end ( ) ) ;
if ( size % 2 = = 0 ) {
return ( scores [ size / 2 - 1 ] + scores [ size / 2 ] ) / 2 ;
} else {
return scores [ size / 2 ] ;
}
}
2018-08-13 13:18:00 +02:00
void CalculatePercentilesBySize ( CAmount result [ NUM_GETBLOCKSTATS_PERCENTILES ] , std : : vector < std : : pair < CAmount , int64_t > > & scores , int64_t total_size )
{
if ( scores . empty ( ) ) {
return ;
}
std : : sort ( scores . begin ( ) , scores . end ( ) ) ;
// 10th, 25th, 50th, 75th, and 90th percentile weight units.
const double weights [ NUM_GETBLOCKSTATS_PERCENTILES ] = {
total_size / 10.0 , total_size / 4.0 , total_size / 2.0 , ( total_size * 3.0 ) / 4.0 , ( total_size * 9.0 ) / 10.0
} ;
int64_t next_percentile_index = 0 ;
int64_t cumulative_weight = 0 ;
for ( const auto & element : scores ) {
cumulative_weight + = element . second ;
while ( next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES & & cumulative_weight > = weights [ next_percentile_index ] ) {
result [ next_percentile_index ] = element . first ;
+ + next_percentile_index ;
}
}
// Fill any remaining percentiles with the last value.
for ( int64_t i = next_percentile_index ; i < NUM_GETBLOCKSTATS_PERCENTILES ; i + + ) {
result [ i ] = scores . back ( ) . first ;
}
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
template < typename T >
static inline bool SetHasKeys ( const std : : set < T > & set ) { return false ; }
template < typename T , typename Tk , typename . . . Args >
static inline bool SetHasKeys ( const std : : set < T > & set , const Tk & key , const Args & . . . args )
{
return ( set . count ( key ) ! = 0 ) | | SetHasKeys ( set , args . . . ) ;
}
// outpoint (needed for the utxo index) + nHeight + fCoinBase
static constexpr size_t PER_UTXO_OVERHEAD = sizeof ( COutPoint ) + sizeof ( uint32_t ) + sizeof ( bool ) ;
static UniValue getblockstats ( const JSONRPCRequest & request )
{
2021-12-12 14:38:12 +01:00
const RPCHelpMan help { " getblockstats " ,
2021-10-11 23:55:23 +02:00
" \n Compute per block statistics for a given window. All amounts are in duffs. \n "
" It won't work for some heights with pruning. \n "
" It won't work without -txindex for utxo_size_inc, *fee or *feerate stats. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " hash_or_height " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The block hash or height of the target block " , " " , { " " , " string or numeric " } } ,
{ " stats " , RPCArg : : Type : : ARR , /* default */ " all values " , " Values to plot (see result below) " ,
2021-10-11 23:55:23 +02:00
{
2019-02-13 00:42:50 +01:00
{ " height " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " Selected statistic " } ,
{ " time " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " Selected statistic " } ,
2021-10-11 23:55:23 +02:00
} ,
2018-12-05 17:02:57 +01:00
" stats " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
" { (json object) \n "
" \" avgfee \" : xxxxx, (numeric) Average fee in the block \n "
" \" avgfeerate \" : xxxxx, (numeric) Average feerate (in duffs per byte) \n "
" \" avgtxsize \" : xxxxx, (numeric) Average transaction size \n "
" \" blockhash \" : xxxxx, (string) The block hash (to check for potential reorgs) \n "
2018-08-13 13:18:00 +02:00
" \" feerate_percentiles \" : [ (array of numeric) Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in duffs per byte) \n "
" \" 10th_percentile_feerate \" , (numeric) The 10th percentile feerate \n "
" \" 25th_percentile_feerate \" , (numeric) The 25th percentile feerate \n "
" \" 50th_percentile_feerate \" , (numeric) The 50th percentile feerate \n "
" \" 75th_percentile_feerate \" , (numeric) The 75th percentile feerate \n "
" \" 90th_percentile_feerate \" , (numeric) The 90th percentile feerate \n "
" ], \n "
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
" \" height \" : xxxxx, (numeric) The height of the block \n "
" \" ins \" : xxxxx, (numeric) The number of inputs (excluding coinbase) \n "
" \" maxfee \" : xxxxx, (numeric) Maximum fee in the block \n "
" \" maxfeerate \" : xxxxx, (numeric) Maximum feerate (in duffs per byte) \n "
" \" maxtxsize \" : xxxxx, (numeric) Maximum transaction size \n "
" \" medianfee \" : xxxxx, (numeric) Truncated median fee in the block \n "
" \" mediantime \" : xxxxx, (numeric) The block median time past \n "
" \" mediantxsize \" : xxxxx, (numeric) Truncated median transaction size \n "
" \" minfee \" : xxxxx, (numeric) Minimum fee in the block \n "
" \" minfeerate \" : xxxxx, (numeric) Minimum feerate (in duffs per byte) \n "
" \" mintxsize \" : xxxxx, (numeric) Minimum transaction size \n "
" \" outs \" : xxxxx, (numeric) The number of outputs \n "
" \" subsidy \" : xxxxx, (numeric) The block subsidy \n "
" \" time \" : xxxxx, (numeric) The block time \n "
" \" total_out \" : xxxxx, (numeric) Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee]) \n "
" \" total_size \" : xxxxx, (numeric) Total size of all non-coinbase transactions \n "
" \" totalfee \" : xxxxx, (numeric) The fee total \n "
" \" txs \" : xxxxx, (numeric) The number of transactions (excluding coinbase) \n "
" \" utxo_increase \" : xxxxx, (numeric) The increase/decrease in the number of unspent outputs \n "
" \" utxo_size_inc \" : xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar) \n "
" } \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples {
2020-04-20 13:15:21 +02:00
HelpExampleCli ( " getblockstats " , R " (' " 00000000 c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 " ' '[ " minfeerate " , " avgfeerate " ]') " ) +
HelpExampleCli ( " getblockstats " , R " (1000 '[ " minfeerate " , " avgfeerate " ]') " ) +
HelpExampleRpc ( " getblockstats " , R " ( " 00000000 c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 " , [ " minfeerate " , " avgfeerate " ]) " ) +
HelpExampleRpc ( " getblockstats " , R " (1000, [ " minfeerate " , " avgfeerate " ]) " )
2019-01-29 15:55:37 +01:00
} ,
2021-12-12 14:38:12 +01:00
} ;
if ( request . fHelp | | ! help . IsValidNumArgs ( request . params . size ( ) ) ) {
throw std : : runtime_error ( help . ToString ( ) ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
}
2021-05-25 12:48:04 +02:00
if ( g_txindex ) {
g_txindex - > BlockUntilSyncedToCurrentChain ( ) ;
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
LOCK ( cs_main ) ;
CBlockIndex * pindex ;
if ( request . params [ 0 ] . isNum ( ) ) {
const int height = request . params [ 0 ] . get_int ( ) ;
2021-10-16 12:54:22 +02:00
const int current_tip = : : ChainActive ( ) . Height ( ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
if ( height < 0 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Target block height %d is negative " , height ) ) ;
}
if ( height > current_tip ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Target block height %d after current tip %d " , height , current_tip ) ) ;
}
2021-10-16 12:54:22 +02:00
pindex = : : ChainActive ( ) [ height ] ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
} else {
const uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2021-10-16 19:42:59 +02:00
if ( : : BlockIndex ( ) . count ( hash ) = = 0 )
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2021-10-16 19:42:59 +02:00
pindex = : : BlockIndex ( ) [ hash ] ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
// pindex = LookupBlockIndex(hash);
// if (!pindex) {
// throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
// }
2021-10-16 12:54:22 +02:00
if ( ! : : ChainActive ( ) . Contains ( pindex ) ) {
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Block is not in chain %s " , Params ( ) . NetworkIDString ( ) ) ) ;
}
}
assert ( pindex ! = nullptr ) ;
std : : set < std : : string > stats ;
if ( ! request . params [ 1 ] . isNull ( ) ) {
const UniValue stats_univalue = request . params [ 1 ] . get_array ( ) ;
for ( unsigned int i = 0 ; i < stats_univalue . size ( ) ; i + + ) {
const std : : string stat = stats_univalue [ i ] . get_str ( ) ;
stats . insert ( stat ) ;
}
}
const CBlock block = GetBlockChecked ( pindex ) ;
const bool do_all = stats . size ( ) = = 0 ; // Calculate everything if nothing selected (default)
const bool do_mediantxsize = do_all | | stats . count ( " mediantxsize " ) ! = 0 ;
const bool do_medianfee = do_all | | stats . count ( " medianfee " ) ! = 0 ;
2018-08-13 13:18:00 +02:00
const bool do_feerate_percentiles = do_all | | stats . count ( " feerate_percentiles " ) ! = 0 ;
const bool loop_inputs = do_all | | do_medianfee | | do_feerate_percentiles | |
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
SetHasKeys ( stats , " utxo_size_inc " , " totalfee " , " avgfee " , " avgfeerate " , " minfee " , " maxfee " , " minfeerate " , " maxfeerate " ) ;
const bool loop_outputs = do_all | | loop_inputs | | stats . count ( " total_out " ) ;
const bool do_calculate_size = do_all | | do_mediantxsize | |
2018-08-13 13:18:00 +02:00
SetHasKeys ( stats , " total_size " , " avgtxsize " , " mintxsize " , " maxtxsize " , " avgfeerate " , " feerate_percentiles " , " minfeerate " , " maxfeerate " ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
2018-10-26 13:21:11 +02:00
if ( loop_inputs & & ! g_txindex ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " One or more of the selected stats requires -txindex enabled " ) ;
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
CAmount maxfee = 0 ;
CAmount maxfeerate = 0 ;
CAmount minfee = MAX_MONEY ;
CAmount minfeerate = MAX_MONEY ;
CAmount total_out = 0 ;
CAmount totalfee = 0 ;
int64_t inputs = 0 ;
int64_t maxtxsize = 0 ;
2020-12-15 22:54:51 +01:00
int64_t mintxsize = MaxBlockSize ( ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
int64_t outputs = 0 ;
int64_t total_size = 0 ;
int64_t utxo_size_inc = 0 ;
std : : vector < CAmount > fee_array ;
2018-08-13 13:18:00 +02:00
std : : vector < std : : pair < CAmount , int64_t > > feerate_array ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
std : : vector < int64_t > txsize_array ;
for ( const auto & tx : block . vtx ) {
outputs + = tx - > vout . size ( ) ;
CAmount tx_total_out = 0 ;
if ( loop_outputs ) {
for ( const CTxOut & out : tx - > vout ) {
tx_total_out + = out . nValue ;
utxo_size_inc + = GetSerializeSize ( out , SER_NETWORK , PROTOCOL_VERSION ) + PER_UTXO_OVERHEAD ;
}
}
if ( tx - > IsCoinBase ( ) ) {
continue ;
}
inputs + = tx - > vin . size ( ) ; // Don't count coinbase's fake input
total_out + = tx_total_out ; // Don't count coinbase reward
int64_t tx_size = 0 ;
if ( do_calculate_size ) {
tx_size = tx - > GetTotalSize ( ) ;
if ( do_mediantxsize ) {
txsize_array . push_back ( tx_size ) ;
}
maxtxsize = std : : max ( maxtxsize , tx_size ) ;
mintxsize = std : : min ( mintxsize , tx_size ) ;
total_size + = tx_size ;
}
if ( loop_inputs ) {
CAmount tx_total_in = 0 ;
for ( const CTxIn & in : tx - > vin ) {
CTransactionRef tx_in ;
uint256 hashBlock ;
2021-08-05 17:46:17 +02:00
if ( ! GetTransaction ( in . prevout . hash , tx_in , Params ( ) . GetConsensus ( ) , hashBlock ) ) {
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
throw JSONRPCError ( RPC_INTERNAL_ERROR , std : : string ( " Unexpected internal error (tx index seems corrupt) " )) ;
}
CTxOut prevoutput = tx_in - > vout [ in . prevout . n ] ;
tx_total_in + = prevoutput . nValue ;
utxo_size_inc - = GetSerializeSize ( prevoutput , SER_NETWORK , PROTOCOL_VERSION ) + PER_UTXO_OVERHEAD ;
}
CAmount txfee = tx_total_in - tx_total_out ;
assert ( MoneyRange ( txfee ) ) ;
if ( do_medianfee ) {
fee_array . push_back ( txfee ) ;
}
maxfee = std : : max ( maxfee , txfee ) ;
minfee = std : : min ( minfee , txfee ) ;
totalfee + = txfee ;
CAmount feerate = tx_size ? txfee / tx_size : 0 ;
2018-08-13 13:18:00 +02:00
if ( do_feerate_percentiles ) {
feerate_array . emplace_back ( std : : make_pair ( feerate , tx_size ) ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
}
maxfeerate = std : : max ( maxfeerate , feerate ) ;
minfeerate = std : : min ( minfeerate , feerate ) ;
}
}
2018-08-13 13:18:00 +02:00
CAmount feerate_percentiles [ NUM_GETBLOCKSTATS_PERCENTILES ] = { 0 } ;
CalculatePercentilesBySize ( feerate_percentiles , feerate_array , total_size ) ;
UniValue feerates_res ( UniValue : : VARR ) ;
for ( int64_t i = 0 ; i < NUM_GETBLOCKSTATS_PERCENTILES ; i + + ) {
feerates_res . push_back ( feerate_percentiles [ i ] ) ;
}
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
UniValue ret_all ( UniValue : : VOBJ ) ;
ret_all . pushKV ( " avgfee " , ( block . vtx . size ( ) > 1 ) ? totalfee / ( block . vtx . size ( ) - 1 ) : 0 ) ;
ret_all . pushKV ( " avgfeerate " , total_size ? totalfee / total_size : 0 ) ; // Unit: sat/byte
ret_all . pushKV ( " avgtxsize " , ( block . vtx . size ( ) > 1 ) ? total_size / ( block . vtx . size ( ) - 1 ) : 0 ) ;
ret_all . pushKV ( " blockhash " , pindex - > GetBlockHash ( ) . GetHex ( ) ) ;
2018-08-13 13:18:00 +02:00
ret_all . pushKV ( " feerate_percentiles " , feerates_res ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
ret_all . pushKV ( " height " , ( int64_t ) pindex - > nHeight ) ;
ret_all . pushKV ( " ins " , inputs ) ;
ret_all . pushKV ( " maxfee " , maxfee ) ;
ret_all . pushKV ( " maxfeerate " , maxfeerate ) ;
ret_all . pushKV ( " maxtxsize " , maxtxsize ) ;
ret_all . pushKV ( " medianfee " , CalculateTruncatedMedian ( fee_array ) ) ;
ret_all . pushKV ( " mediantime " , pindex - > GetMedianTimePast ( ) ) ;
ret_all . pushKV ( " mediantxsize " , CalculateTruncatedMedian ( txsize_array ) ) ;
ret_all . pushKV ( " minfee " , ( minfee = = MAX_MONEY ) ? 0 : minfee ) ;
ret_all . pushKV ( " minfeerate " , ( minfeerate = = MAX_MONEY ) ? 0 : minfeerate ) ;
2020-12-15 22:54:51 +01:00
ret_all . pushKV ( " mintxsize " , mintxsize = = MaxBlockSize ( ) ? 0 : mintxsize ) ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
ret_all . pushKV ( " outs " , outputs ) ;
ret_all . pushKV ( " subsidy " , pindex - > pprev ? GetBlockSubsidy ( pindex - > pprev - > nBits , pindex - > pprev - > nHeight , Params ( ) . GetConsensus ( ) ) : 50 * COIN ) ;
ret_all . pushKV ( " time " , pindex - > GetBlockTime ( ) ) ;
ret_all . pushKV ( " total_out " , total_out ) ;
ret_all . pushKV ( " total_size " , total_size ) ;
ret_all . pushKV ( " totalfee " , totalfee ) ;
ret_all . pushKV ( " txs " , ( int64_t ) block . vtx . size ( ) ) ;
ret_all . pushKV ( " utxo_increase " , outputs - inputs ) ;
ret_all . pushKV ( " utxo_size_inc " , utxo_size_inc ) ;
if ( do_all ) {
return ret_all ;
}
UniValue ret ( UniValue : : VOBJ ) ;
for ( const std : : string & stat : stats ) {
const UniValue & value = ret_all [ stat ] ;
if ( value . isNull ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Invalid selected statistic %s " , stat ) ) ;
}
ret . pushKV ( stat , value ) ;
}
return ret ;
}
2018-05-04 22:42:39 +02:00
static UniValue getspecialtxes ( const JSONRPCRequest & request )
2019-01-30 19:53:22 +01:00
{
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 5 )
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getspecialtxes " ,
" Returns an array of special transactions found in the specified block \n "
" \n If verbosity is 0, returns tx hash for each transaction. \n "
" If verbosity is 1, returns hex-encoded data for each transaction. \n "
" If verbosity is 2, returns an Object with information for each transaction. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The block hash " } ,
{ " type " , RPCArg : : Type : : NUM , /* default */ " -1 " , " Filter special txes by type, -1 means all types " } ,
{ " count " , RPCArg : : Type : : NUM , /* default */ " 10 " , " The number of transactions to return " } ,
{ " skip " , RPCArg : : Type : : NUM , /* default */ " 0 " , " The number of transactions to skip " } ,
{ " verbosity " , RPCArg : : Type : : NUM , /* default */ " 0 " , " 0 for hashes, 1 for hex-encoded data, and 2 for json object " } ,
} ,
RPCResults {
{ " for verbosity = 0 " ,
2019-01-30 19:53:22 +01:00
" [ \n "
" \" txid \" : \" xxxx \" , (string) The transaction id \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} , { " for verbosity = 1 " ,
2019-01-30 19:53:22 +01:00
" [ \n "
" \" data \" , (string) A string that is serialized, hex-encoded data for the transaction \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} , { " for verbosity = 2 " ,
2019-01-30 19:53:22 +01:00
" [ (array of Objects) The transactions in the format of the getrawtransaction RPC. \n "
" ..., \n "
" ] \n "
2021-11-05 19:47:35 +01:00
} } ,
RPCExamples {
HelpExampleCli ( " getspecialtxes " , " \" 00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2 \" " )
2019-01-30 19:53:22 +01:00
+ HelpExampleRpc ( " getspecialtxes " , " \" 00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2 \" " )
2021-11-05 19:47:35 +01:00
} ,
} . ToString ( ) ) ;
2019-01-30 19:53:22 +01:00
LOCK ( cs_main ) ;
std : : string strHash = request . params [ 0 ] . get_str ( ) ;
uint256 hash ( uint256S ( strHash ) ) ;
int nTxType = - 1 ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 1 ] . isNull ( ) ) {
2019-01-30 19:53:22 +01:00
nTxType = request . params [ 1 ] . get_int ( ) ;
}
int nCount = 10 ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 2 ] . isNull ( ) ) {
2019-01-30 19:53:22 +01:00
nCount = request . params [ 2 ] . get_int ( ) ;
if ( nCount < 0 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Negative count " ) ;
}
int nSkip = 0 ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 3 ] . isNull ( ) ) {
2019-01-30 19:53:22 +01:00
nSkip = request . params [ 3 ] . get_int ( ) ;
if ( nSkip < 0 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Negative skip " ) ;
}
int nVerbosity = 0 ;
2017-08-22 09:24:31 +02:00
if ( ! request . params [ 4 ] . isNull ( ) ) {
2019-01-30 19:53:22 +01:00
nVerbosity = request . params [ 4 ] . get_int ( ) ;
if ( nVerbosity < 0 | | nVerbosity > 2 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Verbosity must be in range 0..2 " ) ;
}
}
2021-10-16 19:42:59 +02:00
if ( : : BlockIndex ( ) . count ( hash ) = = 0 )
2019-01-30 19:53:22 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2021-10-16 19:42:59 +02:00
CBlockIndex * pblockindex = : : BlockIndex ( ) [ hash ] ;
Merge #10757: RPC: Introduce getblockstats to plot things (#3058)
* Merge #10757: RPC: Introduce getblockstats to plot things
41d0476f62269027ec2193a5f80d508d789de8aa Tests: Add data file (Anthony Towns)
4cbfb6aad9ba8fa17b5e7ed3e9a36dc8a24f1fcf Tests: Test new getblockstats RPC (Jorge Timón)
35e77a0288bcac5594ff25c10c9679a161cb730b RPC: Introduce getblockstats (Jorge Timón)
cda8e36f019dd181e5c3774961b4f1335e5602cb Refactor: RPC: Separate GetBlockChecked() from getblock() (Jorge Timón)
Pull request description:
It returns per block statistics about several things. It should be easy to add more if people think of other things to add or remove some if I went too far (but once written, why not keep it? EDIT: answer: not to test or maintain them).
The currently available options are: minfee,maxfee,totalfee,minfeerate,maxfeerate,avgfee,avgfeerate,txs,ins,outs (EDIT: see updated list in the rpc call documentation)
For the x axis, one can use height or block.nTime (I guess I could add mediantime if there's interest [EDIT: nobody showed interest but I implemented mediantime nonetheless, in fact there's no distinction between x or y axis anymore, that's for the caller to judge]).
To calculate fees, -txindex is required.
Tree-SHA512: 2b2787a3c7dc4a11df1fce62c8a4c748f5347d7f7104205d5f0962ffec1e0370c825b49fd4d58ce8ce86bf39d8453f698bcd46206eea505f077541ca7d59b18c
* Replace get_mocktime() usage with self.mocktime
2019-08-28 13:50:29 +02:00
const CBlock block = GetBlockChecked ( pblockindex ) ;
2019-01-30 19:53:22 +01:00
int nTxNum = 0 ;
UniValue result ( UniValue : : VARR ) ;
for ( const auto & tx : block . vtx )
{
if ( tx - > nVersion ! = 3 | | tx - > nType = = TRANSACTION_NORMAL // ensure it's in fact a special tx
| | ( nTxType ! = - 1 & & tx - > nType ! = nTxType ) ) { // ensure special tx type matches filter, if given
continue ;
}
nTxNum + + ;
if ( nTxNum < = nSkip ) continue ;
if ( nTxNum > nSkip + nCount ) break ;
switch ( nVerbosity )
{
case 0 : result . push_back ( tx - > GetHash ( ) . GetHex ( ) ) ; break ;
case 1 : result . push_back ( EncodeHexTx ( * tx ) ) ; break ;
case 2 :
{
UniValue objTx ( UniValue : : VOBJ ) ;
TxToJSON ( * tx , uint256 ( ) , objTx ) ;
result . push_back ( objTx ) ;
break ;
}
default : throw JSONRPCError ( RPC_INTERNAL_ERROR , " Unsupported verbosity " ) ;
}
}
return result ;
}
2018-05-04 22:42:39 +02:00
static UniValue savemempool ( const JSONRPCRequest & request )
2017-09-06 22:48:00 +02:00
{
if ( request . fHelp | | request . params . size ( ) ! = 0 ) {
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " savemempool " ,
2019-01-29 15:55:37 +01:00
" \n Dumps the mempool to disk. It will fail until the previous dump is fully loaded. \n " ,
{ } ,
RPCResults { } ,
RPCExamples {
HelpExampleCli ( " savemempool " , " " )
2017-09-06 22:48:00 +02:00
+ HelpExampleRpc ( " savemempool " , " " )
2019-01-29 15:55:37 +01:00
} ,
} . ToString ( ) ) ;
2017-09-06 22:48:00 +02:00
}
2019-05-01 16:06:11 +02:00
if ( ! : : mempool . IsLoaded ( ) ) {
2018-03-30 00:25:43 +02:00
throw JSONRPCError ( RPC_MISC_ERROR , " The mempool was not loaded yet " ) ;
}
2019-05-01 16:06:11 +02:00
if ( ! DumpMempool ( : : mempool ) ) {
2017-09-06 22:48:00 +02:00
throw JSONRPCError ( RPC_MISC_ERROR , " Unable to dump mempool to disk " ) ;
}
return NullUniValue ;
}
2018-01-15 22:23:44 +01:00
//! Search for a given set of pubkey scripts
bool FindScriptPubKey ( std : : atomic < int > & scan_progress , const std : : atomic < bool > & should_abort , int64_t & count , CCoinsViewCursor * cursor , const std : : set < CScript > & needles , std : : map < COutPoint , Coin > & out_results ) {
scan_progress = 0 ;
count = 0 ;
while ( cursor - > Valid ( ) ) {
COutPoint key ;
Coin coin ;
if ( ! cursor - > GetKey ( key ) | | ! cursor - > GetValue ( coin ) ) return false ;
if ( + + count % 8192 = = 0 ) {
boost : : this_thread : : interruption_point ( ) ;
if ( should_abort ) {
// allow to abort the scan via the abort reference
return false ;
}
}
if ( count % 256 = = 0 ) {
// update progress reference every 256 item
uint32_t high = 0x100 * * key . hash . begin ( ) + * ( key . hash . begin ( ) + 1 ) ;
scan_progress = ( int ) ( high * 100.0 / 65536.0 + 0.5 ) ;
}
if ( needles . count ( coin . out . scriptPubKey ) ) {
out_results . emplace ( key , coin ) ;
}
cursor - > Next ( ) ;
}
scan_progress = 100 ;
return true ;
}
/** RAII object to prevent concurrency issue when scanning the txout set */
static std : : mutex g_utxosetscan ;
static std : : atomic < int > g_scan_progress ;
static std : : atomic < bool > g_scan_in_progress ;
static std : : atomic < bool > g_should_abort_scan ;
class CoinsViewScanReserver
{
private :
bool m_could_reserve ;
public :
explicit CoinsViewScanReserver ( ) : m_could_reserve ( false ) { }
bool reserve ( ) {
assert ( ! m_could_reserve ) ;
std : : lock_guard < std : : mutex > lock ( g_utxosetscan ) ;
if ( g_scan_in_progress ) {
return false ;
}
g_scan_in_progress = true ;
m_could_reserve = true ;
return true ;
}
~ CoinsViewScanReserver ( ) {
if ( m_could_reserve ) {
std : : lock_guard < std : : mutex > lock ( g_utxosetscan ) ;
g_scan_in_progress = false ;
}
}
} ;
UniValue scantxoutset ( const JSONRPCRequest & request )
{
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 )
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " scantxoutset " ,
" \n EXPERIMENTAL warning: this call may be removed or changed in future releases. \n "
" \n Scans the unspent transaction output set for entries that match certain output descriptors. \n "
" Examples of output descriptors are: \n "
" addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK) \n "
" raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts \n "
" combo(<pubkey>) P2PK and P2PKH outputs for the given pubkey \n "
" pkh(<pubkey>) P2PKH outputs for the given pubkey \n "
" sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys \n "
" \n In the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one \n "
" or more path elements separated by \" / \" , and optionally ending in \" /* \" (unhardened), or \" /*' \" or \" /*h \" (hardened) to specify all \n "
" unhardened or hardened child keys. \n "
" In the latter case, a range needs to be specified by below if different from 1000. \n "
" For more information on output descriptors, see the documentation in the doc/descriptors.md file. \n " ,
{
2019-02-13 00:42:50 +01:00
{ " action " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The action to execute \n "
2018-12-05 17:02:57 +01:00
" \" start \" for starting a scan \n "
" \" abort \" for aborting the current scan (returns true when abort was successful) \n "
" \" status \" for progress report (in %) of the current scan " } ,
2019-12-15 13:06:59 +01:00
{ " scanobjects " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED , " Array of scan objects. Required for \" start \" action \n "
2018-12-05 17:02:57 +01:00
" Every scan object is either a string descriptor or an object: " ,
2021-10-11 23:55:23 +02:00
{
2019-02-13 00:42:50 +01:00
{ " descriptor " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " An output descriptor " } ,
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " An object with output descriptor and metadata " ,
2021-10-11 23:55:23 +02:00
{
2019-02-13 00:42:50 +01:00
{ " desc " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " An output descriptor " } ,
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
{ " range " , RPCArg : : Type : : RANGE , /* default */ " 1000 " , " The range of HD chain indexes to explore (either end or [begin,end]) " } ,
2021-10-11 23:55:23 +02:00
} ,
2018-12-05 17:02:57 +01:00
} ,
2021-10-11 23:55:23 +02:00
} ,
2018-12-05 17:02:57 +01:00
" [scanobjects,...] " } ,
2019-01-29 15:55:37 +01:00
} ,
RPCResult {
2018-01-15 22:23:44 +01:00
" { \n "
2019-09-09 08:08:32 +02:00
" \" success \" : true|false, (boolean) Whether the scan was completed \n "
" \" txouts \" : n, (numeric) The number of unspent transaction outputs scanned \n "
" \" height \" : n, (numeric) The current block height (index) \n "
" \" bestblock \" : \" hex \" , (string) The hash of the block at the tip of the chain \n "
2018-01-15 22:23:44 +01:00
" \" unspents \" : [ \n "
2019-09-09 08:08:32 +02:00
" { \n "
" \" txid \" : \" hash \" , (string) The transaction id \n "
" \" vout \" : n, (numeric) The vout value \n "
" \" scriptPubKey \" : \" script \" , (string) The script key \n "
" \" desc \" : \" descriptor \" , (string) A specialized descriptor for the matched scriptPubKey \n "
" \" amount \" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output \n "
" \" height \" : n, (numeric) Height of the unspent transaction output \n "
2018-01-15 22:23:44 +01:00
" } \n "
2019-09-09 08:08:32 +02:00
" ,...], \n "
" \" total_amount \" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + " \n "
2018-01-15 22:23:44 +01:00
" ] \n "
2019-01-29 15:55:37 +01:00
} ,
RPCExamples { " " } ,
} . ToString ( )
2018-01-15 22:23:44 +01:00
) ;
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VARR } ) ;
UniValue result ( UniValue : : VOBJ ) ;
if ( request . params [ 0 ] . get_str ( ) = = " status " ) {
CoinsViewScanReserver reserver ;
if ( reserver . reserve ( ) ) {
// no scan in progress
return NullUniValue ;
}
result . pushKV ( " progress " , g_scan_progress ) ;
return result ;
} else if ( request . params [ 0 ] . get_str ( ) = = " abort " ) {
CoinsViewScanReserver reserver ;
if ( reserver . reserve ( ) ) {
// reserve was possible which means no scan was running
return false ;
}
// set the abort flag
g_should_abort_scan = true ;
return true ;
} else if ( request . params [ 0 ] . get_str ( ) = = " start " ) {
CoinsViewScanReserver reserver ;
if ( ! reserver . reserve ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Scan already in progress, use action \" abort \" or \" status \" " ) ;
}
2019-12-15 13:06:59 +01:00
if ( request . params . size ( ) < 2 ) {
throw JSONRPCError ( RPC_MISC_ERROR , " scanobjects argument is required for the start action " ) ;
}
2018-01-15 22:23:44 +01:00
std : : set < CScript > needles ;
2018-10-13 03:22:22 +02:00
std : : map < CScript , std : : string > descriptors ;
2018-01-15 22:23:44 +01:00
CAmount total_in = 0 ;
// loop through the scan objects
for ( const UniValue & scanobject : request . params [ 1 ] . get_array ( ) . getValues ( ) ) {
2021-07-20 17:59:35 +02:00
std : : string desc_str ;
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
std : : pair < int64_t , int64_t > range = { 0 , 1000 } ;
2021-07-20 17:59:35 +02:00
if ( scanobject . isStr ( ) ) {
desc_str = scanobject . get_str ( ) ;
} else if ( scanobject . isObject ( ) ) {
UniValue desc_uni = find_value ( scanobject , " desc " ) ;
if ( desc_uni . isNull ( ) ) throw JSONRPCError ( RPC_INVALID_PARAMETER , " Descriptor needs to be provided in scan object " ) ;
desc_str = desc_uni . get_str ( ) ;
UniValue range_uni = find_value ( scanobject , " range " ) ;
if ( ! range_uni . isNull ( ) ) {
2019-05-10 14:09:34 +02:00
range = ParseDescriptorRange ( range_uni ) ;
2018-01-15 22:23:44 +01:00
}
2021-07-20 17:59:35 +02:00
} else {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Scan object needs to be either a string or an object " ) ;
}
2018-01-15 22:23:44 +01:00
2021-07-20 17:59:35 +02:00
FlatSigningProvider provider ;
2021-12-12 13:27:10 +01:00
std : : string error ;
auto desc = Parse ( desc_str , provider , error ) ;
2021-07-20 17:59:35 +02:00
if ( ! desc ) {
2021-12-12 13:27:10 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , error ) ;
2021-07-20 17:59:35 +02:00
}
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
if ( ! desc - > IsRange ( ) ) {
range . first = 0 ;
range . second = 0 ;
}
for ( int i = range . first ; i < = range . second ; + + i ) {
2021-07-20 17:59:35 +02:00
std : : vector < CScript > scripts ;
if ( ! desc - > Expand ( i , provider , scripts , provider ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " Cannot derive script without private keys: '%s' " , desc_str ) ) ;
2018-01-15 22:23:44 +01:00
}
2018-10-13 03:22:22 +02:00
for ( const auto & script : scripts ) {
std : : string inferred = InferDescriptor ( script , provider ) - > ToString ( ) ;
needles . emplace ( script ) ;
descriptors . emplace ( std : : move ( script ) , std : : move ( inferred ) ) ;
}
2018-01-15 22:23:44 +01:00
}
}
// Scan the unspent transaction output set for inputs
UniValue unspents ( UniValue : : VARR ) ;
std : : vector < CTxOut > input_txos ;
std : : map < COutPoint , Coin > coins ;
g_should_abort_scan = false ;
g_scan_progress = 0 ;
int64_t count = 0 ;
std : : unique_ptr < CCoinsViewCursor > pcursor ;
2019-09-09 08:08:32 +02:00
CBlockIndex * tip ;
2018-01-15 22:23:44 +01:00
{
LOCK ( cs_main ) ;
2021-10-09 16:14:44 +02:00
: : ChainstateActive ( ) . ForceFlushStateToDisk ( ) ;
2019-07-24 17:45:04 +02:00
pcursor = std : : unique_ptr < CCoinsViewCursor > ( : : ChainstateActive ( ) . CoinsDB ( ) . Cursor ( ) ) ;
2018-01-15 22:23:44 +01:00
assert ( pcursor ) ;
2019-09-09 08:08:32 +02:00
tip = : : ChainActive ( ) . Tip ( ) ;
assert ( tip ) ;
2018-01-15 22:23:44 +01:00
}
bool res = FindScriptPubKey ( g_scan_progress , g_should_abort_scan , count , pcursor . get ( ) , needles , coins ) ;
result . pushKV ( " success " , res ) ;
2019-09-09 08:08:32 +02:00
result . pushKV ( " txouts " , count ) ;
result . pushKV ( " height " , tip - > nHeight ) ;
result . pushKV ( " bestblock " , tip - > GetBlockHash ( ) . GetHex ( ) ) ;
2018-01-15 22:23:44 +01:00
for ( const auto & it : coins ) {
const COutPoint & outpoint = it . first ;
const Coin & coin = it . second ;
const CTxOut & txo = coin . out ;
input_txos . push_back ( txo ) ;
total_in + = txo . nValue ;
UniValue unspent ( UniValue : : VOBJ ) ;
unspent . pushKV ( " txid " , outpoint . hash . GetHex ( ) ) ;
unspent . pushKV ( " vout " , ( int32_t ) outpoint . n ) ;
2021-07-20 17:59:35 +02:00
unspent . pushKV ( " scriptPubKey " , HexStr ( txo . scriptPubKey ) ) ;
2018-10-13 03:22:22 +02:00
unspent . pushKV ( " desc " , descriptors [ txo . scriptPubKey ] ) ;
2018-01-15 22:23:44 +01:00
unspent . pushKV ( " amount " , ValueFromAmount ( txo . nValue ) ) ;
unspent . pushKV ( " height " , ( int32_t ) coin . nHeight ) ;
unspents . push_back ( unspent ) ;
}
result . pushKV ( " unspents " , unspents ) ;
result . pushKV ( " total_amount " , ValueFromAmount ( total_in ) ) ;
} else {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid command " ) ;
}
return result ;
}
2021-08-12 09:04:28 +02:00
static UniValue getblockfilter ( const JSONRPCRequest & request )
{
if ( request . fHelp | | request . params . size ( ) < 1 | | request . params . size ( ) > 2 ) {
throw std : : runtime_error (
2021-10-11 23:55:23 +02:00
RPCHelpMan { " getblockfilter " ,
" \n Retrieve a BIP 157 content filter for a particular block. \n " ,
{
2021-11-05 19:47:35 +01:00
{ " blockhash " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The hash of the block " } ,
{ " filtertype " , RPCArg : : Type : : STR , /* default */ " basic " , " The type name of the filter " } ,
} ,
RPCResult {
2021-08-12 09:04:28 +02:00
" { \n "
" \" filter \" : (string) the hex-encoded filter data \n "
" \" header \" : (string) the hex-encoded filter header \n "
" } \n "
2021-11-05 19:47:35 +01:00
} ,
RPCExamples {
HelpExampleCli ( " getblockfilter " , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 \" \" basic \" " )
} ,
} . ToString ( ) ) ;
2021-08-12 09:04:28 +02:00
}
uint256 block_hash = ParseHashV ( request . params [ 0 ] , " blockhash " ) ;
std : : string filtertype_name = " basic " ;
if ( ! request . params [ 1 ] . isNull ( ) ) {
filtertype_name = request . params [ 1 ] . get_str ( ) ;
}
BlockFilterType filtertype ;
if ( ! BlockFilterTypeByName ( filtertype_name , filtertype ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Unknown filtertype " ) ;
}
BlockFilterIndex * index = GetBlockFilterIndex ( filtertype ) ;
if ( ! index ) {
throw JSONRPCError ( RPC_MISC_ERROR , " Index is not enabled for filtertype " + filtertype_name ) ;
}
const CBlockIndex * block_index ;
bool block_was_connected ;
{
LOCK ( cs_main ) ;
block_index = LookupBlockIndex ( block_hash ) ;
if ( ! block_index ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
}
block_was_connected = block_index - > IsValid ( BLOCK_VALID_SCRIPTS ) ;
}
bool index_ready = index - > BlockUntilSyncedToCurrentChain ( ) ;
BlockFilter filter ;
uint256 filter_header ;
if ( ! index - > LookupFilter ( block_index , filter ) | |
! index - > LookupFilterHeader ( block_index , filter_header ) ) {
int err_code ;
std : : string errmsg = " Filter not found. " ;
if ( ! block_was_connected ) {
err_code = RPC_INVALID_ADDRESS_OR_KEY ;
errmsg + = " Block was not connected to active chain. " ;
} else if ( ! index_ready ) {
err_code = RPC_MISC_ERROR ;
errmsg + = " Block filters are still in the process of being indexed. " ;
} else {
err_code = RPC_INTERNAL_ERROR ;
errmsg + = " This error is unexpected and indicates index corruption. " ;
}
throw JSONRPCError ( err_code , errmsg ) ;
}
UniValue ret ( UniValue : : VOBJ ) ;
ret . pushKV ( " filter " , HexStr ( filter . GetEncodedFilter ( ) ) ) ;
ret . pushKV ( " header " , filter_header . GetHex ( ) ) ;
return ret ;
}
2018-09-10 18:13:11 +02:00
// clang-format off
2016-03-31 10:55:06 +02:00
static const CRPCCommand commands [ ] =
2017-09-05 18:43:07 +02:00
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
{ " blockchain " , " getblockchaininfo " , & getblockchaininfo , { } } ,
{ " blockchain " , " getchaintxstats " , & getchaintxstats , { " nblocks " , " blockhash " } } ,
{ " blockchain " , " getblockstats " , & getblockstats , { " hash_or_height " , " stats " } } ,
{ " blockchain " , " getbestblockhash " , & getbestblockhash , { } } ,
{ " blockchain " , " getbestchainlock " , & getbestchainlock , { } } ,
{ " blockchain " , " getblockcount " , & getblockcount , { } } ,
{ " blockchain " , " getblock " , & getblock , { " blockhash " , " verbosity|verbose " } } ,
{ " blockchain " , " getblockhashes " , & getblockhashes , { " high " , " low " } } ,
{ " blockchain " , " getblockhash " , & getblockhash , { " height " } } ,
{ " blockchain " , " getblockheader " , & getblockheader , { " blockhash " , " verbose " } } ,
{ " blockchain " , " getblockheaders " , & getblockheaders , { " blockhash " , " count " , " verbose " } } ,
{ " blockchain " , " getmerkleblocks " , & getmerkleblocks , { " filter " , " blockhash " , " count " } } ,
{ " blockchain " , " getchaintips " , & getchaintips , { " count " , " branchlen " } } ,
{ " blockchain " , " getdifficulty " , & getdifficulty , { } } ,
{ " blockchain " , " getmempoolancestors " , & getmempoolancestors , { " txid " , " verbose " } } ,
{ " blockchain " , " getmempooldescendants " , & getmempooldescendants , { " txid " , " verbose " } } ,
{ " blockchain " , " getmempoolentry " , & getmempoolentry , { " txid " } } ,
{ " blockchain " , " getmempoolinfo " , & getmempoolinfo , { } } ,
{ " blockchain " , " getrawmempool " , & getrawmempool , { " verbose " } } ,
{ " blockchain " , " getspecialtxes " , & getspecialtxes , { " blockhash " , " type " , " count " , " skip " , " verbosity " } } ,
{ " blockchain " , " gettxout " , & gettxout , { " txid " , " n " , " include_mempool " } } ,
{ " blockchain " , " gettxoutsetinfo " , & gettxoutsetinfo , { } } ,
{ " blockchain " , " pruneblockchain " , & pruneblockchain , { " height " } } ,
2017-09-06 22:48:00 +02:00
{ " blockchain " , " savemempool " , & savemempool , { } } ,
2017-09-05 18:43:07 +02:00
{ " blockchain " , " verifychain " , & verifychain , { " checklevel " , " nblocks " } } ,
{ " blockchain " , " preciousblock " , & preciousblock , { " blockhash " } } ,
2018-01-15 22:23:44 +01:00
{ " blockchain " , " scantxoutset " , & scantxoutset , { " action " , " scanobjects " } } ,
2021-08-12 09:04:28 +02:00
{ " blockchain " , " getblockfilter " , & getblockfilter , { " blockhash " , " filtertype " } } ,
2016-10-18 21:35:27 +02:00
2016-03-31 10:55:06 +02:00
/* Not shown in help */
2017-09-05 18:43:07 +02:00
{ " hidden " , " invalidateblock " , & invalidateblock , { " blockhash " } } ,
{ " hidden " , " reconsiderblock " , & reconsiderblock , { " blockhash " } } ,
{ " hidden " , " waitfornewblock " , & waitfornewblock , { " timeout " } } ,
{ " hidden " , " waitforblock " , & waitforblock , { " blockhash " , " timeout " } } ,
{ " hidden " , " waitforblockheight " , & waitforblockheight , { " height " , " timeout " } } ,
2018-01-18 14:26:21 +01:00
{ " hidden " , " syncwithvalidationinterfacequeue " , & syncwithvalidationinterfacequeue , { } } ,
2016-03-31 10:55:06 +02:00
} ;
2018-09-10 18:13:11 +02:00
// clang-format on
2016-03-31 10:55:06 +02:00
2016-08-31 16:04:22 +02:00
void RegisterBlockchainRPCCommands ( CRPCTable & t )
2016-03-31 10:55:06 +02:00
{
for ( unsigned int vcidx = 0 ; vcidx < ARRAYLEN ( commands ) ; vcidx + + )
2016-08-31 16:04:22 +02:00
t . appendCommand ( commands [ vcidx ] . name , & commands [ vcidx ] ) ;
2016-03-31 10:55:06 +02:00
}