ℹ️ NOTA: Questa sezione è stata recentemente aggiunta al corso ed è una bozza preliminare che potrebbe essere ancora in fase di revisione. Avvertenza per il lettore.
Libwally è limitato. Si occupa della manipolazione di semi, chiavi, indirizzi e altri elementi dei portafogli, con alcune funzioni aggiuntive relative alle transazioni e ai PSBT che potrebbero essere utili per servizi non collegati ai nodi completi su Internet. Tuttavia, alla fine avrai bisogno di servizi di nodi completi per sfruttare appieno Libwally.
Questa sezione finale offrirà alcuni esempi di utilizzo dei programmi Libwally per completare un ambiente bitcoin-cli
. Anche se questi esempi implicano che questi servizi siano tutti sulla stessa macchina, potrebbero diventare ancora più potenti se il servizio bitcoin-cli
è direttamente connesso a Internet e il servizio Libwally no.
Capitolo 17.5: Usare Scripts in Libwally ha dettagliato come Libwally potrebbe essere utilizzato per riscrivere una transazione esistente, per fare qualcosa che bitcoin-cli
non può: produrre una transazione che contiene uno P2SH unico. Ovviamente, questo è un elemento fondamentale; se decidi di approfondire Libwally, creerai transazioni complete da solo. Ma, anche questa metodologia abbreviata ha il suo utilizzo: mostra come le transazioni possono essere passate avanti e indietro tra bitcoin-cli
e Libwally, dimostrando un primo esempio di utilizzo complementare.
Per dimostrare completamente questa metodologia, creerai una transazione con bitcoin-cli
, utilizzando questo UTXO:
{
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
"vout": 1,
"address": "mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo",
"label": "",
"scriptPubKey": "76a914a2a68c5f9b8e25fdd1213c38d952ab2be2e271be88ac",
"amount": 0.00094000,
"confirmations": 17375,
"spendable": true,
"solvable": true,
"desc": "pkh([ce0c7e14/0'/0'/5']0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65)#qldtsl65",
"safe": true
}
Ormai sai come impostare una transazione con bitcoin-cli
:
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
$ recipient=tb1qycsmq3jas5wkhf8xrfn8k7438cm5pc8h9ae2k0
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.0009 }''')
Anche se hai inserito un destinatario e un importo nell'output, non è rilevante, perché riscriverai quei dati. Un codice più sofisticato potrebbe leggere le informazioni vout
esistenti prima della riscrittura, ma noi manteniamo tutto molto vicino al nostro codice originale.
Ecco la sola modifica necessaria, per permetterti di specificare il satoshi vout
, senza doverlo codificare a mano, come nel caso originale:
...
int satoshis = atoi(argv[3]);
...
lw_response = wally_tx_output_init_alloc(satoshis,p2sh,sizeof(p2sh),&tx_output);
...
Poi esegui le operazioni come prima:
$ newtxhex=$(./replacewithscript $rawtxhex $script 9000)
Ecco come appariva la transazione originale:
$ bitcoin-cli decoderawtransaction $rawtxhex
{
"txid": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
"hash": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
"version": 2,
"size": 82,
"vsize": 82,
"weight": 328,
"locktime": 0,
"vin": [
{
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.00090000,
"n": 0,
"scriptPubKey": {
"asm": "0 2621b0465d851d6ba4e61a667b7ab13e3740e0f7",
"hex": "00142621b0465d851d6ba4e61a667b7ab13e3740e0f7",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"tb1qycsmq3jas5wkhf8xrfn8k7438cm5pc8h9ae2k0"
]
}
}
]
}
Ecco la transazione riscritta da Libwally per utilizzare uno P2SH:
standup@btctest:~/c$ bitcoin-cli decoderawtransaction $newtxhex
{
"txid": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
"hash": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
"version": 2,
"size": 83,
"vsize": 83,
"weight": 332,
"locktime": 0,
"vin": [
{
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 0
}
],
"vout": [
{
"value": 0.00090000,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
]
}
}
]
}
Successivamente puoi firmarla come al solito con bitcoin-cli
:
$ signedtx=$(bitcoin-cli signrawtransactionwithwallet $newtxhex | jq -r '.hex')
E come puoi vedere, il risultato è una transazione legittima pronta per essere inviata alla rete Bitcoin:
$ bitcoin-cli decoderawtransaction $signedtx
{
"txid": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
"hash": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
"version": 2,
"size": 189,
"vsize": 189,
"weight": 756,
"locktime": 0,
"vin": [
{
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
"vout": 1,
"scriptSig": {
"asm": "3044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe0[ALL] 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65",
"hex": "473044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe001210368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65"
},
"sequence": 0
}
],
"vout": [
{
"value": 0.00090000,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
]
}
}
]
}
Voila! Questa è la potenza de Libwally con bitcoin-cli
.
Ovviamente, puoi anche passare un PSBT utilizzando le funzioni descritte nel Capitolo17.4 e questa è una metodologia più aggiornata per l'uso moderno di Bitcoin, ma in entrambi gli esempi, il concetto di passare le transazioni tra bitcoin-cli
e il codice di Libwally e viceversa dovrebbe essere simile.
Purtroppo, non tutte le interazioni tra Libwally e bitcoin-cli
sono così fluide. Ad esempio, sarebbe utile poter esportare un seme HD da bitcoin-cli
per generare la frase mnemonica con Libwally, o generare un seme da una frase mnemonica utilizzando Libwally, e poi importarlo in bitcoin-cli
. Sfortunatamente, nessuna di queste operazioni è possibile al momento. Una frase mnemonica viene tradotta in un seme utilizzando HMAC-SHA512, il che significa che il risultato è di 512 bit. Tuttavia, bitcoin-cli
esporta semi HD (utilizzando dumpwallet
) e importa semi HD (utilizzando sethdseed
) con una lunghezza di 256 bit. Finché non verrà modificato, non ci sarà incontro tra i due.
📖 Qual è la differenza tra Entropia e un Seme? Libwally afferma di creare le sue frasi mnemoniche a partire dall'entropia. Questo è essenzialmente la stessa cosa di un seme: entrambi sono numeri grandi e casuali. Quindi, se
bitcoin-cli
fosse compatibile con i semi di frase mnemonica a 512 bit, potresti usare uno di essi per generare le frasi mnemoniche e ottenere i risultati che ti aspetti.
📖 Qual è la differenza tra Entropia e Entropia Grezza? Non tutta l'entropia è uguale. Quando inserisci l'entropia in un comando che crea un seme mnemonico, deve avere una lunghezza e un formato specifici. Trasformare l'entropia grezza in entropia richiede la regolazione dell'entropia grezza fino a ottenere la lunghezza e il formato giusti, e a quel punto puoi riutilizzare quell'entropia (non grezza) per ricreare sempre le stesse mnemoniche (il che è il motivo per cui l'entropia è effettivamente la stessa cosa di un seme a quel punto, ma l'entropia grezza no).
Fortunatamente, puoi fare quasi la stessa cosa importando una chiave privata generata in Libwally. Dai un'occhiata a genhd-for-import.c, una versione semplificata del programma genhd
del Capitolo 17.3 che utilizza anche la libreria jansson
nel Capitolo 16.1 per un'uscita regolarizzata.
Il codice aggiornato contiene anche una modifica importante: richiede un'impronta (fingerprint) da Libwally in modo da poter creare correttamente un percorso di derivazione:
char account_fingerprint[BIP32_KEY_FINGERPRINT_LEN];
lw_response = bip32_key_get_fingerprint(key_account,account_fingerprint,BIP32_KEY_FINGERPRINT_LEN);
char *fp_hex;
lw_response = wally_hex_from_bytes(account_fingerprint,BIP32_KEY_FINGERPRINT_LEN,&fp_hex);
⚠️ ATTENZIONE: Ricorda che l'impronta nel percorso di derivazione è arbitraria. Poiché Libwally ne fornisce una, la stiamo usando, ma se non ne avessi una, potresti aggiungere un codice esadecimale arbitrario di 4 byte come impronta al tuo percorso di derivazione.
Assicurati di compilare il nuovo codice con la libreria jansson
, dopo averla installata (se necessario) come indicato nel Capitolo 16.1.
$ cc genhd-for-import.c -lwallycore -lsodium -ljansson -o genhd-for-import
Quando esegui il nuovo programma, otterrai un elenco ben formattato di tutto:
$ ./genhd-for-import
{
"mnemonic": "physical renew say quit enjoy eager topic remind riot concert refuse chair",
"account-xprv": "tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn",
"address": "tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n",
"derivation": "[d1280779/84h/1h/0h]"
}
Hai la mnemonic
da cui puoi recuperare, un account-xprv
che puoi importare, una derivation
da usare per l'importazione e un address
di esempio, che puoi usare per testare l'importazione.
Ora puoi ricorrere alle lezioni apprese nel Capitolo 3.5 su come trasformare quel xprv in un descrittore e importarlo.
Prima, devi determinare il checksum:
$ xprv=tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn
$ dp=[d1280779/84h/1h/0h]
$ bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)"
{
"descriptor": "wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHFv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z",
"checksum": "46c00dk5",
"isrange": true,
"issolvable": true,
"hasprivatekeys": true
}
Ci sono tre cose da notare qui:
- Usiamo
wpkh
come funzione nel nostro percorso di derivazione. Questo perché vogliamo generare indirizzi Segwit moderni, non indirizzi legacy. Questo corrisponde al nostro utilizzo nella funzionewally_bip32_key_to_addr_segwit
di Libwally. La cosa più importante, tuttavia, è avere le stesse aspettative con Libwally ebitcoin-cli
(e il tuo descrittore) su che tipo di indirizzo stai generando, in modo che tutto corrisponda! - Utilizziamo il percorso
/0/*
perché volevamo gli indirizzi esterni per questo account. Se invece volessimo gli indirizzi di cambio, useremmo/1/*
. - Non useremo la riga
descriptor
restituita, poiché è per un indirizzoxpub
. Invece, applicheremo ilchecksum
restituito alxprv
che già possediamo.
$ cs=$(bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)" | jq -r ' .checksum')
Poi lo inserisci in importmulti
per importare questa chiave in bitcoin-cli
:
$ bitcoin-cli importmulti '''[{ "desc": "wpkh('$dp''$xprv'/0/*)#'$cs'", "timestamp": "now", "range": 10, "watchonly": false, "label": "LibwallyImports", "keypool": false, "rescan": false }]'''
[
{
"success": true
}
]
Qui hai importato/generato i primi dieci indirizzi per la chiave privata.
Esaminando la nuova etichetta LibwallyImported
, li mostra:
$ bitcoin-cli getaddressesbylabel "LibwallyImports"
{
"tb1qzeqrrt77xhvazq5g8sc9th0lzjwstknan8gzq7": {
"purpose": "receive"
},
"tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n": {
"purpose": "receive"
},
"tb1q8fsgxt0z9r9hfl5mst5ylxka2yljjxlxlvaf8j": {
"purpose": "receive"
},
"tb1qg6dayhdk4qc6guutxvdweh6pctc9dpguu6awqc": {
"purpose": "receive"
},
"tb1qdphaj0exvemxhgfpyh4p99wn84e2533u7p96l6": {
"purpose": "receive"
},
"tb1qwv9mdqkpx6trtmvgw3l95npq8gk9pgllucvata": {
"purpose": "receive"
},
"tb1qwh92pkrv6sps62udnmez65vfxe9n5ceuya56xz": {
"purpose": "receive"
},
"tb1q4e98ln8xlym64qjzy3k8zyfyt5q60dgcn39d90": {
"purpose": "receive"
},
"tb1qhzje887fyl65j4mulqv9ysmntwn95zpgmgvtqd": {
"purpose": "receive"
},
"tb1q62xf9ec8zcfkh2qy5qnq4qcxrx8l0jm27dd8ru": {
"purpose": "receive"
},
"tb1qlw85usfk446ssxejm9dmxsfn40kzsqce77aq20": {
"purpose": "receive"
}
}
Il secondo sulla tua lista corrisponde effettivamente al tuo esempio (tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n
). L'importazione di questa chiave privata e la derivazione di dieci indirizzi è stata effettuata con successo.
Se guardi di nuovo il Capitolo 7.3, vedrai che questo è lo stesso metodo che abbiamo usato per importare indirizzi da un Hardware Wallet (anche se in questo caso abbiamo importato anche la chiave privata come prova di concetto). La principale differenza è che in precedenza le informazioni erano create da una black box (letteralmente: era un dispositivo Ledger), e questa volta hai creato le informazioni tu stesso utilizzando Libwally, dimostrando come puoi fare questo tipo di lavoro su dispositivi airgapped o altri dispositivi più remoti, per poi portarli su bitcoin-cli
.
Ovviamente, se puoi importare chiavi private, puoi importare anche indirizzi — il che di solito significa importare indirizzi in sola visualizzazione senza le chiavi private.
Un modo per farlo è utilizzare la metodologia importmulti
sopra, ma utilizzare l'indirizzo xpub fornito (wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHFv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z
) piuttosto che l'xprv originale. Questo è il modo migliore per importare una sequenza intera di indirizzi in sola visualizzazione.
In alternativa, puoi importare indirizzi individuali. Ad esempio, considera l'indirizzo di esempio restituito attualmente dal programma genhd-for-import
:
$ ./genhd-for-import
{
"mnemonic": "finish lady crucial walk illegal ride hamster strategy desert file twin nature",
"account-xprv": "tprv8xRujYeVN7CwBHxLoTHRdmzwdW7dKUzDfruSo56GqqfRW9QXtnxnaRG8ke7j65uNjxmCVfcagz5uuaMi2vVJ8jpiGZvLwahmNB8F3SHUSyv",
"address": "tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d",
"derivation": "[6214ecff/84h/1h/0h]"
}
Puoi importare quello come indirizzo in sola visualizzazione con importaddress
:
$ bitcoin-cli -named importaddress address=tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d label=LibwallyWO rescan=false
$ bitcoin-cli getaddressesbylabel "LibwallyWO"
{
"tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d": {
"purpose": "receive"
}
}
}
Con una conoscenza fondamentale di Libwally, puoi ora completare tutto il lavoro delle lezioni precedenti. Trasferire indirizzi, chiavi, transazioni e PSBT è solo alcuni dei modi in cui potresti utilizzare questi due potenti metodi di programmazione Bitcoin insieme. C'è anche molta più profondità se vuoi approfondire la vasta libreria di funzioni di Libwally.
🔥 Qual è il Potere dell'Integrazione tra Libwally e Bitcoin-CLI? Uno dei maggiori vantaggi di Libwally è che ha molte funzioni che possono essere utilizzate offline. In confronto, Bitcoin Core è un programma connesso alla rete. Questo può aiutarti ad aumentare la sicurezza passando chiavi, indirizzi, transazioni o PSBT a una fonte offline (che eseguirà programmi Libwally). Inoltre, Libwally può fare cose che Bitcoin Core attualmente non può, come generare un seme da una frase mnemonica BIP39 (e anche se attualmente non puoi importare il seme in Bitcoin Core, puoi ancora importare la chiave principale per l'account, come mostrato qui).
Scopri altri tipi di programmazione nel Capitolo 18: Parlare a Bitcoind in Altri Linguaggi.