id: cache-graph
uses: actions/cache@v2
with:
- path: lightning/net_graph-2021-02-12.bin
- key: ldk-net_graph-05f0c5a0d772-2020-02-12.bin
+ path: lightning/net_graph-2021-05-27.bin
+ key: ldk-net_graph-45d86ead641d-2021-05-27.bin
- name: Fetch routing graph snapshot
if: steps.cache-graph.outputs.cache-hit != 'true'
run: |
- wget -O lightning/net_graph-2021-02-12.bin https://bitcoin.ninja/ldk-net_graph-05f0c5a0d772-2020-02-12.bin
- if [ "$(sha256sum lightning/net_graph-2021-02-12.bin | awk '{ print $1 }')" != "7116fca78551fedc714a604cec0ad1ca66caa77bb4d0051290258e7a10e0c6e7" ]; then
+ wget -O lightning/net_graph-2021-05-27.bin https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin
+ if [ "$(sha256sum lightning/net_graph-2021-05-27.bin | awk '{ print $1 }')" != "3d6261187cfa583255d978efb908b51c2f4dc4ad9a7160cd2c5263c9a4830121" ]; then
echo "Bad hash"
exit 1
fi
// 0c007d - connect a block with one transaction of len 125
// 02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c0000000000000160014280000000000000000000000000000000000000005000020 - the commitment transaction for channel 3f00000000000000000000000000000000000000000000000000000000000000
// 00fd - A feerate request (returning min feerate, which our open_channel also uses) (gonna be ingested by FuzzEstimator)
- // 00fd - A feerate request (returning min feerate, which our open_channel also uses) (gonna be ingested by FuzzEstimator)
// 0c005e - connect a block with one transaction of len 94
// 0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b20000000000000000000000000000000000000000000000000000000000000000000000 - the HTLC timeout transaction
// 0c0000 - connect a block with no transactions
// - client now fails the HTLC backwards as it was unable to extract the payment preimage (CHECK 9 duplicate and CHECK 10)
let logger = Arc::new(TrackingLogger { lines: Mutex::new(HashMap::new()) });
- super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012000a0300000000000000000000000000000003001a00100002200000022000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c3500000000000000000000000000000014affffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112000a0100000000000000000000000000000003011a0010000220000002200001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000014a00000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500026600000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000927c0000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4b000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c000000000000016001428000000000000000000000000000000000000000500002000fd00fd0c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
+ super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012000a0300000000000000000000000000000003001a00100002200000022000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c3500000000000000000000000000000014affffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112000a0100000000000000000000000000000003011a0010000220000002200001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000014a00000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500026600000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000927c0000000a00000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4b000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c000000000000016001428000000000000000000000000000000000000000500002000fd0c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
let log_entries = logger.lines.lock().unwrap();
assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1
fn create_nodes(num_nodes: usize, persist_dir: String) -> Vec<Node> {
let mut nodes = Vec::new();
for i in 0..num_nodes {
- let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+ let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
let fee_estimator = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
use util::events;
use util::events::EventHandler;
+use prelude::*;
use std::collections::{HashMap, hash_map};
use std::sync::RwLock;
use core::ops::Deref;
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
use util::events::EventsProvider;
- let events = std::cell::RefCell::new(Vec::new());
+ let events = core::cell::RefCell::new(Vec::new());
let event_handler = |event| events.borrow_mut().push(event);
self.process_pending_events(&event_handler);
events.into_inner()
use util::byte_utils;
use util::events::Event;
+use prelude::*;
use std::collections::{HashMap, HashSet};
use core::{cmp, mem};
use std::io::Error;
macro_rules! claim_htlcs {
($commitment_number: expr, $txid: expr) => {
let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
}
}
if let Some(txid) = self.current_counterparty_commitment_txid {
// holder commitment transactions.
if self.broadcasted_holder_revokable_script.is_some() {
let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, 0);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, 0);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
}
}
}
for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() {
if let Some(transaction_output_index) = htlc.transaction_output_index {
- let htlc_output = HolderHTLCOutput::build(if !htlc.offered {
- if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
- Some(preimage.clone())
+ let htlc_output = if htlc.offered {
+ HolderHTLCOutput::build_offered(htlc.amount_msat, htlc.cltv_expiry)
} else {
- // We can't build an HTLC-Success transaction without the preimage
- continue;
- }
- } else { None }, htlc.amount_msat);
+ let payment_preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
+ preimage.clone()
+ } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
+ };
+ HolderHTLCOutput::build_accepted(payment_preimage, htlc.amount_msat)
+ };
let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height);
claim_requests.push(htlc_package);
}
self.holder_tx_signed = true;
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
- let mut res = vec![commitment_tx];
+ let mut holder_transactions = vec![commitment_tx];
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
// We can't build an HTLC-Success transaction without the preimage
continue;
}
+ } else if htlc.0.cltv_expiry > self.best_block.height() + 1 {
+ // Don't broadcast HTLC-Timeout transactions immediately as they don't meet the
+ // current locktime requirements on-chain. We will broadcast them in
+ // `block_confirmed` when `would_broadcast_at_height` returns true.
+ // Note that we add + 1 as transactions are broadcastable when they can be
+ // confirmed in the next block.
+ continue;
} else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
&::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ holder_transactions.push(htlc_tx);
}
}
}
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
- return res;
+ holder_transactions
}
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
+ /// Note that this includes possibly-locktimed-in-the-future transactions!
fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
log_trace!(logger, "Getting signed copy of latest holder commitment transaction!");
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
- let mut res = vec![commitment_tx];
+ let mut holder_transactions = vec![commitment_tx];
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
} else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
&::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ holder_transactions.push(htlc_tx);
}
}
}
- return res
+ holder_transactions
}
pub fn block_connected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec<TransactionOutputs>
}
}
- self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
+ self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, height, &&*broadcaster, &&*fee_estimator, &&*logger);
// Determine new outputs to watch by comparing against previously known outputs to watch,
// updating the latter in the process.
use bitcoin::secp256k1::Secp256k1;
use std::sync::{Arc, Mutex};
use chain::keysinterface::InMemorySigner;
+ use prelude::*;
#[test]
fn test_prune_preimages() {
let secp_ctx = Secp256k1::new();
let logger = Arc::new(TestLogger::new());
- let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+ let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 });
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction};
use ln::msgs::UnsignedChannelAnnouncement;
+use prelude::*;
use std::collections::HashSet;
use core::sync::atomic::{AtomicUsize, Ordering};
use std::io::Error;
use chain::keysinterface::Sign;
use chain::transaction::{OutPoint, TransactionData};
+use prelude::*;
+
pub mod chaininterface;
pub mod chainmonitor;
pub mod channelmonitor;
use util::ser::{Readable, ReadableArgs, Writer, Writeable, VecWriter};
use util::byte_utils;
+use prelude::*;
+use alloc::collections::BTreeMap;
use std::collections::HashMap;
use core::cmp;
use core::ops::Deref;
#[cfg(not(test))]
claimable_outpoints: HashMap<BitcoinOutPoint, (Txid, u32)>,
- onchain_events_awaiting_threshold_conf: Vec<OnchainEventEntry>,
+ locktimed_packages: BTreeMap<u32, Vec<PackageTemplate>>,
- latest_height: u32,
+ onchain_events_awaiting_threshold_conf: Vec<OnchainEventEntry>,
pub(super) secp_ctx: Secp256k1<secp256k1::All>,
}
claim_and_height.1.write(writer)?;
}
+ writer.write_all(&byte_utils::be64_to_array(self.locktimed_packages.len() as u64))?;
+ for (ref locktime, ref packages) in self.locktimed_packages.iter() {
+ locktime.write(writer)?;
+ writer.write_all(&byte_utils::be64_to_array(packages.len() as u64))?;
+ for ref package in packages.iter() {
+ package.write(writer)?;
+ }
+ }
+
writer.write_all(&byte_utils::be64_to_array(self.onchain_events_awaiting_threshold_conf.len() as u64))?;
for ref entry in self.onchain_events_awaiting_threshold_conf.iter() {
entry.txid.write(writer)?;
}
}
}
- self.latest_height.write(writer)?;
write_tlv_fields!(writer, {}, {});
Ok(())
let height = Readable::read(reader)?;
claimable_outpoints.insert(outpoint, (ancestor_claim_txid, height));
}
+
+ let locktimed_packages_len: u64 = Readable::read(reader)?;
+ let mut locktimed_packages = BTreeMap::new();
+ for _ in 0..locktimed_packages_len {
+ let locktime = Readable::read(reader)?;
+ let packages_len: u64 = Readable::read(reader)?;
+ let mut packages = Vec::with_capacity(cmp::min(packages_len as usize, MAX_ALLOC_SIZE / std::mem::size_of::<PackageTemplate>()));
+ for _ in 0..packages_len {
+ packages.push(Readable::read(reader)?);
+ }
+ locktimed_packages.insert(locktime, packages);
+ }
+
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
let mut onchain_events_awaiting_threshold_conf = Vec::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
for _ in 0..waiting_threshold_conf_len {
};
onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid, height, event });
}
- let latest_height = Readable::read(reader)?;
read_tlv_fields!(reader, {}, {});
signer,
channel_transaction_parameters: channel_parameters,
claimable_outpoints,
+ locktimed_packages,
pending_claim_requests,
onchain_events_awaiting_threshold_conf,
- latest_height,
secp_ctx,
})
}
channel_transaction_parameters: channel_parameters,
pending_claim_requests: HashMap::new(),
claimable_outpoints: HashMap::new(),
+ locktimed_packages: BTreeMap::new(),
onchain_events_awaiting_threshold_conf: Vec::new(),
- latest_height: 0,
secp_ctx,
}
// Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
let new_timer = Some(cached_request.get_height_timer(height));
- let amt = cached_request.package_amount();
if cached_request.is_malleable() {
let predicted_weight = cached_request.package_weight(&self.destination_script);
- if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, amt, fee_estimator, logger) {
+ if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) {
assert!(new_feerate != 0);
let transaction = cached_request.finalize_package(self, output_value, self.destination_script.clone(), logger).unwrap();
// Note: Currently, amounts of holder outputs spending witnesses aren't used
// as we can't malleate spending package to increase their feerate. This
// should change with the remaining anchor output patchset.
- debug_assert!(amt == 0);
- if let Some(transaction) = cached_request.finalize_package(self, amt, self.destination_script.clone(), logger) {
+ if let Some(transaction) = cached_request.finalize_package(self, 0, self.destination_script.clone(), logger) {
return Some((None, 0, transaction));
}
}
/// for this channel, provide new relevant on-chain transactions and/or new claim requests.
/// Formerly this was named `block_connected`, but it is now also used for claiming an HTLC output
/// if we receive a preimage after force-close.
- pub(crate) fn update_claims_view<B: Deref, F: Deref, L: Deref>(&mut self, txn_matched: &[&Transaction], requests: Vec<PackageTemplate>, latest_height: Option<u32>, broadcaster: &B, fee_estimator: &F, logger: &L)
+ pub(crate) fn update_claims_view<B: Deref, F: Deref, L: Deref>(&mut self, txn_matched: &[&Transaction], requests: Vec<PackageTemplate>, height: u32, broadcaster: &B, fee_estimator: &F, logger: &L)
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
{
- let height = match latest_height {
- Some(h) => h,
- None => self.latest_height,
- };
log_trace!(logger, "Updating claims view at height {} with {} matched transactions and {} claim requests", height, txn_matched.len(), requests.len());
let mut preprocessed_requests = Vec::with_capacity(requests.len());
let mut aggregated_request = None;
// <= CLTV_SHARED_CLAIM_BUFFER) and they don't require an immediate nLockTime (aggregable).
for req in requests {
// Don't claim a outpoint twice that would be bad for privacy and may uselessly lock a CPFP input for a while
- if let Some(_) = self.claimable_outpoints.get(req.outpoints()[0]) { log_trace!(logger, "Bouncing off outpoint {}:{}, already registered its claiming request", req.outpoints()[0].txid, req.outpoints()[0].vout); } else {
+ if let Some(_) = self.claimable_outpoints.get(req.outpoints()[0]) {
+ log_trace!(logger, "Ignoring second claim for outpoint {}:{}, already registered its claiming request", req.outpoints()[0].txid, req.outpoints()[0].vout);
+ } else {
+ let timelocked_equivalent_package = self.locktimed_packages.iter().map(|v| v.1.iter()).flatten()
+ .find(|locked_package| locked_package.outpoints() == req.outpoints());
+ if let Some(package) = timelocked_equivalent_package {
+ log_trace!(logger, "Ignoring second claim for outpoint {}:{}, we already have one which we're waiting on a timelock at {} for.",
+ req.outpoints()[0].txid, req.outpoints()[0].vout, package.package_timelock());
+ continue;
+ }
+
+ if req.package_timelock() > height + 1 {
+ log_debug!(logger, "Delaying claim of package until its timelock at {} (current height {}), the following outpoints are spent:", req.package_timelock(), height);
+ for outpoint in req.outpoints() {
+ log_debug!(logger, " Outpoint {}", outpoint);
+ }
+ self.locktimed_packages.entry(req.package_timelock()).or_insert(Vec::new()).push(req);
+ continue;
+ }
+
log_trace!(logger, "Test if outpoint can be aggregated with expiration {} against {}", req.timelock(), height + CLTV_SHARED_CLAIM_BUFFER);
if req.timelock() <= height + CLTV_SHARED_CLAIM_BUFFER || !req.aggregable() {
// Don't aggregate if outpoint package timelock is soon or marked as non-aggregable
preprocessed_requests.push(req);
}
+ // Claim everything up to and including height + 1
+ let remaining_locked_packages = self.locktimed_packages.split_off(&(height + 2));
+ for (pop_height, mut entry) in self.locktimed_packages.iter_mut() {
+ log_trace!(logger, "Restoring delayed claim of package(s) at their timelock at {}.", pop_height);
+ preprocessed_requests.append(&mut entry);
+ }
+ self.locktimed_packages = remaining_locked_packages;
+
// Generate claim transactions and track them to bump if necessary at
// height timer expiration (i.e in how many blocks we're going to take action).
for mut req in preprocessed_requests {
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
use ln::PaymentPreimage;
-use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, HTLC_OUTPUT_IN_COMMITMENT_SIZE};
+use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
use ln::chan_utils;
use ln::msgs::DecodeError;
use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
use util::logger::Logger;
use util::ser::{Readable, Writer, Writeable};
-use std::cmp;
-use std::mem;
-use std::ops::Deref;
+use core::cmp;
+use core::mem;
+use core::ops::Deref;
const MAX_ALLOC_SIZE: usize = 64*1024;
}
}
-impl_writeable!(RevokedOutput, 33*3 + 32 + 8 + 8 + 2, {
- per_commitment_point,
- counterparty_delayed_payment_base_key,
- counterparty_htlc_base_key,
- per_commitment_key,
- weight,
- amount,
- on_counterparty_tx_csv
-});
+impl_writeable_tlv_based!(RevokedOutput, {
+ (0, per_commitment_point),
+ (2, counterparty_delayed_payment_base_key),
+ (4, counterparty_htlc_base_key),
+ (6, per_commitment_key),
+ (8, weight),
+ (10, amount),
+ (12, on_counterparty_tx_csv),
+}, {}, {});
/// A struct to describe a revoked offered output and corresponding information to generate a
/// solving witness.
}
}
-impl_writeable!(RevokedHTLCOutput, 33*3 + 32 + 8 + 8 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, {
- per_commitment_point,
- counterparty_delayed_payment_base_key,
- counterparty_htlc_base_key,
- per_commitment_key,
- weight,
- amount,
- htlc
-});
+impl_writeable_tlv_based!(RevokedHTLCOutput, {
+ (0, per_commitment_point),
+ (2, counterparty_delayed_payment_base_key),
+ (4, counterparty_htlc_base_key),
+ (6, per_commitment_key),
+ (8, weight),
+ (10, amount),
+ (12, htlc),
+}, {}, {});
/// A struct to describe a HTLC output on a counterparty commitment transaction.
///
}
}
-impl_writeable!(CounterpartyOfferedHTLCOutput, 33*3 + 32 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, {
- per_commitment_point,
- counterparty_delayed_payment_base_key,
- counterparty_htlc_base_key,
- preimage,
- htlc
-});
+impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, {
+ (0, per_commitment_point),
+ (2, counterparty_delayed_payment_base_key),
+ (4, counterparty_htlc_base_key),
+ (6, preimage),
+ (8, htlc),
+}, {}, {});
/// A struct to describe a HTLC output on a counterparty commitment transaction.
///
}
}
-impl_writeable!(CounterpartyReceivedHTLCOutput, 33*3 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, {
- per_commitment_point,
- counterparty_delayed_payment_base_key,
- counterparty_htlc_base_key,
- htlc
-});
+impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, {
+ (0, per_commitment_point),
+ (2, counterparty_delayed_payment_base_key),
+ (4, counterparty_htlc_base_key),
+ (6, htlc),
+}, {}, {});
/// A struct to describe a HTLC output on holder commitment transaction.
///
pub(crate) struct HolderHTLCOutput {
preimage: Option<PaymentPreimage>,
amount: u64,
+ /// Defaults to 0 for HTLC-Success transactions, which have no expiry
+ cltv_expiry: u32,
}
impl HolderHTLCOutput {
- pub(crate) fn build(preimage: Option<PaymentPreimage>, amount: u64) -> Self {
+ pub(crate) fn build_offered(amount: u64, cltv_expiry: u32) -> Self {
HolderHTLCOutput {
- preimage,
- amount
+ preimage: None,
+ amount,
+ cltv_expiry,
+ }
+ }
+
+ pub(crate) fn build_accepted(preimage: PaymentPreimage, amount: u64) -> Self {
+ HolderHTLCOutput {
+ preimage: Some(preimage),
+ amount,
+ cltv_expiry: 0,
}
}
}
-impl_writeable!(HolderHTLCOutput, 0, {
- preimage,
- amount
-});
+impl_writeable_tlv_based!(HolderHTLCOutput, {
+ (0, amount),
+ (2, cltv_expiry),
+}, {
+ (4, preimage),
+}, {});
/// A struct to describe the channel output on the funding transaction.
///
}
}
-impl_writeable!(HolderFundingOutput, 0, {
- funding_redeemscript
-});
+impl_writeable_tlv_based!(HolderFundingOutput, {
+ (0, funding_redeemscript),
+}, {}, {});
/// A wrapper encapsulating all in-protocol differing outputs types.
///
// Note: Currently, amounts of holder outputs spending witnesses aren't used
// as we can't malleate spending package to increase their feerate. This
// should change with the remaining anchor output patchset.
- PackageSolvingData::HolderHTLCOutput(..) => { 0 },
- PackageSolvingData::HolderFundingOutput(..) => { 0 },
+ PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() },
+ PackageSolvingData::HolderFundingOutput(..) => { unreachable!() },
};
amt
}
// Note: Currently, weights of holder outputs spending witnesses aren't used
// as we can't malleate spending package to increase their feerate. This
// should change with the remaining anchor output patchset.
- PackageSolvingData::HolderHTLCOutput(..) => { debug_assert!(false); 0 },
- PackageSolvingData::HolderFundingOutput(..) => { debug_assert!(false); 0 },
+ PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() },
+ PackageSolvingData::HolderFundingOutput(..) => { unreachable!() },
};
weight
}
_ => { panic!("API Error!"); }
}
}
+ fn absolute_tx_timelock(&self, output_conf_height: u32) -> u32 {
+ // Get the absolute timelock at which this output can be spent given the height at which
+ // this output was confirmed. We use `output_conf_height + 1` as a safe default as we can
+ // be confirmed in the next block and transactions with time lock `current_height + 1`
+ // always propagate.
+ let absolute_timelock = match self {
+ PackageSolvingData::RevokedOutput(_) => output_conf_height + 1,
+ PackageSolvingData::RevokedHTLCOutput(_) => output_conf_height + 1,
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(_) => output_conf_height + 1,
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => std::cmp::max(outp.htlc.cltv_expiry, output_conf_height + 1),
+ PackageSolvingData::HolderHTLCOutput(ref outp) => std::cmp::max(outp.cltv_expiry, output_conf_height + 1),
+ PackageSolvingData::HolderFundingOutput(_) => output_conf_height + 1,
+ };
+ absolute_timelock
+ }
}
impl Writeable for PackageSolvingData {
}
self.height_timer = cmp::min(self.height_timer, merge_from.height_timer);
}
- pub(crate) fn package_amount(&self) -> u64 {
+ /// Gets the amount of all outptus being spent by this package, only valid for malleable
+ /// packages.
+ fn package_amount(&self) -> u64 {
let mut amounts = 0;
for (_, outp) in self.inputs.iter() {
amounts += outp.amount();
}
amounts
}
+ pub(crate) fn package_timelock(&self) -> u32 {
+ self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original))
+ .max().expect("There must always be at least one output to spend in a PackageTemplate")
+ }
pub(crate) fn package_weight(&self, destination_script: &Script) -> usize {
let mut inputs_weight = 0;
let mut witnesses_weight = 2; // count segwit flags
return Some(bumped_tx);
},
PackageMalleability::Untractable => {
+ debug_assert_eq!(value, 0, "value is ignored for non-malleable packages, should be zero to ensure callsites are correct");
if let Some((outpoint, outp)) = self.inputs.first() {
if let Some(final_tx) = outp.get_finalized_tx(outpoint, onchain_handler) {
log_trace!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
current_height + LOW_FREQUENCY_BUMP_INTERVAL
}
/// Returns value in satoshis to be included as package outgoing output amount and feerate with which package finalization should be done.
- pub(crate) fn compute_package_output<F: Deref, L: Deref>(&self, predicted_weight: usize, input_amounts: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
+ pub(crate) fn compute_package_output<F: Deref, L: Deref>(&self, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
where F::Target: FeeEstimator,
L::Target: Logger,
{
+ debug_assert!(self.malleability == PackageMalleability::Malleable, "The package output is fixed for non-malleable packages");
+ let input_amounts = self.package_amount();
// If old feerate is 0, first iteration of this claim, use normal fee calculation
if self.feerate_previous != 0 {
if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, self.feerate_previous, fee_estimator, logger) {
outpoint.write(writer)?;
rev_outp.write(writer)?;
}
- self.soonest_conf_deadline.write(writer)?;
- self.feerate_previous.write(writer)?;
- self.height_timer.write(writer)?;
- self.height_original.write(writer)?;
+ write_tlv_fields!(writer, {
+ (0, self.soonest_conf_deadline),
+ (2, self.feerate_previous),
+ (4, self.height_original),
+ }, { (6, self.height_timer) });
Ok(())
}
}
PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) },
}
} else { return Err(DecodeError::InvalidValue); };
- let soonest_conf_deadline = Readable::read(reader)?;
- let feerate_previous = Readable::read(reader)?;
- let height_timer = Readable::read(reader)?;
- let height_original = Readable::read(reader)?;
+ let mut soonest_conf_deadline = 0;
+ let mut feerate_previous = 0;
+ let mut height_timer = None;
+ let mut height_original = 0;
+ read_tlv_fields!(reader, {
+ (0, soonest_conf_deadline),
+ (2, feerate_previous),
+ (4, height_original)
+ }, { (6, height_timer) });
Ok(PackageTemplate {
inputs,
malleability,
() => {
{
let preimage = PaymentPreimage([2;32]);
- PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(Some(preimage), 0))
+ PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0))
}
}
}
vout: self.index as u32,
}
}
+
+ /// Creates a dummy BitcoinOutPoint, useful for deserializing into.
+ pub(crate) fn null() -> Self {
+ Self {
+ txid: Default::default(),
+ index: 0
+ }
+ }
}
impl_writeable!(OutPoint, 0, { txid, index });
#![cfg_attr(all(any(test, feature = "_test_utils"), feature = "unstable"), feature(test))]
#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))] extern crate test;
+extern crate alloc;
extern crate bitcoin;
extern crate core;
#[cfg(any(test, feature = "_test_utils"))] extern crate hex;
pub mod chain;
pub mod ln;
pub mod routing;
+
+mod prelude {
+ pub use alloc::{vec, vec::Vec, string::String};
+}
\ No newline at end of file
use bitcoin::secp256k1::Error as SecpError;
use bitcoin::secp256k1;
+use prelude::*;
use core::cmp;
use ln::chan_utils;
use util::transaction_utils::sort_outputs;
writer.write_all(secret)?;
writer.write_all(&byte_utils::be64_to_array(*idx))?;
}
+ write_tlv_fields!(writer, {}, {});
Ok(())
}
}
*secret = Readable::read(reader)?;
*idx = Readable::read(reader)?;
}
-
+ read_tlv_fields!(reader, {}, {});
Ok(Self { old_secrets })
}
}
pub broadcaster_delayed_payment_key: PublicKey,
}
-impl_writeable!(TxCreationKeys, 33*5,
- { per_commitment_point, revocation_key, broadcaster_htlc_key, countersignatory_htlc_key, broadcaster_delayed_payment_key });
+impl_writeable_tlv_based!(TxCreationKeys, {
+ (0, per_commitment_point),
+ (2, revocation_key),
+ (4, broadcaster_htlc_key),
+ (6, countersignatory_htlc_key),
+ (8, broadcaster_delayed_payment_key),
+}, {}, {});
/// One counterparty's public keys which do not change over the life of a channel.
#[derive(Clone, PartialEq)]
pub htlc_basepoint: PublicKey,
}
-impl_writeable!(ChannelPublicKeys, 33*5, {
- funding_pubkey,
- revocation_basepoint,
- payment_point,
- delayed_payment_basepoint,
- htlc_basepoint
-});
-
+impl_writeable_tlv_based!(ChannelPublicKeys, {
+ (0, funding_pubkey),
+ (2, revocation_basepoint),
+ (4, payment_point),
+ (6, delayed_payment_basepoint),
+ (8, htlc_basepoint),
+}, {}, {});
impl TxCreationKeys {
/// Create per-state keys from channel base points and the per-commitment point.
pub transaction_output_index: Option<u32>,
}
-impl_writeable_len_match!(HTLCOutputInCommitment, {
- { HTLCOutputInCommitment { transaction_output_index: None, .. }, HTLC_OUTPUT_IN_COMMITMENT_SIZE - 4 },
- { _, HTLC_OUTPUT_IN_COMMITMENT_SIZE }
- }, {
- offered,
- amount_msat,
- cltv_expiry,
- payment_hash,
- transaction_output_index
-});
+impl_writeable_tlv_based!(HTLCOutputInCommitment, {
+ (0, offered),
+ (2, amount_msat),
+ (4, cltv_expiry),
+ (6, payment_hash),
+}, {
+ (8, transaction_output_index)
+}, {});
#[inline]
pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
}
}
-impl_writeable!(CounterpartyChannelTransactionParameters, 0, {
- pubkeys,
- selected_contest_delay
-});
+impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, {
+ (0, pubkeys),
+ (2, selected_contest_delay),
+}, {}, {});
-impl_writeable!(ChannelTransactionParameters, 0, {
- holder_pubkeys,
- holder_selected_contest_delay,
- is_outbound_from_holder,
- counterparty_parameters,
- funding_outpoint
-});
+impl_writeable_tlv_based!(ChannelTransactionParameters, {
+ (0, holder_pubkeys),
+ (2, holder_selected_contest_delay),
+ (4, is_outbound_from_holder),
+}, {
+ (6, counterparty_parameters),
+ (8, funding_outpoint),
+}, {});
/// Static channel fields used to build transactions given per-commitment fields, organized by
/// broadcaster/countersignatory.
}
}
-impl_writeable!(HolderCommitmentTransaction, 0, {
- inner, counterparty_sig, counterparty_htlc_sigs, holder_sig_first
+impl_writeable_tlv_based!(HolderCommitmentTransaction, {
+ (0, inner),
+ (2, counterparty_sig),
+ (4, holder_sig_first),
+}, {}, {
+ (6, counterparty_htlc_sigs),
});
impl HolderCommitmentTransaction {
pub txid: Txid,
}
-impl_writeable!(BuiltCommitmentTransaction, 0, { transaction, txid });
+impl_writeable_tlv_based!(BuiltCommitmentTransaction, {
+ (0, transaction),
+ (2, txid)
+}, {}, {});
impl BuiltCommitmentTransaction {
/// Get the SIGHASH_ALL sighash value of the transaction.
}
}
-impl_writeable!(CommitmentTransaction, 0, {
- commitment_number,
- to_broadcaster_value_sat,
- to_countersignatory_value_sat,
- feerate_per_kw,
- htlcs,
- keys,
- built
-});
+impl_writeable_tlv_based!(CommitmentTransaction, {
+ (0, commitment_number),
+ (2, to_broadcaster_value_sat),
+ (4, to_countersignatory_value_sat),
+ (6, feerate_per_kw),
+ (8, htlcs),
+ (10, keys),
+ (12, built),
+}, {}, {});
impl CommitmentTransaction {
/// Construct an object of the class while assigning transaction output indices to HTLCs.
mod tests {
use super::CounterpartyCommitmentSecrets;
use hex;
+ use prelude::*;
#[test]
fn test_per_commitment_storage() {
//! here. See also the chanmon_fail_consistency fuzz test.
use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::constants::genesis_block;
use bitcoin::hash_types::BlockHash;
use bitcoin::network::constants::Network;
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr};
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
use util::errors::APIError;
use util::ser::{ReadableArgs, Writeable};
+use util::test_utils::TestBroadcaster;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use util::test_utils;
+use prelude::*;
use std::collections::HashMap;
+use std::sync::{Arc, Mutex};
// If persister_fail is true, we have the persister return a PermanentFailure
// instead of the higher-level ChainMonitor.
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let logger = test_utils::TestLogger::with_id(format!("node {}", 0));
let persister = test_utils::TestPersister::new();
+ let tx_broadcaster = TestBroadcaster {
+ txn_broadcasted: Mutex::new(Vec::new()),
+ // Because we will connect a block at height 200 below, we need the TestBroadcaster to know
+ // that we are at height 200 so that it doesn't think we're violating the time lock
+ // requirements of transactions broadcasted at that point.
+ blocks: Arc::new(Mutex::new(vec![(genesis_block(Network::Testnet).header, 200); 200])),
+ };
let chain_mon = {
let monitors = nodes[0].chain_monitor.chain_monitor.monitors.read().unwrap();
let monitor = monitors.get(&outpoint).unwrap();
let new_monitor = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(
&mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
- let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
+ let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
assert!(chain_mon.watch_channel(outpoint, new_monitor).is_ok());
chain_mon
};
use util::config::{UserConfig,ChannelConfig};
use util::scid_utils::scid_from_parts;
+use prelude::*;
use core::{cmp,mem,fmt};
use core::ops::Deref;
#[cfg(any(test, feature = "fuzztarget"))]
use bitcoin::hashes::Hash;
use bitcoin::hash_types::{Txid, WPubkeyHash};
use std::sync::Arc;
+ use prelude::*;
struct TestFeeEstimator {
fee_est: u32
use util::logger::Logger;
use util::errors::APIError;
+use prelude::*;
use core::{cmp, mem};
-use std::cell::RefCell;
+use core::cell::RefCell;
use std::collections::{HashMap, hash_map, HashSet};
use std::io::{Cursor, Read};
use std::sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
- let events = std::cell::RefCell::new(Vec::new());
+ let events = core::cell::RefCell::new(Vec::new());
let event_handler = |event| events.borrow_mut().push(event);
self.process_pending_events(&event_handler);
events.into_inner()
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
-impl Writeable for PendingHTLCInfo {
+impl Writeable for PendingHTLCRouting {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- match &self.routing {
+ match &self {
&PendingHTLCRouting::Forward { ref onion_packet, ref short_channel_id } => {
0u8.write(writer)?;
onion_packet.write(writer)?;
incoming_cltv_expiry.write(writer)?;
},
}
- self.incoming_shared_secret.write(writer)?;
- self.payment_hash.write(writer)?;
- self.amt_to_forward.write(writer)?;
- self.outgoing_cltv_value.write(writer)?;
Ok(())
}
}
-impl Readable for PendingHTLCInfo {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<PendingHTLCInfo, DecodeError> {
- Ok(PendingHTLCInfo {
- routing: match Readable::read(reader)? {
- 0u8 => PendingHTLCRouting::Forward {
- onion_packet: Readable::read(reader)?,
- short_channel_id: Readable::read(reader)?,
- },
- 1u8 => PendingHTLCRouting::Receive {
- payment_data: msgs::FinalOnionHopData {
- payment_secret: Readable::read(reader)?,
- total_msat: Readable::read(reader)?,
- },
- incoming_cltv_expiry: Readable::read(reader)?,
+impl Readable for PendingHTLCRouting {
+ fn read<R: ::std::io::Read>(reader: &mut R) -> Result<PendingHTLCRouting, DecodeError> {
+ match Readable::read(reader)? {
+ 0u8 => Ok(PendingHTLCRouting::Forward {
+ onion_packet: Readable::read(reader)?,
+ short_channel_id: Readable::read(reader)?,
+ }),
+ 1u8 => Ok(PendingHTLCRouting::Receive {
+ payment_data: msgs::FinalOnionHopData {
+ payment_secret: Readable::read(reader)?,
+ total_msat: Readable::read(reader)?,
},
- _ => return Err(DecodeError::InvalidValue),
- },
- incoming_shared_secret: Readable::read(reader)?,
- payment_hash: Readable::read(reader)?,
- amt_to_forward: Readable::read(reader)?,
- outgoing_cltv_value: Readable::read(reader)?,
- })
+ incoming_cltv_expiry: Readable::read(reader)?,
+ }),
+ _ => Err(DecodeError::InvalidValue),
+ }
}
}
+impl_writeable_tlv_based!(PendingHTLCInfo, {
+ (0, routing),
+ (2, incoming_shared_secret),
+ (4, payment_hash),
+ (6, amt_to_forward),
+ (8, outgoing_cltv_value)
+}, {}, {});
+
impl Writeable for HTLCFailureMsg {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
match self {
}
}
-impl_writeable!(HTLCPreviousHopData, 0, {
- short_channel_id,
- outpoint,
- htlc_id,
- incoming_packet_shared_secret
-});
+impl_writeable_tlv_based!(HTLCPreviousHopData, {
+ (0, short_channel_id),
+ (2, outpoint),
+ (4, htlc_id),
+ (6, incoming_packet_shared_secret)
+}, {}, {});
impl Writeable for ClaimableHTLC {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- self.prev_hop.write(writer)?;
- self.value.write(writer)?;
- self.payment_data.payment_secret.write(writer)?;
- self.payment_data.total_msat.write(writer)?;
- self.cltv_expiry.write(writer)
+ write_tlv_fields!(writer, {
+ (0, self.prev_hop),
+ (2, self.value),
+ (4, self.payment_data.payment_secret),
+ (6, self.payment_data.total_msat),
+ (8, self.cltv_expiry)
+ }, {});
+ Ok(())
}
}
impl Readable for ClaimableHTLC {
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ let mut prev_hop = HTLCPreviousHopData {
+ short_channel_id: 0, htlc_id: 0,
+ incoming_packet_shared_secret: [0; 32],
+ outpoint: OutPoint::null(),
+ };
+ let mut value = 0;
+ let mut payment_secret = PaymentSecret([0; 32]);
+ let mut total_msat = 0;
+ let mut cltv_expiry = 0;
+ read_tlv_fields!(reader, {
+ (0, prev_hop),
+ (2, value),
+ (4, payment_secret),
+ (6, total_msat),
+ (8, cltv_expiry)
+ }, {});
Ok(ClaimableHTLC {
- prev_hop: Readable::read(reader)?,
- value: Readable::read(reader)?,
+ prev_hop,
+ value,
payment_data: msgs::FinalOnionHopData {
- payment_secret: Readable::read(reader)?,
- total_msat: Readable::read(reader)?,
+ payment_secret,
+ total_msat,
},
- cltv_expiry: Readable::read(reader)?,
+ cltv_expiry,
})
}
}
}
}
-impl_writeable!(PendingInboundPayment, 0, {
- payment_secret,
- expiry_time,
- user_payment_id,
- payment_preimage,
- min_value_msat
-});
+impl_writeable_tlv_based!(PendingInboundPayment, {
+ (0, payment_secret),
+ (2, expiry_time),
+ (4, user_payment_id),
+ (6, payment_preimage),
+ (8, min_value_msat),
+}, {}, {});
impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable for ChannelManager<Signer, M, T, K, F, L>
where M::Target: chain::Watch<Signer>,
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::{Block, BlockHeader, Transaction, TxOut};
- use std::sync::Mutex;
+ use std::sync::{Arc, Mutex};
use test::Bencher;
let network = bitcoin::Network::Testnet;
let genesis_hash = bitcoin::blockdata::constants::genesis_block(network).header.block_hash();
- let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
+ let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
let mut config: UserConfig = Default::default();
//! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
//! [messages]: crate::ln::msgs
+use prelude::*;
use core::{cmp, fmt};
use core::marker::PhantomData;
use util::ser::{Readable, Writeable, Writer};
mod sealed {
+ use prelude::*;
use ln::features::Features;
/// The context in which [`Features`] are applicable. Defines which features are required and
use bitcoin::secp256k1::key::PublicKey;
+use prelude::*;
use core::cell::RefCell;
use std::rc::Rc;
-use std::sync::Mutex;
+use std::sync::{Arc, Mutex};
use core::mem;
use std::collections::HashMap;
}
}
node.node.test_process_background_events();
- node.blocks.borrow_mut().push((block.header, height));
+ node.blocks.lock().unwrap().push((block.header, height));
}
pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) {
for i in 0..count {
- let orig_header = node.blocks.borrow_mut().pop().unwrap();
+ let orig_header = node.blocks.lock().unwrap().pop().unwrap();
assert!(orig_header.1 > 0); // Cannot disconnect genesis
- let prev_header = node.blocks.borrow().last().unwrap().clone();
+ let prev_header = node.blocks.lock().unwrap().last().unwrap().clone();
match *node.connect_style.borrow() {
ConnectStyle::FullBlockViaListen => {
}
pub fn disconnect_all_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>) {
- let count = node.blocks.borrow_mut().len() as u32 - 1;
+ let count = node.blocks.lock().unwrap().len() as u32 - 1;
disconnect_blocks(node, count);
}
pub network_payment_count: Rc<RefCell<u8>>,
pub network_chan_count: Rc<RefCell<u32>>,
pub logger: &'c test_utils::TestLogger,
- pub blocks: RefCell<Vec<(BlockHeader, u32)>>,
+ pub blocks: Arc<Mutex<Vec<(BlockHeader, u32)>>>,
pub connect_style: Rc<RefCell<ConnectStyle>>,
}
impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
pub fn best_block_hash(&self) -> BlockHash {
- self.blocks.borrow_mut().last().unwrap().0.block_hash()
+ self.blocks.lock().unwrap().last().unwrap().0.block_hash()
}
pub fn best_block_info(&self) -> (BlockHash, u32) {
- self.blocks.borrow_mut().last().map(|(a, b)| (a.block_hash(), *b)).unwrap()
+ self.blocks.lock().unwrap().last().map(|(a, b)| (a.block_hash(), *b)).unwrap()
}
}
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: 253 },
chain_monitor: self.chain_monitor,
tx_broadcaster: &test_utils::TestBroadcaster {
- txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone())
+ txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone()),
+ blocks: Arc::new(Mutex::new(self.tx_broadcaster.blocks.lock().unwrap().clone())),
},
logger: &test_utils::TestLogger::new(),
channel_monitors,
let persister = test_utils::TestPersister::new();
let broadcaster = test_utils::TestBroadcaster {
- txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone())
+ txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone()),
+ blocks: Arc::new(Mutex::new(self.tx_broadcaster.blocks.lock().unwrap().clone())),
};
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager);
pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
let mut chan_mon_cfgs = Vec::new();
for i in 0..node_count {
- let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
+ let tx_broadcaster = test_utils::TestBroadcaster {
+ txn_broadcasted: Mutex::new(Vec::new()),
+ blocks: Arc::new(Mutex::new(vec![(genesis_block(Network::Testnet).header, 0)])),
+ };
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let logger = test_utils::TestLogger::with_id(format!("node {}", i));
keys_manager: &cfgs[i].keys_manager, node: &chan_mgrs[i], net_graph_msg_handler,
node_seed: cfgs[i].node_seed, network_chan_count: chan_count.clone(),
network_payment_count: payment_count.clone(), logger: cfgs[i].logger,
- blocks: RefCell::new(vec![(genesis_block(Network::Testnet).header, 0)]),
+ blocks: Arc::clone(&cfgs[i].tx_broadcaster.blocks),
connect_style: Rc::clone(&connect_style),
})
}
use chain::keysinterface::{KeysInterface, BaseSign};
use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT};
+use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
use ln::channel::{Channel, ChannelError};
use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use regex;
-use std::collections::{BTreeSet, HashMap, HashSet};
+use prelude::*;
+use alloc::collections::BTreeSet;
+use std::collections::{HashMap, HashSet};
use core::default::Default;
-use std::sync::Mutex;
+use std::sync::{Arc, Mutex};
use ln::functional_test_utils::*;
use ln::chan_utils::CommitmentTransaction;
mine_transaction(&nodes[0], &remote_txn[0]);
check_added_monitors!(nodes[0], 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
// Check we only broadcast 1 timeout tx
let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
- let htlc_pair = if claim_txn[0].output[0].value == 800_000 / 1000 { (claim_txn[0].clone(), claim_txn[1].clone()) } else { (claim_txn[1].clone(), claim_txn[0].clone()) };
- assert_eq!(claim_txn.len(), 5);
- check_spends!(claim_txn[2], chan_1.3);
- check_spends!(claim_txn[3], claim_txn[2]);
- assert_eq!(htlc_pair.0.input.len(), 1);
- assert_eq!(htlc_pair.0.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
- check_spends!(htlc_pair.0, remote_txn[0]);
- assert_eq!(htlc_pair.1.input.len(), 1);
- assert_eq!(htlc_pair.1.input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
- check_spends!(htlc_pair.1, remote_txn[0]);
+ assert_eq!(claim_txn.len(), 8);
+ assert_eq!(claim_txn[1], claim_txn[4]);
+ assert_eq!(claim_txn[2], claim_txn[5]);
+ check_spends!(claim_txn[1], chan_1.3);
+ check_spends!(claim_txn[2], claim_txn[1]);
+ check_spends!(claim_txn[7], claim_txn[1]);
+
+ assert_eq!(claim_txn[0].input.len(), 1);
+ assert_eq!(claim_txn[3].input.len(), 1);
+ assert_eq!(claim_txn[0].input[0].previous_output, claim_txn[3].input[0].previous_output);
+
+ assert_eq!(claim_txn[0].input.len(), 1);
+ assert_eq!(claim_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
+ check_spends!(claim_txn[0], remote_txn[0]);
+ assert_eq!(remote_txn[0].output[claim_txn[0].input[0].previous_output.vout as usize].value, 800);
+ assert_eq!(claim_txn[6].input.len(), 1);
+ assert_eq!(claim_txn[6].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
+ check_spends!(claim_txn[6], remote_txn[0]);
+ assert_eq!(remote_txn[0].output[claim_txn[6].input[0].previous_output.vout as usize].value, 900);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 3);
// One pending HTLC is discarded by the force-close:
let payment_preimage_1 = route_payment(&nodes[1], &vec!(&nodes[2], &nodes[3])[..], 3000000).0;
- // Simple case of one pending HTLC to HTLC-Timeout
+ // Simple case of one pending HTLC to HTLC-Timeout (note that the HTLC-Timeout is not
+ // broadcasted until we reach the timelock time).
nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), true);
check_closed_broadcast!(nodes[1], false);
check_added_monitors!(nodes[1], 1);
{
- let mut node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
+ let mut node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::NONE);
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + MIN_CLTV_EXPIRY_DELTA as u32 + 1);
+ test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
mine_transaction(&nodes[2], &node_txn[0]);
check_added_monitors!(nodes[2], 1);
test_txn_broadcast(&nodes[2], &chan_2, None, HTLCType::NONE);
check_closed_broadcast!(nodes[2], false);
let node2_commitment_txid;
{
- let node_txn = test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::TIMEOUT);
+ let node_txn = test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::NONE);
+ connect_blocks(&nodes[2], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + MIN_CLTV_EXPIRY_DELTA as u32 + 1);
+ test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::TIMEOUT);
node2_commitment_txid = node_txn[0].txid();
// Claim the payment on nodes[3], giving it knowledge of the preimage
test_txn_broadcast(&nodes[1], &chan_5, None, HTLCType::NONE);
mine_transaction(&nodes[0], &revoked_local_txn[0]);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
// Verify broadcast of revoked HTLC-timeout
let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
check_added_monitors!(nodes[0], 1);
expect_payment_failed!(nodes[1], payment_hash_2, true);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 3); // ChannelMonitor: penalty tx, ChannelManager: local commitment + HTLC-timeout
+ assert_eq!(node_txn.len(), 2); // ChannelMonitor: penalty tx, ChannelManager: local commitment
assert_eq!(node_txn[0].input.len(), 3); // Claim the revoked output + both revoked HTLC outputs
check_spends!(node_txn[0], revoked_local_txn[0]);
// Next nodes[1] broadcasts its current local tx state:
assert_eq!(node_txn[1].input.len(), 1);
assert_eq!(node_txn[1].input[0].previous_output.txid, chan_1.3.txid()); //Spending funding tx unique txouput, tx broadcasted by ChannelManager
-
- assert_eq!(node_txn[2].input.len(), 1);
- let witness_script = node_txn[2].clone().input[0].witness.pop().unwrap();
- assert_eq!(witness_script.len(), OFFERED_HTLC_SCRIPT_WEIGHT); //Spending an offered htlc output
- assert_eq!(node_txn[2].input[0].previous_output.txid, node_txn[1].txid());
- assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid);
- assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[1].previous_output.txid);
}
get_announce_close_broadcast_events(&nodes, 0, 1);
assert_eq!(nodes[0].node.list_channels().len(), 0);
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ // Ensure all nodes are at the same height
+ let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
+ connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
+ connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
+ connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
+
// Rebalance the network a bit by relaying one payment through all the channels...
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
// Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[1], &Block { header, txdata: node_txn});
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
{
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
macro_rules! check_tx_local_broadcast {
($node: expr, $htlc_offered: expr, $commitment_tx: expr, $chan_tx: expr) => { {
let mut node_txn = $node.tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 5);
+ assert_eq!(node_txn.len(), 3);
// Node[1]: ChannelManager: 3 (commitment tx, 2*HTLC-Timeout tx), ChannelMonitor: 2 (timeout tx)
// Node[0]: ChannelManager: 3 (commtiemtn tx, 2*HTLC-Timeout tx), ChannelMonitor: 2 HTLC-timeout
- check_spends!(node_txn[0], $commitment_tx);
check_spends!(node_txn[1], $commitment_tx);
- assert_ne!(node_txn[0].lock_time, 0);
+ check_spends!(node_txn[2], $commitment_tx);
assert_ne!(node_txn[1].lock_time, 0);
+ assert_ne!(node_txn[2].lock_time, 0);
if $htlc_offered {
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_eq!(node_txn[2].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert!(node_txn[1].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert!(node_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
} else {
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert_eq!(node_txn[2].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
assert!(node_txn[1].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert!(node_txn[2].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
}
- check_spends!(node_txn[2], $chan_tx);
- check_spends!(node_txn[3], node_txn[2]);
- check_spends!(node_txn[4], node_txn[2]);
- assert_eq!(node_txn[2].input[0].witness.last().unwrap().len(), 71);
- assert_eq!(node_txn[3].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(node_txn[4].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert!(node_txn[3].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
- assert!(node_txn[4].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
- assert_ne!(node_txn[3].lock_time, 0);
- assert_ne!(node_txn[4].lock_time, 0);
+ check_spends!(node_txn[0], $chan_tx);
+ assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 71);
node_txn.clear();
} }
}
// Broadcast legit commitment tx from A on B's chain
// Broadcast preimage tx by B on offered output from A commitment tx on A's chain
- let commitment_tx = get_local_commitment_txn!(nodes[0], chan_1.2);
- check_spends!(commitment_tx[0], chan_1.3);
- mine_transaction(&nodes[1], &commitment_tx[0]);
+ let node_a_commitment_tx = get_local_commitment_txn!(nodes[0], chan_1.2);
+ check_spends!(node_a_commitment_tx[0], chan_1.3);
+ mine_transaction(&nodes[1], &node_a_commitment_tx[0]);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
- let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 3 (commitment tx + HTLC-Sucess * 2), ChannelMonitor : 1 (HTLC-Success)
- assert_eq!(node_txn.len(), 4);
- check_spends!(node_txn[0], commitment_tx[0]);
- assert_eq!(node_txn[0].input.len(), 2);
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(node_txn[0].input[1].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(node_txn[0].lock_time, 0);
- assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
- check_spends!(node_txn[1], chan_1.3);
- assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71);
- check_spends!(node_txn[2], node_txn[1]);
- check_spends!(node_txn[3], node_txn[1]);
+ let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
+ assert_eq!(node_txn.len(), 6); // ChannelManager : 3 (commitment tx + HTLC-Sucess * 2), ChannelMonitor : 3 (HTLC-Success, 2* RBF bumps of above HTLC txn)
+ let commitment_spend =
+ if node_txn[0].input[0].previous_output.txid == node_a_commitment_tx[0].txid() {
+ check_spends!(node_txn[1], commitment_tx[0]);
+ check_spends!(node_txn[2], commitment_tx[0]);
+ assert_ne!(node_txn[1].input[0].previous_output.vout, node_txn[2].input[0].previous_output.vout);
+ &node_txn[0]
+ } else {
+ check_spends!(node_txn[0], commitment_tx[0]);
+ check_spends!(node_txn[1], commitment_tx[0]);
+ assert_ne!(node_txn[0].input[0].previous_output.vout, node_txn[1].input[0].previous_output.vout);
+ &node_txn[2]
+ };
+
+ check_spends!(commitment_spend, node_a_commitment_tx[0]);
+ assert_eq!(commitment_spend.input.len(), 2);
+ assert_eq!(commitment_spend.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(commitment_spend.input[1].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(commitment_spend.lock_time, 0);
+ assert!(commitment_spend.output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ check_spends!(node_txn[3], chan_1.3);
+ assert_eq!(node_txn[3].input[0].witness.clone().last().unwrap().len(), 71);
+ check_spends!(node_txn[4], node_txn[3]);
+ check_spends!(node_txn[5], node_txn[3]);
// We don't bother to check that B can claim the HTLC output on its commitment tx here as
// we already checked the same situation with A.
// Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
- connect_block(&nodes[0], &Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone()] });
+ connect_block(&nodes[0], &Block { header, txdata: vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()] });
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let events = nodes[0].node.get_and_clear_pending_events();
_ => panic!("Unexpected event"),
}
}
- check_tx_local_broadcast!(nodes[0], true, commitment_tx[0], chan_1.3);
+ check_tx_local_broadcast!(nodes[0], true, node_a_commitment_tx[0], chan_1.3);
}
fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
check_spends!(commitment_tx[0], chan_1.3);
mine_transaction(&nodes[0], &commitment_tx[0]);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
- let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 timeout tx
- assert_eq!(node_txn.len(), 3);
- check_spends!(node_txn[0], commitment_tx[0]);
- assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[1], chan_1.3);
- check_spends!(node_txn[2], node_txn[1]);
- assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), 71);
- assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 commitment tx, ChannelMonitor : 1 timeout tx
+ assert_eq!(node_txn.len(), 2);
+ check_spends!(node_txn[0], chan_1.3);
+ assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), 71);
+ check_spends!(node_txn[1], commitment_tx[0]);
+ assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
}
#[test]
route_payment(&nodes[0], &[&nodes[1]], 10000000);
nodes[0].node.force_close_channel(&nodes[0].node.list_channels()[0].channel_id).unwrap();
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 2);
+ assert_eq!(node_txn.len(), 3);
+ assert_eq!(node_txn[0], node_txn[1]);
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]});
// Duplicate the connect_block call since this may happen due to other listeners
// registering new transactions
header.prev_blockhash = header.block_hash();
- connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]});
+ connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[2].clone()]});
}
#[test]
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
+ // Connect blocks until the CLTV timeout is up so that we get an HTLC-Timeout transaction
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
- assert_eq!(node_txn.len(), 2);
+ assert_eq!(node_txn.len(), 3);
+ assert_eq!(node_txn[0], node_txn[1]);
assert!(nodes[1].node.claim_funds(payment_preimage));
check_added_monitors!(nodes[1], 1);
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]});
+ connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[1].clone(), node_txn[2].clone()]});
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
let claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
- connect_block(&nodes[0], &Block { header, txdata: node_txn});
+ header.prev_blockhash = nodes[0].best_block_hash();
+ connect_block(&nodes[0], &Block { header, txdata: vec![node_txn[1].clone(), node_txn[2].clone()]});
// Serialize out the ChannelMonitor before connecting the on-chain claim transactions. This is
// fairly normal behavior as ChannelMonitor(s) are often not re-serialized when on-chain events
let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new());
nodes[0].chain_monitor.chain_monitor.monitors.read().unwrap().iter().next().unwrap().1.write(&mut chan_0_monitor_serialized).unwrap();
- header.prev_blockhash = header.block_hash();
+ header.prev_blockhash = nodes[0].best_block_hash();
let claim_block = Block { header, txdata: claim_txn};
connect_block(&nodes[0], &claim_block);
expect_payment_sent!(nodes[0], payment_preimage);
// Note that if we re-connect the block which exposed nodes[0] to the payment preimage (but
// which the current ChannelMonitor has not seen), the ChannelManager's de-duplication of
// payment events should kick in, leaving us with no pending events here.
- nodes[0].chain_monitor.chain_monitor.block_connected(&claim_block, nodes[0].blocks.borrow().len() as u32 - 1);
+ let height = nodes[0].blocks.lock().unwrap().len() as u32 - 1;
+ nodes[0].chain_monitor.chain_monitor.block_connected(&claim_block, height);
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
}
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- { // Channel close should result in a commitment tx and an HTLC tx
+ { // Channel close should result in a commitment tx
let txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(txn.len(), 2);
+ assert_eq!(txn.len(), 1);
+ check_spends!(txn[0], funding_tx);
assert_eq!(txn[0].input[0].previous_output.txid, funding_tx.txid());
- assert_eq!(txn[1].input[0].previous_output.txid, txn[0].txid());
}
for monitor in node_0_monitors.drain(..) {
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
_ => panic!("Unexpected event"),
}
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
// Check B's monitor was able to send back output descriptor event for timeout tx on A's commitment tx
- let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 3); // ChannelManager : 2 (local commitent tx + HTLC-timeout), ChannelMonitor: timeout tx
- check_spends!(node_txn[0], commitment_tx[0].clone());
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[1], chan_1.3.clone());
- check_spends!(node_txn[2], node_txn[1]);
+ let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+ assert_eq!(node_txn.len(), 2); // ChannelManager : 1 local commitent tx, ChannelMonitor: timeout tx
+ check_spends!(node_txn[0], chan_1.3.clone());
+ check_spends!(node_txn[1], commitment_tx[0].clone());
+ assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- mine_transaction(&nodes[1], &node_txn[0]);
+ mine_transaction(&nodes[1], &node_txn[1]);
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
expect_payment_failed!(nodes[1], our_payment_hash, true);
let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000);
assert_eq!(spend_txn.len(), 3); // SpendableOutput: remote_commitment_tx.to_remote, timeout_tx.output
check_spends!(spend_txn[0], commitment_tx[0]);
- check_spends!(spend_txn[1], node_txn[0]);
- check_spends!(spend_txn[2], node_txn[0], commitment_tx[0]); // All outputs
+ check_spends!(spend_txn[1], node_txn[1]);
+ check_spends!(spend_txn[2], node_txn[1], commitment_tx[0]); // All outputs
}
#[test]
mine_transaction(&nodes[0], &revoked_local_txn[0]);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(revoked_htlc_txn.len(), 2);
- assert_eq!(revoked_htlc_txn[0].input.len(), 1);
- assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]);
- check_spends!(revoked_htlc_txn[1], chan_1.3);
+ check_spends!(revoked_htlc_txn[0], chan_1.3);
+ assert_eq!(revoked_htlc_txn[1].input.len(), 1);
+ assert_eq!(revoked_htlc_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]);
+ assert_ne!(revoked_htlc_txn[1].lock_time, 0); // HTLC-Timeout
// B will generate justice tx from A's revoked commitment/HTLC tx
let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] });
+ connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[1].clone()] });
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 3); // ChannelMonitor: bogus justice tx, justice tx on revoked outputs, ChannelManager: local commitment tx
// The first transaction generated is bogus - it spends both outputs of revoked_local_txn[0]
- // including the one already spent by revoked_htlc_txn[0]. That's OK, we'll spend with valid
+ // including the one already spent by revoked_htlc_txn[1]. That's OK, we'll spend with valid
// transactions next...
assert_eq!(node_txn[0].input.len(), 3);
- check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[0]);
+ check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[1]);
assert_eq!(node_txn[1].input.len(), 2);
- check_spends!(node_txn[1], revoked_local_txn[0], revoked_htlc_txn[0]);
- if node_txn[1].input[1].previous_output.txid == revoked_htlc_txn[0].txid() {
- assert_ne!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
+ check_spends!(node_txn[1], revoked_local_txn[0], revoked_htlc_txn[1]);
+ if node_txn[1].input[1].previous_output.txid == revoked_htlc_txn[1].txid() {
+ assert_ne!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
} else {
- assert_eq!(node_txn[1].input[0].previous_output.txid, revoked_htlc_txn[0].txid());
- assert_ne!(node_txn[1].input[1].previous_output, revoked_htlc_txn[0].input[0].previous_output);
+ assert_eq!(node_txn[1].input[0].previous_output.txid, revoked_htlc_txn[1].txid());
+ assert_ne!(node_txn[1].input[1].previous_output, revoked_htlc_txn[1].input[0].previous_output);
}
assert_eq!(node_txn[2].input.len(), 1);
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ // Ensure all nodes are at the same height
+ let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
+ connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
+ connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
+ connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
+
// Rebalance the network a bit by relaying one payment through all the channels ...
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
// So we broadcast C's commitment tx and HTLC-Success on B's chain, we should successfully be able to extract preimage and update downstream monitor
let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[1], &Block { header, txdata: vec![c_txn[1].clone(), c_txn[2].clone()]});
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
{
let mut b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- // ChannelMonitor: claim tx, ChannelManager: local commitment tx + HTLC-timeout tx
- assert_eq!(b_txn.len(), 3);
- check_spends!(b_txn[1], chan_2.3); // B local commitment tx, issued by ChannelManager
- check_spends!(b_txn[2], b_txn[1]); // HTLC-Timeout on B local commitment tx, issued by ChannelManager
- assert_eq!(b_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert!(b_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
- assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
- check_spends!(b_txn[0], c_txn[1]); // timeout tx on C remote commitment tx, issued by ChannelMonitor
- assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
- assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
+ // ChannelMonitor: claim tx, ChannelManager: local commitment tx
+ assert_eq!(b_txn.len(), 2);
+ check_spends!(b_txn[0], chan_2.3); // B local commitment tx, issued by ChannelManager
+ check_spends!(b_txn[1], c_txn[1]); // timeout tx on C remote commitment tx, issued by ChannelMonitor
+ assert_eq!(b_txn[1].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert!(b_txn[1].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert_ne!(b_txn[1].lock_time, 0); // Timeout tx
b_txn.clear();
}
check_added_monitors!(nodes[1], 1);
let commitment_tx = get_local_commitment_txn!(nodes[0], chan_1.2);
mine_transaction(&nodes[1], &commitment_tx[0]);
let b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- // ChannelMonitor: HTLC-Success tx, ChannelManager: local commitment tx + HTLC-Success tx
- assert_eq!(b_txn.len(), 3);
- check_spends!(b_txn[1], chan_1.3);
- check_spends!(b_txn[2], b_txn[1]);
- check_spends!(b_txn[0], commitment_tx[0]);
- assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
- assert_eq!(b_txn[0].lock_time, 0); // Success tx
+ // ChannelMonitor: HTLC-Success tx + HTLC-Timeout RBF Bump, ChannelManager: local commitment tx + HTLC-Success tx
+ assert_eq!(b_txn.len(), 4);
+ check_spends!(b_txn[2], chan_1.3);
+ check_spends!(b_txn[3], b_txn[2]);
+ let (htlc_success_claim, htlc_timeout_bumped) =
+ if b_txn[0].input[0].previous_output.txid == commitment_tx[0].txid()
+ { (&b_txn[0], &b_txn[1]) } else { (&b_txn[1], &b_txn[0]) };
+ check_spends!(htlc_success_claim, commitment_tx[0]);
+ assert_eq!(htlc_success_claim.input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert!(htlc_success_claim.output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert_eq!(htlc_success_claim.lock_time, 0); // Success tx
+ check_spends!(htlc_timeout_bumped, c_txn[1]); // timeout tx on C remote commitment tx, issued by ChannelMonitor
+ assert_ne!(htlc_timeout_bumped.lock_time, 0); // Success tx
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
+ let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
+ connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
+ connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
+ connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
+ connect_blocks(&nodes[3], node_max_height - nodes[3].best_block_info().1);
+
let (our_payment_preimage, duplicate_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000);
let payment_secret = nodes[3].node.create_inbound_payment_for_hash(duplicate_payment_hash, None, 7200, 0).unwrap();
+ // We reduce the final CLTV here by a somewhat arbitrary constant to keep it under the one-byte
+ // script push size limit so that the below script length checks match
+ // ACCEPTED_HTLC_SCRIPT_WEIGHT.
let route = get_route(&nodes[0].node.get_our_node_id(), &nodes[0].net_graph_msg_handler.network_graph.read().unwrap(),
- &nodes[3].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 900000, TEST_FINAL_CLTV, nodes[0].logger).unwrap();
+ &nodes[3].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 900000, TEST_FINAL_CLTV - 40, nodes[0].logger).unwrap();
send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2], &nodes[3]]], 900000, duplicate_payment_hash, payment_secret);
let commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2);
mine_transaction(&nodes[1], &commitment_txn[0]);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 40 + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
let htlc_timeout_tx;
{ // Extract one of the two HTLC-Timeout transaction
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- // ChannelMonitor: timeout tx * 2, ChannelManager: local commitment tx + HTLC-timeout * 2
- assert_eq!(node_txn.len(), 5);
- check_spends!(node_txn[0], commitment_txn[0]);
- assert_eq!(node_txn[0].input.len(), 1);
+ // ChannelMonitor: timeout tx * 3, ChannelManager: local commitment tx
+ assert_eq!(node_txn.len(), 4);
+ check_spends!(node_txn[0], chan_2.3);
+
check_spends!(node_txn[1], commitment_txn[0]);
assert_eq!(node_txn[1].input.len(), 1);
- assert_ne!(node_txn[0].input[0], node_txn[1].input[0]);
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[2], commitment_txn[0]);
+ assert_eq!(node_txn[2].input.len(), 1);
+ assert_eq!(node_txn[1].input[0].previous_output, node_txn[2].input[0].previous_output);
+ check_spends!(node_txn[3], commitment_txn[0]);
+ assert_ne!(node_txn[1].input[0].previous_output, node_txn[3].input[0].previous_output);
+
assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[2], chan_2.3);
- check_spends!(node_txn[3], node_txn[2]);
- check_spends!(node_txn[4], node_txn[2]);
+ assert_eq!(node_txn[2].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(node_txn[3].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
htlc_timeout_tx = node_txn[1].clone();
}
}
let htlc_success_txn: Vec<_> = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
assert_eq!(htlc_success_txn.len(), 5); // ChannelMonitor: HTLC-Success txn (*2 due to 2-HTLC outputs), ChannelManager: local commitment tx + HTLC-Success txn (*2 due to 2-HTLC outputs)
- check_spends!(htlc_success_txn[2], chan_2.3);
- check_spends!(htlc_success_txn[3], htlc_success_txn[2]);
- check_spends!(htlc_success_txn[4], htlc_success_txn[2]);
- assert_eq!(htlc_success_txn[0], htlc_success_txn[3]);
+ check_spends!(htlc_success_txn[0], commitment_txn[0]);
+ check_spends!(htlc_success_txn[1], commitment_txn[0]);
assert_eq!(htlc_success_txn[0].input.len(), 1);
assert_eq!(htlc_success_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(htlc_success_txn[1], htlc_success_txn[4]);
assert_eq!(htlc_success_txn[1].input.len(), 1);
assert_eq!(htlc_success_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
- assert_ne!(htlc_success_txn[0].input[0], htlc_success_txn[1].input[0]);
- check_spends!(htlc_success_txn[0], commitment_txn[0]);
- check_spends!(htlc_success_txn[1], commitment_txn[0]);
+ assert_ne!(htlc_success_txn[0].input[0].previous_output, htlc_success_txn[1].input[0].previous_output);
+ assert_eq!(htlc_success_txn[2], commitment_txn[0]);
+ assert_eq!(htlc_success_txn[3], htlc_success_txn[0]);
+ assert_eq!(htlc_success_txn[4], htlc_success_txn[1]);
+ assert_ne!(htlc_success_txn[0].input[0].previous_output, htlc_timeout_tx.input[0].previous_output);
mine_transaction(&nodes[1], &htlc_timeout_tx);
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
mine_transaction(&nodes[0], &local_txn[0]);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[0], local_txn[0]);
- node_txn[0].clone()
+ assert_eq!(node_txn.len(), 2);
+ check_spends!(node_txn[0], chan_1.3);
+ assert_eq!(node_txn[1].input.len(), 1);
+ assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[1], local_txn[0]);
+ node_txn[1].clone()
};
mine_transaction(&nodes[0], &htlc_timeout);
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
assert_ne!(chan_0.3.output[0].script_pubkey, chan_1.3.output[0].script_pubkey);
+ // Ensure all nodes are at the same height
+ let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
+ connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
+ connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
+ connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
+
let (_, our_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 9000000);
let local_txn_0 = get_local_commitment_txn!(nodes[0], chan_0.2);
let local_txn_1 = get_local_commitment_txn!(nodes[0], chan_1.2);
// Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx
mine_transaction(&nodes[0], &local_txn_1[0]);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[0], local_txn_1[0]);
- node_txn[0].clone()
+ assert_eq!(node_txn[1].input.len(), 1);
+ assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[1], local_txn_1[0]);
+ node_txn[1].clone()
};
mine_transaction(&nodes[0], &htlc_timeout);
if local {
// We fail dust-HTLC 1 by broadcast of local commitment tx
mine_transaction(&nodes[0], &as_commitment_tx[0]);
+ connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
+ expect_payment_failed!(nodes[0], dust_hash, true);
+
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS - ANTI_REORG_DELAY);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
- timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].clone());
- connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
- expect_payment_failed!(nodes[0], dust_hash, true);
+ timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[1].clone());
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
// We fail non-dust-HTLC 2 by broadcast of local HTLC-timeout tx on local commitment tx
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
- timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].clone());
- connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[1].clone());
if !revoked {
expect_payment_failed!(nodes[0], dust_hash, true);
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
logger = test_utils::TestLogger::with_id(format!("node {}", 0));
let mut chain_monitor = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut ::std::io::Cursor::new(previous_chain_monitor_state.0), keys_manager).unwrap().1;
chain_source = test_utils::TestChainSource::new(Network::Testnet);
- tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
+ tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
persister = test_utils::TestPersister::new();
monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &fee_estimator, &persister, keys_manager);
let feerate_1;
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 3); // justice tx (broadcasted from ChannelMonitor) + local commitment tx + local HTLC-timeout (broadcasted from ChannelManager)
+ assert_eq!(node_txn.len(), 2); // justice tx (broadcasted from ChannelMonitor) + local commitment tx
assert_eq!(node_txn[0].input.len(), 3); // Penalty txn claims to_local, offered_htlc and received_htlc outputs
assert_eq!(node_txn[0].output.len(), 1);
check_spends!(node_txn[0], revoked_txn[0]);
connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone()] });
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
+ connect_blocks(&nodes[1], 49); // Confirm blocks until the HTLC expires (note CLTV was explicitly 50 above)
let revoked_htlc_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(revoked_htlc_txn.len(), 4);
- if revoked_htlc_txn[0].input[0].witness.last().unwrap().len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
- assert_eq!(revoked_htlc_txn[0].input.len(), 1);
- check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]);
- assert_eq!(revoked_htlc_txn[1].input.len(), 1);
- assert_eq!(revoked_htlc_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(revoked_htlc_txn[1].output.len(), 1);
- check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]);
- } else if revoked_htlc_txn[1].input[0].witness.last().unwrap().len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
- assert_eq!(revoked_htlc_txn[1].input.len(), 1);
- check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]);
- assert_eq!(revoked_htlc_txn[0].input.len(), 1);
- assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(revoked_htlc_txn[0].output.len(), 1);
- check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]);
- }
+ assert_eq!(revoked_htlc_txn.len(), 3);
+ check_spends!(revoked_htlc_txn[1], chan.3);
+
+ assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(revoked_htlc_txn[0].input.len(), 1);
+ check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]);
+
+ assert_eq!(revoked_htlc_txn[2].input.len(), 1);
+ assert_eq!(revoked_htlc_txn[2].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(revoked_htlc_txn[2].output.len(), 1);
+ check_spends!(revoked_htlc_txn[2], revoked_local_txn[0]);
// Broadcast set of revoked txn on A
let hash_128 = connect_blocks(&nodes[0], 40);
let header_11 = BlockHeader { version: 0x20000000, prev_blockhash: hash_128, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
connect_block(&nodes[0], &Block { header: header_11, txdata: vec![revoked_local_txn[0].clone()] });
let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_11.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- connect_block(&nodes[0], &Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] });
+ connect_block(&nodes[0], &Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[2].clone()] });
expect_pending_htlcs_forwardable_ignore!(nodes[0]);
let first;
let feerate_1;
assert_ne!(node_txn[1].input[0].previous_output, node_txn[2].input[0].previous_output);
assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
- assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
+ assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[2].input[0].previous_output);
// node_txn[3] is the local commitment tx broadcast just because (and somewhat in case of
// reorgs, though its not clear its ever worth broadcasting conflicting txn like this when
// output, checked above).
assert_eq!(node_txn[4].input.len(), 2);
assert_eq!(node_txn[4].output.len(), 1);
- check_spends!(node_txn[4], revoked_htlc_txn[0], revoked_htlc_txn[1]);
+ check_spends!(node_txn[4], revoked_htlc_txn[0], revoked_htlc_txn[2]);
first = node_txn[4].txid();
// Store both feerates for later comparison
- let fee_1 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[1].output[0].value - node_txn[4].output[0].value;
+ let fee_1 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[2].output[0].value - node_txn[4].output[0].value;
feerate_1 = fee_1 * 1000 / node_txn[4].get_weight() as u64;
penalty_txn = vec![node_txn[2].clone()];
node_txn.clear();
check_spends!(node_txn[1], revoked_local_txn[0]);
// Note that these are both bogus - they spend outputs already claimed in block 129:
if node_txn[0].input[0].previous_output == revoked_htlc_txn[0].input[0].previous_output {
- assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
+ assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[2].input[0].previous_output);
} else {
- assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
+ assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[2].input[0].previous_output);
assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
}
assert_eq!(node_txn.len(), 1);
assert_eq!(node_txn[0].input.len(), 2);
- check_spends!(node_txn[0], revoked_htlc_txn[0], revoked_htlc_txn[1]);
+ check_spends!(node_txn[0], revoked_htlc_txn[0], revoked_htlc_txn[2]);
// Verify bumped tx is different and 25% bump heuristic
assert_ne!(first, node_txn[0].txid());
- let fee_2 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[1].output[0].value - node_txn[0].output[0].value;
+ let fee_2 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[2].output[0].value - node_txn[0].output[0].value;
let feerate_2 = fee_2 * 1000 / node_txn[0].get_weight() as u64;
assert!(feerate_2 * 100 > feerate_1 * 125);
let txn = vec![node_txn[0].clone()];
nodes[1].node.claim_funds(payment_preimage);
mine_transaction(&nodes[1], &remote_txn[0]);
check_added_monitors!(nodes[1], 2);
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
// One or more claim tx should have been broadcast, check it
let timeout;
let preimage;
+ let preimage_bump;
let feerate_timeout;
let feerate_preimage;
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 5); // 2 * claim tx (broadcasted from ChannelMonitor) + local commitment tx + local HTLC-timeout + local HTLC-success (broadcasted from ChannelManager)
+ // 9 transactions including:
+ // 1*2 ChannelManager local broadcasts of commitment + HTLC-Success
+ // 1*3 ChannelManager local broadcasts of commitment + HTLC-Success + HTLC-Timeout
+ // 2 * HTLC-Success (one RBF bump we'll check later)
+ // 1 * HTLC-Timeout
+ assert_eq!(node_txn.len(), 8);
assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[1].input.len(), 1);
+ assert_eq!(node_txn[6].input.len(), 1);
check_spends!(node_txn[0], remote_txn[0]);
- check_spends!(node_txn[1], remote_txn[0]);
- check_spends!(node_txn[2], chan.3);
- check_spends!(node_txn[3], node_txn[2]);
- check_spends!(node_txn[4], node_txn[2]);
- if node_txn[0].input[0].witness.last().unwrap().len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
- timeout = node_txn[0].txid();
- let index = node_txn[0].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
- feerate_timeout = fee * 1000 / node_txn[0].get_weight() as u64;
-
- preimage = node_txn[1].txid();
- let index = node_txn[1].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[1].output[0].value;
- feerate_preimage = fee * 1000 / node_txn[1].get_weight() as u64;
- } else {
- timeout = node_txn[1].txid();
- let index = node_txn[1].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[1].output[0].value;
- feerate_timeout = fee * 1000 / node_txn[1].get_weight() as u64;
-
- preimage = node_txn[0].txid();
- let index = node_txn[0].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
- feerate_preimage = fee * 1000 / node_txn[0].get_weight() as u64;
- }
+ check_spends!(node_txn[6], remote_txn[0]);
+ assert_eq!(node_txn[0].input[0].previous_output, node_txn[3].input[0].previous_output);
+ preimage_bump = node_txn[3].clone();
+
+ check_spends!(node_txn[1], chan.3);
+ check_spends!(node_txn[2], node_txn[1]);
+ assert_eq!(node_txn[1], node_txn[4]);
+ assert_eq!(node_txn[2], node_txn[5]);
+
+ timeout = node_txn[6].txid();
+ let index = node_txn[6].input[0].previous_output.vout;
+ let fee = remote_txn[0].output[index as usize].value - node_txn[6].output[0].value;
+ feerate_timeout = fee * 1000 / node_txn[6].get_weight() as u64;
+
+ preimage = node_txn[0].txid();
+ let index = node_txn[0].input[0].previous_output.vout;
+ let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
+ feerate_preimage = fee * 1000 / node_txn[0].get_weight() as u64;
+
node_txn.clear();
};
assert_ne!(feerate_timeout, 0);
connect_blocks(&nodes[1], 15);
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 2);
+ assert_eq!(node_txn.len(), 1);
assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[1].input.len(), 1);
+ assert_eq!(preimage_bump.input.len(), 1);
check_spends!(node_txn[0], remote_txn[0]);
- check_spends!(node_txn[1], remote_txn[0]);
- if node_txn[0].input[0].witness.last().unwrap().len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
- let index = node_txn[0].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
- let new_feerate = fee * 1000 / node_txn[0].get_weight() as u64;
- assert!(new_feerate * 100 > feerate_timeout * 125);
- assert_ne!(timeout, node_txn[0].txid());
-
- let index = node_txn[1].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[1].output[0].value;
- let new_feerate = fee * 1000 / node_txn[1].get_weight() as u64;
- assert!(new_feerate * 100 > feerate_preimage * 125);
- assert_ne!(preimage, node_txn[1].txid());
- } else {
- let index = node_txn[1].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[1].output[0].value;
- let new_feerate = fee * 1000 / node_txn[1].get_weight() as u64;
- assert!(new_feerate * 100 > feerate_timeout * 125);
- assert_ne!(timeout, node_txn[1].txid());
-
- let index = node_txn[0].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
- let new_feerate = fee * 1000 / node_txn[0].get_weight() as u64;
- assert!(new_feerate * 100 > feerate_preimage * 125);
- assert_ne!(preimage, node_txn[0].txid());
- }
+ check_spends!(preimage_bump, remote_txn[0]);
+
+ let index = preimage_bump.input[0].previous_output.vout;
+ let fee = remote_txn[0].output[index as usize].value - preimage_bump.output[0].value;
+ let new_feerate = fee * 1000 / preimage_bump.get_weight() as u64;
+ assert!(new_feerate * 100 > feerate_timeout * 125);
+ assert_ne!(timeout, preimage_bump.txid());
+
+ let index = node_txn[0].input[0].previous_output.vout;
+ let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
+ let new_feerate = fee * 1000 / node_txn[0].get_weight() as u64;
+ assert!(new_feerate * 100 > feerate_preimage * 125);
+ assert_ne!(preimage, node_txn[0].txid());
+
node_txn.clear();
}
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(100_000), 2, 0) {
assert_eq!(err, "Duplicate payment hash");
} else { panic!(); }
- let mut block = Block {
- header: BlockHeader {
- version: 0x2000000,
- prev_blockhash: nodes[1].blocks.borrow().last().unwrap().0.block_hash(),
- merkle_root: Default::default(),
- time: nodes[1].blocks.borrow().len() as u32 + 7200, bits: 42, nonce: 42 },
- txdata: vec![],
+ let mut block = {
+ let node_1_blocks = nodes[1].blocks.lock().unwrap();
+ Block {
+ header: BlockHeader {
+ version: 0x2000000,
+ prev_blockhash: node_1_blocks.last().unwrap().0.block_hash(),
+ merkle_root: Default::default(),
+ time: node_1_blocks.len() as u32 + 7200, bits: 42, nonce: 42 },
+ txdata: vec![],
+ }
};
connect_block(&nodes[1], &block);
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(100_000), 2, 0) {
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ // Make the tx_broadcaster aware of enough blocks that it doesn't think we're violating
+ // transaction lock time requirements here.
+ chanmon_cfgs[0].tx_broadcaster.blocks.lock().unwrap().resize(200, (header, 0));
watchtower.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200);
// Try to update ChannelMonitor
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ // Make the tx_broadcaster aware of enough blocks that it doesn't think we're violating
+ // transaction lock time requirements here.
+ chanmon_cfgs[0].tx_broadcaster.blocks.lock().unwrap().resize((CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS) as usize, (header, 0));
watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
// Watchtower Alice should have broadcast a commitment/HTLC-timeout
chain::Listen::block_connected(&nodes[0].chain_monitor.chain_monitor, &Block { header, txdata: vec![local_txn[0].clone()] }, nodes[0].best_block_info().1 + 1);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- check_spends!(node_txn[0], local_txn[0]);
- node_txn[0].clone()
+ assert_eq!(node_txn[1].input.len(), 1);
+ assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[1], local_txn[0]);
+ node_txn[1].clone()
};
- let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
connect_block(&nodes[0], &Block { header: header_201, txdata: vec![htlc_timeout.clone()] });
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
expect_payment_failed!(nodes[0], our_payment_hash, true);
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
pub struct PaymentSecret(pub [u8;32]);
+use prelude::*;
use bitcoin::bech32;
use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, WriteBase32, u5};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
+use prelude::*;
use core::{cmp, fmt};
use core::fmt::Debug;
use std::io::Read;
}
}
+impl Readable for NetAddress {
+ fn read<R: Read>(reader: &mut R) -> Result<NetAddress, DecodeError> {
+ match Readable::read(reader) {
+ Ok(Ok(res)) => Ok(res),
+ Ok(Err(_)) => Err(DecodeError::UnknownVersion),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+
/// The unsigned part of a node_announcement
#[derive(Clone, Debug, PartialEq)]
pub struct UnsignedNodeAnnouncement {
}
mod fuzzy_internal_msgs {
+ use prelude::*;
use ln::PaymentSecret;
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
use bitcoin::secp256k1::key::{PublicKey,SecretKey};
use bitcoin::secp256k1::{Secp256k1, Message};
+ use prelude::*;
use std::io::Cursor;
#[test]
use bitcoin::secp256k1::Secp256k1;
use bitcoin::secp256k1::key::SecretKey;
+use prelude::*;
use core::default::Default;
use std::io;
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1;
+use prelude::*;
use std::io::Cursor;
use core::ops::Deref;
#[cfg(test)]
mod tests {
+ use prelude::*;
use ln::PaymentHash;
use ln::features::{ChannelFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
// You may not use this file except in accordance with one or both of these
// licenses.
+use prelude::*;
+
use ln::msgs::LightningError;
use ln::msgs;
use util::logger::Logger;
use routing::network_graph::NetGraphMsgHandler;
-use std::collections::{HashMap,hash_map,HashSet,LinkedList};
+use prelude::*;
+use alloc::collections::LinkedList;
+use std::collections::{HashMap,hash_map,HashSet};
use std::sync::{Arc, Mutex};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{cmp, hash, fmt, mem};
use bitcoin::secp256k1::Secp256k1;
use bitcoin::secp256k1::key::{SecretKey, PublicKey};
+ use prelude::*;
use std::sync::{Arc, Mutex};
use core::sync::atomic::Ordering;
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::hash_types::BlockHash;
+use prelude::*;
use std::collections::HashMap;
use core::mem;
// Give node 1 node 2's commitment transaction and get its response (timing the HTLC out)
mine_transaction(&nodes[1], &node_2_commitment_txn[0]);
- let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_1_commitment_txn.len(), 3); // ChannelMonitor: 1 offered HTLC-Timeout, ChannelManger: 1 local commitment tx, 1 Offered HTLC-Timeout
- assert_eq!(node_1_commitment_txn[1].output.len(), 2); // to-local and Offered HTLC (to-remote is dust)
- check_spends!(node_1_commitment_txn[1], chan_2.3);
- check_spends!(node_1_commitment_txn[2], node_1_commitment_txn[1]);
- check_spends!(node_1_commitment_txn[0], node_2_commitment_txn[0]);
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
+ assert_eq!(node_1_commitment_txn.len(), 2); // ChannelMonitor: 1 offered HTLC-Timeout, ChannelManger: 1 local commitment tx
+ assert_eq!(node_1_commitment_txn[0].output.len(), 2); // to-local and Offered HTLC (to-remote is dust)
+ check_spends!(node_1_commitment_txn[0], chan_2.3);
+ check_spends!(node_1_commitment_txn[1], node_2_commitment_txn[0]);
// Confirm node 2's commitment txn (and node 1's HTLC-Timeout) on node 1
header.prev_blockhash = nodes[1].best_block_hash();
- connect_block(&nodes[1], &Block { header, txdata: vec![node_2_commitment_txn[0].clone(), node_1_commitment_txn[0].clone()] });
+ let block = Block { header, txdata: vec![node_2_commitment_txn[0].clone(), node_1_commitment_txn[1].clone()] };
+ connect_block(&nodes[1], &block);
// ...but return node 2's commitment tx (and claim) in case claim is set and we're preparing to reorg
node_2_commitment_txn
};
mod tests {
use super::*;
use util::byte_utils;
+ use prelude::*;
// Big-endian wire encoding of Pong message (type = 19, byteslen = 2).
const ENCODED_PONG: [u8; 6] = [0u8, 19u8, 0u8, 2u8, 0u8, 0u8];
use util::events::{MessageSendEvent, MessageSendEventsProvider};
use util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK};
+use prelude::*;
+use alloc::collections::{BTreeMap, btree_map::Entry as BtreeEntry};
use core::{cmp, fmt};
use std::sync::{RwLock, RwLockReadGuard};
use core::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
-use std::collections::BTreeMap;
-use std::collections::btree_map::Entry as BtreeEntry;
use core::ops::Deref;
use bitcoin::hashes::hex::ToHex;
}
}
-impl_writeable!(DirectionalChannelInfo, 0, {
- last_update,
- enabled,
- cltv_expiry_delta,
- htlc_minimum_msat,
- htlc_maximum_msat,
- fees,
- last_update_message
-});
+impl_writeable_tlv_based!(DirectionalChannelInfo, {
+ (0, last_update),
+ (2, enabled),
+ (4, cltv_expiry_delta),
+ (6, htlc_minimum_msat),
+ (8, htlc_maximum_msat),
+ (10, fees),
+ (12, last_update_message),
+}, {}, {});
#[derive(Clone, Debug, PartialEq)]
/// Details about a channel (both directions).
}
}
-impl_writeable!(ChannelInfo, 0, {
- features,
- node_one,
- one_to_two,
- node_two,
- two_to_one,
- capacity_sats,
- announcement_message
-});
+impl_writeable_tlv_based!(ChannelInfo, {
+ (0, features),
+ (2, node_one),
+ (4, one_to_two),
+ (6, node_two),
+ (8, two_to_one),
+ (10, capacity_sats),
+ (12, announcement_message),
+}, {}, {});
/// Fees for routing via a given channel or a node
pub proportional_millionths: u32,
}
-impl Readable for RoutingFees{
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<RoutingFees, DecodeError> {
- let base_msat: u32 = Readable::read(reader)?;
- let proportional_millionths: u32 = Readable::read(reader)?;
- Ok(RoutingFees {
- base_msat,
- proportional_millionths,
- })
- }
-}
-
-impl Writeable for RoutingFees {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- self.base_msat.write(writer)?;
- self.proportional_millionths.write(writer)?;
- Ok(())
- }
-}
+impl_writeable_tlv_based!(RoutingFees, {(0, base_msat), (2, proportional_millionths)}, {}, {});
#[derive(Clone, Debug, PartialEq)]
/// Information received in the latest node_announcement from this node.
pub announcement_message: Option<NodeAnnouncement>
}
-impl Writeable for NodeAnnouncementInfo {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- self.features.write(writer)?;
- self.last_update.write(writer)?;
- self.rgb.write(writer)?;
- self.alias.write(writer)?;
- (self.addresses.len() as u64).write(writer)?;
- for ref addr in &self.addresses {
- addr.write(writer)?;
- }
- self.announcement_message.write(writer)?;
- Ok(())
- }
-}
-
-impl Readable for NodeAnnouncementInfo {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<NodeAnnouncementInfo, DecodeError> {
- let features = Readable::read(reader)?;
- let last_update = Readable::read(reader)?;
- let rgb = Readable::read(reader)?;
- let alias = Readable::read(reader)?;
- let addresses_count: u64 = Readable::read(reader)?;
- let mut addresses = Vec::with_capacity(cmp::min(addresses_count, MAX_ALLOC_SIZE / 40) as usize);
- for _ in 0..addresses_count {
- match Readable::read(reader) {
- Ok(Ok(addr)) => { addresses.push(addr); },
- Ok(Err(_)) => return Err(DecodeError::InvalidValue),
- Err(DecodeError::ShortRead) => return Err(DecodeError::BadLengthDescriptor),
- _ => unreachable!(),
- }
- }
- let announcement_message = Readable::read(reader)?;
- Ok(NodeAnnouncementInfo {
- features,
- last_update,
- rgb,
- alias,
- addresses,
- announcement_message
- })
- }
-}
+impl_writeable_tlv_based!(NodeAnnouncementInfo, {
+ (0, features),
+ (2, last_update),
+ (4, rgb),
+ (6, alias),
+}, {
+ (8, announcement_message),
+}, {
+ (10, addresses),
+});
#[derive(Clone, Debug, PartialEq)]
/// Details about a node in the network, known from the network announcement.
}
}
-impl Writeable for NodeInfo {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- (self.channels.len() as u64).write(writer)?;
- for ref chan in self.channels.iter() {
- chan.write(writer)?;
- }
- self.lowest_inbound_channel_fees.write(writer)?;
- self.announcement_info.write(writer)?;
- Ok(())
- }
-}
-
-const MAX_ALLOC_SIZE: u64 = 64*1024;
-
-impl Readable for NodeInfo {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<NodeInfo, DecodeError> {
- let channels_count: u64 = Readable::read(reader)?;
- let mut channels = Vec::with_capacity(cmp::min(channels_count, MAX_ALLOC_SIZE / 8) as usize);
- for _ in 0..channels_count {
- channels.push(Readable::read(reader)?);
- }
- let lowest_inbound_channel_fees = Readable::read(reader)?;
- let announcement_info = Readable::read(reader)?;
- Ok(NodeInfo {
- channels,
- lowest_inbound_channel_fees,
- announcement_info,
- })
- }
-}
+impl_writeable_tlv_based!(NodeInfo, {}, {
+ (0, lowest_inbound_channel_fees),
+ (2, announcement_info),
+}, {
+ (4, channels),
+});
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
use bitcoin::secp256k1::key::{PublicKey, SecretKey};
use bitcoin::secp256k1::{All, Secp256k1};
+ use prelude::*;
use std::sync::Arc;
fn create_net_graph_msg_handler() -> (Secp256k1<All>, NetGraphMsgHandler<Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>) {
use util::ser::{Writeable, Readable};
use util::logger::Logger;
+use prelude::*;
+use alloc::collections::BinaryHeap;
use core::cmp;
-use std::collections::{HashMap, BinaryHeap};
+use std::collections::HashMap;
use core::ops::Deref;
/// A hop in a route
use bitcoin::secp256k1::key::{PublicKey,SecretKey};
use bitcoin::secp256k1::{Secp256k1, All};
+ use prelude::*;
use std::sync::Arc;
// Using the same keys for LN and BTC ids
use util::ser::Readable;
/// Tries to open a network graph file, or panics with a URL to fetch it.
pub(super) fn get_route_file() -> Result<std::fs::File, std::io::Error> {
- let res = File::open("net_graph-2021-02-12.bin") // By default we're run in RL/lightning
- .or_else(|_| File::open("lightning/net_graph-2021-02-12.bin")) // We may be run manually in RL/
+ let res = File::open("net_graph-2021-05-27.bin") // By default we're run in RL/lightning
+ .or_else(|_| File::open("lightning/net_graph-2021-05-27.bin")) // We may be run manually in RL/
.or_else(|_| { // Fall back to guessing based on the binary location
// path is likely something like .../rust-lightning/target/debug/deps/lightning-...
let mut path = std::env::current_exe().unwrap();
path.pop(); // debug
path.pop(); // target
path.push("lightning");
- path.push("net_graph-2021-02-12.bin");
+ path.push("net_graph-2021-05-27.bin");
eprintln!("{}", path.to_str().unwrap());
File::open(path)
});
let mut d = match get_route_file() {
Ok(f) => f,
Err(_) => {
- eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-05f0c5a0d772-2020-02-12.bin and place it at lightning/net_graph-2021-02-12.bin");
+ eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
return;
},
};
let mut d = match get_route_file() {
Ok(f) => f,
Err(_) => {
- eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-05f0c5a0d772-2020-02-12.bin and place it at lightning/net_graph-2021-02-12.bin");
+ eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
return;
},
};
use super::*;
use util::logger::{Logger, Record};
+ use prelude::*;
use test::Bencher;
struct DummyLogger {}
#[bench]
fn generate_routes(bench: &mut Bencher) {
let mut d = tests::get_route_file()
- .expect("Please fetch https://bitcoin.ninja/ldk-net_graph-05f0c5a0d772-2020-02-12.bin and place it at lightning/net_graph-2021-02-12.bin");
+ .expect("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
let graph = NetworkGraph::read(&mut d).unwrap();
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
#[bench]
fn generate_mpp_routes(bench: &mut Bencher) {
let mut d = tests::get_route_file()
- .expect("Please fetch https://bitcoin.ninja/ldk-net_graph-05f0c5a0d772-2020-02-12.bin and place it at lightning/net_graph-2021-02-12.bin");
+ .expect("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
let graph = NetworkGraph::read(&mut d).unwrap();
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
#[cfg(test)]
mod test {
+ use prelude::*;
use core::iter::repeat;
use super::ChaCha20;
use ln::{chan_utils, msgs};
use chain::keysinterface::{Sign, InMemorySigner, BaseSign};
+use prelude::*;
use core::cmp;
use std::sync::{Mutex, Arc};
//! Error types live here.
+use alloc::string::String;
use core::fmt;
/// Indicates an error on the client's part (usually some variant of attempting to use too-low or
use bitcoin::secp256k1::key::PublicKey;
+use prelude::*;
use core::time::Duration;
-use std::ops::Deref;
+use core::ops::Deref;
/// An Event which you should probably take some action in response to.
///
//! https://lightning.readthedocs.io/lightning-signmessage.7.html
//! https://api.lightning.community/#signmessage
+use prelude::*;
use crate::util::zbase32;
use bitcoin::hashes::{sha256d, Hash};
use bitcoin::secp256k1::recovery::{RecoverableSignature, RecoveryId};
#[cfg(test)]
mod test {
+ use prelude::*;
use core::iter::repeat;
use util::poly1305::Poly1305;
//! A very simple serialization framework which is used to serialize/deserialize messages as well
//! as ChannelsManagers and ChannelMonitors.
+use prelude::*;
use std::io::{Read, Write};
use std::collections::HashMap;
use core::hash::Hash;
fn read<R: Read>(reader: &mut R) -> Result<Option<Self>, DecodeError>;
}
+pub(crate) struct OptionDeserWrapper<T: Readable>(pub Option<T>);
+impl<T: Readable> Readable for OptionDeserWrapper<T> {
+ fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ Ok(Self(Some(Readable::read(reader)?)))
+ }
+}
+
+const MAX_ALLOC_SIZE: u64 = 64*1024;
+
+pub(crate) struct VecWriteWrapper<'a, T: Writeable>(pub &'a Vec<T>);
+impl<'a, T: Writeable> Writeable for VecWriteWrapper<'a, T> {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+ (self.0.len() as u64).write(writer)?;
+ for ref v in self.0.iter() {
+ v.write(writer)?;
+ }
+ Ok(())
+ }
+}
+pub(crate) struct VecReadWrapper<T: Readable>(pub Vec<T>);
+impl<T: Readable> Readable for VecReadWrapper<T> {
+ fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ let count: u64 = Readable::read(reader)?;
+ let mut values = Vec::with_capacity(cmp::min(count, MAX_ALLOC_SIZE / (core::mem::size_of::<T>() as u64)) as usize);
+ for _ in 0..count {
+ match Readable::read(reader) {
+ Ok(v) => { values.push(v); },
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(Self(values))
+ }
+}
+
pub(crate) struct U48(pub u64);
impl Writeable for U48 {
#[inline]
_ => {},
}
// As we read types, make sure we hit every required type:
- $(if (last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype) && typ.0 > $reqtype {
- Err(DecodeError::InvalidValue)?
+ $({
+ #[allow(unused_comparisons)] // Note that $reqtype may be 0 making the second comparison always true
+ let invalid_order = (last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype) && typ.0 > $reqtype;
+ if invalid_order {
+ Err(DecodeError::InvalidValue)?
+ }
})*
last_seen_type = Some(typ.0);
s.eat_remaining()?;
}
// Make sure we got to each required type after we've read every TLV:
- $(if last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype {
- Err(DecodeError::InvalidValue)?
+ $({
+ #[allow(unused_comparisons)] // Note that $reqtype may be 0 making the second comparison always true
+ let missing_req_type = last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype;
+ if missing_req_type {
+ Err(DecodeError::InvalidValue)?
+ }
})*
} }
}
/// This is the preferred method of adding new fields that old nodes can ignore and still function
/// correctly.
macro_rules! write_tlv_fields {
- ($stream: expr, {$(($type: expr, $field: expr)),*}, {$(($optional_type: expr, $optional_field: expr)),*}) => {
+ ($stream: expr, {$(($type: expr, $field: expr)),* $(,)*}, {$(($optional_type: expr, $optional_field: expr)),* $(,)*}) => {
encode_varint_length_prefixed_tlv!($stream, {$(($type, $field)),*} , {$(($optional_type, $optional_field)),*});
}
}
/// Reads a suffix added by write_tlv_fields.
macro_rules! read_tlv_fields {
- ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),*}, {$(($type: expr, $field: ident)),*}) => { {
+ ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),* $(,)*}, {$(($type: expr, $field: ident)),* $(,)*}) => { {
let tlv_len = ::util::ser::BigSize::read($stream)?;
let mut rd = ::util::ser::FixedLengthReader::new($stream, tlv_len.0);
decode_tlv!(&mut rd, {$(($reqtype, $reqfield)),*}, {$(($type, $field)),*});
} }
}
+// If we naively create a struct in impl_writeable_tlv_based below, we may end up returning
+// `Self { ,,vecfield: vecfield }` which is obviously incorrect. Instead, we have to match here to
+// detect at least one empty field set and skip the potentially-extra comma.
+macro_rules! _init_tlv_based_struct {
+ ({}, {$($field: ident),*}, {$($vecfield: ident),*}) => {
+ Ok(Self {
+ $($field),*,
+ $($vecfield: $vecfield.unwrap().0),*
+ })
+ };
+ ({$($reqfield: ident),*}, {}, {$($vecfield: ident),*}) => {
+ Ok(Self {
+ $($reqfield: $reqfield.0.unwrap()),*,
+ $($vecfield: $vecfield.unwrap().0),*
+ })
+ };
+ ({$($reqfield: ident),*}, {$($field: ident),*}, {}) => {
+ Ok(Self {
+ $($reqfield: $reqfield.0.unwrap()),*,
+ $($field),*
+ })
+ };
+ ({$($reqfield: ident),*}, {$($field: ident),*}, {$($vecfield: ident),*}) => {
+ Ok(Self {
+ $($reqfield: $reqfield.0.unwrap()),*,
+ $($field),*,
+ $($vecfield: $vecfield.unwrap().0),*
+ })
+ }
+}
+
+// If we don't have any optional types below, but do have some vec types, we end up calling
+// `write_tlv_field!($stream, {..}, {, (vec_ty, vec_val)})`, which is obviously broken.
+// Instead, for write and read we match the missing values and skip the extra comma.
+macro_rules! _write_tlv_fields {
+ ($stream: expr, {$(($type: expr, $field: expr)),* $(,)*}, {}, {$(($optional_type: expr, $optional_field: expr)),* $(,)*}) => {
+ write_tlv_fields!($stream, {$(($type, $field)),*} , {$(($optional_type, $optional_field)),*});
+ };
+ ($stream: expr, {$(($type: expr, $field: expr)),* $(,)*}, {$(($optional_type: expr, $optional_field: expr)),* $(,)*}, {$(($optional_type_2: expr, $optional_field_2: expr)),* $(,)*}) => {
+ write_tlv_fields!($stream, {$(($type, $field)),*} , {$(($optional_type, $optional_field)),*, $(($optional_type_2, $optional_field_2)),*});
+ }
+}
+macro_rules! _read_tlv_fields {
+ ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),* $(,)*}, {}, {$(($type: expr, $field: ident)),* $(,)*}) => {
+ read_tlv_fields!($stream, {$(($reqtype, $reqfield)),*}, {$(($type, $field)),*});
+ };
+ ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),* $(,)*}, {$(($type: expr, $field: ident)),* $(,)*}, {$(($type_2: expr, $field_2: ident)),* $(,)*}) => {
+ read_tlv_fields!($stream, {$(($reqtype, $reqfield)),*}, {$(($type, $field)),*, $(($type_2, $field_2)),*});
+ }
+}
+
+/// Implements Readable/Writeable for a struct storing it as a set of TLVs
+/// First block includes all the required fields including a dummy value which is used during
+/// deserialization but which will never be exposed to other code.
+/// The second block includes optional fields.
+/// The third block includes any Vecs which need to have their individual elements serialized.
+macro_rules! impl_writeable_tlv_based {
+ ($st: ident, {$(($reqtype: expr, $reqfield: ident)),* $(,)*}, {$(($type: expr, $field: ident)),* $(,)*}, {$(($vectype: expr, $vecfield: ident)),* $(,)*}) => {
+ impl ::util::ser::Writeable for $st {
+ fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+ _write_tlv_fields!(writer, {
+ $(($reqtype, self.$reqfield)),*
+ }, {
+ $(($type, self.$field)),*
+ }, {
+ $(($vectype, Some(::util::ser::VecWriteWrapper(&self.$vecfield)))),*
+ });
+ Ok(())
+ }
+ }
+
+ impl ::util::ser::Readable for $st {
+ fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, ::ln::msgs::DecodeError> {
+ $(
+ let mut $reqfield = ::util::ser::OptionDeserWrapper(None);
+ )*
+ $(
+ let mut $field = None;
+ )*
+ $(
+ let mut $vecfield = Some(::util::ser::VecReadWrapper(Vec::new()));
+ )*
+ _read_tlv_fields!(reader, {
+ $(($reqtype, $reqfield)),*
+ }, {
+ $(($type, $field)),*
+ }, {
+ $(($vectype, $vecfield)),*
+ });
+ _init_tlv_based_struct!({$($reqfield),*}, {$($field),*}, {$($vecfield),*})
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
+ use prelude::*;
use std::io::{Cursor, Read};
use ln::msgs::DecodeError;
use util::ser::{Readable, Writeable, HighZeroBytesDroppedVarInt, VecWriter};
use bitcoin::blockdata::transaction::{Transaction, TxOut};
use bitcoin::blockdata::script::{Builder, Script};
use bitcoin::blockdata::opcodes;
+use bitcoin::blockdata::block::BlockHeader;
use bitcoin::network::constants::Network;
use bitcoin::hash_types::{BlockHash, Txid};
use regex;
+use prelude::*;
use core::time::Duration;
use std::sync::{Mutex, Arc};
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
pub struct TestBroadcaster {
pub txn_broadcasted: Mutex<Vec<Transaction>>,
+ pub blocks: Arc<Mutex<Vec<(BlockHeader, u32)>>>,
}
impl chaininterface::BroadcasterInterface for TestBroadcaster {
fn broadcast_transaction(&self, tx: &Transaction) {
+ assert!(tx.lock_time < 1_500_000_000);
+ if tx.lock_time > self.blocks.lock().unwrap().len() as u32 + 1 && tx.lock_time < 500_000_000 {
+ for inp in tx.input.iter() {
+ if inp.sequence != 0xffffffff {
+ panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time);
+ }
+ }
+ }
self.txn_broadcasted.lock().unwrap().push(tx.clone());
}
}
use ln::msgs::MAX_VALUE_MSAT;
+use prelude::*;
use core::cmp::Ordering;
pub fn sort_outputs<T, C : Fn(&T, &T) -> Ordering>(outputs: &mut Vec<(TxOut, T)>, tie_breaker: C) {
use hex::decode;
+ use alloc::vec;
+
#[test]
fn sort_output_by_value() {
let txout1 = TxOut {
* at your option.
*/
+use prelude::*;
+
const ALPHABET: &'static [u8] = b"ybndrfg8ejkmcpqxot1uwisza345h769";
/// Encodes some bytes as a zbase32 string