commit 7b6f64a402bf4836cae4ab825988ed07cdeaf75e
parent 52ae63990ff9c3af19c10256cbfdebb9de776937
Author: ThomasV <thomasv@electrum.org>
Date: Fri, 13 Apr 2018 15:17:14 +0200
lnbase: create unit test for commitment tx
Diffstat:
2 files changed, 93 insertions(+), 28 deletions(-)
diff --git a/lib/lnbase.py b/lib/lnbase.py
@@ -21,12 +21,12 @@ import hashlib
import hmac
import cryptography.hazmat.primitives.ciphers.aead as AEAD
-from .bitcoin import public_key_from_private_key, ser_to_point, point_to_ser, string_to_number, deserialize_privkey, EC_KEY, rev_hex
+from .bitcoin import public_key_from_private_key, ser_to_point, point_to_ser, string_to_number, deserialize_privkey, EC_KEY, rev_hex, int_to_hex
from . import bitcoin
from .constants import set_testnet, set_simnet
from . import constants
from . import transaction
-from .util import PrintError, bh2u
+from .util import PrintError, bh2u, print_error
from .wallet import Wallet
from .storage import WalletStorage
from .transaction import opcodes, Transaction
@@ -248,6 +248,45 @@ def aiosafe(f):
traceback.print_exc()
return f2
+def get_locktime(cn, local, remote):
+ print_error(len(local), len(remote))
+ q = local + remote
+ mask = int.from_bytes(H256(q)[-6:], byteorder="big")
+ print_error('mask', hex(mask))
+ obs = cn ^ mask
+ print_error('obs ', hex(obs))
+ locktime = (0x20 << 48) + obs
+ return locktime
+
+def make_commitment(local_pubkey, remote_pubkey, payment_pubkey, remote_payment_pubkey, revocation_pubkey, delayed_pubkey, funding_txid, funding_pos, funding_satoshis):
+ pubkeys = sorted([bh2u(local_pubkey), bh2u(remote_pubkey)])
+ # commitment tx input
+ c_inputs = [{
+ 'type': 'p2wsh',
+ 'x_pubkeys': pubkeys,
+ 'signatures':[None, None],
+ 'num_sig': 2,
+ 'prevout_n': funding_pos,
+ 'prevout_hash': funding_txid,
+ 'value': funding_satoshis,
+ 'coinbase': False
+ }]
+ # commitment tx outputs
+ local_script = bytes([opcodes.OP_IF]) + revocation_pubkey + bytes([opcodes.OP_ELSE, opcodes.OP_CSV, opcodes.OP_DROP]) + delayed_pubkey + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
+ local_address = bitcoin.redeem_script_to_address('p2wsh', bh2u(local_script))
+ local_amount = funding_satoshis
+ remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remote_pubkey))
+ remote_amount = 0
+ to_local = (bitcoin.TYPE_ADDRESS, local_address, local_amount)
+ to_remote = (bitcoin.TYPE_ADDRESS, remote_address, remote_amount)
+ # no htlc for the moment
+ c_outputs = [to_local, to_remote]
+ # create commitment tx
+ locktime = get_locktime(0, payment_pubkey, remote_payment_pubkey)
+ print_error('locktime', locktime, hex(locktime))
+ tx = Transaction.from_io(c_inputs, c_outputs, locktime=locktime, version=2)
+ return tx
+
class Peer(PrintError):
def __init__(self, host, port, pubkey):
@@ -418,36 +457,13 @@ class Peer(PrintError):
pubkeys = sorted([bh2u(funding_pubkey), bh2u(remote_pubkey)])
redeem_script = transaction.multisig_script(pubkeys, 2)
funding_address = bitcoin.redeem_script_to_address('p2wsh', redeem_script)
- #TODO support passwd, fix fee
funding_output = (bitcoin.TYPE_ADDRESS, funding_address, funding_satoshis)
funding_tx = wallet.mktx([funding_output], None, config, 1000)
funding_index = funding_tx.outputs().index(funding_output)
- # commitment tx input
- c_inputs = [{
- 'type': 'p2wsh',
- 'x_pubkeys': pubkeys,
- 'signatures':[None, None],
- 'num_sig': 2,
- 'prevout_n': funding_index,
- 'prevout_hash': funding_tx.txid(),
- 'value': funding_satoshis,
- 'coinbase': False
- }]
- # commitment tx outputs
- local_script = bytes([opcodes.OP_IF]) + revocation_pubkey + bytes([opcodes.OP_ELSE, opcodes.OP_CSV, opcodes.OP_DROP]) + delayed_pubkey + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
- local_address = bitcoin.redeem_script_to_address('p2wsh', bh2u(local_script))
- local_amount = funding_satoshis
- remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remote_pubkey))
- remote_amount = 0
- to_local = (bitcoin.TYPE_ADDRESS, local_address, local_amount)
- to_remote = (bitcoin.TYPE_ADDRESS, remote_address, remote_amount)
- # no htlc for the moment
- c_outputs = [to_local, to_remote]
- # create commitment tx
- c_tx = Transaction.from_io(c_inputs, c_outputs)
+ remote_payment_pubkey = accept_channel['payment_basepoint']
+ c_tx = make_commitment(funding_pubkey, remote_pubkey, payment_pubkey, remote_payment_pubkey, revocation_pubkey, delayed_pubkey, funding_tx.txid(), funding_index, funding_satoshis)
c_tx.sign({bh2u(funding_pubkey): (funding_privkey, True)})
- #
- self.print_error('ctx inputs', c_tx.inputs())
+
sig_index = pubkeys.index(bh2u(funding_pubkey))
sig = bytes.fromhex(c_tx.inputs()[0]["signatures"][sig_index])
self.print_error('sig', len(sig))
diff --git a/lib/tests/test_lnbase.py b/lib/tests/test_lnbase.py
@@ -0,0 +1,49 @@
+import unittest
+from lib.util import bh2u
+from lib.lnbase import make_commitment, get_locktime
+
+class Test_LNBase(unittest.TestCase):
+
+ def test_commitment_tx(self):
+
+ funding_tx_id = '8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be'
+ funding_output_index = 0
+ funding_amount_satoshi = 10000000
+ commitment_number = 42
+ local_delay = 144
+ local_dust_limit_satoshi = 546
+
+ local_payment_basepoint = bytes.fromhex('034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa')
+ remote_payment_basepoint = bytes.fromhex('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991')
+ locktime = get_locktime(42, local_payment_basepoint, remote_payment_basepoint)
+
+ local_funding_privkey = bytes.fromhex('30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f374901')
+ local_funding_pubkey = bytes.fromhex('023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb')
+ remote_funding_pubkey = bytes.fromhex('030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1')
+ local_privkey = bytes.fromhex('bb13b121cdc357cd2e608b0aea294afca36e2b34cf958e2e6451a2f27469449101')
+ localpubkey = bytes.fromhex('030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7')
+ remotepubkey = bytes.fromhex('0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b')
+ local_delayedpubkey = bytes.fromhex('03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c')
+ local_revocation_pubkey = bytes.fromhex('0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19')
+ # funding wscript = 5221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae
+
+ #name: simple commitment tx with no HTLCs
+ to_local_msat = 7000000000
+ to_remote_msat = 3000000000
+ local_feerate_per_kw = 15000
+ # base commitment transaction fee = 10860
+ # actual commitment transaction fee = 10860
+ # to_local amount 6989140 wscript 63210212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b1967029000b2752103fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c68ac
+ # to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
+ #remote_signature = 3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0
+ # local_signature = 3044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c3836939
+ #num_htlcs: 0
+ c_tx = make_commitment(
+ local_funding_pubkey, remote_funding_pubkey,
+ local_payment_basepoint, remote_payment_basepoint,
+ local_revocation_pubkey, local_delayedpubkey,
+ funding_tx_id, funding_output_index, funding_amount_satoshi)
+
+ commit_tx = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'
+ self.assertEqual(str(c_tx), commit_tx)
+