Żeby dobrze zrozumieć sieć Lightning Network, warto zacząć od podstaw, czyli od tego, w jaki sposób Lightning Network wygląda on-chain. Sama koncepcja bierze się stąd, że przetwarzanie wszystkich możliwych transakcji przez wszystkie pełne węzły zostało uznane za niewydajne i niepotrzebne. Jak łatwo zauważyć, mempool potrafi się zapchać, rozmiar oczekujących transakcji dochodzi do nawet ponad stu bloków naprzód, co sprawia, że opłaty stale rosną, bo ludzie nie chcą czekać w nieskończoność na pierwsze potwierdzenie.
Z tego powodu powstał pomysł utworzenia kanałów płatności, dzięki czemu dowolne dwa podmioty mogłyby wymieniać się monetami bez konieczności każdorazowego wykonywania transakcji on-chain. Założenie jest takie, że na początku dwie strony blokują swoje monety na wspólnym adresie 2-of-2 multisig (co powoduje otwarcie kanału), a następnie obie strony tworzą transakcję wydającą współdzielone monety z powrotem na osobne adresy (co powoduje zamknięcie kanału).
Portfel Bitcoin Core oprócz głównej sieci (mainnet) oraz sieci testowej (testnet), umożliwia także uruchomienie lokalnej sieci testowej (regtest), gdzie samodzielnie można tworzyć całkowicie dowolne transakcje. Umożliwia to sprawdzenie, co jest, a co nie jest możliwe w Bitcoinie oraz oswojenie się z tymi monetami bez konieczności ryzykowania od razu prawdziwych pieniędzy.
Aby odpalić sieć regtest, należy uruchomić klienta Bitcoin Core z poziomu konsoli, podając odpowiedni argument:
To powinno wystarczyć, przy starcie powinniśmy ujrzeć jasnoniebieski kolor zamiast pomarańczowego oraz napis "regtest" w tytule okna. Od razu możemy zauważyć, że jesteśmy daleko w tyle za siecią, Genesis Block jest gdzieś w roku 2011 zamiast 2009, a nasz klient z nikim się nie łączy i nie pobiera żadnych bloków z sieci. Tutaj sami jesteśmy górnikami i możemy generować do 15 tysięcy monet zamiast 21 milionów, co powinno wystarczyć nam do wszelakich zastosowań. Otwórzmy więc konsolę (Window -> Console lub domyślnie CTRL+T) i wygenerujmy nowy adres:
getnewaddress
bcrt1qxae40vjtrtzu4cy3tnswf6xmpk3rlg7k5uqynk
Skoro już mamy swój adres, to możemy coś wykopać, w regteście trudność jest minimalna i umożliwia tworzenie setek bloków na sekundę:
generatetoaddress 101 bcrt1qxae40vjtrtzu4cy3tnswf6xmpk3rlg7k5uqynk
Naszym oczom powinna się ukazać lista z hashami wygenerowanych bloków. Poza konsolą w głównym oknie możemy zauważyć, że mamy 50 monet, a 5000 czeka na kolejne potwierdzenia. Każdy nowy blok musi uzyskać 100 potwierdzeń, aby górnik mógł wydać swoje monety, stąd 101 bloków pozwala nam dostać cokolwiek. Teraz możemy uzyskać kolejny adres, żeby sprawdzić, czy nasze monety rzeczywiście da się wydać.
getnewaddress "Alice"
bcrt1q4zuu8hra39kxpcpktag67492e9r346a69wfuwl
Same adresy możemy również generować z poziomu interfejsu graficznego, podobnie z wysyłaniem transakcji. Jak do tej pory, jedynie generowanie bloków musimy wykonać z konsoli, bo z założenia to nie jest coś, co przeciętny użytkownik robi, więc ta opcja została usunięta z okienkowej wersji klienta. Żeby jednak nie wykonywać transakcji z samym sobą, możemy uruchomić drugiego klienta, wtedy nasze testy będą bardziej realistyczne:
bitcoin-qt -regtest -choosedatadir -port=12345
Opcja "-choosedatadir" sprawia, że możemy wybrać sobie osobny folder, w którym nasz drugi węzeł będzie trzymał wszystkie dane, zaś "-port" umożliwia zmianę numeru portu, gdyż jeśli oba węzły są uruchomione na jednym komputerze, to nie mogą jednocześnie używać tego samego portu. Ponieważ w regteście domyślnie węzły się ze sobą nie łączą, musimy zrobić to ręcznie w konsoli (CTRL+T), wpisując:
addnode "127.0.0.1" "add"
Od tej pory, w prawym dolnym rogu powinniśmy zobaczyć w obu klientach, że liczba połączeń wynosi jeden. Oprócz tego, węzeł niebędący górnikiem powinien pobrać wszystkie bloki od swojego sąsiada. Załóżmy, że drugi węzeł też ma jakiś adres, na przykład:
getnewaddress "Bob"
bcrt1qqfw2atr0kledrcu5r6xztsxwxg63n7lct9yj9v
Mamy zatem dwa węzły, jeden to "Alice" (również jako górnik), a drugim jest "Bob", jako zwykły użytkownik. Moglibyśmy mieć trzy węzły (albo i więcej), wtedy nasze testy byłyby jeszcze bardziej realistyczne, bo górnik nie musiałby być jednym z użytkowników, no ale myślę, że na początek dwa węzły nam wystarczą. Idźmy dalej z dwoma węzłami, chcemy mieć wspólny adres należący do obu węzłów tak, aby nie musiały sobie ufać i mogły wymieniać się monetami tak, jak w Lightning Network. Żeby utworzyć adres 2-of-2 multisig, potrzebujemy kluczy publicznych. Sprawdźmy zatem, jakie te klucze są:
getaddressinfo "bcrt1q4zuu8hra39kxpcpktag67492e9r346a69wfuwl"
{
"address": "bcrt1q4zuu8hra39kxpcpktag67492e9r346a69wfuwl",
"scriptPubKey": "0014a8b9c3dc7d896c60e0365f51af54aac9471aebba",
"ismine": true,
"solvable": true,
"desc": "wpkh([085ffa1d/0'/0'/1']02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe)#kjdtmlkf",
"iswatchonly": false,
"isscript": false,
"iswitness": true,
"witness_version": 0,
"witness_program": "a8b9c3dc7d896c60e0365f51af54aac9471aebba",
"pubkey": "02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe",
"ischange": false,
"timestamp": 1611830525,
"hdkeypath": "m/0'/0'/1'",
"hdseedid": "194bc24b7b521ce16031bfba670eb31bf1b20eea",
"hdmasterfingerprint": "085ffa1d",
"labels": [
"Alice"
]
}
Analogicznie postępujemy z drugim węzłem:
getaddressinfo "bcrt1qqfw2atr0kledrcu5r6xztsxwxg63n7lct9yj9v"
{
"address": "bcrt1qqfw2atr0kledrcu5r6xztsxwxg63n7lct9yj9v",
"scriptPubKey": "0014025caeac6fb7f2d1e3941e8c25c0ce323519fbf8",
"ismine": true,
"solvable": true,
"desc": "wpkh([995aa32b/0'/0'/0']0313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf1)#dvwjdqdn",
"iswatchonly": false,
"isscript": false,
"iswitness": true,
"witness_version": 0,
"witness_program": "025caeac6fb7f2d1e3941e8c25c0ce323519fbf8",
"pubkey": "0313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf1",
"ischange": false,
"timestamp": 1611831683,
"hdkeypath": "m/0'/0'/0'",
"hdseedid": "8c58a942c276db10c49500ca0827f7df170fc5e3",
"hdmasterfingerprint": "995aa32b",
"labels": [
"Bob"
]
}
Teraz mamy już wszystko, aby utworzyć adres 2-of-2 multisig:
createmultisig 2 "[\"02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe\",\"0313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf1\"]" "bech32"
{
"address": "bcrt1q8md79rv8v2tsf0rjzxprfl0l48qtu05j5e83hctyxhgka79pfk8qxrth0n",
"redeemScript": "522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae",
"descriptor": "wsh(multi(2,02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe,0313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf1))#42ssa8ux"
}
Na razie jako typ adresu wybieramy Segwit, czyli "bech32", w przyszłości możliwe, że użyjemy tutaj adresu Taproot. Skoro już mamy adres, to moglibyśmy po prostu wysłać nasze monety na wspólne konto. W przypadku Lightning Network w praktyce najpierw jedynie tworzymy transakcję, natomiast wysyłamy ją później. Chodzi o to, że gdyby na przykład Alice wysłała do wspólnego kanału swoje monety otwierając go, to nie mogłaby go później zamknąć bez odpowiedniej transakcji! Zatem żeby zrobić to tak, jak należy, to musimy utworzyć najpierw obie transakcje, a dopiero później wysłać pierwszą z nich (bo nie chcemy od razu przecież zamykać kanału). Do utworzenia transakcji z poziomu konsoli potrzebujemy przede wszystkim hashu poprzedniej transakcji i numeru wyjścia, przy którym są nasze monety. Jesteśmy to w stanie uzyskać z poziomu interfejsu graficznego, klikając przycisk "Transactions". Prawym kliknięciem możemy zaznaczyć naszą transakcję i wybrać "Copy raw transaction". To nam wystarczy, aby w konsoli podejrzeć szczegóły transakcji:
decoderawtransaction "0200000000010196a5f1f57f44c91b15fd2974cb7c0f294cdaac342dcad1c20aa36349616d39f50000000000fdffffff0192f1052a01000000160014a8b9c3dc7d896c60e0365f51af54aac9471aebba0247304402204e1fb465daa4d33d58776aed215d437d8dc9d95623e7775c44c6c35e738ca17c0220029f92a0b8ba047defa89605bdf76dd52046b6a8f386878932616334caa55508012102a3cd82ea50a125b2f86bed870dc96220f80a95a64bbab0dc269af02c4abe211665000000"
{
"txid": "1538679909fc2030ea9420b737cbad55ff129ea96dbedfe9379898f39cf0d261",
"hash": "0bfed83cf0de3a4e8a0b5f5e5279dc0783bb35f093e76c692a9694dde39e6868",
"version": 2,
"size": 191,
"vsize": 110,
"weight": 437,
"locktime": 101,
"vin": [
{
"txid": "f5396d614963a30ac2d1ca2d34acda4c290f7ccb7429fd151bc9447ff5f1a596",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"304402204e1fb465daa4d33d58776aed215d437d8dc9d95623e7775c44c6c35e738ca17c0220029f92a0b8ba047defa89605bdf76dd52046b6a8f386878932616334caa5550801",
"02a3cd82ea50a125b2f86bed870dc96220f80a95a64bbab0dc269af02c4abe2116"
],
"sequence": 4294967293
}
],
"vout": [
{
"value": 49.99999890,
"n": 0,
"scriptPubKey": {
"asm": "0 a8b9c3dc7d896c60e0365f51af54aac9471aebba",
"hex": "0014a8b9c3dc7d896c60e0365f51af54aac9471aebba",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"bcrt1q4zuu8hra39kxpcpktag67492e9r346a69wfuwl"
]
}
}
]
}
W ten sposób możemy zaglądać w dowolne transakcje, wystarczy, że będziemy mieli dane szesnastkowe transakcji (wzięte choćby z jakiegoś block explorera) i już możemy patrzeć na wszelkie szczegóły, które nas interesują. Stąd widać wyraźnie, że musimy podać "1538679909fc2030ea9420b737cbad55ff129ea96dbedfe9379898f39cf0d261" jako hash transakcji oraz zero jako numer wyjścia. Natomiast co do wyjść, to jedno nam wystarczy jako przykład, po prostu wrzucamy wszystko na nasz wspólny adres, czyli "bcrt1q8md79rv8v2tsf0rjzxprfl0l48qtu05j5e83hctyxhgka79pfk8qxrth0n". Piszemy zatem:
createrawtransaction "[{\"txid\":\"1538679909fc2030ea9420b737cbad55ff129ea96dbedfe9379898f39cf0d261\",\"vout\":0}]" "[{\"bcrt1q8md79rv8v2tsf0rjzxprfl0l48qtu05j5e83hctyxhgka79pfk8qxrth0n\":49.99999000}]"
020000000161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e00000000
Jeśli ta transakcja rzeczywiście miałaby się wydarzyć, to opłata byłaby zależna od tego, jak bardzo mempool jest zapchany. Moglibyśmy tutaj dać minimalną opłatę, ale to wymagałoby policzenia rozmiaru transakcji, więc sobie to na razie darujemy i zaokrąglimy kwotę do równych tysięcy satoshi. Chodzi nam głównie jednak nie tyle o tą transakcję, ile o kolejną, która pozwoli zamknąć kanał. Potrzebujemy zatem hasha transakcji i numeru wyjścia. Mamy już dane szesnastkowe transakcji, więc możemy ją zdekodować:
decoderawtransaction "020000000161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e00000000"
{
"txid": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"hash": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"version": 2,
"size": 94,
"vsize": 94,
"weight": 376,
"locktime": 0,
"vin": [
{
"txid": "1538679909fc2030ea9420b737cbad55ff129ea96dbedfe9379898f39cf0d261",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 49.99999000,
"n": 0,
"scriptPubKey": {
"asm": "0 3edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e",
"hex": "00203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e",
"reqSigs": 1,
"type": "witness_v0_scripthash",
"addresses": [
"bcrt1q8md79rv8v2tsf0rjzxprfl0l48qtu05j5e83hctyxhgka79pfk8qxrth0n"
]
}
}
]
}
Dzięki adresom typu Segwit nie musimy martwić się o ID transakcji, bo dołączenie podpisów tego nie zmieni (w starszych adresach tak nie jest). Zatem możemy śmiało zbudować kolejną transakcję, która wypłaci Alice wszystkie środki (bo po stronie Boba niczego nie ma). Wygenerujmy nowy adres Alice, żeby go nie używać ponownie:
getnewaddress "Alice"
bcrt1qywzj7g9sdw7dlm4h5k82yevuqcr5utwzt3j5k9
Znów zaokrąglamy sobie fee i możemy utworzyć kolejną transakcję:
createrawtransaction "[{\"txid\":\"2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85\",\"vout\":0}]" "[{\"bcrt1qywzj7g9sdw7dlm4h5k82yevuqcr5utwzt3j5k9\":49.99998000}]"
0200000001850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc200000000
Teraz z kolei przy składaniu podpisów zaczynamy od transakcji zamykającej kanał. Chodzi o to, aby nie otworzyć kanału nie mając kompletu podpisów. Do tego oprócz danych szesnastkowych transakcji do podpisu, potrzebujemy również danych poprzedniej transakcji. Żeby łatwiej posługiwać się wspólnym adresem, możemy go zaimportować jako watch-only (gdyż nie mamy obu kluczy prywatnych, zarówno Alice, jak i Bob mają jedynie swoje klucze).
importmulti "[{\"desc\":\"wsh(multi(2,02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe,0313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf1))#42ssa8ux\",\"timestamp\":\"now\",\"watchonly\":true,\"label\":\"AliceAndBob\"}]"
Import wspólnego adresu spowoduje, że portfel sam załatwi część rzeczy za nas i nie będziemy musieli podawać wszystkiego w konsoli. Każda ze stron może złożyć podpis, tyle informacji w zupełności wystarcza, zacznijmy od Alice, choć nie ma to większego znaczenia:
signrawtransactionwithwallet "0200000001850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc200000000" "[{\"txid\":\"2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85\",\"vout\":0,\"scriptPubKey\":\"00203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e\",\"redeemScript\":\"522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae\",\"amount\":49.99999000}]"
{
"hex": "02000000000101850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc2040047304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b010047522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae00000000",
"complete": false,
"errors": [
{
"txid": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"vout": 0,
"witness": [
"",
"304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b01",
"",
"522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae"
],
"scriptSig": "",
"sequence": 4294967295,
"error": "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"
}
]
}
Teraz z kolei Bob może wziąć sygnaturę od Alice i dokończyć całość, uzyskując kompletną transakcję:
signrawtransactionwithwallet "02000000000101850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc2040047304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b010047522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae00000000" "[{\"txid\":\"2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85\",\"vout\":0,\"scriptPubKey\":\"00203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e\",\"amount\":49.99999000}]"
{
"hex": "02000000000101850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc2040047304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b014730440220194262dbb1be43f0f5ccdf7e0e3af7864153493dc435e9350d77f50c30b7cf8a02204303e0604e049ea6220aebb597442a58ad52f46ca1df73adac6da593646721520147522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae00000000",
"complete": true
}
Zatem ostatecznie obie strony dysponują kompletną transakcją i obie strony mogą ją zdekodować:
decoderawtransaction "02000000000101850fe338cbfe3caca2be004fe1ba7afdf6a49d2fb7391acb4fe81f1b2a840c2c0000000000ffffffff0130ea052a0100000016001423852f20b06bbcdfeeb7a58ea2659c06074e2dc2040047304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b014730440220194262dbb1be43f0f5ccdf7e0e3af7864153493dc435e9350d77f50c30b7cf8a02204303e0604e049ea6220aebb597442a58ad52f46ca1df73adac6da593646721520147522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae00000000"
{
"txid": "f650b54f0c53e479f1bed78e469bed20654eda910a420314ed386af93257e485",
"hash": "076f5442855c4b73470cfcf7b09d02cb8421ddda248552a62715111682fe5536",
"version": 2,
"size": 302,
"vsize": 137,
"weight": 548,
"locktime": 0,
"vin": [
{
"txid": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"",
"304402201354bae6297085d01db2f2a3edb3a9f3f0e3c30da3d345801078be1d3d43270a022071cae276ede6229cd97cb54680e0f5462b8a11ca87b123739f1410ef3ee2cb4b01",
"30440220194262dbb1be43f0f5ccdf7e0e3af7864153493dc435e9350d77f50c30b7cf8a02204303e0604e049ea6220aebb597442a58ad52f46ca1df73adac6da5936467215201",
"522102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe210313fc2401362129bd664490e21070d8ffd48d4e38837ec1b3ee9df1156dccadf152ae"
],
"sequence": 4294967295
}
],
"vout": [
{
"value": 49.99998000,
"n": 0,
"scriptPubKey": {
"asm": "0 23852f20b06bbcdfeeb7a58ea2659c06074e2dc2",
"hex": "001423852f20b06bbcdfeeb7a58ea2659c06074e2dc2",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"bcrt1qywzj7g9sdw7dlm4h5k82yevuqcr5utwzt3j5k9"
]
}
}
]
}
Ponieważ Bob nie wkłada do kanału żadnych swoich monet, Alice musi wypuścić pierwszą transakcję, aby kanał mógł zostać otwarty. Podpisuje ją zatem:
signrawtransactionwithwallet "020000000161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e00000000"
{
"hex": "0200000000010161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e0247304402206bc49093755da7513e832786d16d4c9cbaee25a9addd97a2f45b99ca93ec081702205b91ab034b269ac019cf855b0a94a73dd5f4ce1f62bf3545b006783dcf237ada012102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe00000000",
"complete": true
}
Możemy rzucić okiem, że ID transakcji jest nadal identyczne, choć jej hash oczywiście się zmienia po dodaniu sygnatur:
decoderawtransaction "0200000000010161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e0247304402206bc49093755da7513e832786d16d4c9cbaee25a9addd97a2f45b99ca93ec081702205b91ab034b269ac019cf855b0a94a73dd5f4ce1f62bf3545b006783dcf237ada012102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe00000000"
{
"txid": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"hash": "b1acecf6673e10695ab1bb57c5705a9cd03505193fa8da15d3df00763647ff1d",
"version": 2,
"size": 203,
"vsize": 122,
"weight": 485,
"locktime": 0,
"vin": [
{
"txid": "1538679909fc2030ea9420b737cbad55ff129ea96dbedfe9379898f39cf0d261",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"304402206bc49093755da7513e832786d16d4c9cbaee25a9addd97a2f45b99ca93ec081702205b91ab034b269ac019cf855b0a94a73dd5f4ce1f62bf3545b006783dcf237ada01",
"02a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe"
],
"sequence": 4294967295
}
],
"vout": [
{
"value": 49.99999000,
"n": 0,
"scriptPubKey": {
"asm": "0 3edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e",
"hex": "00203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e",
"reqSigs": 1,
"type": "witness_v0_scripthash",
"addresses": [
"bcrt1q8md79rv8v2tsf0rjzxprfl0l48qtu05j5e83hctyxhgka79pfk8qxrth0n"
]
}
}
]
}
Przed wysłaniem transakcji, Alice może sprawdzić, czy taka transakcja będzie zaakceptowana przez inne węzły. Może to być przydatne przy ustawianiu fee tak, aby było możliwie minimalne:
testmempoolaccept "[\"0200000000010161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e0247304402206bc49093755da7513e832786d16d4c9cbaee25a9addd97a2f45b99ca93ec081702205b91ab034b269ac019cf855b0a94a73dd5f4ce1f62bf3545b006783dcf237ada012102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe00000000\"]"
[
{
"txid": "2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85",
"allowed": true
}
]
Wszystko jest w porządku, zatem Alice wysyła pierwszą transakcję i otwiera w ten sposób kanał:
sendrawtransaction "0200000000010161d2f09cf3989837e9dfbe6da99e12ff55adcb37b72094ea3020fc09996738150000000000ffffffff0118ee052a010000002200203edbe28d87629704bc72118234fdffa9c0be3e92a64f1be16435d16ef8a14d8e0247304402206bc49093755da7513e832786d16d4c9cbaee25a9addd97a2f45b99ca93ec081702205b91ab034b269ac019cf855b0a94a73dd5f4ce1f62bf3545b006783dcf237ada012102a04782a942b08c9aaadfd1529f47520959eda975c1f2ff174d28a415f8b367fe00000000"
2c0c842a1b1fe84fcb1a39b72f9da4f6fd7abae14f00bea2ac3cfecb38e30f85
No i mamy to. Krok po kroku dotknęliśmy Lightninga od strony czysto technicznej. Dalej wystarczy, że Alice i Bob wspólnie zmienią transakcję zamykającą na jakąś inną, starczy zamienić tam kwoty i będzie dobrze. Trzeba także dołożyć transakcję kary, żeby zapobiec wypuszczeniu starej transakcji przez drugą stronę. Oprócz tego, w praktyce transakcja zamykająca trzymana przez obie strony wygląda tak, że wiadomo dokładnie, kto zamknął kanał jednostronnie, bo jedna strona dostaje środki natychmiast, a druga strona ma je zablokowane (czas takiej blokady jest określony z góry przez obie strony w momencie tworzenia kanału). Tutaj mamy najprostszy możliwy przykład transakcji zamykającej kanał za zgodą obu stron, żeby uzyskać przykłady z życia wzięte, należałoby to jeszcze rozbudować.
Myślę, że na początek ten wpis i tak jest dość techniczny, bardziej złożone rzeczy można ewentualnie powyjaśniać po przetrawieniu tego.