במהירות הבזק – פרק ב'

במהירות הבזק – פרק ב' – המימוש בפועל של רשת הברק

המשך מפרק א'.

גרסה מתורגמת של שני הפרקים לעברית רב-מגדרית ניתן למצוא כאן.

הטרנזקציות ברשת הברק הן לא יותר משרשרת של טרנזקציות התחייבות שמצביעות על ה-Outputs של טרנזקציית התקצוב. רשת הברק של היום לקחה את הרעיון של RSMC והוסיפה מספר שיפורים. תחילה הופעלה תוכנית התחייבות (commitment scheme), בשיטת "הסתרה וחשיפה של סוד" שראינו קודם, כדי לאפשר העברה-הלאה (forward) של תשלומים. שנית, הוחלפה פעולת ריבוי-החתימות (multisig) בהכפלת-נקודות-על-עקומה-אליפטית (elliptic curve point multiplication).

מבנה הטרנזקציות

יש ארבעה סוגים של טרנזקציות ברשת הברק. שניים מהם נועדו להעביר כסף בין רשת הברק ורשת הביטקוין (טרנזקציות בין-שכבות), והשאר נועדו לעדכן את המאזנים ברשת הברק (טרנזקציות שכבה שנייה).

  1. טרנזקציית תקצוב (Funding transaction). טרנזקציית תקצוב נוצרת כשהערוץ נפתח. היא מעבירה כסף מרשת הביטקוין לרשת הברק ושמה את הכספים בכתובת מרובת-חתימות.
  2. טרנזקציית התחייבות (Commitment transaction). טרנזקציית ההתחייבות היא הבסיס של רשת הברק. בכל פעם שהמאזן משתנה, נוצרות טרנזקציות התחייבות חדשות.
  3. טרנזקציות HTLC. טרנזקציות HTLC-Success ו-HTLC-Timeout הוכנסו במקור לתוך טרנזקציית ההתחייבות, אבל לבסוף הופרדו מהן בגרסה הסופית. כמו שנסביר בהמשך, אפשר להסתכל על טרנזקציות HTLC כחלק מטרנזקציית ההתחייבות, מכיוון שכל המטרה שלהן היא להוציא כספים מ-Outputים מסויימים בטרנזקציית ההתחייבות.
  4. טרנזקציית סגירה. טרנזקציית סגירה נוצרת כששני המשתתפים מחליטים לסגור את הערוץ בשיתוף פעולה. היא מעבירה כספים מרשת הברק לרשת הביטקוין.

טרנזקציות התחייבות כאמצעי ל-"ראיית חשבון"

לטרנזקציית התחייבות יש ארבעה סוגים של Outputs, תלוי אם היא מעבירה (forwarding) תשלומים או לא:

  1. Output מקומי (local), ששומר כמה כסף יש למשתתף המקומי (שמחזיק בטרנזקציה).
  2. Output מרוחק (remote), ששומר כמה כסף יש למשתתף בצד השני.
  3. Output זכות (credit), או "ה-HTLC הנכנס", או "ה-HTLC שהתקבל", ששומר כמה כסף המשתתף המקומי מקבל.
  4. Output חובה (debit), או "ה-HTLC היוצא", או "ה-HTLC המוצע", ששומר כמה כסף המשתתף הנוכחי שולח.

Output זכות ו-Output חובה נוצרים כאשר המשתתף יוצר או מעביר תשלום לאחרים. לדוגמא:

רשת הברק משתמשת באופן אינטנסיבי ב-"סקריפטים" של ביטקוין, כדי לאבטח את ה-Outputים ולוודא שהם ינוצלו רק באופן שהם נועדו אליו.

ביטול טרנזקציות – מפתחות ועוד מפתחות

כדי ששכבה שנייה תעבוד, היא צריכה להיות "ניתנת להחזר" (refundable) ו-"ניתנת לביטול" (revocable), כדי להתמודד עם שני המקרים הבאים:

  1. כשמשתתף אחד מפסיק להגיב לתקופה מסוימת, המשתמש השני צריך לקבל את כספו חזרה.
  2. כשטרנזקציה חדשה נוצרת, הטרנזקציה הישנה צריכה להתבטל.

טרנזקציית הביטול, שלפעמים נקראת Breach Remedy Transaction, קיימת כדי להרתיע נגד פעולות זדוניות, והיא הבסיס שמאפשר לרשת הברק להיות בטוחה.

המימוש של רשת הברק משתמש ב-"זוגות מפתחות ביטול" (revocation key pairs) במקום בריבוי-חתימות (multisig). פונקציית הגיבוב הקריפטוגרפית המעורבת היא Elliptic Curve Digital Signature Algorithm – ECDSA ביחד עם הכפלת נקודות עקומה אליפטית. התהליך הוא כדלקמן:

אליס ובוב, כל אחד בנפרד, יוצרים זוג מפתחות פרטי-ציבורי על בסיס ECDSA, שנקרא להם alice_public_key, alice_secret_key, bob_public_key, bob_secret_key.
מפתח ציבורי שנקרא לו revocation_public_key נוצר באמצעות alice_public_key ו-bob_public_key. בשביל הפשטות, אפשר להסתכל על זה כך:

revocation_public_key = alice_public_key + bob_public_key

והמפתח הפרטי המתאים לו יהיה:

revocation_private_key = alice_private_key + bob_private_key

מכיוון שמדובר בזוג מפתחות פרטי-ציבורי, הודעות שיחתמו ע"י revocation_private_key ייצרו revocation_signature, וכל אחד יכול לוודא את החתימה באמצעות revocation_public_key וההודעה.

באופן דומה לכתובת מרובת-חתימות (multisig), נדרשים שני המפתחות הפרטיים של אליס ובוב כדי לייצר חתימה תקינה. השיטה הזו עדיפה מכיוון שהיא נחשבת יותר אינטואיטיבית ויעילה.

שימוש במפתחות ניתנים לביטול. ניתן להשתמש במפתח פרטי כדי לחתום מספר הודעות, ולייצר חתימות עם יחס אחד-לאחד עם ההודעות.

עם הרקע הזה, ננתח כעת לפרטים איך עובדים הפתיחה, העדכון והסגירה של ערוצים.

פתיחת ערוץ – טרנזקציית תקצוב וטרנזקציית ההתחייבות הראשונה.

התהליך לפתיחת ערוץ בין אליס לבוב של 1 ביטקוין הוא כדלקמן:
תחילה, לפני כל טרנזקציה, יש משא ומתן על ההגדרות הראשוניות של הערוץ, כמו מספר ה-confirmations המינימלי הדרוש עבור טרנזקציית התקצוב, והמפתחות הציבוריים של "מפתחות הביטול" (revocation keys), אשר הינם:

  1. מהצד של אליס, היא יוצרת את המפתחות הציבוריים alice_pubkey_tx_a1 ו-alice_pubkey_tx_b1 ושולחת אותם לבוב. את המפתחות הפרטיים התואמים alice_prikey_tx_a1 ו-alice_prikey_tx_b1 היא שומרת לעצמה.
  2. מהצד של בוב, הוא יוצר את המפתחות הציבוריים bob_pubkey_tx_a1 ו-bob_pubkey_tx_b1 ושולח אותם לאליס. את המפתחות הפרטיים התואמים bob_prikey_tx_a1 ו-bob_prikey_tx_b1 הוא שומר לעצמו.
  3. אליס משתמשת ב-alice_pubkey_tx_a1 ו-bob_pubkey_tx_a1 כדי לייצר את revocation_pubkey_tx_a1 שמאפשר לבדוק את החתימה revocation_sig_tx_a1. שימו לב שלא אליס ולא בוב יכולים ליצור את החתימה הזו בינתיים. רק אם אליס תעביר לבוב את alice_prikey_tx_a1, אז בוב יוכל לייצר את החתימה (ורק בוב יוכל לעשות זאת).
  4. בוב משתמש ב-alice_pubkey_tx_b1 ו-bob_pubkey_tx_b1 כדי לייצר את revocation_pubkey_tx_b1 שמאפשר לבדוק את החתימה revocation_sig_tx_b1. שימו לב שלא אליס ולא בוב יכולים ליצור את החתימה הזו בינתיים. רק אם בוב יעביר לאליס את bob_prikey_tx_b1 אז אליס תוכל לייצר את החתימה (ורק אליס תוכל לעשות זאת).

שנית, אליס מייצרת את טרנזקציית התקצוב, חותמת עליה, ומשתפת עם בוב את ה-ID וה-Output Number שלה.

טרנזקציית התקצוב של אליס

שלישית, אליס ובוב יוצרים כל אחד את טרנזקציות ההתחייבות על בסיס טרנזקציית התקצוב, חותמים אותן ומחליפים ביניהם את החתימות.

טרנזקציית ההתחייבות של אליס. שימו לב שאין מאזן מרוחק (Remote Output).

טרנזקציית ההתחייבות של בוב. שימו לב שאין מאזן מקומי (Local Output).

לבסוף, אליס מוודאת את החתימות שקיבלה מבוב ומשדרת את טרנזקציית ההתחייבות.

אודות חלוקת השמות של המפתחות
אנו משתמשים בקיצורים בשמות של המפתחות. מפתחות ציבוריים נקראים pubkey (במקום public_key), מפתחות פרטיים נקראים prikey (במקום private_key), וחתימות נקראות sig (במקום signature). לדוגמא alice_funding_sig היא החתימה שבה משתמשים כדי לשחרר את הנעילה של טרנזקציית התקצוב של אליס.
בכל פעם שאנו משתמשים ב-revocation בשם של מפתח, המשמעות היא שהוא נוצר ע"י שילוב מפתחות של אליס ובוב. לדוגמא, revocation_pubkey_tx_a1 נוצר ע"י alice_pubkey_tx_a1 ו-bob_pubkey_tx_a1. דוגמא נוספת: revocation_prikey_tx_a1 נוצר ע"י alice_prikey_tx_a1 ו-bob_prikey_tx_a1.
בכל פעם שיש tx בשם של מפתח ביטול (revocation key), המשמעות היא שהוא נוצר כדי לאפשר ביטול של טרנזקציה ספציפית. לדוגמא revocation_sig_tx_a1 נועדה לבטל אל הטרנזקציה של אליס TX A01. בינתיים, אין מנגנון ביטול בטרנזקציות של בוב (כי כל הכסף הולך לאליס), אבל בקרוב יהיו.
את החתימה revocation_sig_tx_a1 אפשר לייצר ע"י revocation_prikey_tx_a1, ולבדוק שהיא תואמת למפתח הציבורי revocation_pubkey_tx_a1.

ברגע שמספר ה-confirmations של טרנזקציית התקצוב מגיע ל-N, הערוץ מפתח ונשאר פתוח. אליס מציעה את הערך N, ובוב יכול לסרב להקמת הערוץ אם הוא חושב ש-N גדול מדי.

ל-Output מרוחק (Remote Output) מתייחסים באופן שונה מאשר ל-Output מקומי (Local Output), מכיוון שהמשתתף המקומי: א. לא יכול לבזבז את ה-Output המרוחק ו-ב. אין שום אינטרס לשדר אותו. לדוגמא, לבוב אין שום אינטרס לשדר את TX B01 לעולם, מכיוון שהוא לא ירוויח מזה כלום, ולכן אין צורך לשים בטרנזקציה מפתח ביטול (revocation_sig_tx_b1). מאידך, ל-Output מקומי חייבים להיות גם Timeout וגם יכולת ביטול, מכיוון שלמשתתף המקומי יש אינטרס לרצות לקבל את כספו חזרה אם הצד השני לא מגיב, וגם אינטרס לנסות לרמות אם המאזן שלו ירד בעתיד.

עדכון מאזנים בערוצים – טרנזקציית ההתחייבות השנייה, ואלה שאחריה.

התהליך המורכב ביותר מתרחש כאשר מעדכנים את המאזן בערוץ. כאשר המאזן בערוץ משתנה, זה בא לידי ביטוי בטרנזקציות ההתחייבות החדשות. הכסף שנשלח/מתקבל נרשם ב-Outputים של ה-זכות/חובה (Credit/Debit), והצדדים מחליפים ביניהם את מפתחות הביטול של הטרנזקציות הקודמות.

לדוגמא, אם אליס שולחת לבוב 0.1 ביטקוין, שניהם ייצרו טרנזקציות חדשות ויחליפו ביניהם את המפתחות. ראשית, הם יחליפו ביניהם את המפתחות הפרטיים alice_prikey_tx_a1 ו-bob_prikey_tx_b1. כעת, כשלבוב יש את alice_prikey_tx_a1, הוא יכול לחשב את revocation_prikey_tx_a1, ולייצר את revocation_sig_tx_a1, אשר משחררת את הנעילה של ה-Output המקומי ב-TX A01 (במידה ואליס תשדר אותה). שנית, הם מחליפים את מפתחות הביטול הציבוריים החדשים, alice_pubkey_tx_a2, alice_pubkey_tx_b2, bob_pubkey_tx_a2, bob_pubkey_tx_b2, אשר מייצרים את revocation_pubkey_tx_a2 ו-revocation_pubkey_tx_b2, ומשתמשים בהם בטרנזקציות ההתחייבות החדשות.

(הערת תרגום: לדעתי הכותב התבלבל כאן בסדר הכרונולוגי – קודם המשתתפים ישתפו את מפתחות הביטול הציבוריים החדשים, ואת החתימות של טרנזקציות ההתחייבות החדשות, ורק אחרי זה הם יחליפו ביניהם את המפתחות הפרטיים של הטרנזקציות הישנות, כדי להבטיח לצד השני שהם לא ירמו – אם הן ישודרו הצד השני יכול להגיב בזמן ולקחת את כל הכסף).

בטרנזקציית ההתחייבות החדשה של אליס, TX A02, יש שני Outputים:

  1. Output מקומי, ששומר את המאזן הנוכחי שלה: 0.9 ביטקוין.
  2. Output חובה, ששומר את הכסף שהיא שלחה לבוב: 0.1 ביטקוין.

טרנזקציית ההתחייבות השנייה של אליס. שימו לב שכל טרנזקציות ההתחייבות תמיד מצביעות לאותה טרנזקציית תקצוב ראשונית.

מהצד של בוב, הוא מחזיק ב-TX B02, עם ה-Outputים:

  1. Output מרוחק, ששומר את המאזן של אליס: 0.9 ביטקוין.
  2. Output זכות, ששומר את הכסף שהוא מקבל: 0.1 ביטקוין.

טרנזקציית ההתחייבות השנייה של בוב. שימו לב שכל טרנזקציות ההתחייבות תמיד מצביעות לאותה טרנזקציית תקצוב ראשונית.

לפני שניכנס לתכנון של ה-Outputים החדשים (חובה/זכות), בואו נוודא שה-Output המקומי והמרוחק אכן תקפים ולא ניתן לרמות.

Outputים מקומיים ומרוחקים מאובטחים

ברור מראש שלבוב אין שום אינטרס לשדר את הטרנזקציה הישנה TX B01, כי ב-TX B02 הוא יקבל יותר כסף. מצד שני, עבור אליס:

  1. אם בוב נעלם, היא יכולה לשדר את TX A02 ואז אחרי שבועיים היא תוכל להשתמש בכסף.
  2. בנוסף, אם אליס משדרת את TX A02, לבוב אין דרך לקחת את ה-Output המקומי, מכיוון שאין לו את revocation_prikey_tx_a2, שנוצר ע"י alice_prikey_tx_a2 ו-bob_prikey_tx_a2 (לבוב יש את השני אבל לא את הראשון).
  3. אם אליס משדרת את טרנזקציית TX A01 הישנה, היא צריכה לחכות שבועיים לפני שהיא יכולה להשתמש בכסף. באותו זמן, בוב יכול להשתמש ב-alice_prikey_tx_a1 (שאליס נתנה לו) וב-bob_prikey_tx_a1, כדי ליצור את revocation_prikey_tx_a1 ולייצר revocation_sig_tx_a1 שישחרר את ה-Output, מה שייתן לבוב את כל הכסף, כעונש לאליס.

לפיכך, עדכון ה-Output המקומי וה-Output המרוחק הוא בטוח והוגן. מקבל הכסף לא דואג ששולח הכסף ינסה לרמות, ושולח הכסף לא דואג שמקבל הכסף יעלם באמצע.
השאלה המסובכת יותר היא איך אנחנו מאבטחים את ה-Output של הזכות והחובה?

ביצוע תשלומים עם אפשרות ביטול

נניח שלבוב יש תרנגולת והוא מוכן למכור אותה לאליס עבור 0.1 ביטקוין (למה? כי תרנגולת היא חברתו הטובה ביותר של האדם!). הם לא ממהרים ומצידם שייקח לתשלום אפילו שלושה ימים להגיע. בוב מתחיל את התהליך באמצעות "בקשת תשלום" (payment request). התהליך הוא כדלקמן:

  1. בוב מייצר סוד בשם payment_secret ושומר אותו לעצמו (נקרא גם Preimage).
  2. בוב מפעיל את פונקציית הגיבוב על payment_secret, כדי לייצר payment_hash, ושולח אותו לאליס.
  3. אליס מייצרת טרנזקציית התחייבות חדשה, שבה יש Output חובה שאותו ניתן לבזבז באחד משני מקרים:
    א. אם בוב יכול לחשוף את ה-payment_secret בתוך שלושה ימים, בוב מקבל את הכסף.
    ב. אם חלפו שלושה ימים מרגע ההסכם ובוב לא חשף את ה-payment_secret, אליס מקבלת את הכסף שלה חזרה.
  4. בוב מייצר טרנזקציית התחייבות חדשה דומה, שבה במקום Output חובה לאליס יש Output זכות לבוב, תחת אותם תנאים.

נניח שה-Outputים החדשים ייראו כך:

Output החובה של אליס ב-TX A02. האם הוא יעבוד בכל המקרים והתגובות? הערת מתרגם: ה-Else כאן הוא לא במובן של שפת-תכנות, כלומר הוא לא מבצע בדיקה ש-"חלפו פחות משלושה ימים". למעשה אין אופרטור בסקריפט של ביטקוין שבודק דבר כזה (הסבר בהמשך). המשמעות של ה-Else כאן היא "עוד דרך לבזבז את ה-Output, בין אם חלפו או לא חלפו שלושה ימים".

Output הזכות של בוב ב-TX B02, שכרגע זהה ל-Output חובה של אליס. האם הוא יעבוד בכל המקרים והתגובות? הערת מתרגם: ההערה הקודמת על ה-Else תקפה גם פה.

המטרה שלנו היא ליצור מנגנון שבו אם בוב יודע ומוכן לחשוף את payment_secret בזמן הקצוב, בוב יקבל את הכסף במאזן החדש, ואם אליס לא מגיבה הוא יכול לשדר לרשת הביטקוין טרנזקציה (שכוללת את ה-payment_secret) שתיתן לו את הכסף. כל מי ששופט מהצד ומסתכל על הבלוקצ'יין ייראה שבוב אכן ידע את ה-payment_secret בזמן הקצוב. מאידך, אם הוא לא חשף לאליס/לבלוקצ'יין את ה-payment_secret בזמן הקצוב, לא מגיע לו לקבל את הכסף, אפילו אם הוא פתאום התעורר והתחיל לשדר טרנזקציות כלשהן. אם בוב לא מצליח לחשוף לאליס את payment_secret בזמן הקצוב, ומפסיק להגיב כדי שיחזרו למאזן הישן, אליס צריכה להיות מסוגלת לשדר בסוף הזמן הקצוב טרנזקציה שתחזיר לה את הכסף. האם לדעתכם ה-Outputים האחרונים מקיימים את כל הדרישות של כל המקרים והתגובות הללו?
זה מבלבל, אני יודע. מכיוון שהדרישה של רשת הברק היא לדאוג שהטרנזקציות יגיעו לרשת הביטקוין לעיתים רחוקות ככל הניתן, רק כאשר אחד הצדדים מפסיק להגיב או פועל בזדון. במצב הרגיל, אנחנו רוצים לתכנן דרך שבה אליס ובוב ירגישו בטוחים לגבי הכסף שלהם, מבלי לשדר את טרנזקציות ההתחייבות, ושהערוץ יישאר פתוח ככל שניתן. במקרה שלנו, בוב כבר יודע את ה-payment_secret בתוך שלושה ימים, אבל אנחנו לא רוצים לחייב אותו לשדר את הטרנזקציה כדי להוכיח את זה.
הערת מתרגם: בדוגמאות הנ"ל, הזמן הקצוב הוא יחסי ולא אבסולוטי ("תוך 3 ימים מרגע שליחת הטרנזקציה"), כלומר אם אליס רוצה להפעיל לחץ על בוב לחשוף את payment_secret, היא חייבת לשדר את הטרנזקציה – ואנחנו רוצים להימנע מזה. אבל אפילו אם נמצא דרך כזו, אין מנגנון ביטול לטרנזקציה, כלומר אם המשתתפים יחליטו על מאזן חדש בעתיד, שום דבר לא יעניש את מי שינסה לשדר את הטרנזקציה הישנה הזו. אפילו אם בוב חשף בפני אליס את payment_secret, ואליס הסכימה על מאזן חדש בטרנזקציות התחייבות חדשות שבה יש לבוב יותר כסף ב-Output המקומי/מרוחק בהתאמה, בוב ידאג שאליס עלולה להשתמש באופן לא הוגן בטרנזקציה הישנה הזו (אחרי שלושה ימים אבסולטיים). הסבר מפורט יגיע בהמשך.
אז לפני שבוב שולח את התרנגולת האהובה שלו, אנחנו חייבים להבין לעומק את מנגנוני נעילת-הזמן, ואיך אנחנו יכולים להשתמש בהם.

נעילת זמן בביטקוין

בביטקוין יש שני סוגים של נעילות-זמן, אחד הוא זמן אבסולוטי, והשני זמן יחסי. ההבדל בינם הוא פשוט כמו "ניפגש בשעה 15:00" מול "ניפגש בעוד שעתיים" – כאשר נעילת הזמן היחסי מתחילה ברגע שהטרנזקציה נכרית בבלוק. המקום שבו שמים את נעילת הזמן קובע מתי אפשר לשדר את הטרנזקציה או מתי אפשר להשתמש/לבזבז את ה-Outputים שלה. בתוך כל טרנזקציה, יש שלושה מיקומים שקובעים את נעילת הזמן.

  1. בתוך מחלקת ה-Input, לכל Input יש שדה nSequence שמשתמשים בו עבור נעילת זמן יחסית.
  2. בתוך מחלקת ה-Output, לכל סקריפט נעילה של כל Output, האופרטור CheckLockTimeVerify (בקיצור CLTV) קובע את נעילת הזמן האבסולוטית, והאופרטור CheckSequenceVerify (בקיצור CSV) קובע את נעילת הזמן היחסית.
  3. ברמת הטרנזקציה, השדה nLocktime קובע נעילת זמן אבסולוטית.

טרנזקציה לדוגמא שבה מודגשים המיקומים של נעילות הזמן

רשת הברק משתמשת ב-nLocktime, CheckSequenceVerify ו-CheckLockTimeVerify בתכנון שלה.
השדה nLocktime שולט מתי לטרנזקציה מותר להיכנס לבלוקצ'יין. אם יש טרנזקציה שבה כתוב nLocktime של 2140/01/01 12:00, ניתן יהיה לשדר אותה רק בעוד יותר ממאה שנים. האופרטורים CheckSequenceVerify ו-CheckLockTimeVerify שולטים במתי ניתן לבזבז את ה-Outputים. אם הסקריפט מכיל CheckSequenceVerify עם "30 ימים", ניתן יהיה לבזבז את ה-Output רק אחרי 30 ימים. אם הסקריפט מכיל CheckLockTimeVerify עם 2140/01/01 12:00, ניתן יהיה לבזבז את ה-Outputים רק כשהגיע התאריך 2140/01/01 12:00. באופן פשוט, nLocktime שולט בזמן השידור של הטרנזקציה, ו-CheckSequenceVerify, CheckLockTimeVerify שולטים בזמן השימוש ב-Outputים של הטרנזקציה.
הערת מתרגם: שימו לב שכל נעילות הזמן הן "מותר לבצע פעולה X החל מנקודת זמן Y", ואין אף פעולה בסגנון "מותר לבצע פעולה X רק עד נקודת זמן Y". זהו עקרון בסיסי חשוב ברשת הביטקוין: מרגע שיש טרנזקציה שניתן להכניס לבלוקצ'יין, תמיד יהיה אפשר להכניס אותה לבלוקצ'יין, אלא אם כן אחד ה-Inputים שלה מבוזבז (ניסיון Double-Spend או Replace-By-Fee). הסיבה היא להקל על הצמתים כשמגיע בלוק חדש. נניח שטרנזקציה ב-Mempool יכולה הייתה להיכנס לבלוק האחרון, כלומר הצומת בדק שמתקיימים שני התנאים:

  1. ה-Inputים שלה מצביעים על Outputים שלא בוזבזו עדיין (UTXO) ולא מתנגשים עם Inputים של טרנזקציה אחרת ב-Mempool (פרט למקרה Replace-By-Fee).
  2. אפשר להריץ בהצלחה את סקריפט הנעילה והשחרור של ה-Inputים שלה.

ונניח שעכשיו מגיע בלוק חדש – מספיק לנו לעבור על הטרנזקציות ב-Mempool ולבדוק את הסעיף הראשון (ה-Inputים לא מתנגשים עם ה-Inputים של הטרנזקציות בבלוק החדש), ואין צורך לבדוק שוב את כל סקריפטי הנעילה והשחרור. אם הסקריפטים רצו בעבר בהצלחה הם בטוח ירוצו בהצלחה גם עכשיו.

שימוש בנעילת זמן ב-Outputים

Outputים ניתנים לביטול, כמו ה-Output המקומי והמרוחק, משתמשים בנעילת-זמן יחסית, מכיוון שהם רלוונטיים כאשר נחשפת טרנזקציית התחייבות ישנה (ע"י משתתף רמאי). לפיכך, הגיוני להתחיל את הספירה לאחור כאשר הטרנזקציה הישנה משודרת או נכרית. לדוגמא, אם אליס מנסה לרמות ולשדר את TX A01, ברגע שהטרנזקציה נכרית ע"י הכורים, היא צריכה לחכות שבועיים כדי לבזבז את ה-Outputים שלה, מה שנותן לבוב זמן לשים לב לכך ולהגיב (אם הוא עוקב אחרי הבלוקצ'יין). מצד שני, אם נשתמש פה בנעילת זמן אבסולוטית, לדוגמא 2019/12/31 23:59:59, אליס תוכל לחכות לערב ראש השנה האזרחית כדי לשדר את הטרנזקציה ומייד לבזבז את ה-Output שלה, מבלי שבוב שם לב (נניח כי חיבור האינטרנט שלו היה איטי באותו רגע).
Outputים לרישום תשלומים שמתבצעים כרגע, כמו Output חובה ו-Output זכות, משתמשים בנעילת-זמן אבסולוטית, מכיוון שהם נועדו להפעיל לחץ על מקבל התשלום (במקרה שלנו בוב) לחשוף את הסוד, מבלי לשדר את הטרנזקציה. אם בוב לא יכול לספק את ה-payment_secret לפני זמן אבסולוטי מסוים, לדוגמא "היום ב-6pm", אליס צריכה לקבל חזרה את היכולת לבזבז את הכסף (אחרי 6pm). אם היינו משתמשים בזמן יחסי "שלושה ימים", לבוב לא היה שום אינטרס למהר, אלא אם כן הוא היה רואה שאליס ממש שידרה את הטרנזקציה.
נניח שהם מבצעים את התשלום ב-8:00AM היום, ואליס רוצה לתת לבוב 10 שעות לחשוף את ה-payment_secret. האם יספיק לשנות את ה-Outputים שייראו כמו בשרטוט הבא?

Output החובה של אליס ב-TX A02. ההערה על ה-Else תקפה גם כאן.

Output הזכות של בוב ב-TX B02, שכרגע זהה ל-Output חובה של אליס. ההערה על ה-Else תקפה גם כאן.

נעילת הזמן האבסולטית פתרה את הבעיה האחרונה, מכיוון שאף אחד לא צריך לשדר אף טרנזקציה כדי להתחיל להפעיל את מנגנוני נעילת הזמן.

אבטחת Output החובה ו-Output הזכות

השעה 5pm. בעוד שעה אחת בלבד, אליס תוכל לשדר את TX A02 ולקחת לעצמה את הכספים ב-Output החובה. למרות שלבוב יש את ה-payment_secret והוא מוכן למסור אותו לאליס, נראה שאליס תמיד תוכל לשדר את TX A02 בעתיד ולקחת את הכסף, אפילו אם היא תיתן לו טרנזקציות התחייבות חדשות. הדרך היחידה של בוב למנוע את זה היא לשדר בעצמו את TX B02. האם יש דרך אחרת למנוע מאליס לרמות? אולי ננסה להוסיף נעילת זמן יחסית, לדוגמא שבועיים, ל-Output החובה של אליס.

Output החובה של אליס ב-TX A02. גם כאן המשמעות של ה-Else היא "עוד דרך לבזבז את ה-Output בין אם הגיעה או לא הגיעה השעה 6pm".

אם אליס הסכימה למאזנים חדשים בטרנזקציות התחייבות חדשות, אבל פתאום מרמה ומשדרת את TX A02 הישנה, היא צריכה לחכות שבועיים כדי לבזבז את הכסף שלה. באותו זמן, בוב יכול לגלות את זה, ולבזבז את ה-Output הזה באופן מיידי (עם ה-payment_secret שלו). אבל עכשיו תורה של אליס לדאוג! נניח הגיעה השעה 6pm בלי שבוב הגיב ובלי שהוא חשף בפניה את ה-payment_secret. אם אליס רוצה את כספה חזרה ותשדר את TX A02, בוב יכול לחכות שבוע שלם עם ה-payment_secret שמור אצלו בסוד, ורק אז לחשוף את payment_secret ולבזבז את ה-Output. בוב יכול לרמות ולא לעמוד בהסכם (לפרסם את payment_secret לפני 6pm), ועדיין לקבל את הכסף. האם יש דרך למנוע מבוב לעשות את זה?

במקום לשים נעילת-זמן על Output החובה של אליס, נאפשר לה לבזבז את ה-Output הזה באופן מיידי אבל עם תנאי אחד: אליס תבטיח לבזבז אותו ל-input של טרנזקציה מיוחדת חדשה, שנקראת HTLC-Timeout.

טרנזקציית ה-HTLC-Timeout של אליס, שאת ה-Outputים שלה רק אליס יכולה לבזבז.

טרנזקציית ה-HTLC-Timeout משתמשת בנעילת-זמן אבסולוטית (nLocktime):

  1. היא משתמשת ב-Output מספר 1 של TX A02 (שהוא Output החובה של אליס).
  2. יש לה nLocktime של 6pm, כלומר לא ניתן לשדר אותה לפני השעה 6pm.
    גם Output החובה עצמו צריך להשתנות:

Output החובה של אליס ב-TX A02

הבעיה שלנו כמעט נפתרה. מהצד של אליס, אם הגיעה השעה 6pm ובוב לא חשף את ה-payment_secret, היא עושה שתי פעולות:

  1. היא משדרת את TX A02 תחילה.
  2. היא משדרת את HTLC-Timeout שמצביעה ל-TX A02.

לפני השעה 6pm, אין לאליס שום אינטרס לשדר את TX A02, מכיוון שאת ה-Output הזה היא אמורה לבזבז רק עם HTLC-Timeout (ואת HTLC-Timeout ניתן לשדר רק בשעה 6pm בגלל ה-nLocktime). כשהגיעה השעה 6pm, אפילו אם בוב מוכן לחשוף את ה-payment_secret, הוא לא יכול להשתמש ב-Output החובה הזה מכיוון שהוא כבר בוזבז ע"י ה-HTLC-Timeout שאליס שידרה (זה ייראה ברשת כמו ניסיון Double-Spend). למרות שסקריפט הנעילה מאפשר לבזבז את ה-Output בשתי דרכים שונות, רשת הביטקוין מוודאת עבורנו ש-Output יתבזבז לכל היותר פעם אחת בלבד. הערת מתרגם: בנוסף, סקריפט הנעילה ב-Output של ה-HTLC-Timeout יכול להתנהג דומה לזה של ה-Output המקומי/המרוחק – לאפשר לאליס לבזבז את הכסף אחרי שבועיים, ואם בוב שם לב לטרנזקציה ואליס נתנה לו את המפתח המתאים (כהבטחה שהיא לא תרמה), הוא יוכל לקחת את הכסף לעצמו מייד.

נראה שכמעט סיימנו, אבל פספסנו נקודה חשובה. אליס הבטיחה שבשעה 6pm היא תבזבז את Output החובה לתוך ה-HTLC-Timeout ולא לאף מקום אחר, אבל למה לה לעשות את זה?

היא לא תעשה את זה, אלא אם נוסיף שינוי אחרון שבאמצעותו בוב יכריח אותה לעשות את זה. Output החובה לא יגיע לידיים של אליס ישירות, אלא לריבוי-חתימות שדורש גם את החתימה של אליס וגם את החתימה של בוב – ובוב יחתום מראש שהוא מסכים שה-Output במקרה הזה יבוזבז רק ע"י ה-HTLC-Timeout.

טרנזקציית ההתחייבות של אליס TX A02. שימו לב ל-multi-sig ב-Output החובה, שדורש גם את alice_htlc_sig וגם את bob_htlc_sig.

כשאליס יוצרת את TX A02, היא מבזבזת את ה-Output של טרנזקציית התקצוב, מה שדורש גם את החתימה של אליס וגם את החתימה של בוב (alice_funding_sig, bob_funding_sig). לכן בוב יכול לבדוק ש-TX A02, נוצרה לפי הדרישות לפני שהוא שולח את החתימה שלו bob_funding_sig לאליס (ואם אליס רוצה לשדר את הטרנזקציה, היא תצרף את החתימה שלה alice_funding_sig ואז תשדר אותה).

טרנזקציית ה-HTLC-Timeout החדשה תיראה כך:

טרנזקציית ה-HTLC-Timeout של אליס. הערת מתרגם: בהמשך נסביר בפירוט מה מכיל סקריפט הנעילה (ה-Locking Script).

כשיוצרים את טרנזקציית ה-HTLC-Timeout, היא מבזבזת את Output החובה מ-TX A02, מה שידרוש גם את החתימה של אליס וגם את החתימה של בוב (alice_htlc_sig, bob_htlc_sig). בוב אז בודק ש-HTLC-Timeout נוצרה באופן המתוכנן, ואז שולח את חתימתו bob_htlc_sig לאליס. בדרך זו, אליס תתנהג כמצופה ממנה, ואם הגיעה השעה 6pm היא תוכל לבזבז את ה-Output רק לתוך טרנזקציית ה-HTLC-Timeout ולא למקומות אחרים. באופן כללי, אנחנו רוצים שהמשתתפים ירגישו בטוחים לגבי הכסף שלהם, מבלי לשדר את הטרנזקציות, ולכן הושקע מאמץ גדול כדי לפתח את המנגנון המורכב הזה. עבור טרנזקציית TX A02 וטרנזקציית ה-HTLC-Timeout, המנגנון עובד כך:

  1. אם לבוב יש את payment_secret, הוא יודע בוודאות שהוא יכול לקבל את כספו לפני 6pm, כי אפילו אם אליס תשדר את TX A02, היא לא תוכל לבזבז את ה-Output עד השעה 6pm, ובוב ישתמש מייד ב-payment_secret כדי לקחת את כספו.
  2. אחרי השעה 6pm, אם בוב לא מגיב, אליס תוכל לשדר גם את TX A02 וגם את טרנזקציית ה-HTLC-Timeout כדי לקבל את כספה.

לפי התכנון הזה, לאליס אין אינטרס לשדר את TX A02 אלא אם כן היא חייבת. מהצד של בוב, ל-TX B02 יהיה מבנה דומה, ותהיה לו טרנזקציית HTLC-Success דומה מאוד לטרנזקציית ה-HTLC-Timeout.

טרנזקציית ההתחייבות TX B02 של בוב. שימו לב ל-multi-sig ב-Output הזכות, שדורש גם את alice_htlc_sig וגם את bob_htlc_sig.

ניתן לבזבז את Output הזכות של בוב באמצעות payment_secret, alice_htlc_sig, bob_htlc_sig ביחד, ואז הוא יגיע לטרנזקציית ה-HTLC-Success. בדומה לטרנזקציית ה-HTLC-Timeout שנבדקת ע"י בוב לפני שהוא שולח לאליס את החתימה שלו, טרנזקציית ה-HTLC-Success נבדקת ע"י אליס לפני שהיא שולחת את החתימה שלה לבוב – כדי שבוב לא ינסה לעשות דברים חריגים.

טרנזקציית ה-HTLC-Success של בוב. הערת מתרגם: סקריפט השחרור (ה-Unlocking script) צריך לכלול גם את ה-payment_secret כדי להתאים ל-Output של TX B02. בנוסף סקריפט הנעילה (ה-Locking script) ייראה קצת שונה: בוב לא אמור לקבל את הכסף מייד אלא כעבור שבועיים, שבהן יש לאליס זמן להגיב ולקחת לו את הכסף אם בוב מרמה והטרנזקציה כבר בוטלה (ע"י מפתח פרטי מסוים שבוב ישלח לה).

אם בוב שולח לאליס את payment_secret לפני השעה 6pm אבל היא לא מגיבה, ולא מוכנה לשלוח לו טרנזקציות התחייבות חדשות ואת המפתחות הדרושים כדי לבטל את הישנות, בוב יפרסם גם את TX B02 וגם את טרנזקציית ה-HTLC-Success (שיכללו על הבלוקצ'יין את ה-payment_secret – סוג של הוכחה לכולם שבוב אכן היה מוכן לפרסם את ה-payment_secret לפני השעה 6pm).

עדכון Output החובה ו-Output הזכות

היכולת לרשום עדכוני מאזן עם נעילות-זמן, היא לא מספיקה – עלינו להיות מסוגלים גם לעדכן אותם. נחזור לעסקת מכירת התרנגולת שהייתה לנו: השעה 6pm תגיע רק בעוד מספר שעות ובוב עדיין לא סיפר לאליס את ה-payment_secret – אבל אליס עכשיו נזכרת שהיא רוצה לקנות מבוב גם כמה ביצים בנוסף לתרנגולת ומוכנה לשלם לו 0.05 ביטקוין נוספים. כדי לבצע את העסקה הנוספת, אליס ובוב יצטרכו לייצר TX A03 ו-TX B03 חדשים, שייצגו את המאזן החדש, ולבטל את TX A02 ואת TX B02 הישנים.

משמאל לימין, המאזנים של אליס ושל בוב בכל טרנזקציה

באופן דומה לאבטחה של Output מקומי ו-Output מרוחק, אנחנו צריכים להוסיף מנגנון ביטול (revocation) גם ל-Output חובה ול-Output זכות, והם ייראו כך:

Output החובה של אליס ב-TX A02

Output הזכות של בוב ב-TX B02

במהלך היצירה של TX A03 ושל TX B03, אליס ובוב ימסרו זה לזה את המפתחות הפרטיים הישנים – אליס תיתן לבוב את alice_prikey_tx_a2 ובוב ייתן לאליס את bob_prikey_tx_b2. מבחינת TX A02, אם אליס תשדר אותה אז בוב (ורק בוב) יוכל "לבטל אותה" (לקחת את הכסף לעצמו), מכיוון שרק לו יש את bob_prikey_tx_a2. עבור TX B02, המנגנון הפוך – אם בוב משדר אותה, אז אליס (ורק אליס) תוכל "לבטל אותה" (לקחת את הכסף לעצמה), מכיוון שרק לה יש את alice_prikey_tx_b2.

לאליס יש מראש את alice_prikey_tx_b2. אם היא קיבלה מבוב את bob_prikey_tx_b2, היא יכולה לחשב את revocation_prikey_tx_b2, שמייצר חתימה דיגיטלית revocation_sig_tx_b2, שיכולה לבטל את TX B02. אם בוב מרמה ומשדר את TX B02, כל הכסף ב-Output הזכות של הטרנזקציה יילקח מיידית ע"י אליס – כעונש לבוב.

לבוב יש מראש את bob_prikey_tx_a2. אם הוא קיבל מאליס את alice_prikey_tx_a2, הוא יכול לחשב את revocation_prikey_tx_a2, שמייצר חתימה דיגיטלית revocation_sig_tx_a2, שיכולה לבטל את TX A02. אם אליס מרמה ומשדרת את TX A02, כל הכסף ב-Output החובה של הטרנזקציה יילקח מיידית ע"י בוב – כעונש לאליס.

מנגנון הביטול (revocation) נכנס גם בתוך טרנזקציות ה-HTLC-Timeout וה-HTLC-Success.

טרנזקציית ה-HTLC-Timeout של אליס. הערת מתרגם: בסקריפט הנעילה אליס לא מקבלת את הכסף מייד, אלא רק כעבור שבועיים, כדי לתת לבוב זמן להגיב.

טרנזקציית ה-HTLC-Success של בוב. הערת מתרגם, בסקריפט הנעילה בוב לא מקבל את הכסף מייד, אלא רק כעבור שבועיים, כדי לתת לאליס זמן להגיב.

למה מנגנון הביטול נכנס בשני מקומות, גם בטרנזקציות ההתחייבות וגם בטרנזקציות HTLC-Timeout/Success?

אם היה לנו מנגנון ביטול רק ב-Output החובה, אליס הייתה יכולה ב-6pm לשדר גם את טרנזקציית TX A02 וגם את טרנזקציית ה-HTLC-Timeout. נכון שלבוב יש את היכולת לבטל את TX A02 אבל בזמן שייקח לו להגיב, רוב הכורים ייראו שיש כבר טרנזקציה שמבזבזת את אותו Output חובה – טרנזקציית ה-HTLC-Timeout. בוב יהיה תלוי בחסדיהם של הכורים להעדיף את הטרנזקציה שלו על פני טרנזקציית ה-HTLC-Timeout.

מצד שני, אם היינו משאירים את הביטול רק בטרנזקציות ה-HTLC-Timeout/Success, ולא מכניסים אותו ל-Output החובה של אליס, היא הייתה יכולה לשדר את TX A02 בלי לשדר את טרנזקציית ה-HTLC-Timeout, ולגרום לכסף של בוב להינעל לתקופות ארוכות (ראה דיון).

סגירת הערוץ – חזרה לרשת הביטקוין

ישנן שלוש דרכים לסגור ערוץ. אליס ובוב יכולים:

  1. הדרך הטובה: סגירה בשיתוף פעולה. אליס ובוב יכולים ליצור טרנזקציית סגירה, ולאסוף את הכסף שלהם מייד.
  2. הדרך הרעה: סגירה חד צדדית באמצעות נעילת-זמן (ו-payment_secret אם צריך), שנחשבת רעה מכיוון שהכסף נשאר נעול לתקופה מסוימת. אליס יכולה לשדר את TX A03 ובוב יכול לשדר את TX B03 כדי לאסוף את הכסף שלהם, אבל הם יצטרכו לחכות שבועיים כדי להשתמש בו.
  3. הדרך המכוערת: ביטול טרנזקציית רמאות של המשתתף השני. אם הצד השני מרמה ומשדר טרנזקציה ישנה, אפשר (וחובה) להשתמש ב-revocation-key כדי לאסוף את הכסף, כעונש לצד השני.

אליס ובוב יחתמו על טרנזקציית הסגירה ביחד, לאחר משא ומתן למזעור העמלות, וישדרו אותה.

המנגנון הסופי – העברת תשלומים

מאמץ גדול הושקע בתכנון של HTLC כדי שרשת הברק תוכל להעביר תשלומים באופן חלק. נניח שיש לנו עכשיו שני ערוצים: הראשון בין אליס לבוב שאליס תקצבה ב-1 ביטקוין, והשני בין בוב לצ'רלי שבוב תקצב ב-2 ביטקוין. אליס רוצה לשלוח לצ'רלי 0.1 ביטקוין דרך בוב. הנה מה שהם צריכים לעשות:

בין בוב לצ'רלי:

  1. צ'רלי מייצר payment_charlie_secret, ומפעיל עליו את פונקציית הגיבוב כדי לקבל payment_charlie_hash.
  2. צ'רלי ובוב מייצרים טרנזקציות התחייבות דומות – לצ'רלי יש עכשיו Output  זכות (HTLC נכנס) של 0.1 ביטקוין, ולבוב יש Output חובה (HTLC יוצא) של 0.1 בטקוין.
  3. צ'רלי חייב לחשוף את ה-payment_charlie_secret לבוב לפני השעה 5pm, אחרת בוב יקבל את כספו חזרה.
  4. צ'רלי ובוב יוצרים גם טרנזקציות HTLC-Timeout ו-HTLC-Success דומות.

טרנזקציית ההתחייבות החדשה של בוב, שבה הוא שולח 0.1 ביטקוין לצ'רלי.

טרנזקציית ה-HTLC-Timeout של בוב, שאותה הוא יכול לשדר החל מהשעה 5pm. הערת מתרגם: גם כאן שכחו לציין בסקריפט הנעילה שבוב יכול לקבל את כספו רק אחרי שבועיים – כדי לתת זמן לצ'רלי להגיב אם הוא יכול לייצר את revocation_sig_tx_bc.

טרנזקציית ההתחייבות של צ'רלי, שבה הוא מקבל 0.1 ביטקוין מבוב.

טרנזקציית ה-HTLC-Success של צ'רלי. הערת מתרגם: גם כאן שכחו לציין בסקריפט הנעילה שצ'רלי יכול לקבל את כספו רק אחרי שבועיים – כדי לתת זמן לבוב להגיב אם הוא יכול לייצר את revocation_sig_tx_cb.

בין אליס ובוב, הם יחזרו על התהליך, כאשר בוב הוא זה שתפקידו "לאסוף כסף". טרנזקציות ההתחייבות שלהם יהיו:

  1. לבוב יש Output זכות (ה-HTLC הנכנס) של 0.1 ביטקוין.
  2. לאליס יש Output חובה (ה-HTLC היוצא) של 0.1 ביטקוין.
  3. בוב צריך לחשוף את payment_charlie_secret לפני 6pm (שעה אחרי ה-deadline בעסקה שלו מול צ'רלי). אחרת אליס מקבלת את הכסף חזרה.

בוב ואליס גם ייצרו טרנזקציות HTLC-Timeout ו-HTLC-Success דומות. כדי להשלים את התשלום:

  1. צ'רלי יחשוף את payment_charlie_secret לבוב לפני 5pm, כדי לקבל את הכסף שלו מבוב.
  2. לבוב תהיה לפחות שעה שלמה לחשוף את payment_charlie_secret כדי לקבל את כספו מאליס.

במציאות, בוב, שרק מעביר הלאה את התשלום, יכול לדרוש מאליס עמלה קטנה עבור השירות שהוא נותן (כלומר, אליס תשלם לבוב קצת יותר מאשר מה שצ'רלי דרש מבוב). הטכנולוגיה לכך כבר בשימוש היום, אבל יהיה מרתק לראות בעתיד אילו השפעות פוליטיות וכלכליות יבואו לידי ביטוי במנגנוני העמלות הללו!

 הערות מתרגם:

  1. בוב ישלח לצ'רלי את החתימות הדיגיטליות הרלוונטיות רק אחרי שקיבל את החתימות שהוא צריך מאליס. בוב הרי לא רוצה להבטיח לצ'רלי 0.1 ביטקוין תמורת אותו payment_charlie_secret, לפני שהוא יודע שהוא יכול לקבל מאליס את אותו הסכום תמורת אותו payment_charlie_secret.
  2. ראוי לציין שברשת הברק יש מנגנוני פרטיות נוספים שלא מצוינים פה: בוב לא באמת יודע אם התשלום התבצע מאליס לצ'רלי, או ממקור שנמצא לפני אליס אל יעד שנמצא אחרי צ'רלי. בוב רק יודע שאליס וצ'רלי עושים עסקה להעברת payment-secret, בלי לדעת אם מדובר בשרשרת ארוכה של עסקאות כאלה שהוא רק חלק קטן ממנה.

הבהרה לסיום – עבור מפתחים/חוקרים

בשביל הפשטות, קיצרתי במכוון את סקריפט הנעילה כדי להתרכז בתמונה הגדולה. אני חושב שיהיה נחמד להבהיר מהו הסקריפט שמשתמשים בו בפועל.

כשאנו מדברים על הפעולה "לוודא שהחתימה של אליס נמצאת" בסקריפט נעילה, מה שנכנס לסקריפט זה:

<Alice's public key> OP_CHECKSIG

כאשר אליס מבזבזת את ה-Output, היא שמה ב-Input של הטרנזקציה הבאה את Alice's public key. אותו דבר קורה עבור חתימת revocation (ביטול) ועבור payment-secret. לפרטים נוספים, ראה: הערות ומקורות ידע לפרק ב'.

הבהרה נוספת היא האלגוריתם שבו משתמשים כדי ליצור את "זוגות מפתחות הביטול" (revocation key pairs). קודם לכן, תיארנו את זה כחיבור פשוט של המפתחות, אבל המתמטיקה בפועל היא כדלקמן:

revocation_public_key = bob_public_key * SHA256(bob_public_key || alice_public_key) + alice_public_key * SHA256(alice_public_key || bob_public_key)

revocation_private_key = bob_secret_key * SHA256(bob_public_key || alice_public_key) + alice_secret_key * SHA256(alice_public_key || bob_public_key)

אם נרצה להתאים את שמות המפתחות ל-RFC, נניח שבוב הוא הצומת המקומי (local node) ואליס היא הצומת המרוחק (remote node), ונחליף את השמות כך:

  1. bob_public_key הוא revocation_basepoint.
  2. bob_secret_key הוא revocation_basepoint_secret.
  3. alice_public_key הוא per_commitment_point.
  4. alice_secret_key הוא per_commitment_secret.

הנוסחאות שנקבל יהיו זהות.

הטקסטים שצבועים בירוק בתאים האדומים (סקריפט נעילה) משותפים בין כולם.

הערות ומקורות ידע לפרק ב'

  1. The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments, Joseph Poon, Thaddeus Dryja
  2. Reaching the ground with lightning, Rusty Russell
  3. Elliptic Curve Point Multiplication
  4. The Lightning Network Specifications is a great place to find all the details, though it’s difficult to read. Regarding how transactions work, BOLT #2: Peer Protocol for Channel Management, BOLT #3: Bitcoin Transaction and Script Formats and BOLT #5: Recommendations for On-chain Transaction Handling explain it in technical detail.
  5. Rene Pickhardt, who works with Andreas M. Antonopoulos to write the book, Mastering the Lightning Network. He has helped to explain the general process of the transaction, how the keys exchanged and created this presentation, which I found very helpful.
  6. Hongchao wrote Payment Channels in Lightning Network which gave an overview of how the lightning network works, it’s easy to understand for readers with knowledge on Bitcoin script.
  7. Rusty Russell(the main contributor to the lightning-RFC) has summarized the rationality behind the two-stage HTLC outputs design in his blog, The #Bitcoin #Lightning Spec Part 3/8: Peer Protocol for Channel Management.
  8. About the timelock, James Prestwich’s Bitcoin’s Time Locks has provided great insight, in addition to the Bitcoin Developer Guide and Andreas M. Antonopoulos’s Mastering Bitcoin, Advanced Transactions and Scripting.
  9. I’ve set up a testing environment using bitcoind and lnd to help me understand the whole process. Here’s the gist of the trimmed log generated from lnd, which recorded how Alice sent Bob money.
  10. A clarification on the locking scripts. The red boxes represent the actual format of the locking script. To unlock it, you need to supply the unlocking script in the corresponding green box.