@ -6,13 +6,15 @@
Test the following RPCs :
- getblockchaininfo
- getchaintxstats
- gettxoutsetinfo
- getdifficulty
- getbestblockhash
- getblockhash
- getblockheader
- get chaintxstats
- getdifficulty
- getnetworkhashps
- waitforblockheight
- getblock
- getblockhash
- getbestblockhash
- verifychain
Tests correspond to code in rpc / blockchain . cpp .
@ -49,6 +51,12 @@ from test_framework.util import (
from test_framework . wallet import MiniWallet
HEIGHT = 200 # blocks mined
TIME_RANGE_STEP = 600 # ten-minute steps
TIME_RANGE_MTP = TIME_GENESIS_BLOCK + ( HEIGHT - 6 ) * TIME_RANGE_STEP
TIME_RANGE_END = TIME_GENESIS_BLOCK + HEIGHT * TIME_RANGE_STEP
class BlockchainTest ( BitcoinTestFramework ) :
def set_test_params ( self ) :
self . setup_clean_chain = True
@ -71,12 +79,11 @@ class BlockchainTest(BitcoinTestFramework):
assert self . nodes [ 0 ] . verifychain ( 4 , 0 )
def mine_chain ( self ) :
self . log . info ( ' Create some old blocks ' )
for t in range ( TIME_GENESIS_BLOCK , TIME_GENESIS_BLOCK + 200 * 600 , 600 ) :
# ten-minute steps from genesis block time
self . log . info ( f " Generate { HEIGHT } blocks after the genesis block in ten-minute steps " )
for t in range ( TIME_GENESIS_BLOCK , TIME_RANGE_END , TIME_RANGE_STEP ) :
self . nodes [ 0 ] . setmocktime ( t )
self . nodes [ 0 ] . generatetoaddress ( 1 , ADDRESS_BCRT1_P2WSH_OP_TRUE )
assert_equal ( self . nodes [ 0 ] . getblockchaininfo ( ) [ ' blocks ' ] , 200 )
assert_equal ( self . nodes [ 0 ] . getblockchaininfo ( ) [ ' blocks ' ] , HEIGHT )
def _test_getblockchaininfo ( self ) :
self . log . info ( " Test getblockchaininfo " )
@ -99,7 +106,8 @@ class BlockchainTest(BitcoinTestFramework):
]
res = self . nodes [ 0 ] . getblockchaininfo ( )
assert isinstance ( res [ ' time ' ] , int )
assert_equal ( res [ ' time ' ] , TIME_RANGE_END - TIME_RANGE_STEP )
assert_equal ( res [ ' mediantime ' ] , TIME_RANGE_MTP )
# result should have these additional pruning keys if manual pruning is enabled
assert_equal ( sorted ( res . keys ( ) ) , sorted ( [ ' pruneheight ' , ' automatic_pruning ' ] + keys ) )
@ -148,8 +156,8 @@ class BlockchainTest(BitcoinTestFramework):
' statistics ' : {
' period ' : 144 ,
' threshold ' : 108 ,
' elapsed ' : 57 ,
' count ' : 57 ,
' elapsed ' : HEIGHT - 143 ,
' count ' : HEIGHT - 143 ,
' possible ' : True ,
} ,
' min_activation_height ' : 0 ,
@ -186,33 +194,33 @@ class BlockchainTest(BitcoinTestFramework):
assert_raises_rpc_error ( - 8 , " blockhash must be of length 64 (not 1, for ' 0 ' ) " , self . nodes [ 0 ] . getchaintxstats , blockhash = ' 0 ' )
assert_raises_rpc_error ( - 8 , " blockhash must be hexadecimal string (not ' ZZZ0000000000000000000000000000000000000000000000000000000000000 ' ) " , self . nodes [ 0 ] . getchaintxstats , blockhash = ' ZZZ0000000000000000000000000000000000000000000000000000000000000 ' )
assert_raises_rpc_error ( - 5 , " Block not found " , self . nodes [ 0 ] . getchaintxstats , blockhash = ' 0000000000000000000000000000000000000000000000000000000000000000 ' )
blockhash = self . nodes [ 0 ] . getblockhash ( 200 )
blockhash = self . nodes [ 0 ] . getblockhash ( HEIGHT )
self . nodes [ 0 ] . invalidateblock ( blockhash )
assert_raises_rpc_error ( - 8 , " Block is not in main chain " , self . nodes [ 0 ] . getchaintxstats , blockhash = blockhash )
self . nodes [ 0 ] . reconsiderblock ( blockhash )
chaintxstats = self . nodes [ 0 ] . getchaintxstats ( nblocks = 1 )
# 200 txs plus genesis tx
assert_equal ( chaintxstats [ ' txcount ' ] , 20 1)
assert_equal ( chaintxstats [ ' txcount ' ] , HEIGHT + 1)
# tx rate should be 1 per 10 minutes, or 1/600
# we have to round because of binary math
assert_equal ( round ( chaintxstats [ ' txrate ' ] * 600 , 10 ) , Decimal ( 1 ) )
assert_equal ( round ( chaintxstats [ ' txrate ' ] * TIME_RANGE_STEP , 10 ) , Decimal ( 1 ) )
b1_hash = self . nodes [ 0 ] . getblockhash ( 1 )
b1 = self . nodes [ 0 ] . getblock ( b1_hash )
b200_hash = self . nodes [ 0 ] . getblockhash ( 200 )
b200_hash = self . nodes [ 0 ] . getblockhash ( HEIGHT )
b200 = self . nodes [ 0 ] . getblock ( b200_hash )
time_diff = b200 [ ' mediantime ' ] - b1 [ ' mediantime ' ]
chaintxstats = self . nodes [ 0 ] . getchaintxstats ( )
assert_equal ( chaintxstats [ ' time ' ] , b200 [ ' time ' ] )
assert_equal ( chaintxstats [ ' txcount ' ] , 20 1)
assert_equal ( chaintxstats [ ' txcount ' ] , HEIGHT + 1)
assert_equal ( chaintxstats [ ' window_final_block_hash ' ] , b200_hash )
assert_equal ( chaintxstats [ ' window_final_block_height ' ] , 200 )
assert_equal ( chaintxstats [ ' window_block_count ' ] , 1 99 )
assert_equal ( chaintxstats [ ' window_tx_count ' ] , 1 99 )
assert_equal ( chaintxstats [ ' window_final_block_height ' ] , HEIGHT )
assert_equal ( chaintxstats [ ' window_block_count ' ] , HEIGHT - 1 )
assert_equal ( chaintxstats [ ' window_tx_count ' ] , HEIGHT - 1 )
assert_equal ( chaintxstats [ ' window_interval ' ] , time_diff )
assert_equal ( round ( chaintxstats [ ' txrate ' ] * time_diff , 10 ) , Decimal ( 1 99 ) )
assert_equal ( round ( chaintxstats [ ' txrate ' ] * time_diff , 10 ) , Decimal ( HEIGHT - 1 ) )
chaintxstats = self . nodes [ 0 ] . getchaintxstats ( blockhash = b1_hash )
assert_equal ( chaintxstats [ ' time ' ] , b1 [ ' time ' ] )
@ -229,18 +237,18 @@ class BlockchainTest(BitcoinTestFramework):
res = node . gettxoutsetinfo ( )
assert_equal ( res [ ' total_amount ' ] , Decimal ( ' 8725.00000000 ' ) )
assert_equal ( res [ ' transactions ' ] , 200 )
assert_equal ( res [ ' height ' ] , 200 )
assert_equal ( res [ ' txouts ' ] , 200 )
assert_equal ( res [ ' transactions ' ] , HEIGHT )
assert_equal ( res [ ' height ' ] , HEIGHT )
assert_equal ( res [ ' txouts ' ] , HEIGHT )
assert_equal ( res [ ' bogosize ' ] , 16800 ) ,
assert_equal ( res [ ' bestblock ' ] , node . getblockhash ( 200 ) )
assert_equal ( res [ ' bestblock ' ] , node . getblockhash ( HEIGHT ) )
size = res [ ' disk_size ' ]
assert size > 6400
assert size < 64000
assert_equal ( len ( res [ ' bestblock ' ] ) , 64 )
assert_equal ( len ( res [ ' hash_serialized_2 ' ] ) , 64 )
self . log . info ( " Test that gettxoutsetinfo() works for blockchain with just the genesis block" )
self . log . info ( " Test gettxoutsetinfo works for blockchain with just the genesis block" )
b1hash = node . getblockhash ( 1 )
node . invalidateblock ( b1hash )
@ -253,7 +261,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal ( res2 [ ' bestblock ' ] , node . getblockhash ( 0 ) )
assert_equal ( len ( res2 [ ' hash_serialized_2 ' ] ) , 64 )
self . log . info ( " Test that gettxoutsetinfo() returns the same result after invalidate/reconsider block" )
self . log . info ( " Test gettxoutsetinfo returns the same result after invalidate/reconsider block" )
node . reconsiderblock ( b1hash )
res3 = node . gettxoutsetinfo ( )
@ -262,7 +270,7 @@ class BlockchainTest(BitcoinTestFramework):
del res [ ' disk_size ' ] , res3 [ ' disk_size ' ]
assert_equal ( res , res3 )
self . log . info ( " Test hash_type option for gettxoutsetinfo() " )
self . log . info ( " Test gettxoutsetinfo hash_type option" )
# Adding hash_type 'hash_serialized_2', which is the default, should
# not change the result.
res4 = node . gettxoutsetinfo ( hash_type = ' hash_serialized_2 ' )
@ -286,6 +294,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_raises_rpc_error ( - 8 , " foohash is not a valid hash_type " , node . gettxoutsetinfo , " foohash " )
def _test_getblockheader ( self ) :
self . log . info ( " Test getblockheader " )
node = self . nodes [ 0 ]
assert_raises_rpc_error ( - 8 , " hash must be of length 64 (not 8, for ' nonsense ' ) " , node . getblockheader , " nonsense " )
@ -293,11 +302,11 @@ class BlockchainTest(BitcoinTestFramework):
assert_raises_rpc_error ( - 5 , " Block not found " , node . getblockheader , " 0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844 " )
besthash = node . getbestblockhash ( )
secondbesthash = node . getblockhash ( 1 99 )
secondbesthash = node . getblockhash ( HEIGHT - 1 )
header = node . getblockheader ( blockhash = besthash )
assert_equal ( header [ ' hash ' ] , besthash )
assert_equal ( header [ ' height ' ] , 200 )
assert_equal ( header [ ' height ' ] , HEIGHT )
assert_equal ( header [ ' confirmations ' ] , 1 )
assert_equal ( header [ ' previousblockhash ' ] , secondbesthash )
assert_is_hex_string ( header [ ' chainwork ' ] )
@ -307,7 +316,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_is_hash_string ( header [ ' merkleroot ' ] )
assert_is_hash_string ( header [ ' bits ' ] , length = None )
assert isinstance ( header [ ' time ' ] , int )
assert isinstance ( header [ ' mediantime ' ] , int )
assert_equal ( header [ ' mediantime ' ] , TIME_RANGE_MTP )
assert isinstance ( header [ ' nonce ' ] , int )
assert isinstance ( header [ ' version ' ] , int )
assert isinstance ( int ( header [ ' versionHex ' ] , 16 ) , int )
@ -325,20 +334,23 @@ class BlockchainTest(BitcoinTestFramework):
assert ' nextblockhash ' not in node . getblockheader ( node . getbestblockhash ( ) )
def _test_getdifficulty ( self ) :
self . log . info ( " Test getdifficulty " )
difficulty = self . nodes [ 0 ] . getdifficulty ( )
# 1 hash in 2 should be valid, so difficulty should be 1/2**31
# binary => decimal => binary math is why we do this check
assert abs ( difficulty * 2 * * 31 - 1 ) < 0.0001
def _test_getnetworkhashps ( self ) :
self . log . info ( " Test getnetworkhashps " )
hashes_per_second = self . nodes [ 0 ] . getnetworkhashps ( )
# This should be 2 hashes every 10 minutes or 1/300
assert abs ( hashes_per_second * 300 - 1 ) < 0.0001
def _test_stopatheight ( self ) :
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , 200 )
self . log . info ( " Test stopping at height " )
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , HEIGHT )
self . nodes [ 0 ] . generatetoaddress ( 6 , ADDRESS_BCRT1_P2WSH_OP_TRUE )
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , 20 6)
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , HEIGHT + 6)
self . log . debug ( ' Node should not stop at this height ' )
assert_raises ( subprocess . TimeoutExpired , lambda : self . nodes [ 0 ] . process . wait ( timeout = 3 ) )
try :
@ -348,7 +360,7 @@ class BlockchainTest(BitcoinTestFramework):
self . log . debug ( ' Node should stop at this height... ' )
self . nodes [ 0 ] . wait_until_stopped ( )
self . start_node ( 0 )
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , 20 7)
assert_equal ( self . nodes [ 0 ] . getblockcount ( ) , HEIGHT + 7)
def _test_waitforblockheight ( self ) :
self . log . info ( " Test waitforblockheight " )
@ -400,20 +412,20 @@ class BlockchainTest(BitcoinTestFramework):
miniwallet . send_self_transfer ( fee_rate = fee_per_kb , from_node = node )
blockhash = node . generate ( 1 ) [ 0 ]
self . log . info ( " Test that getblock with verbosity 1 doesn' t include fee " )
self . log . info ( " Test getblock with verbosity 1 doesn' t include fee " )
block = node . getblock ( blockhash , 1 )
assert ' fee ' not in block [ ' tx ' ] [ 1 ]
self . log . info ( ' Test that getblock with verbosity 2 includes expected fee' )
self . log . info ( ' Test getblock with verbosity 2 includes expected fee' )
block = node . getblock ( blockhash , 2 )
tx = block [ ' tx ' ] [ 1 ]
assert ' fee ' in tx
assert_equal ( tx [ ' fee ' ] , tx [ ' vsize ' ] * fee_per_byte )
self . log . info ( " Test that getblock with verbosity 2 still works with pruned Undo data" )
self . log . info ( " Test getblock with verbosity 2 still works with pruned Undo data" )
datadir = get_datadir_path ( self . options . tmpdir , 0 )
self . log . info ( " Test that getblock with invalid verbosity type returns proper error message" )
self . log . info ( " Test getblock with invalid verbosity type returns proper error message" )
assert_raises_rpc_error ( - 1 , " JSON value is not an integer as expected " , node . getblock , blockhash , " 2 " )
def move_block_file ( old , new ) :