add unit tests for ln_utxo_reserve
This commit is contained in:
6
tests/cause_carbon_wallet.json
Normal file
6
tests/cause_carbon_wallet.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"seed": "cause carbon luggage air humble mistake melt paper supreme sense gravity void",
|
||||||
|
"funding_tx": "020000000001021798e10f8b7220c57ea0d605316a52453ca9b3eed99996b5b7bdf4699548bb520000000000fdffffff277d82678d238ca45dd3490ac9fbb49272f0980b093b9197ff70ec8eb082cfb00100000000fdffffff028c360100000000001600147a9bfd90821be827275023849dd91ee80d494957a08601000000000016001476efaaa243327bf3a2c0f5380cb3914099448cec024730440220354b2a74f5ac039cca3618f7ff98229d243b89ac40550c8b027894f2c5cb88ff022064cb5ab1539b4c5367c2e01a8362e0aa12c2732bc8d08c3fce6eab9e56b7fe19012103e0a1499cb3d8047492c60466722c435dfbcffae8da9b83e758fbd203d12728f502473044022073cef8b0cfb093aed5b8eaacbb58c2fa6a69405a8e266cd65e76b726c9151d7602204d5820b23ab96acc57c272aac96d94740a20a6b89c016aa5aed7c06d1e6b9100012102f09e50a265c6a0dcf7c87153ea73d7b12a0fbe9d7d0bbec5db626b2402c1e85c02fa2400",
|
||||||
|
"outgoing_address": "tb1qkfn0fude7z789uys2u7sf80kd4805zpvs3na0h",
|
||||||
|
"to_self_address": "tb1qyfnv3y866ufedugxxxfksyratv4pz3h78g9dad"
|
||||||
|
}
|
||||||
@@ -14,7 +14,9 @@ from electrum.lnsweep import SweepInfo
|
|||||||
from electrum.fee_policy import FeeTimeEstimates
|
from electrum.fee_policy import FeeTimeEstimates
|
||||||
|
|
||||||
from . import ElectrumTestCase
|
from . import ElectrumTestCase
|
||||||
from .test_wallet_vertical import WalletIntegrityHelper
|
from .test_wallet_vertical import WalletIntegrityHelper, read_test_vector
|
||||||
|
|
||||||
|
WALLET_DATA = read_test_vector('cause_carbon_wallet.json')
|
||||||
|
|
||||||
class MockNetwork(Logger):
|
class MockNetwork(Logger):
|
||||||
|
|
||||||
@@ -49,8 +51,6 @@ class MockNetwork(Logger):
|
|||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
||||||
WALLET_SEED = 'cause carbon luggage air humble mistake melt paper supreme sense gravity void'
|
|
||||||
FUNDING_TX = '020000000001021798e10f8b7220c57ea0d605316a52453ca9b3eed99996b5b7bdf4699548bb520000000000fdffffff277d82678d238ca45dd3490ac9fbb49272f0980b093b9197ff70ec8eb082cfb00100000000fdffffff028c360100000000001600147a9bfd90821be827275023849dd91ee80d494957a08601000000000016001476efaaa243327bf3a2c0f5380cb3914099448cec024730440220354b2a74f5ac039cca3618f7ff98229d243b89ac40550c8b027894f2c5cb88ff022064cb5ab1539b4c5367c2e01a8362e0aa12c2732bc8d08c3fce6eab9e56b7fe19012103e0a1499cb3d8047492c60466722c435dfbcffae8da9b83e758fbd203d12728f502473044022073cef8b0cfb093aed5b8eaacbb58c2fa6a69405a8e266cd65e76b726c9151d7602204d5820b23ab96acc57c272aac96d94740a20a6b89c016aa5aed7c06d1e6b9100012102f09e50a265c6a0dcf7c87153ea73d7b12a0fbe9d7d0bbec5db626b2402c1e85c02fa2400'
|
|
||||||
SWAP_FUNDING_TX = "01000000000101500e9d67647481864edfb020b5c45e1c40d90f06b0130f9faed1a5149c6d26450000000000ffffffff0226080300000000002200205059c44bf57534303ab8f090f06b7bde58f5d2522440247a1ff6b41bdca9348df312c20100000000160014021d4f3b17921d790e1c022367a5bb078ce4deb402483045022100d41331089a2031396a1db8e4dec6dda9cacefe1288644b92f8e08a23325aa19b02204159230691601f7d726e4e6e0b7124d3377620f400d699a01095f0b0a09ee26a012102d60315c72c0cefd41c6d07883c20b88be3fc37aac7912f0052722a95de0de71600000000"
|
SWAP_FUNDING_TX = "01000000000101500e9d67647481864edfb020b5c45e1c40d90f06b0130f9faed1a5149c6d26450000000000ffffffff0226080300000000002200205059c44bf57534303ab8f090f06b7bde58f5d2522440247a1ff6b41bdca9348df312c20100000000160014021d4f3b17921d790e1c022367a5bb078ce4deb402483045022100d41331089a2031396a1db8e4dec6dda9cacefe1288644b92f8e08a23325aa19b02204159230691601f7d726e4e6e0b7124d3377620f400d699a01095f0b0a09ee26a012102d60315c72c0cefd41c6d07883c20b88be3fc37aac7912f0052722a95de0de71600000000"
|
||||||
SWAP_CLAIM_TX = "02000000000101f9db8580febd5c0f85b6f1576c83f7739109e3a2d772743e3217e9537fea7e890000000000fdffffff017005030000000000160014b113a47f3718da3fd161339a6681c150fef2cfe30347304402206736066ce15d34eed20951a9d974a100a72dc034f9c878769ddf27f9a584dcb1022042b14d627b8e8465a3a129bb43c0bd8369f49bbcf473879b9a477263655f1f930120f1939b5723155713855d7ebea6e174f77d41d669269e7f138856c3de190e7a366a8201208763a914d7a62ef0270960fe23f0f351b28caadab62c21838821030bfd61153816df786036ea293edce851d3a4b9f4a1c66bdc1a17f00ffef3d6b167750334ef24b1752102fc8128f17f9e666ea281c702171ab16c1dd2a4337b71f08970f5aa10c608a93268ac00000000"
|
SWAP_CLAIM_TX = "02000000000101f9db8580febd5c0f85b6f1576c83f7739109e3a2d772743e3217e9537fea7e890000000000fdffffff017005030000000000160014b113a47f3718da3fd161339a6681c150fef2cfe30347304402206736066ce15d34eed20951a9d974a100a72dc034f9c878769ddf27f9a584dcb1022042b14d627b8e8465a3a129bb43c0bd8369f49bbcf473879b9a477263655f1f930120f1939b5723155713855d7ebea6e174f77d41d669269e7f138856c3de190e7a366a8201208763a914d7a62ef0270960fe23f0f351b28caadab62c21838821030bfd61153816df786036ea293edce851d3a4b9f4a1c66bdc1a17f00ffef3d6b167750334ef24b1752102fc8128f17f9e666ea281c702171ab16c1dd2a4337b71f08970f5aa10c608a93268ac00000000"
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class TestTxBatcher(ElectrumTestCase):
|
|||||||
return WalletIntegrityHelper.create_standard_wallet(ks, gap_limit=gap_limit, config=config)
|
return WalletIntegrityHelper.create_standard_wallet(ks, gap_limit=gap_limit, config=config)
|
||||||
|
|
||||||
def _create_wallet(self):
|
def _create_wallet(self):
|
||||||
wallet = self.create_standard_wallet_from_seed(WALLET_SEED)
|
wallet = self.create_standard_wallet_from_seed(WALLET_DATA["seed"])
|
||||||
wallet.start_network(self.network)
|
wallet.start_network(self.network)
|
||||||
wallet.txbatcher.SLEEP_INTERVAL = 0.01
|
wallet.txbatcher.SLEEP_INTERVAL = 0.01
|
||||||
self.network.wallets.append(wallet)
|
self.network.wallets.append(wallet)
|
||||||
@@ -99,7 +99,7 @@ class TestTxBatcher(ElectrumTestCase):
|
|||||||
OUTGOING_ADDRESS = 'tb1q7rl9cxr85962ztnsze089zs8ycv52hk43f3m9n'
|
OUTGOING_ADDRESS = 'tb1q7rl9cxr85962ztnsze089zs8ycv52hk43f3m9n'
|
||||||
wallet = self._create_wallet()
|
wallet = self._create_wallet()
|
||||||
# fund wallet
|
# fund wallet
|
||||||
funding_tx = Transaction(FUNDING_TX)
|
funding_tx = Transaction(WALLET_DATA["funding_tx"])
|
||||||
await self.network.try_broadcasting(funding_tx, 'funding')
|
await self.network.try_broadcasting(funding_tx, 'funding')
|
||||||
await self.network.next_tx()
|
await self.network.next_tx()
|
||||||
assert wallet.adb.get_transaction(funding_tx.txid()) is not None
|
assert wallet.adb.get_transaction(funding_tx.txid()) is not None
|
||||||
@@ -140,9 +140,8 @@ class TestTxBatcher(ElectrumTestCase):
|
|||||||
The tx batcher fails to batch, and should create a child transaction
|
The tx batcher fails to batch, and should create a child transaction
|
||||||
"""
|
"""
|
||||||
wallet = self._create_wallet()
|
wallet = self._create_wallet()
|
||||||
|
|
||||||
# fund wallet
|
# fund wallet
|
||||||
funding_tx = Transaction(FUNDING_TX)
|
funding_tx = Transaction(WALLET_DATA['funding_tx'])
|
||||||
await self.network.try_broadcasting(funding_tx, 'funding')
|
await self.network.try_broadcasting(funding_tx, 'funding')
|
||||||
await self.network.next_tx()
|
await self.network.next_tx()
|
||||||
assert wallet.adb.get_transaction(funding_tx.txid()) is not None
|
assert wallet.adb.get_transaction(funding_tx.txid()) is not None
|
||||||
|
|||||||
@@ -82,6 +82,14 @@ class WalletIntegrityHelper:
|
|||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def read_test_vector(filename: str):
|
||||||
|
import os
|
||||||
|
from electrum.util import read_json_file
|
||||||
|
path = os.path.join(os.path.dirname(__file__), filename)
|
||||||
|
data = read_json_file(path)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase):
|
class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -2005,27 +2013,69 @@ class TestWalletSending(ElectrumTestCase):
|
|||||||
wallet.adb.receive_tx_callback(tx, TX_HEIGHT_UNCONFIRMED)
|
wallet.adb.receive_tx_callback(tx, TX_HEIGHT_UNCONFIRMED)
|
||||||
self.assertEqual((0, 3_900_000, 0), wallet.get_balance())
|
self.assertEqual((0, 3_900_000, 0), wallet.get_balance())
|
||||||
|
|
||||||
|
def _create_cause_carbon_wallet(self):
|
||||||
|
data = read_test_vector('cause_carbon_wallet.json')
|
||||||
|
ks = keystore.from_seed(data['seed'], passphrase='', for_multisig=False)
|
||||||
|
wallet = WalletIntegrityHelper.create_standard_wallet(ks, gap_limit=2, config=self.config)
|
||||||
|
# bootstrap wallet (incoming funding_tx0)
|
||||||
|
funding_tx = Transaction(data['funding_tx'])
|
||||||
|
wallet.adb.receive_tx_callback(funding_tx, TX_HEIGHT_UNCONFIRMED)
|
||||||
|
return wallet, data['outgoing_address'], data['to_self_address']
|
||||||
|
|
||||||
|
async def test_ln_reserve_send_everything(self):
|
||||||
|
""" send all the coins, not using 'max' """
|
||||||
|
wallet, outgoing_address, to_self_address = self._create_cause_carbon_wallet()
|
||||||
|
balance = sum(wallet.get_balance())
|
||||||
|
assert balance == 100_000
|
||||||
|
fee_sats = 1000
|
||||||
|
outputs = [PartialTxOutput.from_address_and_value(outgoing_address, balance - fee_sats)]
|
||||||
|
def make_tx(b):
|
||||||
|
return wallet.make_unsigned_transaction(
|
||||||
|
outputs = outputs,
|
||||||
|
is_anchor_channel_opening = b,
|
||||||
|
fee_policy = FixedFeePolicy(fee_sats),
|
||||||
|
)
|
||||||
|
tx = make_tx(False)
|
||||||
|
self.assertEqual(1, len(tx.outputs()))
|
||||||
|
with self.assertRaises(NotEnoughFunds):
|
||||||
|
make_tx(True)
|
||||||
|
|
||||||
|
async def test_ln_reserve_spend_max(self):
|
||||||
|
""" send all the coins using 'max'. test with outgoing and to self address """
|
||||||
|
wallet, outgoing_address, to_self_address = self._create_cause_carbon_wallet()
|
||||||
|
def make_tx(address):
|
||||||
|
outputs = [PartialTxOutput.from_address_and_value(address, '!')]
|
||||||
|
return wallet.make_unsigned_transaction(
|
||||||
|
outputs = outputs,
|
||||||
|
is_anchor_channel_opening = True,
|
||||||
|
fee_policy = FixedFeePolicy(100),
|
||||||
|
)
|
||||||
|
tx = make_tx(outgoing_address)
|
||||||
|
self.assertEqual(2, len(tx.outputs()))
|
||||||
|
tx = make_tx(to_self_address)
|
||||||
|
self.assertEqual(1, len(tx.outputs()))
|
||||||
|
|
||||||
async def test_rbf_batching__cannot_batch_as_would_need_to_use_ismine_outputs_of_basetx(self):
|
async def test_rbf_batching__cannot_batch_as_would_need_to_use_ismine_outputs_of_basetx(self):
|
||||||
"""Wallet history contains unconf tx1 that spends all its coins to two ismine outputs,
|
"""Wallet history contains unconf tx1 that spends all its coins to two ismine outputs,
|
||||||
one 'recv' address (20k sats) and one 'change' (80k sats).
|
one 'recv' address (20k sats) and one 'change' (80k sats).
|
||||||
The user tries to create tx2, that pays an invoice for 90k sats.
|
The user tries to create tx2, that pays an invoice for 90k sats.
|
||||||
Even if batch_rbf==True, no batching should be done. Instead, the outputs of tx1 should be used.
|
Even if batch_rbf==True, no batching should be done. Instead, the outputs of tx1 should be used.
|
||||||
"""
|
"""
|
||||||
wallet = self.create_standard_wallet_from_seed('cause carbon luggage air humble mistake melt paper supreme sense gravity void',
|
wallet, outgoing_address, to_self_address = self._create_cause_carbon_wallet()
|
||||||
config=self.config)
|
|
||||||
|
|
||||||
# bootstrap wallet (incoming funding_tx0)
|
|
||||||
funding_tx = Transaction('020000000001021798e10f8b7220c57ea0d605316a52453ca9b3eed99996b5b7bdf4699548bb520000000000fdffffff277d82678d238ca45dd3490ac9fbb49272f0980b093b9197ff70ec8eb082cfb00100000000fdffffff028c360100000000001600147a9bfd90821be827275023849dd91ee80d494957a08601000000000016001476efaaa243327bf3a2c0f5380cb3914099448cec024730440220354b2a74f5ac039cca3618f7ff98229d243b89ac40550c8b027894f2c5cb88ff022064cb5ab1539b4c5367c2e01a8362e0aa12c2732bc8d08c3fce6eab9e56b7fe19012103e0a1499cb3d8047492c60466722c435dfbcffae8da9b83e758fbd203d12728f502473044022073cef8b0cfb093aed5b8eaacbb58c2fa6a69405a8e266cd65e76b726c9151d7602204d5820b23ab96acc57c272aac96d94740a20a6b89c016aa5aed7c06d1e6b9100012102f09e50a265c6a0dcf7c87153ea73d7b12a0fbe9d7d0bbec5db626b2402c1e85c02fa2400')
|
|
||||||
funding_txid = funding_tx.txid()
|
|
||||||
wallet.adb.receive_tx_callback(funding_tx, TX_HEIGHT_UNCONFIRMED)
|
|
||||||
|
|
||||||
# to_self_payment tx1
|
# to_self_payment tx1
|
||||||
toself_tx = Transaction('02000000000101ce05b8ae96fe8d2875fd1efcb591b6fb5c5d924bf05d75d880a0e44498fe14b80100000000fdffffff02204e0000000000001600142266c890fad71396f106319368107d5b2a1146feb837010000000000160014b113a47f3718da3fd161339a6681c150fef2cfe3024730440220197bfea1bc5c86c35d68029422342de97c1e5d9adc12e48d99ae359940211a660220770ddb228ae75698f827e2fddc574f0c8eb2a3e109678a2a2b6bc9cbb9593b1c012102b07ca318381fcef5998f34ee4197e96c17aa19867cbe99c544d321807db95ed2f1f92400')
|
outputs = [PartialTxOutput.from_address_and_value(to_self_address, 20_000)]
|
||||||
|
toself_tx = wallet.make_unsigned_transaction(
|
||||||
|
outputs = outputs,
|
||||||
|
fee_policy = FixedFeePolicy(200),
|
||||||
|
locktime = 2423281,
|
||||||
|
rbf = True,
|
||||||
|
)
|
||||||
|
wallet.sign_transaction(toself_tx, password=None)
|
||||||
toself_txid = toself_tx.txid()
|
toself_txid = toself_tx.txid()
|
||||||
wallet.adb.receive_tx_callback(toself_tx, TX_HEIGHT_UNCONFIRMED)
|
wallet.adb.receive_tx_callback(toself_tx, TX_HEIGHT_UNCONFIRMED)
|
||||||
|
|
||||||
# create outgoing tx2
|
# create outgoing tx2
|
||||||
outputs = [PartialTxOutput.from_address_and_value("tb1qkfn0fude7z789uys2u7sf80kd4805zpvs3na0h", 90_000)]
|
outputs = [PartialTxOutput.from_address_and_value(outgoing_address, 90_000)]
|
||||||
coins = wallet.get_spendable_coins(domain=None)
|
coins = wallet.get_spendable_coins(domain=None)
|
||||||
self.assertEqual(2, len(coins))
|
self.assertEqual(2, len(coins))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user