/ home / newsletters /
Bulletin Hebdomadaire Bitcoin Optech #345
Le bulletin de cette semaine examine une analyse du trafic P2P vécu par un nœud complet typique, résume la recherche sur le cheminement de LN (Lightning Network) et décrit une nouvelle approche pour créer des paiements probabilistes. Sont également incluses nos sections régulières résumant une réunion du Bitcoin Core PR Review Club, annonçant des mises à jour et des versions candidates, et décrivant les changements notables dans les projets d’infrastructure Bitcoin populaires.
Nouvelles
-
● Analyse du trafic P2P : le développeur Virtu a posté sur Delving Bitcoin une analyse du trafic réseau généré et reçu par son nœud dans quatre modes différents : téléchargement initial de bloc (IBD), non-écoute (connexions sortantes uniquement), écoute non-archiviste (tronquée) et écoute archiviste. Bien que les résultats pour son seul nœud puissent ne pas être représentatifs dans tous les cas, nous avons trouvé plusieurs de ses découvertes intéressantes :
-
● Trafic de blocs élevé en tant que nœud d’écoute archiviste : le nœud de Virtu a servi plusieurs gigaoctets de blocs chaque heure à d’autres nœuds lorsqu’il fonctionnait comme un nœud d’écoute non-tronqué. De nombreux blocs étaient des blocs plus anciens demandés par des connexions entrantes afin qu’ils puissent effectuer l’IBD.
-
● Trafic inv élevé en tant qu’auditeur non-archiviste : environ 20% du trafic total du nœud étaient des messages
inv
avant qu’il n’active le service de blocs plus anciens. Erlay pourrait réduire significativement cet excédent de 20%, qui représentait environ 100 mégaoctets par jour. -
● La majorité des pairs entrants semblent être des nœuds espions : “Intéressant, la majorité des pairs entrants n’échangent qu’environ 1MB de trafic avec mon nœud, ce qui est trop peu (en utilisant le trafic via mes connexions sortantes comme base) pour qu’ils soient des connexions régulières. Tout ce que ces nœuds font, c’est compléter la poignée de main P2P, et répondre poliment aux messages ping. À part ça, ils absorbent juste nos messages
inv
.”
Le post de Virtu contient des insights supplémentaires et plusieurs graphiques illustrant le trafic vécu par son nœud.
-
-
● Recherche sur le parcours de chemin unique LN : Sindura Saraswathi a posté sur Delving Bitcoin à propos de la recherche qu’elle a menée avec Christian Kümmerle sur la recherche de chemins optimaux entre les nœuds LN pour envoyer des paiements en une seule partie. Son post décrit les stratégies actuellement utilisées par Core Lightning, Eclair, LDK et LND. Les auteurs utilisent ensuite huit nœuds LN modifiés et non modifiés dans un réseau LN simulé (basé sur un instantané du réseau actuel) pour tester le cheminement, en évaluant des critères tels que le taux de succès le plus élevé, les ratios de frais les plus bas (coût le plus bas), le verrouillage total le plus court (période d’attente au pire des cas la moins pénible) et le chemin le plus court (moins susceptible de résulter en un paiement bloqué). Aucun algorithme n’a été meilleur que les autres dans tous les cas, et Saraswathi suggère que les implémentations fournissent de meilleures fonctions de pondération qui permettent aux utilisateurs de choisir les compromis qu’ils préfèrent pour différents paiements (par exemple, vous pouvez prioriser un taux de succès élevé pour un petit achat en personne mais préfèrer un ratio de frais faible pour payer une grosse facture mensuelle qui n’est pas due avant quelques semaines). Elle note également que “[bien que] au-delà du cadre de cette étude, nous remarquons que les insights obtenus dans cette étude sont également pertinents pour les améliorations futures dans les algorithmes de recherche de chemin pour les paiements multi-parties.”
-
● Paiements probabilistes utilisant différentes fonctions de hachage comme une fonction xor : Robin Linus a répondu au fil de discussion Delving Bitcoin à propos des paiements probabilistes avec un script conceptuellement simple qui permet à deux parties de s’engager chacune sur une quantité arbitraire d’entropie qui peut plus tard être révélée et xorée ensemble, pour produire une valeur qui peut être utilisée pour déterminer lequel d’entre eux reçoit un paiement. En utilisant (et en étendant légèrement) l’exemple de Linus du post :
-
Alice choisit en privé la valeur
1 0 0
plus une nonce séparée. Bob choisit en privé la valeur1 1 0
plus une autre nonce séparée. -
Chaque partie hache successivement sa nonce, avec les nombres dans leur valeur déterminant quelle fonction de hachage est utilisée. Quand la valeur en haut de la pile est
0
, ils utilisent l’opcodeHASH160
; quand la valeur est1
, ils utilisent l’opcodeSHA256
. Dans le cas d’Alice, elle effectuesha256(hash160(hash160(alice_nonce)))
; dans le cas de Bob, il effectuesha256(sha256(hash160(bob_nonce)))
. Cela produit un engagement pour chacun d’eux, qu’ils s’envoient mutuellement sans révéler ni leur valeur ni leur nonce. -
Avec les engagements partagés, ils créent une transaction de financement onchain avec un script qui validera les entrées en utilisant
OP_IF
pour choisir entre les différentes fonctions de hachage et permet à l’un d’eux de réclamer le paiement. Par exemple, si la somme de leurs deux valeurs xorées est 0 ou 1, Alice reçoit l’argent ; si c’est 2 ou 3, Bob le reçoit. Le contrat peut également avoir une clause de délai et une clause d’accord mutuel économisant de l’espace. -
Après que la transaction de financement soit confirmée à une profondeur appropriée, Alice et Bob se divulguent mutuellement leurs valeurs et leurs nonces. Le xor de
1 0 0
et1 1 0
est0 1 0
, qui se somme à1
, permettant à Alice de réclamer le paiement.
-
Bitcoin Core PR Review Club
Dans cette section mensuelle, nous résumons une récente réunion du Bitcoin Core PR Review Club, en soulignant certaines des questions et réponses importantes. Cliquez sur une question ci-dessous pour voir un résumé de la réponse de la réunion.
Un traitement interne plus strict des blocs invalides est une PR par mzumsande qui améliore la justesse de deux champs de validation non critiques pour le consensus et coûteux à calculer en les mettant à jour immédiatement lorsqu’un bloc est marqué comme invalide. Avant cette PR, ces mises à jour étaient retardées jusqu’à un événement ultérieur pour minimiser l’utilisation des ressources. Cependant, depuis Bitcoin Core #25717, un attaquant aurait besoin d’investir beaucoup plus de travail pour exploiter cela.
Plus précisément, cette PR garantit que le m_best_header
de ChainstateManager
pointe toujours
vers l’en-tête le plus travaillé qui n’est pas connu pour être valide, et que le nStatus
BLOCK_FAILED_CHILD
d’un bloc est toujours correct.
Les avantages de cette approche seraient une meilleure performance et une simplicité accrue lors de l’invalidation des descendants. Cependant, cela augmenterait la complexité de la gestion de la mémoire et pourrait potentiellement introduire de nouveaux bugs liés à la gestion des références circulaires entre les blocs. L’approche actuelle, bien que potentiellement plus coûteuse en termes de performance, évite ces complications en maintenant une séparation claire entre les blocs et leurs états d’invalidation.
-
Quels sont les objectifs de
ChainstateManager::m_best_header
?m_best_header
représente l’en-tête avec le plus de PoW que le nœud a vu jusqu’à présent et qu’il n’a pas encore invalidé mais ne peut pas non plus garantir comme étant valide. Il a de nombreuses utilisations, mais la principale est de servir de cible vers laquelle le nœud peut faire progresser sa meilleure chaîne. D’autres cas d’utilisation incluent la fourniture d’une estimation du temps actuel, et une estimation de la hauteur de la meilleure chaîne lors de la demande d’en-têtes manquants à un pair. Un aperçu plus complet peut être trouvé dans la pull request vieille de ~6 ans Bitcoin Core #16974. ➚ -
Avant cette PR, lequel de ces énoncés est vrai, le cas échéant ? 1) un
CBlockIndex
avec un prédécesseur INVALIDE aura TOUJOURS unBLOCK_FAILED_CHILD
nStatus
. 2) unCBlockIndex
avec un prédécesseur VALIDE n’aura JAMAIS unBLOCK_FAILED_CHILD
nStatus
L’énoncé 1) est faux, et est directement abordé dans cette PR. Avant cette PR,
AcceptBlock()
marquerait un bloc comme invalide, mais pour des raisons de performance, ne mettrait pas immédiatement à jour ses descendants comme tels. Les participants au Review Club n’ont pas pu penser à un scénario où l’énoncé 2) était faux. ➚ -
L’un des objectifs de cette PR est de s’assurer que
m_best_header
, et lenStatus
des successeurs d’un bloc invalide sont toujours correctement définis. Quelles fonctions sont directement responsables de la mise à jour de ces valeurs ?SetBlockFailureFlags()
est responsable de la mise à jour denStatus
. En fonctionnement normal,m_best_header
est le plus souvent défini via le paramètre de sortie dansAddToBlockIndex()
, mais il peut également être calculé et défini viaRecalculateBestHeader()
. ➚ -
La majorité de la logique dans le commit
4100495
validation: in invalidateblock, calculate m_best_header right away
met en œuvre la recherche du nouveau meilleur en-tête. Qu’est-ce qui nous empêche d’utiliser simplementRecalculateBestHeader()
ici ?RecalculateBestHeader()
traverse l’ensemble dem_block_index
, ce qui est une opération coûteuse. Le commit4100495
optimise cela en mettant en cache et en itérant plutôt sur un ensemble de candidats avec des en-têtes à haute PoW. ➚ -
Aurions-nous encore besoin du cache
cand_invalid_descendants
si nous pouvions itérer vers l’avant (c’est-à-dire, loin du bloc de genèse) sur l’arbre des blocs ? Quels seraient les avantages et les inconvénients d’une telle approche, comparée à celle prise dans cette PR ?Si les objets
CBlockIndex
contenaient des références à tous leurs descendants, nous n’aurions pas besoin d’itérer sur l’ensemble dem_block_index
pour invalider les descendants, et par conséquent, nous n’aurions pas besoin du cachecand_invalid_descendants
. Les avantages de cette approche seraient une meilleure performance et une simplicité accrue lors de l’invalidation des descendants. Cependant, cette approche aurait des inconvénients significatifs. Premièrement, cela augmenterait l’empreinte mémoire de chaque objetCBlockIndex
, qui doit être conservé en mémoire pour l’ensemble dum_block_index
. Deuxièmement, la logique d’itération resterait non triviale puisque, bien que chaqueCBlockIndex
ait exactement un ancêtre, il peut n’avoir aucun ou plusieurs descendants. ➚
Mises à jour et versions candidates
Nouvelles versions et versions candidates pour des projets d’infrastructure Bitcoin populaires. Veuillez envisager de mettre à niveau vers les nouvelles versions ou d’aider à tester les versions candidates.
- ● Eclair v0.12.0 est une sortie majeure de ce nœud LN. Elle “ajoute le support pour créer et gérer des offres BOLT12 et un nouveau protocole de fermeture de canal qui supporte RBF. [Elle] ajoute également le support pour stocker de petites quantités de données pour nos pairs” (stockage de pairs), parmi d’autres améliorations et corrections de bugs. Les notes de version mentionnent que plusieurs dépendances majeures ont été mises à jour, nécessitant que les utilisateurs effectuent ces mises à jour avant de déployer la nouvelle version d’Eclair.
Changements notables dans le code et la documentation
Changements récents notables dans Bitcoin Core, Core Lightning, Eclair, LDK, LND, libsecp256k1, Interface de Portefeuille Matériel (HWI), Rust Bitcoin, Serveur BTCPay, BDK, Propositions d’Amélioration de Bitcoin (BIPs), Lightning BOLTs, Lightning BLIPs, Inquisition Bitcoin, et BINANAs.
-
● Bitcoin Core #31407 ajoute le support pour la notarisation des paquets d’applications macOS et des binaires en mettant à jour le script
detached-sig-create.sh
. Le script signe maintenant également les binaires macOS et Windows en autonomie. L’outil récemment mis à jour signapple est utilisé pour effectuer ces tâches. -
● Eclair #3027 ajoute une fonctionnalité de recherche de chemin pour les chemins aveuglés lors de la génération de factures BOLT12 en introduisant la fonction
routeBlindingPaths
, qui calcule un chemin d’un nœud initiateur sélectionné au nœud récepteur en utilisant uniquement des nœuds qui supportent les chemins aveuglés. Le chemin aveuglé est ensuite inclus dans la facture. -
● Eclair #3007 ajoute un paramètre TLV
last_funding_locked
dans les messageschannel_reestablish
pour améliorer la synchronisation entre pairs pendant le splicing de canal après une déconnexion. Cela corrige une condition de concurrence où un nœud envoie unechannel_update
après avoir reçu unchannel_reestablish
mais avantsplice_locked
, ce qui est sans conséquence pour les canaux réguliers mais pourrait perturber les canaux taproot simples qui nécessitent des échanges de nonce entre pairs. -
● Eclair #2976 ajoute le support pour créer des offres sans plugins additionnels en introduisant la commande
createoffer
, qui prend des paramètres optionnels pour la description, le montant, l’expiration en secondes, l’émetteur, etblindedPathsFirstNodeId
pour définir un nœud initiateur pour un chemin masqué. De plus, cette PR introduit les commandesdisableoffer
etlistoffers
pour gérer les offres existantes. -
● LDK #3608 redéfinit le
CLTV_CLAIM_BUFFER
pour représenter le double du nombre maximum attendu de blocs nécessaires pour confirmer une transaction, s’adaptant aux canaux anchor où les transactions de réclamation HTLCs sont retardées par un verrouillage temporelOP_CHECKSEQUENCEVERIFY
(CSV) d’1 bloc. Auparavant, il était fixé à une seule période de confirmation maximale, ce qui était suffisant pour les canaux pré-anchor où les transactions de réclamation HTLC étaient diffusées en même temps que les transactions d’engagement. Une nouvelle constanteMAX_BLOCKS_FOR_CONF
est ajoutée comme valeur de base. -
● LDK #3624 permet la rotation de la clé de financement après une épissure de canal réussi en appliquant une modification scalaire à la clé de financement de base pour obtenir la clé multisig 2-sur-2 du canal. Cela permet à un nœud de dériver des clés supplémentaires à partir du même secret. Le calcul de la modification suit la spécification BOLT3, mais remplace
per_commitment_point
par le txid de financement de l’épissure pour garantir l’unicité, et utilise lerevocation_basepoint
pour restreindre la dérivation aux participants du canal. -
● LDK #3016 ajoute un support pour que les projets externes exécutent des tests fonctionnels et remplacent des composants comme le signataire en introduisant une macro
xtest
. Il inclut un utilitaireMutGlobal
et une structureDynSigner
pour supporter des composants de test dynamiques comme le signataire, expose ces tests sous le drapeau de fonctionnalité_externalize_tests
, et fournit uneTestSignerFactory
pour créer des signataires dynamiques. -
● LDK #3629 améliore la journalisation des échecs distants qui ne peuvent pas être attribués ou interprétés pour offrir plus de visibilité sur ces cas limites. Cette PR modifie
onion_utils.rs
pour journaliser les échecs non attribuables qui pourraient perturber l’opération de l’expéditeur, et introduit une fonctiondecrypt_failure_onion_error_packet
pour la gestion du déchiffrement. Elle corrige également un bug où un échec illisible avec un code d’authentification de message basé sur un hash (HMAC) valide n’était pas correctement attribué à un nœud. Cela peut être lié à permettre aux dépensiers d’éviter d’utiliser des nœuds qui annoncent une haute disponibilité mais ne tiennent pas leurs promesses. -
● BDK #1838 améliore la clarté du flux de synchronisation et d’analyse complète en ajoutant un
sync_time
obligatoire àSyncRequest
etFullScanRequest
, appliquant cesync_time
comme propriétéseen_at
pour les transactions non confirmées tout en permettant aux transactions non canoniques (voir le Bulletin #335) d’exclure un horodatageseen_at
. Il met à jourTxUpdate::seen_ats
en unHashSet
de (Txid, u64) pour supporter plusieurs horodatagesseen_at
par transaction, et changeTxGraph
pour être non exhaustif, parmi d’autres changements.