181 lines
6.0 KiB
Python
181 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) 2014-2022 The Litecoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Random assortment of utility functions"""
|
|
|
|
import os
|
|
|
|
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, MWEBHeader
|
|
from test_framework.util import get_datadir_path, initialize_datadir, satoshi_round
|
|
from test_framework.script_util import DUMMY_P2WPKH_SCRIPT, hogaddr_script
|
|
from test_framework.test_node import TestNode
|
|
|
|
FIRST_MWEB_HEIGHT = 432 # Height of the first block to contain an MWEB if using default regtest params
|
|
|
|
|
|
"""Create a txout with a given amount and scriptPubKey
|
|
|
|
Mines coins as needed.
|
|
|
|
confirmed - txouts created will be confirmed in the blockchain;
|
|
unconfirmed otherwise.
|
|
|
|
Returns the 'COutPoint' of the UTXO
|
|
"""
|
|
def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
|
|
fee = 1*COIN
|
|
while node.getbalance() < satoshi_round((amount + fee)/COIN):
|
|
node.generate(100)
|
|
|
|
new_addr = node.getnewaddress()
|
|
txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
|
|
tx1 = node.getrawtransaction(txid, 1)
|
|
txid = int(txid, 16)
|
|
i = None
|
|
|
|
for i, txout in enumerate(tx1['vout']):
|
|
if txout['scriptPubKey']['addresses'] == [new_addr]:
|
|
break
|
|
assert i is not None
|
|
|
|
tx2 = CTransaction()
|
|
tx2.vin = [CTxIn(COutPoint(txid, i))]
|
|
tx2.vout = [CTxOut(amount, scriptPubKey)]
|
|
tx2.rehash()
|
|
|
|
signed_tx = node.signrawtransactionwithwallet(tx2.serialize().hex())
|
|
|
|
txid = node.sendrawtransaction(signed_tx['hex'], 0)
|
|
|
|
# If requested, ensure txouts are confirmed.
|
|
if confirmed:
|
|
mempool_size = len(node.getrawmempool())
|
|
while mempool_size > 0:
|
|
node.generate(1)
|
|
new_size = len(node.getrawmempool())
|
|
# Error out if we have something stuck in the mempool, as this
|
|
# would likely be a bug.
|
|
assert new_size < mempool_size
|
|
mempool_size = new_size
|
|
|
|
return COutPoint(int(txid, 16), 0)
|
|
|
|
|
|
"""Generates all pre-MWEB blocks, pegs 1 coin into the MWEB,
|
|
then mines the first MWEB block which includes that pegin.
|
|
|
|
mining_node - The node to use to generate blocks
|
|
"""
|
|
def setup_mweb_chain(mining_node):
|
|
# Create all pre-MWEB blocks
|
|
mining_node.generate(FIRST_MWEB_HEIGHT - 1)
|
|
|
|
# Pegin some coins
|
|
mining_node.sendtoaddress(mining_node.getnewaddress(address_type='mweb'), 1)
|
|
|
|
# Create some blocks - activate MWEB
|
|
mining_node.generate(1)
|
|
|
|
|
|
"""Retrieves the HogEx transaction for the block.
|
|
|
|
node - The node to use to lookup the transaction.
|
|
block_hash - The block to retrieve the HogEx for. If not provided, the best block hash will be used.
|
|
|
|
Returns the HogEx as a 'CTransaction'
|
|
"""
|
|
def get_hogex_tx(node, block_hash = None):
|
|
block_hash = block_hash or node.getbestblockhash()
|
|
hogex_tx_id = node.getblock(block_hash)['tx'][-1]
|
|
hogex_tx = FromHex(CTransaction(), node.getrawtransaction(hogex_tx_id, False, block_hash)) # TODO: Should validate that the tx is marked as a hogex tx
|
|
hogex_tx.rehash()
|
|
return hogex_tx
|
|
|
|
|
|
"""Retrieves the HogAddr for a block.
|
|
|
|
node - The node to use to lookup the HogAddr.
|
|
block_hash - The block to retrieve the HogAddr for. If not provided, the best block hash will be used.
|
|
|
|
Returns the HogAddr as a 'CTxOut'
|
|
"""
|
|
def get_hog_addr_txout(node, block_hash = None):
|
|
return get_hogex_tx(node, block_hash).vout[0]
|
|
|
|
|
|
"""Retrieves the MWEB header for a block.
|
|
|
|
node - The node to use to lookup the MWEB header.
|
|
block_hash - The block to retrieve the MWEB header for. If not provided, the best block hash will be used.
|
|
|
|
Returns the MWEB header as an 'MWEBHeader' or None if the block doesn't contain MWEB data.
|
|
"""
|
|
def get_mweb_header(node, block_hash = None):
|
|
block_hash = block_hash or node.getbestblockhash()
|
|
best_block = node.getblock(block_hash, 2)
|
|
if not 'mweb' in best_block:
|
|
return None
|
|
|
|
mweb_header = MWEBHeader()
|
|
mweb_header.from_json(best_block['mweb'])
|
|
return mweb_header
|
|
|
|
|
|
"""Creates a HogEx transaction that commits to the provided MWEB hash.
|
|
# TODO: In the future, this should support passing in pegins and pegouts.
|
|
|
|
node - The node to use to lookup the latest block.
|
|
mweb_hash - The block to retrieve the MWEB header for. If not provided, the best block hash will be used.
|
|
|
|
Returns the built HogEx transaction as a 'CTransaction'
|
|
"""
|
|
def create_hogex(node, mweb_hash):
|
|
hogex_tx = get_hogex_tx(node)
|
|
|
|
tx = CTransaction()
|
|
tx.vin = [CTxIn(COutPoint(hogex_tx.sha256, 0))]
|
|
tx.vout = [CTxOut(hogex_tx.vout[0].nValue, hogaddr_script(mweb_hash.to_byte_arr()))]
|
|
tx.hogex = True
|
|
tx.rehash()
|
|
return tx
|
|
|
|
|
|
""" Create a non-HD wallet from a temporary v15.1.0 node.
|
|
|
|
Returns the path of the wallet.dat.
|
|
"""
|
|
def create_non_hd_wallet(chain, options):
|
|
version = 150100
|
|
bin_dir = os.path.join(options.previous_releases_path, 'v0.15.1', 'bin')
|
|
initialize_datadir(options.tmpdir, 10, chain)
|
|
data_dir = get_datadir_path(options.tmpdir, 10)
|
|
|
|
# adjust conf for pre 17
|
|
conf_file = os.path.join(data_dir, 'litecoin.conf')
|
|
with open(conf_file, 'r', encoding='utf8') as conf:
|
|
conf_data = conf.read()
|
|
with open(conf_file, 'w', encoding='utf8') as conf:
|
|
conf.write(conf_data.replace('[regtest]', ''))
|
|
|
|
v15_node = TestNode(
|
|
i=10,
|
|
datadir=data_dir,
|
|
chain=chain,
|
|
rpchost=None,
|
|
timewait=60,
|
|
timeout_factor=1.0,
|
|
bitcoind=os.path.join(bin_dir, 'litecoind'),
|
|
bitcoin_cli=os.path.join(bin_dir, 'litecoin-cli'),
|
|
version=version,
|
|
coverage_dir=None,
|
|
cwd=options.tmpdir,
|
|
extra_args=["-usehd=0"],
|
|
)
|
|
v15_node.start()
|
|
v15_node.wait_for_cookie_credentials() # ensure cookie file is available to avoid race condition
|
|
v15_node.wait_for_rpc_connection()
|
|
v15_node.stop_node(wait=0)
|
|
v15_node.wait_until_stopped()
|
|
|
|
return os.path.join(v15_node.datadir, chain, "wallet.dat") |