From 87792c508906032b4dc32f711e1bb19f1d93c5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 21 Oct 2024 13:27:33 +0200 Subject: [PATCH] WIP --- models/article.ts | 19 +++++++++++++++++++ tests/fixtures/article-1.json | 1 + tests/models/article_test.ts | 25 +++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 models/article.ts create mode 100644 tests/fixtures/article-1.json create mode 100644 tests/models/article_test.ts diff --git a/models/article.ts b/models/article.ts new file mode 100644 index 0000000..03e1b70 --- /dev/null +++ b/models/article.ts @@ -0,0 +1,19 @@ +import { NEvent } from "../nostr.ts"; +import { render as renderMarkdown } from "@deno/gfm"; + +export default class Article { + private event: NEvent; + + constructor(event: NEvent) { + this.event = event; + } + + get identifier(): string | null { + const tag = this.event.tags.find((t) => t[0] === "d"); + return tag ? tag[1] : null; + } + + get html(): string { + return renderMarkdown(this.event.content); + } +} diff --git a/tests/fixtures/article-1.json b/tests/fixtures/article-1.json new file mode 100644 index 0000000..208d0d8 --- /dev/null +++ b/tests/fixtures/article-1.json @@ -0,0 +1 @@ +{"content":"This week, it finally happened: I still had a Lightning channel open with a node that hadn't been online for the better part of a year now, so I decided to close the channel unilaterally. But force-closing a channel means you have to broadcast the latest commitment transaction, the pre-set fee of which was only ~1 sat/vB for this one.\n\nWith LND, if the channel is created as an [anchor channel](https://lightning.engineering/posts/2021-01-28-lnd-v0.12/) (by default only since version 0.12), then the commitment transaction contains small extra outputs (currently 330 sats), which let either channel partner spend one of them into a child transaction that can be created with higher fees to pay for the parent transaction (CPFP). LND even has a built-in command for that: `lncli wallet bumpclosefee`\n\nHowever, this channel was created in the old-school way, and was thus stuck with its low fee. In fact, even the local bitcoin node refused to accept the transaction into its own mempool, so the bitcoin p2p network didn't even know it existed. So how do we get out of this pickle?\n\n## The solution\n\nEnter the [mempool.space Accelerator](https://mempool.space/accelerator). It is essentially an automated way to create agreements with various mining pools to mine your low-fee transaction in exchange for an out-of-band payment. Mempool.space coordinates these agreements and out-of-band payments with miners and gets a share from the overall fee for that.\n\nNow, if you're in the same situation as I was, you might search for the ID of your closing transaction and find that mempool.space cannot find it. Remember how the local bitcoin node (with mostly default settings) didn't accept it in the first place?\n\n### 1. Get the transaction to be broadcast\n\nIn your `bitcoin.conf`, add the following line:\n\n minrelaytxfee=0\n\nThis sets the minimum fee to 0, meaning it will accept and broadcast your transactions, no matter how low the fee is. Restart `bitcoind` and wait a little bit. LND will retry broadcasting the closing transaction every minute or so until it succeeds. At some point you should be able to find it on mempool.space.\n\n### 2. Use the Accelerator to confirm it\n\nOnce you can see the transaction on [mempool.space](https://mempool.space), you can just click the \"Accelerate\" button next to the ETA. This will bring you to a page that shows you the estimated share of miners that will include your transaction in their blocks, as well as some acceleration fee options for various transaction fee levels, which you can pay for via the Lightning Network, of course.\n\nIf you haven't looked into this service before (which I had), then the fees might be a bit of a surprise to you. This thing is **not** cheap! Bumping my fee from 1 sat/vB to ~9 sats/vB cost a whopping 51,500 sats (~31 USD that day). Bumping it higher only seemed to add the difference in the transaction fee itself, so the service seems to have cost a flat 50K sats at the time.\n\nUnfortunately, this channel wasn't particularly large, so the acceleration fee amounted to ~9% of my remaining channel balance. But 91% of something is better than 100% of nothing, so I actually felt pretty good about it.\n\nNext, you will see something like this:\n\n![Screenshot of an accelerated transaction on mempool.space](https://image.nostr.build/76151cc2ae06a93a8fcd97102bf4fa63541f8f3bd19800b96ff1070c9450945c.png)\n\nTime to lean back and let the miners work for you. In my case, the ETA was eerily precise. It told me that it would take ~56 minutes to confirm the transaction, and almost exactly an hour later it was mined.\n\n### 3. Wait\n\nNow that our transaction is confirmed, our channel is not closed immediately, of course. The [time lock of the HTLC](https://docs.lightning.engineering/the-lightning-network/multihop-payments/hash-time-lock-contract-htlc) protects our channel partner from us broadcasting an old channel state in which our balance might be higher than in the latest state.\n\nIn my case, it was set to 144 blocks, i.e. ~24 hours. So I checked back the next day, et voilá: channel closed and balance restored. 🥳","created_at":1729462158,"id":"b45714c3965549c11dde7228071313bfc53a4df1896d939fb767ed0b6fcdab3a","kind":30023,"pubkey":"1f79058c77a224e5be226c8f024cacdad4d741855d75ed9f11473ba8eb86e1cb","sig":"23d929aa05921f5b10cc4ca1d05cd99b9d595888a94c394ffa1850b97c39b1b3d3d7b7472df959f2675b9f936b3334a55073c8931c52cdcfea18c19cdb9cdcb6","tags":[["d","1726396758485"],["title","How to confirm a stuck Lightning channel closing transaction with the mempool.space Accelerator"],["summary",""],["published_at","1726402055"],["published_at","1726402055"],["alt","This is a long form article, you can read it in https://habla.news/a/naddr1qvzqqqr4gupzq8meqkx80g3yuklzymy0qfx2ekk56aqc2ht4ak03z3em4r4cdcwtqqxnzdejxcenjd3hx5urgwp4676hkz"],["published_at","1726402055"],["published_at","1726402055"],["published_at","1726402055"],["t","lightning"],["t","lightning network"],["t","howto"],["published_at","1726402055"]]} diff --git a/tests/models/article_test.ts b/tests/models/article_test.ts new file mode 100644 index 0000000..7d11689 --- /dev/null +++ b/tests/models/article_test.ts @@ -0,0 +1,25 @@ +import { + beforeAll, + beforeEach, + describe, + it, +} from "@std/testing/bdd"; +import { expect } from "@std/expect"; +import { NEvent } from "../../nostr.ts"; +import Article from "../../models/article.ts"; + +describe("User", () => { + let articleEvent: NEvent; + let article: Article; + + beforeAll(() => { + articleEvent = JSON.parse(Deno.readTextFileSync("tests/fixtures/article-1.json")); + article = new Article(articleEvent); + }); + + describe("#identifier", () => { + it("returns the content of the 'd' tag", () => { + expect(article.identifier).toEqual("1726396758485"); + }); + }); +});