Internet computer wiki

Integrazione di Bitcoin

Integrazione di Bitcoin

Panoramica

Bitcoin è una valuta digitale decentralizzata basata su un protocollo P2P open-source.
Bitcoin utilizza il modello di contabilità UTXO (unspent transaction output), ovvero le transazioni creano output che vengono completamente consumati quando utilizzati come input per altre transazioni che creano nuove transazioni di output.

Bitcoin è un network di pagamento senza supporto per gli smart contract. Il supporto degli smart contract per Bitcoin di Internet Computer aggiunge un valore straordinario: sfrutta la forza combinata della rete Bitcoin come riserva di oro digitale mondiale e di Internet Computer come piattaforma per l’esecuzione di smart contract in modo sicuro ed efficiente. Un esempio di applicazioni che diverranno possibili con questa integrazione sono le applicazioni di finanza decentralizzata (DeFi), che attualmente possono essere implementate solo con Wrapped Bitcoin (WBTC) e che richiedono la fiducia di entità terze. Inoltre, Bitcoin potrebbe essere utilizzato per pagare qualsiasi tipo di servizio su Internet Computer, il che apre a un numero praticamente infinito di scenari applicativi.

Internet Computer è integrato direttamente con la blockchain di Bitcoin con l’obiettivo di rendere disponibili per Bitcoin potenti funzionalità smart contract, senza necessità di bridge.
‘Diretta’ in questo contesto significa che non sono richiesti altri presupposti di fiducia se non quella nel corretto funzionamento della rete Bitcoin e di Internet Computer. In altre parole, non sono necessarie parti aggiuntive che fanno da ponte o altri tipi di intermediari, che rendono l’integrazione molto più pulita e sicura.
In questa integrazione diretta tra Bitcoin e Internet Computer, i canister possono detenere Bitcoin direttamente sulla blockchain di Bitcoin.

L’integrazione diretta di Bitcoin presenta le seguenti caratteristiche:

  • I canister possono avere indirizzi Bitcoin (e quindi ricevere e detenere Bitcoin direttamente sulla blockchain di Bitcoin).
  • I canister possono accedere alle UTXO degli indirizzi Bitcoin.
  • I canister possono firmare in modo sicuro le transazioni Bitcoin.
  • I canister possono inviare transazioni Bitcoin alla rete Bitcoin.

L’integrazione diretta si affida ad un protocollo threshold ECDSA che consente a una subnet di calcolare firme ECDSA, basate su una secret-shared private key, su richiesta di un canister. Con questo protocollo, ogni canister può “controllare” un vasto numero di chiavi ECDSA derivabili e ottenere firme per esse, consentendo ai canister di ricevere, detenere e trasferire BTC direttamente sulla blockchain di Bitcoin in modo sicuro.
Naturalmente, un canister deve essere in grado di recuperare gli UTXO associati ai suoi indirizzi Bitcoin, a tal fine Internet Computer estrae i blocchi direttamente dalla rete Bitcoin.

Di seguito analizziamo nel dettaglio l’architettura alla base di questa integrazione.

Architettura

In questa sezione, presentiamo l’architettura dell’integrazione diretta con la blockchain di Bitcoin. L’integrazione modifica e aggiunge componenti a ogni livello dello stack del protocollo di Internet Computer (IC).

Integrazione diretta di Bitcoin su Internet Computer

Il componente Bitcoin (Bitcoin Component) è implementato al livello di esecuzione come parte della replica ed espone l’API di integrazione Bitcoin tramite il canister di gestione virtuale. L’API offre funzioni per interrogare lo stato di Bitcoin (UTXO, saldi e commissioni di transazione correnti) e per inviare transazioni.

Per poter fornire UTXO aggiornati, i blocchi Bitcoin devono essere estratti continuamente dalla rete Bitcoin e inseriti all’interno di Internet Computer e l’insieme di tutti gli UTXO (denominati “set UTXO”) deve essere aggiornato in base agli input e agli output delle transazioni contenute nei blocchi.

Questo meccanismo richiede un’architettura che si estenda a tutti i livelli dello stack del protocollo IC e che includa anche un nuovo componente esterno alla replica.

Il componente Bitcoin nel livello di esecuzione mantiene una serie di blocchi Bitcoin recenti, l’intero set UTXO e una serie di transazioni in uscita inviate dai canister. Il set UTXO e i blocchi recenti vengono utilizzati per rispondere alle richieste UTXO e di saldo dei canister.

L’adattatore Bitcoin (Bitcoin Adapter), un processo in modalità sandbox a livello di sistema operativo esterno alla replica, si connette a più nodi Bitcoin scelti casualmente utilizzando il protocollo di peer discovery di Bitcoin.

L’adattatore Bitcoin mantiene una copia locale dell’intera catena di intestazione del blocco, nonché una piccola cache di blocchi che fornisce alla replica su richiesta.

In ogni round IC, il block maker, un componente fondamentale del livello di consenso, invia una richiesta dal componente Bitcoin all’adattatore Bitcoin e ottiene la risposta, che viene quindi inclusa nel carico utile (payload) del blocco IC.
Più precisamente, il componente Bitcoin archivia la richiesta nello stato replicato, dove viene prelevata dal generatore di carico nel livello Consensus. Il generatore di carico utilizza la comunicazione tra processi per trasmettere la richiesta all’adattatore Bitcoin esterno, che la gestisce e restituisce il risultato al generatore di carico. Il generatore di carico (payload builder) incorpora quindi il risultato nel blocco IC. Una richiesta contiene gli hash di intestazioni di blocco recenti per i quali il componente Bitcoin dispone del blocco di transazioni così come delle transazioni in uscita. L’adattatore Bitcoin confronta gli hash dei blocchi ricevuti con la sua visione della rete Bitcoin: se la sua cache contiene uno o più successioni dei blocchi che il componente Bitcoin possiede, restituisce questi blocchi. Inoltre, aggiunge le transazioni ricevute nella richiesta a una coda per le transazioni in uscita da inviare in modo asincrono alla rete Bitcoin.

Ogni blocco IC viene trasmesso ai nodi della sottorete e deve passare attraverso il processo di autenticazione e finalizzazione.
Il processo di autenticazione è esteso all’integrazione Bitcoin: ogni replica esegue un controllo deterministico della validità del payload Bitcoin contenuto nel blocco IC. È fondamentale che il block maker (creatore del blocco) proponga un blocco solo se è garantito che il blocco verrà convalidato con successo da tutte le repliche oneste, altrimenti il consenso della sottorete potrebbe fallire, causando l’eliminazione dell’intero blocco IC.

Una volta che il blocco IC con il payload Bitcoin è stato convalidato con successo, la finalizzazione procede senza modifiche. Una volta finalizzato il blocco, il payload Bitcoin deve essere estratto nel livello Message Routing (instradamento dei messaggi) e inviato alla coda della sottorete corretta per l’esecuzione. Quando il payload Bitcoin raggiunge l’Execution Layer (livello di esecuzione), viene eseguito dal componente Bitcoin: il payload viene convalidato e lo stato del componente Bitcoin viene aggiornato di conseguenza.

La creazione di una transazione Bitcoin richiede il calcolo di una firma ECDSA per UTXO utilizzata come input della transazione. I canister possono richiedere firme ECDSA tramite un’API Threshold ECDSA  implementata come parte delle ECDSA signing subnet. Al momento è stata implementata solo una subnet di questo tipo e, se la domanda aumenterà, in futuro potrebbero essere rese disponibili più signing subnet.

L’API della threshold ECDSA consente a un canister di richiedere una firma ECDSA calcolata congiuntamente dalle repliche della sottorete ECDSA sulla base di una chiave privata condivisa.

Dettagli tecnici

Come descritto nella sezione precedente, i canister interagiscono con il componente Bitcoin utilizzando l’API di integrazione Bitcoin esposta tramite il management canister (o canister di gestione). Il componente Bitcoin a sua volta dipende dall’adattatore Bitcoin, che è il componente che interagisce con la rete Bitcoin.

In questa sezione vengono forniti i dettagli tecnici sui singoli componenti, partendo dal basso, con l’adattatore Bitcoin, verso l’alto.

Nota: Alcuni dettagli tecnici non sono implementati nell’Anteprima per sviluppatori, che verrà discussa nella sezione successiva.
Ad esempio, non vengono eseguiti diversi controlli di validità. Queste omissioni non sono cruciali per un ambiente di test locale.

Adattatore Bitcoin

L’adattatore Bitcoin interagisce con la rete Bitcoin per ottenere intestazioni di blocco e blocchi e pubblicare transazioni Bitcoin emesse dai canister.

Connessione ai nodi Bitcoin

Per impostazione predefinita, l’adattatore Bitcoin si connette a 8 nodi Bitcoin scelti casualmente, ma il numero di connessioni è configurabile. Per garantire che l’adattatore Bitcoin di ciascuna replica si connetta a un set casuale diverso, l’adattatore Bitcoin interroga i nodi Bitcoin per ottenere gli indirizzi fino a quando non ha ricevuti 2000, e sceglie casualmente i nodi da questi indirizzi fino a quando non viene stabilito il numero di connessioni desiderato.

Gli esperimenti hanno mostrato che questo processo fa sì che l’adattatore Bitcoin di ciascuna replica si connetta a indirizzi per lo più diversi.

Stato

L’adattatore Bitcoin mira a mantenere il seguente stato:

  • Tutti i Block Headers Bitcoin.
  • Una cache per i blocchi Bitcoin.
  • Una cache per le transazioni in uscita segnalate ma non ancora trasmesse ai nodi Bitcoin.

Inizialmente, l’adattatore ha solo l’hard-coded genesis block header e le cache sono vuote.

Adattatore Bitcoin in funzione

Quando l’adattatore Bitcoin viene avviato, si connette ai nodi Bitcoin e inizia a prelevare le intestazioni dei blocchi fino a quando non è completamente sincronizzato.

Per ogni intestazione di blocco scaricata, l’adattatore Bitcoin esegue i seguenti controlli:

  • L’intestazione del blocco è ben formata, ovvero può essere analizzata come intestazione di blocco corretta.
  • Il campo del blocco precedente punta a un’intestazione di blocco disponibile localmente.
  • Il lavoro di hash nell’intestazione del blocco è sufficiente in base all’obiettivo di difficoltà.
  • Il timestamp nell’intestazione del blocco è maggiore della mediana degli 11 blocchi precedenti.

Le cache rimangono vuote fino a quando non vengono ricevute le richieste dal componente Bitcoin. Periodicamente, il componente Bitcoin invia un elenco di hash di intestazione di blocco delle intestazioni di blocco recenti di cui già possiede i blocchi completi (contenenti tutte le transazioni). I dettagli su quali hash delle intestazioni di blocco vengono inviati sono forniti nella sezione relativa al componente Bitcoin.

L’adattatore Bitcoin controlla se possiede alcuni dei blocchi che mancano al componente Bitcoin e risponde con un messaggio contenente i blocchi mancanti, dando la priorità ai blocchi con un’altezza inferiore. Più blocchi possono essere restituiti in un unico messaggio fino a un soft cap di 2 MB, garantendo che almeno un blocco Bitcoin possa essere restituito anche se la sua dimensione supera i 2 MB. Questo limite superiore implica che venga restituito un solo blocco (e la relativa intestazione del blocco) per la maggior parte dei blocchi recenti la cui dimensione è in genere superiore a 1 MB. La possibilità di inviare più blocchi in un messaggio è utile per assimilare i blocchi più vecchi più rapidamente poiché significativamente più piccoli.

Se l’adattatore Bitcoin non possiede i blocchi mancanti nella sua cache, restituisce immediatamente un messaggio vuoto per non ritardare il consenso. Avendo una visione accurata dello stato del componente Bitcoin, l’adattatore Bitcoin scarica quindi i blocchi mancanti successivi in modo che possa comprimerli in un messaggio di ritorno in una richiesta futura dal componente Bitcoin. Poiché l’adattatore Bitcoin non tiene traccia delle transazioni, non può verificare la validità delle transazioni nei blocchi ricevuti.

Tuttavia, per evitare che il componente Bitcoin venga riempito di blocchi non validi (spamming), esegue alcuni controlli di base:

  • Il blocco è ben formato, cioè può essere analizzato come un blocco Bitcoin corretto.
  • L’hash radice del Merkle Tree corrisponde all’hash nell’intestazione del blocco corrispondente.

I blocchi vengono eliminati dalla cache non appena il set di hash di intestazione del blocco ricevuto indica che il componente Bitcoin ha ricevuto il blocco.

Quando l’adattatore Bitcoin riceve le transazioni in uscita, queste vengono inserite nella cache delle transazioni e pubblicizzate sulla rete Bitcoin. Non appena la transazione è stata trasmessa ai nodi Bitcoin collegati, la transazione viene rimossa dalla cache.

Componente Bitcoin

Il componente Bitcoin fa parte della replica stessa. L’API dell’integrazione Bitcoin viene offerta tramite il management canister.

Stato

Il componente Bitcoin memorizza il seguente stato:

  • L’intero set UTXO dalla genesi fino a una certa altezza di blocco h.
  • I blocchi, comprese le loro intestazioni di blocco, a partire dall’altezza h.
  • La cronologia completa di tutte le intestazioni di blocco ricevute.
  • L’insieme delle transazioni in uscita.

Poiché il componente Bitcoin non memorizza la cronologia completa delle transazioni, deve decidere quando è sicuro eliminare un blocco, basandosi solo sulle informazioni contenute nel set UTXO che mantiene.

A causa del rischio di fork di lunga durata, il componente Bitcoin non utilizza il conteggio di conferma per determinare quando eliminare un blocco. Al contrario, utilizza un concetto leggermente più complesso, che chiamiamo stability (stabilità). In poche parole, consideriamo un blocco stabile se esiste un certo numero di blocchi successivi, che riducono il rischio che il blocco venga scartato in futuro, e se anche la punta di un’eventuale biforcazione (fork) è almeno lo stesso numero di blocchi dietro la punta della catena che contiene il blocco. Più formalmente, se h(b) denota il numero di blocchi predecessori del blocco b a partire dalla genesi e d(b) denota la lunghezza del percorso successore più lungo a partire dal blocco b, la stabilità è definita come segue.

Definizione (𝜹-stability): Sia B a indicare l’insieme di blocchi disponibili localmente. Per un parametro 𝜹>0, diciamo che un blocco b è 𝜹-stable se valgono le seguenti condizioni: * d(b) ≥ 𝜹 * ∀ b’ ∈ B \ {b}, h(b’) = h(b ): d(b) – d(b’) ≥ 𝜹

Il componente Bitcoin è configurato con una soglia di stabilità 𝜹 di 144, ovvero se non ci sono fork, il componente Bitcoin mantiene tutti i blocchi in giro per circa un giorno (in media a un blocco ogni 10 minuti). Quando un blocco diventa 𝜹-stable, le transazioni vengono applicate al set UTXO e il blocco viene scartato. In questo modo, la stabilità (stability) viene utilizzata per definire l’altezza di demarcazione del blocco h menzionata nella descrizione dello stato precedente. Tutti i blocchi con una stabilità al di sotto della soglia sono considerati instabili (unstable).

Componente Bitcoin in funzione

Quando si richiede un aggiornamento dall’adattatore Bitcoin, il componente Bitcoin invia un messaggio contenente gli hash di tutti i blocchi instabili all’adattatore Bitcoin, il quale utilizza gli hash per determinare quali blocchi mancano al componente Bitcoin, se ce ne sono.

Quando si ricevono blocchi e intestazioni di blocco dall’adattatore Bitcoin, vengono eseguiti i seguenti controlli di validità per ciascuna coppia di blocco/intestazione di blocco: 

  • L’intestazione del blocco è ben formata, ovvero può essere analizzata come intestazione di blocco corretta.
  • Il lavoro di hash nell’intestazione del blocco è sufficiente in base all’obiettivo di difficoltà.
  • L’intestazione del blocco punta a un predecessore noto.
  • Il timestamp nell’intestazione del blocco è maggiore della mediana degli 11 blocchi precedenti.
  • Il timestamp nell’intestazione del blocco è al massimo di due ore nel futuro rispetto all’ora IC.
  • Il blocco è ben formato, cioè può essere analizzato come un blocco Bitcoin corretto.
  • L’hash radice del Merkle Tree corrisponde all’hash nell’intestazione del blocco corrispondente.

È importante notare che la validità delle transazioni non è verificata nel componente Bitcoin. Il componente Bitcoin si basa sulla proof of work che viene svolta nei blocchi e sulla verifica dei blocchi nella rete Bitcoin. Per un blocco appena scoperto, un normale nodo Bitcoin (completo) fornisce quindi un livello di sicurezza maggiore rispetto al componente Bitcoin, il che implica che è consigliabile impostare il numero di conferme su un valore ragionevolmente grande, come 6, per acquisire fiducia nella correttezza delle informazioni fornite dalla componente Bitcoin. Se la verifica ha esito positivo, il blocco viene aggiunto all’elenco dei blocchi instabili. Inoltre, se come risultato un blocco diventa 𝜹-stable, il set UTXO viene aggiornato in base alla transazione in questo blocco e il blocco viene scartato, mantenendo solo l’intestazione del blocco corrispondente.

Il componente Bitcoin espone la seguente API:
  • bitcoin_get_utxos: la funzione restituisce gli output di transazione non spesi (UTXO) di un determinato indirizzo Bitcoin.
  • bitcoin_get_balance: La funzione restituisce il saldo di un dato indirizzo Bitcoin.
  • bitcoin_send_transaction: La funzione invia la transazione data alla rete Bitcoin.
  • bitcoin_get_current_fees: La funzione restituisce i percentili delle commissioni, in satoshi/byte, per le ultime 10.000 transazioni.
Sono supportati i seguenti formati di indirizzo:
  • Paga a hash di chiave pubblica (P2PKH)
  • Paga a hash di script (P2SH)
  • Paga a hash di chiave pubblica di controllo (P2WPKH)
  • Paga a hash di script di controllo (P2WSH)

I dettagli sull’API sono disponibili nella pagina GitHub di preview della Bitcoin Integration. Quando risponde alle chiamate get_utxos e get_balance, il che offre un parametro opzionale min_confirmations, il componente Bitcoin considera sia lo stato UTXO che tutte le transazioni nei blocchi instabili che hanno almeno il numero minimo richiesto di conferme. In altre parole, dopo aver estratto i relativi output non spesi dal set UTXO, i blocchi instabili vengono analizzati per trovare output non spesi aggiuntivi. Inoltre, se ci sono transazioni che consumano uno qualsiasi degli output raccolti, gli output vengono eliminati poiché considerati spesi. La funzione bitcoin_get_utxos offre inoltre un’API di impaginazione, utile per indirizzi con un numero elevato di UTXO.

Al fine di ridurre il rischio di incongruenze dovute alle biforcazioni, le conferme vengono conteggiate in modo conservativo, sempre utilizzando la 𝜹-stability. Il conteggio della stability di un blocco è definito come il 𝜹 più grande per cui il blocco è 𝜹-stable. Il processo per determinare il numero di conferme per le transazioni è il seguente: si identifica l’altezza del blocco più grande con un solo blocco a questa altezza. Si considera la catena di blocchi instabili fino al blocco individuato nel primo passaggio, e il numero di conferme per una transazione in un blocco è definito come il conteggio di stabilità (stability count) del blocco più 1 (aggiungendo 1 perché una transazione ha già 1 conferma una volta che appare in un blocco).

Anche se questa regola può sembrare complicata, presenta diverse proprietà interessanti. Se non ci sono biforcazioni, il numero di conferme per ogni transazione è esattamente quello che ci si aspetterebbe: una volta che una transazione è in un blocco, ha una conferma, se c’è un blocco successivo, ha due conferme e così via. Tuttavia, se ci sono più biforcazioni concorrenti con altezze simili, il numero di conferme rimarrà basso fino a quando non prevarrà una catena, a quel punto il numero di conferme inizierà ad aumentare. In breve, la regola ha lo scopo di garantire che un numero elevato di conferme, basato sul conteggio della stabilità, implichi una grande probabilità che la transazione non venga annullata anche in presenza di fork concorrenti.

La figura seguente mostra un esempio di catena con una fork. I numeri all’interno dei blocchi sono i conteggi di stabilità e i numeri nei cerchi nell’angolo in basso a destra dei blocchi indicano il numero di conferme per le transazioni nel blocco corrispondente per tutti i blocchi della catena più lunga.

Viene mostrata una catena con una fork, che include sia i conteggi di stabilità (all’interno dei blocchi) che i conteggi di conferma (all’interno dei cerchi).

Quando il componente Bitcoin riceve una transazione in uscita e la transazione supera i controlli di verifica, inoltra la transazione all’adattatore Bitcoin come descritto sopra. Il componente Bitcoin memorizza la transazione nella cache e la reinvia periodicamente se la transazione non appare in un blocco. La transazione viene abbandonata quando appare in un blocco o scade dopo 24 ore.

Anteprima per sviluppatori

L’anteprima per sviluppatori rilasciata il 3 febbraio 2022 è una versione di anteprima della funzionalità di integrazione Bitcoin. È destinata ad essere utilizzata dagli sviluppatori per iniziare a implementare smart contract tramite l’API e per fornire feedback in modo che l’API possa essere migliorata con il feedback della community verso la versione finale.

L’Anteprima per Sviluppatori è disponibile solo come parte dell’ambiente di sviluppo locale (Canister SDK) e non si integra con la mainnet o la testnet di Bitcoin. Invece, esegue un nodo bitcoin locale (bitcoind) in modalità di test di regressione (“regtest”) che simula una rete Bitcoin reale, pur essendo completamente controllato dallo sviluppatore, facilitando così il debugging. La versione di anteprima per sviluppatori rende disponibile la logica della funzione relativa a Bitcoin tramite la già citata API di integrazione Bitcoin. Tuttavia, l’integrazione con lo stack del protocollo IC è semplificata: non utilizza l’integrazione personalizzata con i livelli del protocollo IC, in particolare il consenso, ma aggiunge un adapter shim come componente esterno che aggancia l’adattatore al normale stack del protocollo IC tramite chiamate di query e messaggi in ingresso.

Gli utenti dell’anteprima per sviluppatori devono installare la versione nel loro ambiente Canister SDK locale e avviarla. Inoltre, il componente Bitcoin è esposto come un canister Wasm, mentre l’API di integrazione Bitcoin è esposta tramite il management canister sulla rete principale (mainnet).

Rilascio di Bitcoin testnet

Nell’estate del 2022, è stata rilasciata l’integrazione Bitcoin Testnet su IC. L’integrazione Testnet ha lo scopo di consentire agli ingegneri di interagire già con l’API Bitcoin su IC, ma solo con Bitcoin Testnet e una chiave di test ECDSA di soglia. L’obiettivo è consentire agli ingegneri di creare e testare le loro dApp integrate con Bitcoin utilizzando una versione beta in esecuzione su IC. Questo è il passaggio successivo all’anteprima per sviluppatori lanciata in precedenza che facilita lo sviluppo di dApp attraverso la community. Si consiglia vivamente agli ingegneri di non associare alcun valore alla chiave di test ECDSA di soglia poiché a un certo punto potrebbe essere eliminata, e funziona solo su una sottorete di dimensioni normali.