2018-01-16 07:34:07 +01:00
#!/usr/bin/env python3
2019-02-21 02:03:13 +01:00
# Copyright (c) 2018-2019 The Bitcoin Core developers
2018-01-16 07:34:07 +01:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
""" Test the scantxoutset rpc call. """
from test_framework . test_framework import BitcoinTestFramework
2019-04-04 09:39:04 +02:00
from test_framework . util import assert_equal , assert_raises_rpc_error
2018-01-16 07:34:07 +01:00
2018-07-07 00:10:35 +02:00
from decimal import Decimal
2018-01-16 07:34:07 +01:00
import shutil
import os
2018-10-19 03:40:25 +02:00
def descriptors ( out ) :
return sorted ( u [ ' desc ' ] for u in out [ ' unspents ' ] )
2018-01-16 07:34:07 +01:00
class ScantxoutsetTest ( BitcoinTestFramework ) :
def set_test_params ( self ) :
self . num_nodes = 1
self . setup_clean_chain = True
2018-09-09 19:32:37 +02:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2018-01-16 07:34:07 +01:00
def run_test ( self ) :
self . log . info ( " Mining blocks... " )
self . nodes [ 0 ] . generate ( 110 )
addr_P2SH_SEGWIT = self . nodes [ 0 ] . getnewaddress ( " " , " p2sh-segwit " )
pubk1 = self . nodes [ 0 ] . getaddressinfo ( addr_P2SH_SEGWIT ) [ ' pubkey ' ]
addr_LEGACY = self . nodes [ 0 ] . getnewaddress ( " " , " legacy " )
pubk2 = self . nodes [ 0 ] . getaddressinfo ( addr_LEGACY ) [ ' pubkey ' ]
addr_BECH32 = self . nodes [ 0 ] . getnewaddress ( " " , " bech32 " )
pubk3 = self . nodes [ 0 ] . getaddressinfo ( addr_BECH32 ) [ ' pubkey ' ]
2019-09-20 17:33:17 +02:00
self . nodes [ 0 ] . sendtoaddress ( addr_P2SH_SEGWIT , 0.00002 )
self . nodes [ 0 ] . sendtoaddress ( addr_LEGACY , 0.00004 )
self . nodes [ 0 ] . sendtoaddress ( addr_BECH32 , 0.00008 )
2018-07-27 11:11:01 +02:00
#send to child keys of tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK
2019-09-20 17:33:17 +02:00
self . nodes [ 0 ] . sendtoaddress ( " mkHV1C6JLheLoUSSZYk7x3FH5tnx9bu7yc " , 0.00016 ) # (m/0'/0'/0')
self . nodes [ 0 ] . sendtoaddress ( " mipUSRmJAj2KrjSvsPQtnP8ynUon7FhpCR " , 0.00032 ) # (m/0'/0'/1')
self . nodes [ 0 ] . sendtoaddress ( " n37dAGe6Mq1HGM9t4b6rFEEsDGq7Fcgfqg " , 0.00064 ) # (m/0'/0'/1500')
self . nodes [ 0 ] . sendtoaddress ( " mqS9Rpg8nNLAzxFExsgFLCnzHBsoQ3PRM6 " , 0.00128 ) # (m/0'/0'/0)
self . nodes [ 0 ] . sendtoaddress ( " mnTg5gVWr3rbhHaKjJv7EEEc76ZqHgSj4S " , 0.00256 ) # (m/0'/0'/1)
self . nodes [ 0 ] . sendtoaddress ( " mketCd6B9U9Uee1iCsppDJJBHfvi6U6ukC " , 0.00512 ) # (m/0'/0'/1500)
self . nodes [ 0 ] . sendtoaddress ( " mj8zFzrbBcdaWXowCQ1oPZ4qioBVzLzAp7 " , 0.01024 ) # (m/1/1/0')
self . nodes [ 0 ] . sendtoaddress ( " mfnKpKQEftniaoE1iXuMMePQU3PUpcNisA " , 0.02048 ) # (m/1/1/1')
self . nodes [ 0 ] . sendtoaddress ( " mou6cB1kaP1nNJM1sryW6YRwnd4shTbXYQ " , 0.04096 ) # (m/1/1/1500')
self . nodes [ 0 ] . sendtoaddress ( " mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ " , 0.08192 ) # (m/1/1/0)
self . nodes [ 0 ] . sendtoaddress ( " mxp7w7j8S1Aq6L8StS2PqVvtt4HGxXEvdy " , 0.16384 ) # (m/1/1/1)
self . nodes [ 0 ] . sendtoaddress ( " mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq " , 0.32768 ) # (m/1/1/1500)
2018-07-27 20:49:26 +02:00
2018-07-27 11:11:01 +02:00
2018-01-16 07:34:07 +01:00
self . nodes [ 0 ] . generate ( 1 )
self . log . info ( " Stop node, remove wallet, mine again some blocks... " )
self . stop_node ( 0 )
shutil . rmtree ( os . path . join ( self . nodes [ 0 ] . datadir , " regtest " , ' wallets ' ) )
self . start_node ( 0 )
self . nodes [ 0 ] . generate ( 110 )
2019-06-25 18:03:50 +02:00
scan = self . nodes [ 0 ] . scantxoutset ( " start " , [ ] )
info = self . nodes [ 0 ] . gettxoutsetinfo ( )
assert_equal ( scan [ ' success ' ] , True )
assert_equal ( scan [ ' height ' ] , info [ ' height ' ] )
assert_equal ( scan [ ' txouts ' ] , info [ ' txouts ' ] )
assert_equal ( scan [ ' bestblock ' ] , info [ ' bestblock ' ] )
2018-01-16 07:34:07 +01:00
self . restart_node ( 0 , [ ' -nowallet ' ] )
self . log . info ( " Test if we have found the non HD unspent outputs. " )
2019-09-20 17:33:17 +02:00
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " pkh( " + pubk1 + " ) " , " pkh( " + pubk2 + " ) " , " pkh( " + pubk3 + " ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00004 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " wpkh( " + pubk1 + " ) " , " wpkh( " + pubk2 + " ) " , " wpkh( " + pubk3 + " ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00008 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " sh(wpkh( " + pubk1 + " )) " , " sh(wpkh( " + pubk2 + " )) " , " sh(wpkh( " + pubk3 + " )) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00002 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo( " + pubk1 + " ) " , " combo( " + pubk2 + " ) " , " combo( " + pubk3 + " ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00014 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " addr( " + addr_P2SH_SEGWIT + " ) " , " addr( " + addr_LEGACY + " ) " , " addr( " + addr_BECH32 + " ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00014 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " addr( " + addr_P2SH_SEGWIT + " ) " , " addr( " + addr_LEGACY + " ) " , " combo( " + pubk3 + " ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00014 " ) )
2018-01-16 07:34:07 +01:00
2019-04-04 09:39:04 +02:00
self . log . info ( " Test range validation. " )
assert_raises_rpc_error ( - 8 , " End of range is too high " , self . nodes [ 0 ] . scantxoutset , " start " , [ { " desc " : " desc " , " range " : - 1 } ] )
assert_raises_rpc_error ( - 8 , " Range should be greater or equal than 0 " , self . nodes [ 0 ] . scantxoutset , " start " , [ { " desc " : " desc " , " range " : [ - 1 , 10 ] } ] )
assert_raises_rpc_error ( - 8 , " End of range is too high " , self . nodes [ 0 ] . scantxoutset , " start " , [ { " desc " : " desc " , " range " : [ ( 2 << 31 + 1 ) - 1000000 , ( 2 << 31 + 1 ) ] } ] )
assert_raises_rpc_error ( - 8 , " Range specified as [begin,end] must not have begin after end " , self . nodes [ 0 ] . scantxoutset , " start " , [ { " desc " : " desc " , " range " : [ 2 , 1 ] } ] )
assert_raises_rpc_error ( - 8 , " Range is too large " , self . nodes [ 0 ] . scantxoutset , " start " , [ { " desc " : " desc " , " range " : [ 0 , 1000001 ] } ] )
2018-07-27 11:11:01 +02:00
self . log . info ( " Test extended key derivation. " )
2018-09-03 23:04:31 +02:00
# Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.
# Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.
2019-09-20 17:33:17 +02:00
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0 ' /1500 ' ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00064 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/0) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00128 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0 ' /0h/1) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00256 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0 ' /1500) " ] ) [ ' total_amount ' ] , Decimal ( " 0.00512 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0 ' /0h/*h) " , " range " : 1499 } ] ) [ ' total_amount ' ] , Decimal ( " 0.00048 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0 ' /0 ' /*h) " , " range " : 1500 } ] ) [ ' total_amount ' ] , Decimal ( " 0.00112 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0 ' /*) " , " range " : 1499 } ] ) [ ' total_amount ' ] , Decimal ( " 0.00384 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0 ' /0h/*) " , " range " : 1500 } ] ) [ ' total_amount ' ] , Decimal ( " 0.00896 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0 ' ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.01024 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1 ' ) " ] ) [ ' total_amount ' ] , Decimal ( " 0.02048 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500h) " ] ) [ ' total_amount ' ] , Decimal ( " 0.04096 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0) " ] ) [ ' total_amount ' ] , Decimal ( " 0.08192 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1) " ] ) [ ' total_amount ' ] , Decimal ( " 0.16384 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500) " ] ) [ ' total_amount ' ] , Decimal ( " 0.32768 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0) " ] ) [ ' total_amount ' ] , Decimal ( " 0.08192 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1) " ] ) [ ' total_amount ' ] , Decimal ( " 0.16384 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500) " ] ) [ ' total_amount ' ] , Decimal ( " 0.32768 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo([abcdef88/1/2 ' /3/4h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1) " ] ) [ ' total_amount ' ] , Decimal ( " 0.16384 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/* ' ) " , " range " : 1500 } ] ) [ ' total_amount ' ] , Decimal ( " 0.07168 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*) " , " range " : 1499 } ] ) [ ' total_amount ' ] , Decimal ( " 0.24576 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*) " , " range " : 1500 } ] ) [ ' total_amount ' ] , Decimal ( " 0.57344 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*) " , " range " : 1499 } ] ) [ ' total_amount ' ] , Decimal ( " 0.24576 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*) " , " range " : 1500 } ] ) [ ' total_amount ' ] , Decimal ( " 0.57344 " ) )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*) " , " range " : [ 1500 , 1500 ] } ] ) [ ' total_amount ' ] , Decimal ( " 0.32768 " ) )
2018-01-16 07:34:07 +01:00
2018-10-19 03:40:25 +02:00
# Test the reported descriptors for a few matches
2019-02-07 03:08:21 +01:00
assert_equal ( descriptors ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0 ' /*) " , " range " : 1499 } ] ) ) , [ " pkh([0c5f9a1e/0 ' /0 ' /0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x " , " pkh([0c5f9a1e/0 ' /0 ' /1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed " ] )
assert_equal ( descriptors ( self . nodes [ 0 ] . scantxoutset ( " start " , [ " combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0) " ] ) ) , [ " pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8 " ] )
assert_equal ( descriptors ( self . nodes [ 0 ] . scantxoutset ( " start " , [ { " desc " : " combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*) " , " range " : 1500 } ] ) ) , [ ' pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8 ' , ' pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g ' , ' pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa ' ] )
2018-10-19 03:40:25 +02:00
2019-12-11 23:11:20 +01:00
# Check that status and abort don't need second arg
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " status " ) , None )
assert_equal ( self . nodes [ 0 ] . scantxoutset ( " abort " ) , False )
# Check that second arg is needed for start
assert_raises_rpc_error ( - 1 , " scanobjects argument is required for the start action " , self . nodes [ 0 ] . scantxoutset , " start " )
2018-01-16 07:34:07 +01:00
if __name__ == ' __main__ ' :
ScantxoutsetTest ( ) . main ( )