name: Il protocollo RGB, dalla teoria alla pratica goal: Acquisire le competenze necessarie per comprendere e utilizzare l'RGB objectives:


Scoprire il protocollo RGB

Immergetevi nel mondo di RGB, un protocollo progettato per implementare e far rispettare i diritti digitali, sotto forma di contratti e asset, sulla base delle regole di consenso e delle operazioni della blockchain Bitcoin. Questo corso di formazione completo vi guida attraverso le basi tecniche e pratiche di RGB, dai concetti di "Client-side Validation" e "Single-use Seals", all'implementazione di smart contract avanzati.

Attraverso un programma strutturato e graduale, scoprirete i meccanismi di convalida lato client, gli impegni deterministici su Bitcoin e i modelli di interazione tra gli utenti. Imparerete a creare, gestire e trasferire i token RGB su Bitcoin o sulla rete Lightning.

Se siete sviluppatori, appassionati di Bitcoin o semplicemente curiosi di saperne di più su questa tecnologia, questo corso di formazione vi fornirà gli strumenti e le conoscenze necessarie per padroneggiare RGB e costruire soluzioni innovative su Bitcoin.

Il corso si basa su un seminario dal vivo organizzato da Fulgur'Ventures e tenuto da tre rinomati insegnanti ed esperti di RGB.

Introduzione

Presentazione del corso

Salve a tutti e benvenuti in questo corso di formazione dedicato a RGB, un sistema di smart contract convalidato lato client che gira su Bitcoin e sulla rete Lightning. La struttura di questo corso è pensata per consentire un'esplorazione approfondita di questo argomento complesso. Ecco come è organizzato il corso:

**Sezione 1: Teoria

La prima sezione è dedicata ai concetti teorici necessari per comprendere i fondamenti della convalida lato client e di RGB. Come scoprirete in questo corso, RGB introduce una serie di concetti tecnici che di solito non si vedono in Bitcoin. In questa sezione troverete anche un glossario che fornisce le definizioni di tutti i termini specifici del protocollo RGB.

**Sezione 2: Pratica

La seconda sezione si concentrerà sull'applicazione dei concetti teorici visti nella sezione 1. Impareremo a creare e manipolare i contratti RGB. Vedremo anche come programmare con questi strumenti. Queste prime due sezioni sono presentate da Maxim Orlovsky.

**Sezione 3: Applicazioni

La sezione finale è guidata da altri relatori che presentano applicazioni concrete basate su RGB, per evidenziare casi d'uso reali.


Questo corso di formazione è nato da un bootcamp di sviluppo avanzato di due settimane a Viareggio, in Toscana, organizzato da Fulgur'Ventures. La prima settimana, incentrata su Rust e sugli SDK, si trova in quest'altro corso:

https://planb.network/courses/9fbd8b57-f278-4304-8d88-a2d384eaff58

In questo corso ci concentriamo sulla seconda settimana del bootcamp, incentrata su RGB.

Settimana 1 - LNP402:

RGB-Bitcoin

Settimana 2 - Formazione in corso CSV402:

RGB-Bitcoin

Grazie agli organizzatori di questi corsi dal vivo e ai 3 insegnanti che vi hanno partecipato:

La versione scritta di questo corso di formazione è stata redatta utilizzando due risorse principali:

Pronto a immergerti nell'universo complesso e affascinante di RGB? Andiamo!

RGB in teoria

Introduzione ai concetti di calcolo distribuito

RGB è un protocollo progettato per applicare e far rispettare i diritti digitali (sotto forma di contratti e beni) in modo scalabile e riservato, basandosi sulle regole di consenso e sulle operazioni della blockchain Bitcoin. L'obiettivo di questo primo capitolo è quello di presentare i concetti e la terminologia di base del protocollo RGB, evidenziando in particolare i suoi stretti legami con i concetti di base dell'informatica distribuita, come la convalida lato client e i sigilli monouso.

In questo capitolo esploriamo i fondamenti dei sistemi di consenso distribuito e vediamo come RGB si inserisce in questa famiglia di tecnologie. Introdurremo anche i principi principali che ci aiutano a capire perché RGB mira a essere estensibile e indipendente dal meccanismo di consenso di Bitcoin, pur affidandosi a esso quando necessario.

Introduzione

L'informatica distribuita, una branca specifica dell'informatica, studia i protocolli utilizzati per far circolare ed elaborare le informazioni su una rete di nodi. Insieme, questi nodi e le regole del protocollo costituiscono il cosiddetto sistema distribuito. Tra le proprietà essenziali che caratterizzano un sistema di questo tipo ci sono :

In particolare, la nozione di consenso in un sistema distribuito copre due aspetti:

La prima implementazione funzionale e senza permessi di un meccanismo di consenso distribuito è stata introdotta da Satoshi Nakamoto con Bitcoin, grazie all'uso combinato di una struttura di dati blockchain e di un algoritmo Proof-of-Work (PoW). In questo sistema, la credibilità della storia del blocco dipende dalla potenza di calcolo ad esso dedicata dai nodi (minatori). Bitcoin è quindi un importante e storico esempio di sistema di consenso distribuito aperto a tutti (permissionless).

Nel mondo della blockchain e dell'informatica distribuita, possiamo distinguere due paradigmi fondamentali: blockchain in senso tradizionale e canali di stato, il cui miglior esempio in produzione è Lightning Network. La blockchain è definita come un registro di eventi ordinati cronologicamente, replicati per consenso all'interno di una rete aperta e senza permessi. I canali di stato, invece, sono canali peer-to-peer che consentono a due (o più) partecipanti di mantenere uno stato aggiornato fuori dalla catena, utilizzando la blockchain solo al momento dell'apertura e della chiusura di questi canali.

Nel contesto di Bitcoin, conoscete senza dubbio i principi di mining, decentralizzazione e finalità delle transazioni sulla blockchain, nonché il funzionamento dei canali di pagamento. Con RGB, stiamo introducendo un nuovo paradigma chiamato Client-side Validation che, a differenza della blockchain o di Lightning, consiste nel memorizzare e validare localmente (lato client) le transizioni di stato di uno smart contract. Questo si differenzia anche da altre tecniche "DeFi" (rollup, plasma, ARK, ecc.), in quanto la Client-side Validation si affida alla blockchain per prevenire i doppi pagamenti e per avere un sistema di time-stamping, mantenendo il registro degli stati e delle transizioni fuori dalla catena, solo con i partecipanti interessati.

RGB-Bitcoin

In seguito, introdurremo anche un termine importante: la nozione di "stash", che si riferisce all'insieme dei dati lato client necessari per preservare lo stato di un contratto, dato che questi dati non sono replicati globalmente nella rete. Infine, esamineremo la logica alla base di RGB, un protocollo che sfrutta la convalida lato client, e il motivo per cui integra gli approcci esistenti (blockchain e canali di stato).

Trilemmi nell'informatica distribuita

Per capire come la convalida lato client e l'RGB affrontino i problemi non risolti da blockchain e Lightning, scopriamo i 3 principali "trilemmi" dell'informatica distribuita:

1. Scalabilità, decentralizzazione e riservatezza

La blockchain è altamente decentralizzata, ma non è molto scalabile. Inoltre, poiché tutto è in un registro pubblico globale, la riservatezza è limitata. Possiamo cercare di migliorare la riservatezza con tecnologie a conoscenza zero (transazioni riservate, schemi mimblewimble, ecc.), ma la catena pubblica non può nascondere il grafico delle transazioni.

I canali statali (come la Lightning Network) sono più scalabili e più privati della blockchain, poiché le transazioni avvengono fuori dalla catena. Tuttavia, l'obbligo di annunciare pubblicamente alcuni elementi (transazioni di finanziamento, topologia della rete) e il monitoraggio del traffico di rete possono in parte compromettere la riservatezza. Anche la decentralizzazione ne risente: il routing richiede molto denaro e i nodi principali possono diventare punti di centralizzazione. Questo è proprio il fenomeno che stiamo iniziando a vedere su Lightning.

Questo nuovo paradigma è ancora più scalabile e più confidenziale, perché non solo possiamo integrare tecniche di proof-of-knowledge a zero rivelazioni, ma non esiste un grafo globale delle transazioni, poiché nessuno possiede l'intero registro. D'altra parte, implica anche un certo compromesso sulla decentralizzazione: l'emittente di uno smart contract può avere un ruolo centrale (come un "contract deployer" in Ethereum). Tuttavia, a differenza della blockchain, con la Client-side Validation si memorizzano e si convalidano solo i contratti a cui si è interessati, il che migliora la scalabilità evitando di dover scaricare e verificare tutti gli stati esistenti.

RGB-Bitcoin

2. Teorema CAP (Consistenza, disponibilità, tolleranza alle partizioni)

Il teorema CAP sottolinea che è impossibile per un sistema distribuito soddisfare simultaneamente la coerenza (Consistenza), la disponibilità (Disponibilità) e la tolleranza alle partizioni (Tolleranza alle partizioni).

La blockchain favorisce la coerenza e la disponibilità, ma non si adatta bene alla suddivisione della rete: se non si può vedere un blocco, non si può agire e avere la stessa visione dell'intera rete.

Un sistema di canali di stato ha una tolleranza alla disponibilità e al partizionamento (poiché due nodi possono rimanere connessi tra loro anche se la rete è frammentata), ma la coerenza complessiva dipende dall'apertura e dalla chiusura dei canali sulla blockchain.

Un sistema come RGB offre coerenza (ogni partecipante convalida i propri dati a livello locale, senza ambiguità) e tolleranza al partizionamento (si conservano i dati in modo autonomo), ma non garantisce la disponibilità globale (ognuno deve assicurarsi di avere i pezzi di storia rilevanti, e alcuni partecipanti potrebbero non pubblicare nulla o smettere di condividere certe informazioni).

RGB-Bitcoin

3. Trilemma CIA (Riservatezza, Integrità, Disponibilità)

Questo trilemma ci ricorda che riservatezza, integrità e disponibilità non possono essere ottimizzate allo stesso tempo. Blockchain, Lightning e Client-side Validation rientrano in questo equilibrio in modo diverso. L'idea è che nessun singolo sistema può fornire tutto; è necessario combinare diversi approcci (il time-stamping della blockchain, l'approccio sincrono di Lightning e la validazione locale con RGB) per ottenere un pacchetto coerente che offra buone garanzie in ogni dimensione.

RGB-Bitcoin

Il ruolo della blockchain e la nozione di sharding

La blockchain (in questo caso, Bitcoin) serve principalmente come meccanismo di stampaggio e protezione contro le doppie spese. Invece di inserire i dati completi di uno smart contract o di un sistema decentralizzato, ci limitiamo a includere impegni crittografici (commitments) alle transazioni (nel senso di Client-side Validation, che chiameremo "transizioni di stato"). Quindi :

Lo sharding è un concetto nato nei database distribuiti (ad esempio MySQL per i social network come Facebook o Twitter). Per risolvere il problema del volume dei dati e delle latenze di sincronizzazione, il database viene segmentato in shard (USA, Europa, Asia, ecc.). Ogni segmento è coerente a livello locale e solo parzialmente sincronizzato con gli altri.

Per gli smart contract di tipo RGB, gli shard vengono suddivisi in base ai contratti stessi. Ogni contratto è uno shard indipendente. Ad esempio, se si possiedono solo token USDT, non è necessario memorizzare o convalidare l'intera storia di un altro token come USDC. Su Bitcoin, la blockchain non fa sharding: si ha un insieme globale di UTXO. Con la convalida lato client, ogni partecipante conserva solo i dati del contratto che detiene o utilizza.

Possiamo quindi immaginare l'ecosistema come segue:

RGB-Bitcoin

Questi tre elementi formano un insieme triangolare, piuttosto che una pila lineare di "strato 2", "strato 3" e così via. Lightning può collegarsi direttamente a Bitcoin o essere associato a transazioni Bitcoin che incorporano dati RGB. Allo stesso modo, un utilizzo "BiFi" (finanza su Bitcoin) può comporsi con la blockchain, con Lightning e con RGB a seconda delle esigenze di riservatezza, scalabilità o logica contrattuale.

RGB-Bitcoin

La nozione di transizioni di stato

In qualsiasi sistema distribuito, l'obiettivo del meccanismo di convalida è quello di essere in grado di determinare la validità e l'ordine cronologico dei cambiamenti di stato. L'obiettivo è verificare che le regole del protocollo siano state rispettate e dimostrare che questi cambiamenti di stato si susseguono in un ordine definitivo e inattaccabile.

Per capire come funziona questa convalida nel contesto di Bitcoin e, più in generale, per comprendere la filosofia che sta alla base della Client-side Validation, diamo prima uno sguardo ai meccanismi della blockchain di Bitcoin, prima di vedere come la Client-side Validation si differenzia da essi e quali ottimizzazioni rende possibili.

RGB-Bitcoin

Nel caso della blockchain Bitcoin, la convalida delle transazioni si basa su una semplice regola:

RGB-Bitcoin

Tuttavia, questo modello presenta due svantaggi principali:

RGB-Bitcoin

In pratica, questo modello funziona per Bitcoin come livello di base (Layer 1), ma può diventare insufficiente per usi più complessi che richiedono contemporaneamente un'elevata velocità di transazione e un certo grado di riservatezza.

La convalida lato client si basa sull'idea opposta: invece di richiedere all'intera rete di convalidare e memorizzare tutte le transazioni, ogni partecipante (client) convaliderà solo la parte della cronologia che lo riguarda:

RGB-Bitcoin

Allo stesso tempo, affinché il resto della rete (o più precisamente il livello sottostante, come Bitcoin) possa bloccare lo stato finale senza vedere i dettagli di questi dati, la convalida lato client si basa sulla nozione di impegno.

Un impegno è un impegno crittografico, tipicamente un hash (SHA-256 per esempio) inserito in una transazione Bitcoin, che dimostra che sono stati inseriti dati privati, senza rivelarli.

Grazie a questi impegni, possiamo dimostrare:

Il contenuto esatto, tuttavia, non viene rivelato, preservando così la sua riservatezza.

In concreto, ecco come funziona una transizione di stato RGB:

RGB-Bitcoin

La convalida lato client offre due vantaggi principali:

Gli impegni (commitments) inclusi nella blockchain sono piccoli (dell'ordine di qualche decina di byte). Ciò garantisce che lo spazio dei blocchi non sia saturo, poiché è necessario includere solo l'hash. Inoltre, consente al protocollo off-chain di evolversi, poiché ogni utente deve memorizzare solo il proprio frammento di storia (il proprio stash).

Le transazioni stesse (cioè il loro contenuto dettagliato) non sono pubblicate sulla catena. Lo sono solo le loro impronte digitali (hash). Pertanto, gli importi, gli indirizzi e la logica del contratto rimangono privati e il destinatario può verificare, localmente, la validità del suo shard ispezionando tutte le transizioni precedenti. Non c'è motivo per il ricevente di rendere pubblici questi dati, se non in caso di controversia o quando è necessaria una prova.

In un sistema come RGB, più transizioni di stato provenienti da contratti diversi (o da asset diversi) possono essere aggregate in un'unica transazione Bitcoin tramite un singolo commitment. Questo meccanismo stabilisce un collegamento deterministico, con data e ora, tra la transazione on-chain e i dati off-chain (le transizioni convalidate dal lato client) e consente a più frammenti di essere registrati simultaneamente in un singolo punto di ancoraggio, riducendo ulteriormente il costo e l'ingombro on-chain.

In pratica, quando questa transazione Bitcoin viene convalidata, "blocca" definitivamente lo stato dei contratti sottostanti, poiché diventa impossibile modificare l'hash già iscritto nella blockchain.

RGB-Bitcoin

Il concetto di scorta

Lo stash è l'insieme dei dati lato client che un partecipante deve assolutamente conservare per mantenere l'integrità e la storia di uno smart contract RGB. A differenza di un canale Lightning, dove alcuni stati possono essere ricostruiti localmente da informazioni condivise, lo stash di un contratto RGB non è replicato altrove: se lo perdete, nessuno sarà in grado di ripristinarlo, poiché siete responsabili della vostra parte di storia. Per questo motivo è necessario adottare un sistema con procedure di backup affidabili in RGB.

RGB-Bitcoin

Sigillo monouso: origini e funzionamento

Quando si accetta un bene come una valuta, sono essenziali due garanzie:

Per i beni fisici, come una banconota, la presenza fisica è sufficiente a dimostrare che non è stata duplicata. Tuttavia, nel mondo digitale, dove gli asset sono puramente informativi, questa verifica è più complessa, poiché le informazioni possono facilmente moltiplicarsi ed essere duplicate.

Come abbiamo visto in precedenza, la rivelazione da parte del mittente della storia delle transizioni di stato ci permette di garantire l'autenticità di un token RGB. Avendo accesso a tutte le transazioni successive alla transazione genetica, possiamo confermare l'autenticità del token. Questo principio è simile a quello di Bitcoin, dove la storia delle monete può essere rintracciata fino alla transazione originale su coinbase per verificarne la validità. Tuttavia, a differenza di Bitcoin, la storia delle transizioni di stato in RGB è privata e conservata dal lato del cliente.

Per evitare il doppio utilizzo dei gettoni RGB, utilizziamo un meccanismo chiamato "Single-use Seal". Questo sistema garantisce che ogni gettone, una volta utilizzato, non possa essere riutilizzato in modo fraudolento una seconda volta.

I sigilli monouso sono primitive crittografiche, proposte nel 2016 da Peter Todd, simili al concetto di sigillo fisico: una volta che un sigillo è stato posto su un contenitore, diventa impossibile aprirlo o modificarlo senza rompere irreversibilmente il sigillo.

RGB-Bitcoin

Questo approccio, trasposto al mondo digitale, permette di dimostrare che una sequenza di eventi è effettivamente avvenuta e che non può più essere alterata a posteriori. I sigilli monouso vanno quindi oltre la semplice logica di "hash + timestamp", aggiungendo la nozione di sigillo che può essere chiuso "una sola volta".

RGB-Bitcoin

Affinché i sigilli monouso funzionino, è necessario un mezzo di prova della pubblicazione in grado di dimostrare l'esistenza o l'assenza di una pubblicazione e difficile (se non impossibile) da falsificare una volta che l'informazione è stata diffusa. Una blockchain (come Bitcoin) può svolgere questo ruolo, così come, ad esempio, un giornale cartaceo a diffusione pubblica. L'idea è la seguente:

Una blockchain si presta in modo ideale a questo ruolo: non appena una transazione viene inserita in un blocco, l'intera rete ha la stessa prova non falsificabile della sua esistenza e del suo contenuto (almeno in parte, dato che l'impegno può nascondere i dettagli, pur dimostrando l'autenticità del messaggio).

Un sigillo monouso può quindi essere visto come una promessa formale di pubblicare un messaggio (ancora sconosciuto in questa fase) una e una sola volta, in un modo che può essere verificato da tutte le parti interessate.

A differenza dei semplici impegni (hash) o dei timestamp, che attestano una data di esistenza, un sigillo monouso offre l'ulteriore garanzia che nessun impegno alternativo può coesistere: non è possibile chiudere due volte lo stesso sigillo, né tentare di sostituire il messaggio sigillato.

Il seguente confronto aiuta a comprendere questo principio:

Impegno semplice (digest/hash)TimestampSigilli monouso
La pubblicazione dell'impegno non rivela il messaggio
Prova della data dell'impegno / esistenza del messaggio prima di una certa dataImpossibilePossibilePossibile
Prova che non può esistere nessun altro impegno alternativoImpossibileImpossibilePossibile

I sigilli monouso funzionano in tre fasi principali:

Definizione di guarnizione :

RGB-Bitcoin

Chiusura ermetica :

RGB-Bitcoin

Verifica della tenuta :

Il processo può essere riassunto come segue:

# Défini par Alice, validé ou accepté par Bob
seal <- Define()
# Fermeture du sceau par Alice avec le message
witness <- Close(seal, message)
# Vérification par Bob
bool <- Verify(seal, witness, message)

La convalida lato client, tuttavia, fa un ulteriore passo avanti: se la definizione stessa di un sigillo rimane al di fuori della blockchain, è possibile (in teoria) che qualcuno contesti l'esistenza o la legittimità del sigillo in questione. Per superare questo problema, viene utilizzata una catena di sigilli monouso interconnessi:

Questo è esattamente ciò che fa il sistema RGB:

Per riassumere:

Questa unicità è importante per la convalida lato client: quando si convalida una transizione di stato, si controlla che corrisponda a un UTXO unico, non speso in precedenza in un impegno concorrente. Questo è ciò che garantisce l'assenza di doppie spese negli smart contract off-chain.

Molteplici impegni e radici

Uno smart contract RGB può avere bisogno di spendere diversi Single-use Seals (diversi UTXO) contemporaneamente. Inoltre, una singola transazione Bitcoin può fare riferimento a diversi contratti distinti, ognuno dei quali sigilla la propria transizione di stato. Ciò richiede un meccanismo di multi-commitment per dimostrare, in modo deterministico e univoco, che nessuno degli impegni esiste in duplice copia. È qui che entra in gioco la nozione di ancora in RGB: una struttura speciale che collega una transazione Bitcoin e uno o più impegni lato client (transizioni di stato), ciascuno potenzialmente appartenente a un contratto diverso. Analizzeremo più da vicino questo concetto nel prossimo capitolo.

RGB-Bitcoin

Due dei principali repository GitHub del progetto (sotto l'organizzazione LNPBP) raggruppano le implementazioni di base di questi concetti studiati nel primo capitolo:

RGB-Bitcoin

Si noti che questi mattoni software sono agnostici rispetto a Bitcoin; in teoria, potrebbero essere applicati a qualsiasi altro mezzo di prova della pubblicazione (un altro registro, una rivista, ecc.). In pratica, RGB si affida a Bitcoin per la sua robustezza e l'ampio consenso.

RGB-Bitcoin

Domande del pubblico

Verso un uso più ampio delle guarnizioni monouso

Peter Todd ha anche creato il protocollo Open Timestamps e il concetto di Single-use Seal è una naturale estensione di queste idee. Oltre a RGB, si possono prevedere altri casi d'uso, come la costruzione di sidechain senza ricorrere al merge mining o proposte legate alle drivechain come BIP300. In linea di principio, qualsiasi sistema che richieda un singolo impegno può sfruttare questa primitiva crittografica. Oggi RGB è la prima grande implementazione su scala reale.

Problemi di disponibilità dei dati

Poiché nella Validazione lato client ogni utente memorizza la propria parte di cronologia, la disponibilità dei dati non è garantita a livello globale. Se l'emittente di un contratto nasconde o revoca alcune informazioni, l'utente potrebbe non essere a conoscenza dell'effettiva evoluzione dell'offerta. In alcuni casi (come le stablecoin), l'emittente è tenuto a mantenere dati pubblici per dimostrare il volume in circolazione, ma non vi è alcun obbligo tecnico in tal senso. È quindi possibile progettare contratti deliberatamente opachi con un'offerta illimitata, il che solleva questioni di fiducia.

Sharding e isolamento dei contratti

Ogni contratto rappresenta uno shard isolato: USDT e USDC, ad esempio, non devono condividere le loro cronologie. Gli scambi atomici sono ancora possibili, ma non comportano la fusione dei loro registri. Tutto avviene tramite impegno crittografico, senza rivelare l'intero grafico della storia a ciascun partecipante.

Conclusione

Abbiamo visto come il concetto di Client-side Validation si inserisca nella blockchain e nei canali di stato, come risponda ai trilemmi dell'informatica distribuita e come sfrutti la blockchain Bitcoin in modo unico per evitare la doppia spesa e per il time-stamping. L'idea si basa sulla nozione di Single-use Seal, che consente di creare impegni unici che non possono essere riutilizzati a piacimento. In questo modo, ogni partecipante carica solo la cronologia strettamente necessaria, aumentando la scalabilità e la riservatezza dei contratti intelligenti e mantenendo la sicurezza di Bitcoin come sfondo.

Il prossimo passo sarà quello di spiegare in modo più dettagliato come questo meccanismo di Single-use Seal viene applicato in Bitcoin (tramite gli UTXO), come vengono create e convalidate le ancore e quindi come vengono costruiti gli smart contract completi in RGB. In particolare, esamineremo la questione degli impegni multipli, la sfida tecnica di dimostrare che una transazione Bitcoin sigilla simultaneamente più transizioni di stato in contratti diversi, senza introdurre vulnerabilità o doppi impegni.

Prima di immergerci nei dettagli tecnici del secondo capitolo, rileggiamo le definizioni chiave (Client-side Validation, Single-use Seal, ancore, ecc.) e teniamo a mente la logica generale: stiamo cercando di conciliare i punti di forza della blockchain Bitcoin (sicurezza, decentralizzazione, time-stamping) con quelli delle soluzioni off-chain (velocità, riservatezza, scalabilità), ed è proprio questo che RGB e Client-side Validation cercano di ottenere.

Il livello di impegno

In questo capitolo esamineremo l'implementazione della convalida lato client e dei sigilli monouso nella blockchain Bitcoin. Presenteremo i principi principali del commitment layer di RGB (layer 1), con particolare attenzione allo schema TxO2, che RGB utilizza per definire e chiudere un sigillo in una transazione Bitcoin. Successivamente, discuteremo due punti importanti che non sono ancora stati trattati in dettaglio:

È la combinazione di questi concetti che ci permette di sovrapporre diversi sistemi o contratti a un unico UTXO e quindi a un'unica blockchain.

Va ricordato che le operazioni crittografiche descritte possono essere applicate, in termini assoluti, ad altre blockchain o supporti editoriali, ma le caratteristiche di Bitcoin (in termini di decentralizzazione, resistenza alla censura e apertura a tutti) lo rendono la base ideale per sviluppare una programmabilità avanzata come quella richiesta da RGB.

Schemi di impegno in Bitcoin e loro utilizzo da parte di RGB

Come abbiamo visto nel primo capitolo del corso, i sigilli monouso sono un concetto generale: facciamo una promessa di includere un impegno (commitment) in una posizione specifica di una transazione, e questa posizione agisce come un sigillo che chiudiamo su un messaggio. Tuttavia, sulla blockchain Bitcoin, ci sono diverse opzioni per scegliere dove collocare questo impegno.

Per capire la logica, ricordiamo il principio di base: per chiudere un sigillo a uso singolo, spendiamo l'area sigillata inserendo il commitment su un determinato messaggio. In Bitcoin, questo può essere fatto in diversi modi:

Possiamo decidere che una chiave o un indirizzo pubblico specifico sia il single-use seal. Non appena questa chiave o indirizzo appare sulla catena in una transazione, significa che il sigillo è stato chiuso con un certo messaggio.

Ciò significa che un sigillo monouso è definito come un preciso outpoint (una coppia TXID + numero di uscita). Non appena questo outpoint viene esaurito, il sigillo viene chiuso.

Mentre lavoravamo su RGB, abbiamo identificato almeno 4 modi diversi per implementare questi sigilli su Bitcoin:

Nome dello schemaDefinizione del sigilloChiusura del sigilloRequisiti aggiuntiviApplicazione principalePossibili schemi di impegno
PkOValore della chiave pubblicaUscita della transazioneP2(W)PKHNessuna al momentoKeytweak, taptweak, opret
TxO2Uscita della transazioneUscita della transazioneRichiede impegni deterministici su BitcoinRGBv1 (universale)Keytweak, tapret, opret
PkIValore della chiave pubblicaIngresso della transazioneSolo Taproot & non compatibile con portafogli legacyIdentità basate su BitcoinSigtweak, witweak
TxO1Uscita della transazioneIngresso della transazioneSolo Taproot & non compatibile con portafogli legacyNessuna al momentoSigtweak, witweak

Non entreremo nel dettaglio di ciascuna di queste configurazioni, poiché in RGB abbiamo scelto di utilizzare un outpoint come definizione del sigillo, e di collocare il commitment nell'output della transazione che spende questo outpoint. Possiamo quindi introdurre i seguenti concetti per il seguito:

Questo schema è stato scelto per la sua compatibilità con l'architettura RGB, ma altre configurazioni potrebbero essere utili per usi diversi.

La "O2" di "TxO2" ci ricorda che sia la definizione che la chiusura si basano sulla spesa (o sulla creazione) di un output di transazione.

Esempio di diagramma TxO2

Come promemoria, la definizione di un single-use seal non richiede necessariamente la pubblicazione di una transazione sulla catena. È sufficiente che Alice, ad esempio, abbia già un UTXO non speso. Può decidere: "Questo outpoint (già esistente) è ora il mio sigillo". Lo annota localmente (lato cliente) e finché questo UTXO non viene speso, il sigillo è considerato aperto.

RGB-Bitcoin

Il giorno in cui vuole chiudere il sigillo (per segnalare un evento o per ancorare un particolare messaggio), spende questo UTXO in una nuova transazione (questa transazione è spesso chiamata "transazione di testimonianza" (non correlata a segwit, è solo il termine che gli diamo). Questa nuova transazione conterrà il commitment al messaggio.

RGB-Bitcoin

Si noti che in questo esempio :

Per illustrare questo schema TxO2, possiamo utilizzare un single-use seal come meccanismo di revoca di una chiave PGP. Invece di pubblicare un certificato di revoca sui server, Alice può dire: "Questa uscita di Bitcoin, se spesa, significa che la mia chiave PGP è revocata".

Alice dispone quindi di uno specifico UTXO, al quale è associato localmente (sul lato client) un determinato stato o dato (noto solo a lei).

Alice informa Bob che se questo UTXO viene speso, si riterrà che si sia verificato un particolare evento. Dall'esterno, tutto ciò che vediamo è una transazione Bitcoin; ma Bob sa che questa spesa ha un significato nascosto.

RGB-Bitcoin

Quando Alice spende questo UTXO, chiude il sigillo su un messaggio che indica la sua nuova chiave, o semplicemente la revoca di quella vecchia. In questo modo, chiunque controlli la catena vedrà che l'UTXO è stato speso, ma solo chi ha la prova completa saprà che si tratta proprio della revoca della chiave PGP.

RGB-Bitcoin

Affinché Bob o chiunque altro possa verificare il messaggio nascosto, Alice deve fornirgli informazioni fuori dalla catena.

RGB-Bitcoin

Alice deve quindi fornire a Bob :

RGB-Bitcoin

Le terze parti non dispongono di queste informazioni. Vedono solo che è stato speso un UTXO. La riservatezza è quindi garantita.

Per chiarire la struttura, riassumiamo il processo in due operazioni:

RGB-Bitcoin RGB-Bitcoin

Per questo motivo chiamiamo la seconda transazione "transazione del testimone".

Per illustrare questo aspetto da un altro punto di vista, possiamo rappresentare due strati:

RGB-Bitcoin

Ma al momento di chiudere il sigillo, si pone il problema di dove inserire l'impegno

Nella sezione precedente, abbiamo brevemente accennato a come il modello di validazione lato client possa essere applicato a RGB e ad altri sistemi. Qui affrontiamo la parte relativa agli impegni deterministici di Bitcoin e a come integrarli in una transazione. L'idea è quella di capire perché stiamo cercando di inserire un singolo impegno nella transazione testimone, e soprattutto come garantire che non ci possano essere altri impegni concorrenti non rivelati.

Luoghi di impegno in una transazione

Quando si fornisce a qualcuno la prova che un certo messaggio è incorporato in una transazione, bisogna essere in grado di garantire che non ci sia un'altra forma di impegno (un secondo messaggio nascosto) nella stessa transazione che non è stata rivelata. Affinché la validazione lato client rimanga robusta, è necessario un meccanismo deterministico per inserire un singolo impegno nella transazione che chiuda il single-use seal.

La transazione testimone spende il famoso UTXO (o definizione del sigillo) e questa spesa corrisponde alla chiusura del sigillo. Tecnicamente parlando, sappiamo che ogni outpoint può essere speso una sola volta. È proprio questo che sta alla base della resistenza di Bitcoin alla doppia spesa. Ma la transazione di spesa può avere diversi ingressi, diverse uscite, o essere composta in modo complesso (coinjoin, canali Lightning, ecc.). Occorre quindi definire chiaramente dove inserire il commitment in questa struttura, in modo univoco e uniforme.

Qualunque sia il metodo (PkO, TxO2, ecc.), il commitment può essere inserito:

RGB-Bitcoin

Ecco i dettagli di ciascun metodo:

RGB-Bitcoin

Tipo di firma (sign-to-contract) :

Uno schema precedente prevedeva lo sfruttamento della parte casuale di una firma (ECDSA o Schnorr) per incorporare il commitment: questa è la tecnica nota come "Sign-to-contract". Si sostituisce il nonce generato casualmente con un hash contenente i dati. In questo modo, la firma rivela implicitamente il vostro impegno, senza alcuno spazio aggiuntivo nella transazione. Questo approccio presenta una serie di vantaggi:

Tuttavia, sono emersi due inconvenienti principali:

In pratica, sig tweak non è molto compatibile con l'hardware (portafogli hardware) e i formati esistenti (Lightning, ecc.). Quindi questa grande idea è difficile da mettere in pratica.

Modifica chiave (pay-to-contract) :

Il tweak della chiave riprende il concetto storico di pay-to-contract. Prendiamo la chiave pubblica X' e la modifichiamo aggiungendo il valoreH(messaggio). In particolare, seX = x * Geh = H(messaggio), la nuova chiave saràX' = X + h * G. Questa chiave modificata nasconde l'impegno nei confronti delmessaggio'. Il detentore della chiave privata originale può, aggiungendo h' alla sua chiave privatax', dimostrare di avere la chiave per spendere l'output. In teoria, questo è elegante, perché :

In pratica, però, ci si scontra con le seguenti difficoltà:

Nel contesto di RGB, questo percorso era previsto fino al 2021, ma si è rivelato troppo complicato da far funzionare con gli standard e le infrastrutture attuali.

Modifica del testimone :

Un'altra idea, che alcuni protocolli come inscrizioni ordinali hanno messo in pratica, è quella di inserire i dati direttamente nella sezione "testimone" della transazione (da qui l'espressione "witness tweak"). Tuttavia, questo metodo :

Inoltre, il testimone è stato progettato per essere potatile in determinati contesti, il che può rendere più complicato avere prove robuste.

Apertura-ritorno (opret) :

Molto semplice nel suo funzionamento, un `OP_RETURN' permette di memorizzare un hash o un messaggio in un campo speciale della transazione. Ma è immediatamente rilevabile: tutti vedono che c'è un commitment nella transazione, e può essere censurato o scartato, oltre ad aggiungere output extra. Poiché questo aumenta la trasparenza e le dimensioni, è considerato meno soddisfacente dal punto di vista di una soluzione di validazione lato client.

34-byte_Opret_Commitment =
OP_RETURN   OP_PUSHBYTE_32   <mpc::Commitment>
|_________| |______________| |_________________|
1-byte       1-byte         32 bytes

Tapret

L'ultima opzione è l'uso di Taproot (introdotto con BIP341) con lo schema Tapret. Tapret è una forma più complessa di impegno deterministico, che apporta miglioramenti in termini di ingombro sulla blockchain e di riservatezza per le operazioni contrattuali. L'idea principale è quella di nascondere l'impegno nella parte Script Path Spend di una [taproot transaction] (https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki).

RGB-Bitcoin

Prima di descrivere come l'impegno viene inserito in una transazione taproot, vediamo la forma esatta dell'impegno, che deve imperativamente corrispondere a una stringa di 64 byte costruita come segue:

64-byte_Tapret_Commitment =
OP_RESERVED ...  ... .. OP_RESERVED   OP_RETURN   OP_PUSHBYTE_33  <mpc::Commitment>  <Nonce>
|___________________________________| |_________| |______________| |_______________|  |______|
OP_RESERVED x 29 times = 29 bytes      1 byte         1 byte          32 bytes        1 byte
|________________________________________________________________| |_________________________|
TAPRET_SCRIPT_COMMITMENT_PREFIX = 31 bytes                    MPC commitment + NONCE = 33 bytes

Quindi il metodo Tapret a 64 byte assomiglia a una Opret a cui abbiamo anteposto 29 byte di OP_RESERVED e aggiunto un byte extra come Nonce.

Per mantenere la flessibilità in termini di implementazione, riservatezza e scalabilità, lo schema Tapret tiene conto di diversi casi d'uso, a seconda dei requisiti:

Analizziamo più da vicino ciascuno di questi due scenari.

Incorporazione di Tapret senza percorso di scrittura esistente

In questo primo caso, si parte da una chiave di uscita taproot (Taproot Output Key) Q che contiene solo la chiave pubblica interna P (Internal Key), senza alcun percorso di script associato (Script Path):

RGB-Bitcoin

Per includere un impegno Tapret, aggiungere un Script Path Spend con uno scritto unico, come segue:

RGB-Bitcoin

La prova dell'inclusione e dell'unicità nell'albero della radice si riduce alla singola chiave pubblica interna P.

Integrazione di Tapret in un percorso di script preesistente

Il secondo scenario riguarda un output Q taproot** più complesso, che contiene già diversi script. Ad esempio, abbiamo un albero di 3 script:

RGB-Bitcoin

Per aggiungere l'impegno di Tapret, dobbiamo inserire uno scritto non spendibile al primo livello dell'albero, spostando gli script esistenti un livello più in basso. Visivamente, l'albero diventa :

RGB-Bitcoin

Secondo le regole del taproot, ogni ramo/foglia deve essere combinato secondo un ordine lessicografico di hash. Ci sono due casi possibili:

Esempio visivo per il primo caso (tHABC < tHT):

RGB-Bitcoin

Esempio per il secondo caso (tHABC > tHT):

RGB-Bitcoin

Ottimizzazione con il nonce

Per migliorare la riservatezza, possiamo "estrarre" (un termine più preciso sarebbe "bruteforcing") il valore della <Nonce> (l'ultimo byte del Tapret a 64 byte) nel tentativo di ottenere un hash tHT tale che tHABC < tHT. In questo caso, l'impegno è posto a destra, evitando all'utente di dover divulgare l'intero contenuto di script esistenti per dimostrare l'unicità del Tapret.

In sintesi, il Tapret offre un modo discreto e deterministico di incorporare un impegno in una transazione taproot, rispettando al contempo i requisiti di unicità e univocità essenziali per la logica di convalida lato cliente e di sigillo monouso di RGB.

Uscite valide

Per le transazioni con impegno RGB, il requisito principale per uno schema di impegno Bitcoin valido è il seguente: La transazione (transazione testimone) deve contenere un unico impegno. Questo requisito rende impossibile costruire una cronologia alternativa per i dati convalidati dal lato client all'interno della stessa transazione. Ciò significa che il messaggio attorno al quale si chiude il single-use seal è unico.

Per soddisfare questo principio, e indipendentemente dal numero di uscite in una transazione, si richiede che una e una sola uscita possa contenere un impegno (impegno). Per ciascuno degli schemi utilizzati (Opret o Tapret), le uniche uscite valide che possono contenere un impegno RGB sono :

Si noti che è possibile che una transazione contenga un singolo impegno Opret e un singolo impegno Tapret in due output separati. Grazie alla natura deterministica della Seal Definition, questi due impegni corrispondono a due dati distinti convalidati sul lato client.

Analisi e scelte pratiche in RGB

Quando abbiamo avviato RGB, abbiamo esaminato tutti questi metodi per determinare dove e come inserire un impegno in una transazione in modo deterministico. Abbiamo definito alcuni criteri:

MetodoTraccia e dimensione on-chainDimensione lato clientIntegrazione walletCompatibilità hardwareCompatibilità LightningCompatibilità Taproot
Keytweak (P2C deterministico)🟢🟡🔴🟠🔴 BOLT, 🔴 Bifrost🟠 Taproot, 🟢 MuSig
Sigtweak (S2C deterministico)🟢🟢🟠🔴🔴 BOLT, 🔴 Bifrost🟠 Taproot, 🔴 MuSig
Opret (OP_RETURN)🔴🟢🟢🟠🔴 BOLT, 🟠 Bifrost-
Algoritmo Tapret: nodo in alto a sinistra🟠🔴🟠🟢🔴 BOLT, 🟢 Bifrost🟢 Taproot, 🟢 MuSig
Algoritmo Tapret #4: qualsiasi nodo + prova🟢🟠🟠🟢🔴 BOLT, 🟢 Bifrost🟢 Taproot, 🟢 MuSig
Schema di impegno deterministicoStandardCosto on-chainDimensione della prova lato client
Keytweak (P2C deterministico)LNPBP-1, 20 byte33 byte (chiave non modificata)
Sigtweak (S2C deterministico)WIP (LNPBP-39)0 byte0 byte
Opret (OP_RETURN)-36 (v)byte (TxOut aggiuntivo)0 byte
Algoritmo Tapret: nodo in alto a sinistraLNPBP-632 byte nel testimone (8 vbyte) per qualsiasi multisig n-of-m e spesa tramite il percorso script0 byte negli scriptless scripts taproot ~270 byte per un unico script, ~128 byte se ci sono più script
Algoritmo Tapret #4: qualsiasi nodo + prova di unicitàLNPBP-632 byte nel testimone (8 vbyte) nei casi di script singolo, 0 byte nel testimone nella maggior parte degli altri casi0 byte negli scriptless scripts taproot, 65 byte fino a quando il Taptree contiene una dozzina di script
LivelloCosto on-chain (bytes/vbytes)Costo on-chain (bytes/vbytes)Costo on-chain (bytes/vbytes)Costo on-chain (bytes/vbytes)Costo on-chain (bytes/vbytes)Costo lato client (bytes)Costo lato client (bytes)Costo lato client (bytes)Costo lato client (bytes)Costo lato client (bytes)
TipoTapretTapret #4KeytweakSigtweakOpretTapretTapret #4KeytweakSigtweakOpret
Single-sig00003200320?0
MuSig (n-of-n)0000320032? > 00
Multi-sig 2-of-332/832/8 o 00n/a32~2706532n/a0
Multi-sig 3-of-532/832/8 o 00n/a32~3406532n/a0
Multi-sig 2-of-3 con timeout32/800n/a32646532n/a0
LivelloCosto on-chain (vbytes)Costo on-chain (vbytes)Costo on-chain (vbytes)Costo lato client (bytes)Costo lato client (bytes)
TipoBaseTapret #2Tapret #4Tapret #2Tapret #4
MuSig (n-of-n)16.50000
FROST (n-of-m)?0000
Multi_a (n-of-m)1+16n+8m8833 * m65
Ramo MuSig / Multi_a (n-of-m)1+16n+8n+8xlog(n)806465
Con timeout (n-of-m)1+16n+8n+8xlog(n)806465
MetodoPrivacy e ScalabilitàInteroperabilitàCompatibilitàPortabilitàComplessità
Keytweak (P2C deterministico)🟢🔴🔴🟡🟡
Sigtweak (S2C deterministico)🟢🔴🔴🟢🔴
Opret (OP_RETURN)🔴🟠🔴🟢🟢
Algo Tapret: Nodo in alto a sinistra🟠🟢🟢🔴🟠
Algo Tapret #4: Qualsiasi nodo + prova🟢🟢🟢🟠🔴

Nel corso dello studio è emerso chiaramente che nessuno degli schemi di impegno era pienamente compatibile con l'attuale standard Lightning (che non utilizza Taproot, muSig2 o un supporto aggiuntivo per gli impegni). Sono in corso sforzi per modificare la costruzione dei canali di Lightning (BiFrost) per consentire l'inserimento di impegni RGB. Questa è un'altra area in cui è necessario rivedere la struttura delle transazioni, le chiavi e il modo in cui gli aggiornamenti dei canali vengono firmati.

L'analisi ha mostrato che, in realtà, altri metodi (key tweak, sig tweak, witness tweak, ecc.) presentavano altre forme di complicazione:

Per l'RGB, si distinguono due metodi in particolare: Opret e Tapret, entrambi classificati come "Transaction Output" e compatibili con la modalità TxO2 utilizzata dal protocollo.

Impegni multiprotocollo - MPC

In questa sezione, vediamo come RGB gestisce l'aggregazione di più contratti (o, più precisamente, dei loro transition bundles) all'interno di un singolo impegno (commitment) registrato in una transazione Bitcoin attraverso uno schema deterministico (secondo Opret o Tapret). Per ottenere questo risultato, l'ordine di Merkelizzazione dei vari contratti avviene in una struttura chiamata albero MPC (Multi Protocol Commitment Tree). In questa sezione vedremo la costruzione di questo albero MPC, come ottenere la sua radice e come più contratti possono condividere la stessa transazione in modo confidenziale e non ambiguo.

L'impegno multiprotocollo (MPC) è stato progettato per soddisfare due esigenze:

In concreto, ogni fascio di transizione appartiene a un particolare contratto. Tutte queste informazioni vengono inserite in un albero MPC, la cui radice (mpc::Root) viene poi sottoposta a un nuovo hash per ottenere il mpc::Commitment. È quest'ultimo hash che viene inserito nella transazione Bitcoin (transazione testimone), secondo il metodo deterministico scelto.

RGB-Bitcoin

Hash radice MPC

Il valore effettivamente scritto sulla catena (in Opret o Tapret) è chiamato mpc::Commitment. Viene calcolato nella forma BIP-341, secondo la formula :

mpc::Commitment = SHA-256(SHA-256(mpc_tag) || SHA-256(mpc_tag) || depth || cofactor || mpc::Root )

dove :

RGB-Bitcoin

Costruzione di alberi MPC

Per costruire questo albero MPC, dobbiamo assicurarci che ogni contratto corrisponda a un'unica posizione della foglia. Supponiamo di avere :

Si costruisce quindi un albero di larghezza w e profondità d tale che 2^d = w, con w > C, in modo che ogni contratto possa essere collocato in una foglia separata. La posizione pos(c_i) di ogni contratto nell'albero è determinata da :

pos(c_i) = c_i mod (w - cofactor)

dove `cofattore' è un numero intero che aumenta la probabilità di ottenere posizioni distinte per ogni contratto. In pratica, la costruzione segue un processo iterativo:

L'obiettivo è evitare gli alberi troppo alti, mantenendo il rischio di collisione al minimo. Si noti che il fenomeno della collisione segue una logica di distribuzione casuale, legata al Paradosso degli Anniversari.

Foglie abitate

Una volta ottenute C posizioni distinte pos(c_i) per i contratti i = {0,1,...,C-1}, ogni foglio viene riempito con una funzione hash (tagged hash):

tH_MPC_LEAF(c_i) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || 0x10 || c_i || BundleId(c_i))

dove :

Foglie disabitate

Le foglie rimanenti, non assegnate a un contratto (cioè le foglie w - C), sono riempite con un valore "fittizio" (foglia di entropia) :

tH_MPC_LEAF(j) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || 0x11 || entropy || j )

dove :

Nodi MPC

Dopo aver generato le w foglie (abitate o meno), si procede alla merkelizzazione. Tutti i nodi interni vengono sottoposti a hash come segue:

tH_MPC_BRANCH(tH1 || tH2) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || b || d || w || tH1 || tH2)

dove :

Procedendo in questo modo, si ottiene la radice mpc::Root. Possiamo quindi calcolare mpc::Commitment (come spiegato sopra) e inserirlo nella catena.

Per illustrarlo, immaginiamo un esempio in cui C=3 (tre contratti). Le loro posizioni sono assunte come pos(c_0)=7, pos(c_1)=4, pos(c_2)=2. Le altre foglie (posizioni 0, 1, 3, 5, 6) sono foglie di entropia. Il diagramma seguente mostra la sequenza di hash fino alla radice con :

Il risultato finale è mpc::Root, quindi mpc::Commitment.

RGB-Bitcoin

Controllo dell'albero MPC

Quando un verificatore vuole assicurarsi che un contratto c_i (e il suo BundleId) sia incluso nel contratto finale mpc::Commitment, riceve semplicemente una prova Merkle. Questa prova indica i nodi necessari per risalire dalle foglie (in questo caso, la foglia di contratto di c_i) alla radice. Non è necessario rivelare l'intero albero MPC: questo protegge la riservatezza degli altri contratti.

Nell'esempio, un verificatore c_2 ha bisogno solo di un hash intermedio (tH_MPC_LEAF(D)), di due tH_MPC_BRANCH(...), della prova di posizione pos(c_2) e del valore cofattore. Può quindi ricostruire localmente la radice, ricalcolare il mpc::Commitment e confrontarlo con quello scritto nella transazione Bitcoin (all'interno di Opret o Tapret).

RGB-Bitcoin

Questo meccanismo garantisce che :

Sintesi della struttura dell'MPC

Il Multi Protocol Commitment* (MPC) è il principio che consente a RGB di aggregare più contratti in un'unica transazione Bitcoin, mantenendo l'unicità degli impegni e la riservatezza nei confronti degli altri partecipanti. Grazie alla costruzione deterministica dell'albero, a ogni contratto viene assegnata una posizione unica e la presenza di foglie "fittizie" (foglie di entropia) maschera parzialmente il numero totale di contratti che partecipano alla transazione.

L'intero albero di Merkle non viene mai memorizzato sul client. Viene semplicemente generato un percorso Merkle per ogni contratto interessato, da trasmettere al destinatario (che può quindi convalidare l'impegno). In alcuni casi, si possono avere diverse attività che sono passate attraverso lo stesso UTXO. È quindi possibile unire diversi tracciati Merkle in un cosiddetto blocco di impegno multiprotocollo, per evitare di duplicare troppi dati.

Ogni prova di Merkle è quindi leggera, soprattutto perché la profondità dell'albero non supera i 32 in RGB. Esiste anche una nozione di "blocco Merkle", che conserva più informazioni (sezione trasversale, entropia, ecc.), utile per combinare o separare diversi rami.

Ecco perché ci è voluto così tanto tempo per finalizzare RGB. Avevamo la visione generale dal 2019: mettere tutto sul lato client e far circolare i token fuori dalla catena. Ma per dettagli come lo sharding per contratti multipli, la struttura dell'albero di Merkle, la gestione delle collisioni e delle prove di fusione... tutto questo ha richiesto iterazioni.

Ancore: un'assemblea globale

Dopo aver costruito i nostri impegni (Opret o Tapret) e il nostro MPC (Multi Protocol Commitment), dobbiamo affrontare la nozione di Anchor nel protocollo RGB. Un Anchor è una struttura convalidata dal lato client che riunisce gli elementi necessari per verificare che un impegno Bitcoin contenga effettivamente informazioni contrattuali specifiche. In altre parole, un Anchor riassume tutti i dati necessari per convalidare gli impegni descritti sopra.

Un'ancora è composta da tre campi ordinati:

Ognuno di questi campi svolge un ruolo nel processo di convalida, sia che si tratti di ricostruire la transazione Bitcoin sottostante, sia che si tratti di provare l'esistenza di un impegno nascosto (in particolare nel caso di Tapret).

TxId

Il campo Txid corrisponde all'identificatore a 32 byte della transazione Bitcoin contenente l'impegno Opret o Tapret.

In teoria, sarebbe possibile trovare questo Txid tracciando la catena di transizioni di stato che a loro volta puntano a ogni transazione testimone, seguendo la logica dei sigilli monouso. Tuttavia, per facilitare e accelerare la verifica, questo Txid è semplicemente incluso nell'Anchor, evitando così al validatore di dover ripercorrere l'intera storia fuori catena.

Prova MPC

Il secondo campo, MPC Proof, si riferisce alla prova che questo particolare contratto (ad esempio c_i) è incluso nel Multi Protocol Commitment. È una combinazione di :

Questo meccanismo è stato descritto nella sezione precedente sulla costruzione dell'albero MPC, dove ogni contratto ottiene una foglia unica grazie alla funzione :

pos(c_i) = c_i mod (w - cofactor)

Quindi, viene utilizzato uno schema di merkelizzazione deterministico per aggregare tutte le foglie (contratti + entropia). Alla fine, la MPC Proof permette di ricostruire localmente la radice e di confrontarla con la mpc::Commitment inclusa nella catena.

Prova di transazione extra - ETP

Il terzo campo, il ETP, dipende dal tipo di impegno utilizzato. Se l'impegno è di tipo Opret, non è richiesta alcuna prova aggiuntiva. Il validatore ispeziona il primo output OP_RETURN della transazione e trova il mpc::Commitment direttamente lì.

Se l'impegno è di tipo Tapret, deve essere fornita una prova aggiuntiva chiamata Extra Transaction Proof - ETP. Essa contiene :

Questa prova aggiuntiva è essenziale perché, a differenza di Opret, l'impegno di Tapret è integrato nella struttura di uno script taproot, che richiede la rivelazione di parte dell'albero taproot per validare correttamente la posizione dell'impegno.

RGB-Bitcoin

Gli Anchors incapsulano quindi tutte le informazioni necessarie per convalidare un impegno Bitcoin nel contesto di RGB. Indicano sia la transazione pertinente (Txid) che la prova del posizionamento del contratto (MPC Proof), mentre gestiscono la prova aggiuntiva (ETP) nel caso di Tapret. In questo modo, un Anchor protegge l'integrità e l'unicità dello stato fuori catena, garantendo che la stessa transazione non possa essere reinterpretata per altri dati contrattuali.

Conclusione

In questo capitolo vengono trattati i temi :

In pratica, l'implementazione tecnica è divisa tra diverse crate Rust dedicate (in client_side_validation, commit-verify, bp_core, ecc.) Le nozioni fondamentali ci sono:

RGB-Bitcoin

Nel prossimo capitolo, esamineremo la componente puramente off-chain di RGB, ovvero la logica dei contratti. Vedremo come i contratti RGB, organizzati come macchine a stati finiti parzialmente replicate, raggiungano un'espressività molto più elevata rispetto agli script Bitcoin, preservando al contempo la riservatezza dei loro dati.

Introduzione ai contratti intelligenti e ai loro stati

In questo e nel prossimo capitolo, esamineremo la nozione di contratto intelligente all'interno dell'ambiente RGB ed esploreremo i diversi modi in cui questi contratti possono definire ed evolvere il loro stato. Vedremo perché l'architettura RGB, utilizzando la sequenza ordinata di Single-use Seals, rende possibile l'esecuzione di vari tipi di operazioni contrattuali in modo scalabile e senza passare attraverso un registro centralizzato. Vedremo anche il ruolo fondamentale della Logica di business nell'inquadrare l'evoluzione dello stato del contratto.

Contratti intelligenti e diritti digitali al portatore

L'obiettivo di RGB è fornire un'infrastruttura per l'implementazione di contratti intelligenti su Bitcoin. Per "contratto intelligente" si intende un accordo tra più parti che viene applicato automaticamente e computazionalmente, senza l'intervento umano per far rispettare le clausole. In altre parole, la legge del contratto è applicata dal software, non da una terza parte fidata.

Questa automazione solleva la questione della decentralizzazione: come possiamo liberarci da un registro centralizzato (ad esempio una piattaforma o un database centrale) per gestire la proprietà e l'esecuzione dei contratti? L'idea originale, ripresa da RGB, è quella di tornare a una modalità di proprietà nota come "strumenti al portatore". Storicamente, alcuni titoli (obbligazioni, azioni, ecc.) venivano emessi al portatore, consentendo a chiunque possedesse fisicamente il documento di far valere i propri diritti.

RGB-Bitcoin

RGB applica questo concetto al mondo digitale: i diritti (e gli obblighi) sono incapsulati in dati che vengono manipolati fuori dalla catena, e lo stato di questi dati è convalidato dagli stessi partecipanti. Ciò consente, a priori, un grado di riservatezza e di indipendenza molto maggiore di quello offerto da altri approcci basati su registri pubblici.

Introduzione al contratto intelligente Stato RGB

Uno smart contract in RGB può essere visto come una macchina a stati, definita da :

RGB-Bitcoin

È importante capire che questi contratti non si limitano al semplice trasferimento di token. Essi possono incorporare un'ampia varietà di applicazioni: dai beni tradizionali (token, azioni, obbligazioni) a meccaniche più complesse (diritti d'uso, termini commerciali, ecc.). A differenza di altre blockchain, dove il codice del contratto è accessibile ed eseguibile da tutti, l'approccio di RGB compartimenta l'accesso e la conoscenza del contratto ai partecipanti ("partecipanti al contratto"). Esistono diversi ruoli:

Questa separazione dei ruoli contribuisce alla resistenza alla censura, garantendo che solo le persone autorizzate possano interagire con lo stato contrattuale. Inoltre, dà a RGB la capacità di scalare orizzontalmente: la maggior parte delle convalide avviene al di fuori della blockchain e solo le ancore crittografiche (gli impegni) sono iscritte su Bitcoin.

Stato e logica aziendale in RGB

Da un punto di vista pratico, la Business Logic del contratto assume la forma di regole e script, definiti in quello che RGB chiama uno Schema. Lo Schema codifica :

Allo stesso tempo, lo Stato contrattuale spesso si scompone in due componenti:

Come vedremo nei capitoli successivi, ogni aggiornamento di stato (Operazione di contratto) deve agganciarsi a un commitment di Bitcoin (tramite Opret o Tapret) e rispettare gli script di Business Logic per essere considerato valido.

Operazioni contrattuali: creazione ed evoluzione dello Stato

Nell'universo RGB, una Operazione di contratto è un qualsiasi evento che cambia il contratto da un vecchio stato a un nuovo stato. Queste operazioni seguono la seguente logica:

RGB-Bitcoin

Il risultato finale è un contratto aggiornato, ora con uno stato diverso. Questa transizione non richiede che l'intera rete Bitcoin si occupi dei dettagli, poiché solo una piccola impronta crittografica (il commitment) viene registrata nella blockchain. La sequenza di sigilli monouso impedisce qualsiasi doppio utilizzo dello Stato.

Catena operativa: dalla Genesi allo Stato terminale

Per mettere le cose in prospettiva, uno smart contract RGB inizia con una Genesi, il primo stato. Successivamente, si susseguono varie operazioni contrattuali, formando un DAG (grafo aciclico diretto) di operazioni:

RGB-Bitcoin

Questa topologia DAG (invece di una semplice catena lineare) riflette la possibilità che diverse parti del contratto si evolvano in parallelo, purché non si contraddicano a vicenda. RGB si occupa quindi di evitare qualsiasi incoerenza attraverso la verifica sul lato cliente di ogni partecipante coinvolto.

Sintesi

I contratti intelligenti in RGB introducono un modello di strumenti digitali al portatore, decentralizzati ma ancorati a Bitcoin per la marcatura temporale e la garanzia dell'ordine delle transazioni. L'esecuzione automatica di questi contratti si basa su :

Nel prossimo capitolo approfondiremo la rappresentazione concreta di questi stati e transizioni di stato a livello off-chain e il loro rapporto con gli UTXO e i Single-use Seals incorporati in Bitcoin. Sarà l'occasione per vedere come la meccanica interna di RGB, basata sulla convalida lato client, riesca a mantenere la coerenza dei contratti intelligenti preservando la riservatezza dei dati.

Operazioni di contratto RGB

In questo capitolo vedremo come funzionano le operazioni negli smart contract e le transizioni di stato, sempre nell'ambito del protocollo RGB. Lo scopo sarà anche quello di capire come più partecipanti cooperano per trasferire la proprietà di un bene.

Transizioni di stato e loro meccanica

Il principio generale è ancora quello della convalida lato client, in cui i dati di stato sono detenuti dal proprietario e convalidati dal destinatario. Tuttavia, la specificità di RGB sta nel fatto che Bob, in qualità di destinatario, chiede ad Alice di incorporare alcune informazioni nei dati del contratto per avere un controllo reale sul bene ricevuto, tramite un riferimento nascosto a uno dei suoi UTXO.

Per illustrare il processo di una Transizione di stato (che è una delle Operazioni contrattuali fondamentali in RGB), facciamo un esempio passo passo di un trasferimento di beni tra Alice e Bob:

Situazione iniziale:

Alice ha uno stash RGB di dati convalidati localmente (lato cliente). Questo stash si riferisce a uno dei suoi UTXO su Bitcoin. Ciò significa che una definizione di sigillo in questi dati punta a un UTXO appartenente ad Alice. L'idea è di consentirle di trasferire a Bob alcuni diritti digitali legati a un bene (ad esempio, i token RGB).

RGB-Bitcoin

Bob ha anche gli UTXO :

Bob, invece, ha almeno un proprio UTXO, senza alcun legame diretto con quello di Alice. Nel caso in cui Bob non abbia un UTXO, è comunque possibile effettuare il trasferimento a lui utilizzando la stessa transazione di testimonianza: l'output di questa transazione includerà quindi l'impegno (commitment) e assocerà implicitamente la proprietà del nuovo contratto a Bob.

RGB-Bitcoin

Costruzione della nuova proprietà (Nuovo Stato) :

Bob invia ad Alice informazioni codificate sotto forma di fattura (approfondiremo la costruzione delle fatture nei capitoli successivi), chiedendole di creare un nuovo stato conforme alle regole del contratto. Questo stato includerà una nuova definizione di sigillo che punta a uno degli UTXO di Bob. In questo modo, Bob ottiene la proprietà delle attività definite in questo nuovo stato, ad esempio una certa quantità di gettoni RGB.

RGB-Bitcoin

Preparazione della transazione campione:

Alice crea quindi una transazione Bitcoin spendendo l'UTXO a cui si è fatto riferimento nel sigillo precedente (quello che l'ha legittimata come titolare). Nell'output di questa transazione, viene inserito un impegno (tramite Opret o Tapret) per ancorare il nuovo stato RGB. Gli impegni Opret o Tapret sono derivati da un albero MPC (come visto nei capitoli precedenti), che può aggregare diverse transizioni da contratti diversi.

Trasmissione di Consegna a Bob:

Prima di trasmettere la transazione, Alice invia a Bob un Consignment contenente tutti i dati necessari sul lato cliente (il suo stash) e le nuove informazioni sullo stato a favore di Bob. A questo punto, Bob applica le regole di consenso RGB:

Completamento della transizione:

Se Bob è soddisfatto, può dare la sua approvazione (ad esempio, firmando l'incarico). Alice può quindi trasmettere la transazione campione preparata. Una volta confermata, questa chiude il sigillo precedentemente detenuto da Alice e formalizza la proprietà da parte di Bob. La sicurezza anti-doppio spreco si basa sullo stesso meccanismo di Bitcoin: l'UTXO viene speso, dimostrando che Alice non può più riutilizzarlo.

RGB-Bitcoin

Il nuovo stato fa ora riferimento all'UTXO di Bob, conferendo a Bob la proprietà precedentemente detenuta da Alice. L'uscita Bitcoin in cui sono ancorati i dati RGB diventa la prova irrevocabile del trasferimento di proprietà.

Un esempio di DAG (grafo aciclico diretto) minimo che comprende due operazioni contrattuali (una Genesi e una Transizione di stato) può illustrare come lo stato RGB (strato lato cliente, in rosso) si connette alla blockchain Bitcoin (strato Commitment, in arancione).

RGB-Bitcoin

Mostra che una Genesi definisce un sigillo (definizione del sigillo), quindi una Transizione di stato chiude questo sigillo per crearne uno nuovo in un altro UTXO.

In questo contesto, ecco alcuni richiami alla terminologia:

Le transizioni di stato**, descritte nel capitolo precedente, sono la forma principale di operazione contrattuale. Fanno riferimento a uno o più stati precedenti (da Genesis o da un'altra transizione di stato) e li aggiornano a un nuovo stato.

RGB-Bitcoin

Questo diagramma mostra come, in un Bundle di transizione di stato, diversi sigilli possano essere chiusi in una singola transazione campione, aprendo contemporaneamente nuovi sigilli. In effetti, una caratteristica interessante del protocollo RGB è la sua capacità di scalare: diverse transizioni possono essere aggregate in un Transition Bundle, ogni aggregazione è associata a una foglia distinta dell'albero MPC (un identificatore unico del bundle). Grazie al meccanismo Deterministic Bitcoin Commitment (DBC), l'intero messaggio viene inserito in un'uscita Tapret o Opret, chiudendo i sigilli precedenti ed eventualmente definendone di nuovi. L'`Anchor* funge da collegamento diretto tra l'impegno memorizzato nella blockchain e la struttura di validazione lato client (client-side).

Nei capitoli seguenti verranno esaminati tutti i componenti e i processi coinvolti nella costruzione e nella convalida di una transizione di stato. La maggior parte di questi elementi fa parte del consenso RGB, implementato nella RGB Core Library.

Pacchetto di transizione

Su RGB è possibile raggruppare diverse transizioni di stato appartenenti allo stesso contratto (cioè che condividono lo stesso ContractId, derivato dal OpId di Genesis). Nel caso più semplice, come quello tra Alice e Bob nell'esempio precedente, un Bundle di transizioni contiene una sola transizione. Ma il supporto per le operazioni multi-pagatore (come coinjoin, aperture di canali Lightning, ecc.) significa che più utenti possono combinare le loro transizioni di stato in un unico bundle.

Una volta raccolte, queste transizioni sono ancorate (dal meccanismo MPC + DBC) in una singola transazione Bitcoin:

Tecnicamente, il BundleId inserito nel foglio MPC è ottenuto da un hash taggato applicato alla serializzazione rigorosa del campo InputMap del bundle:

BundleId = SHA256( SHA256(bundle_tag) || SHA256(bundle_tag) || InputMap )

In cui bundle_tag = urn:lnp-bp:rgb:bundle#2024-02-03 per esempio.

La InputMap è una struttura dati che elenca, per ogni ingresso i della transazione campione, il riferimento all'OpId della transizione di stato corrispondente. Ad esempio:

InputMap =
N               input_0    OpId(input_0)    input_1    OpId(input_1)   ...    input_N-1  OpId(input_N-1)
|____________________| |_________||______________| |_________||______________|       |__________||_______________|
16-bit Little Endian   32-bit LE   32-byte hash
|_________________________| |_________________________|  ...  |___________________________|
MapElement1                MapElement2                       MapElementN

Facendo riferimento a ogni voce una sola volta e in modo ordinato, si evita che lo stesso sigillo venga speso due volte in due transizioni di stato simultanee.

Generazione dello stato e stato attivo

Le transizioni di stato possono quindi essere utilizzate per trasferire la proprietà di un bene da una persona a un'altra. Tuttavia, non sono le uniche operazioni possibili nel protocollo RGB. Il protocollo definisce tre operazioni di contratto :

Tra queste, Genesis e State Extension sono talvolta chiamate "operazioni di generazione di stati*", perché creano nuovi stati senza chiuderne immediatamente alcuno. Questo è un punto molto importante: Genesi e Estensione dello stato non comportano la chiusura di un sigillo. Piuttosto, definiscono un nuovo sigillo, che deve poi essere speso da una successiva Transizione di Stato per essere veramente convalidato nella storia della blockchain.

RGB-Bitcoin

Lo Stato attivo di un contratto è spesso definito come l'insieme degli ultimi stati risultanti dalla storia (il DAG) delle transazioni, a partire dalla Genesi e seguendo tutte le ancore nella blockchain Bitcoin. I vecchi stati che sono già obsoleti (cioè legati a UTXO esauriti) non sono più considerati attivi, ma rimangono essenziali per controllare la coerenza della storia.

Genesi

La Genesi è il punto di partenza di ogni contratto RGB. Viene creata dall'emittente del contratto e definisce i parametri iniziali, in conformità con lo Schema. Nel caso di un token RGB, la Genesi può specificare, ad esempio :

Essendo la prima transazione del contratto, la Genesis non fa riferimento a nessuno stato precedente, né chiude alcun sigillo. Tuttavia, per apparire nella cronologia ed essere convalidata, la Genesis deve essere consumata (chiusa) da una prima transizione di stato (spesso una transazione di scansione/autospesa verso l'emittente stesso, o la distribuzione iniziale agli utenti).

Estensione dello Stato

Le Estensioni di Stato** offrono una funzionalità originale per gli smart contract. Esse consentono di riscattare alcuni diritti digitali (Valenze) previsti nella definizione del contratto, senza chiudere immediatamente il sigillo. Il più delle volte si tratta di :

Tecnicamente, un'Estensione di Stato fa riferimento a una Redenzione (un particolare tipo di input RGB) che corrisponde a una Valenza definita in precedenza (ad esempio, in Genesi o in un'altra Transizione di Stato). Definisce un nuovo sigillo, disponibile per la persona o la condizione che ne beneficia. Perché questo sigillo diventi effettivo, deve essere speso da una successiva Transizione di Stato.

RGB-Bitcoin

Ad esempio: la Genesi crea un diritto di emissione (Valenza). Questo può essere esercitato da un attore autorizzato, che poi costruisce un'Estensione di Stato:

Componenti di un'operazione contrattuale

Vorrei ora dare un'occhiata dettagliata a ciascuno degli elementi costitutivi di una Operazione contrattuale in RGB. Una Contract Operation è l'azione che modifica lo stato di un contratto e che viene convalidata sul lato client, in modo deterministico, dal legittimo destinatario. In particolare, vedremo come la Contract Operation tenga conto, da un lato, del vecchio stato (Old State) del contratto e, dall'altro, della definizione di un nuovo stato (New State).

+---------------------------------------------------------------------------------------------------------------------+
|  Contract Operation                                                                                                 |
|                                                                                                                     |
|  +-----+     +-----------------------+      +--------------------------------+      +---------+     +------------+  |
|  | Ffv |     | ContractId | SchemaId |      | TransitionType | ExtensionType |      | Testnet |     | AltLayers1 |  |
|  +-----+     +-----------------------+      +--------------------------------+      +---------+     +------------+  |
|                                                                                                                     |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |
|  | Metadata                                      |  | Global State                                               |  |
|  |                                               |  | +----------------------------------+                       |  |
|  | +-------------------------------------+       |  | | +-------------------+ +--------+ |                       |  |
|  | |          Structured Data            |       |  | | |  GlobalStateType  | |  Data  | |     ...     ...       |  |
|  | +-------------------------------------+       |  | | +-------------------+ +--------+ |                       |  |
|  |                                               |  | +----------------------------------+                       |  |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |         +------+
|                                                                                                                     +---------> OpId |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |         +------+
|  | Inputs                                        |  | Assignments                                                |  |
|  |                                               |  |                                                            |  |
|  | +-------------------------------------------+ |  | +--------------------------------------------------------+ |  |
|  | | Input #1                                  | |  | | Assignment #1                                          | |  |
+------+       |  | | +----------+ +----------------+ +-------+ | |  | | +----------------+ +-------------+ +-----------------+ | |  |       +--------------+
| OpId +--------------> PrevOpId | | AssignmentType | | Index | | |  | | | AssignmentType | | Owned State | | Seal Definition +--------------> Bitcoin UTXO |
+------+       |  | | +----------+ + ---------------+ +-------+ | |  | | +----------------+ +-------------+ +-----------------+ | |  |       +--------------+
|  | +-------------------------------------------+ |  | +--------------------------------------------------------+ |  |
|  |                                               |  |                                                            |  |
|  | +-------------------------------------------+ |  | +--------------------------------------------------------+ |  |
|  | | Input #2                                  | |  | | Assignment #2                                          | |  |
+------+       |  | | +----------+ +----------------+ +-------+ | |  | | +----------------+ +-------------+ +-----------------+ | |  |       +--------------+
| OpId +--------------> PrevOpId | | AssignmentType | | Index | | |  | | | AssignmentType | | Owned State | | Seal Definition +--------------> Bitcoin UTXO |
+------+       |  | | +----------+ +----------------+ +-------+ | |  | | +----------------+ +-------------+ +-----------------+ | |  |       +--------------+
|  | +-------------------------------------------+ |  | +--------------------------------------------------------+ |  |
|  |                                               |  |                                                            |  |
|  |       ...           ...          ...          |  |     ...          ...             ...                       |  |
|  |                                               |  |                                                            |  |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |
|                                                                                                                     |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |
|  | Redeems                                       |  | Valencies                                                  |  |
|  |                                               |  |                                                            |  |
|  | +------------------------------+              |  |                                                            |  |
+------+       |  | | +----------+ +-------------+ |              |  |  +-------------+  +-------------+                          |  |
| OpId +--------------> PrevOpId | | ValencyType | |  ...   ...   |  |  | ValencyType |  | ValencyType |         ...              |  |
+------+       |  | | +----------+ +-------------+ |              |  |  +-------------+  +-------------+                          |  |
|  | +------------------------------+              |  |                                                            |  |
|  |                                               |  |                                                            |  |
|  +-----------------------------------------------+  +------------------------------------------------------------+  |
|                                                                                                                     |
+---------------------------------------------------------------------------------------------------------------------+

Se osserviamo il diagramma precedente, possiamo notare che un'operazione di contratto include elementi che si riferiscono al nuovo stato e altri che si riferiscono al vecchio stato aggiornato.

Gli elementi del Nuovo Stato sono :

Il vecchio Stato è referenziato tramite :

Inoltre, un'Operazione a contratto include campi più generali specifici per l'operazione:

Infine, tutti questi campi sono condensati da un processo di hashing personalizzato, per produrre un'impronta digitale unica, l'OpId. Questo OpId viene quindi integrato nel bundle di transizione, consentendone l'autenticazione e la convalida all'interno del protocollo.

Ogni operazione contrattuale è quindi identificata da un hash di 32 byte denominato OpId. Questo hash è calcolato mediante un hash SHA256 di tutti gli elementi che compongono l'operazione. In altre parole, ogni Operazione contrattuale ha un proprio impegno crittografico, che include tutti i dati necessari per verificare l'autenticità e la coerenza dell'operazione.

Un contratto RGB è quindi identificato da un ContractId, derivato dall'OpId di Genesis (poiché non esiste un'operazione precedente a Genesis). In concreto, prendiamo l'OpId di Genesis, invertiamo l'ordine dei byte e applichiamo una codifica Base58. Questa codifica rende il ContractId più facile da gestire e riconoscere.

Metodi e regole di aggiornamento dello stato

Lo Stato del contratto rappresenta l'insieme di informazioni che il protocollo RGB deve tracciare per un determinato contratto. È composto da :

RGB-Bitcoin

Lo Stato globale è direttamente incluso nell'Operazione contratto come blocco singolo. Gli Stati proprietari sono definiti in ogni Assegnazione, insieme alla Definizione di tenuta.

Una caratteristica importante di RGB è il modo in cui vengono modificati lo Stato globale e gli Stati posseduti. Esistono generalmente due tipi di comportamento:

Se nel contratto un elemento di stato non è definito come mutabile o cumulativo, questo elemento rimarrà vuoto per le operazioni successive (in altre parole, non ci saranno nuove versioni per questo campo). È lo Schema del contratto (cioè la logica aziendale codificata) a determinare se uno stato (Globale o di proprietà) è mutabile, cumulativo o fisso. Una volta definita la Genesi, queste proprietà possono essere modificate solo se il contratto stesso lo consente, ad esempio tramite una specifica Estensione di Stato.

La tabella seguente illustra come ogni tipo di operazione contrattuale può manipolare (o meno) lo Stato globale e lo Stato proprietario:

GenesiEstensione di StatoTransizione di Stato
Aggiunta di Global State+-+
Mutazione di Global Staten/a-+
Aggiunta di Owned State+-+
Mutazione di Owned Staten/aNo+
Aggiunta di Valencies+++

+ : azione possibile se lo Schema del contratto lo consente.

-: l'operazione deve essere confermata da una successiva transizione di stato (la sola estensione di stato non chiude il sigillo monouso).

Inoltre, l'ambito temporale e i diritti di aggiornamento di ciascun tipo di dati possono essere distinti nella tabella seguente:

MetadataStato GlobaleStato Posseduto
AmbitoDefinito per una singola operazione del contrattoDefinito globalmente per il contrattoDefinito per ogni sigillo (Assignment)
Chi può aggiornarlo?Non aggiornabile (dati effimeri)Operazione emessa dagli attori (emittente, ecc.)Dipende dal legittimo detentore che possiede il sigillo (colui che può spenderlo in una transazione successiva)
Ambito TemporaleSolo per l'operazione correnteLo stato è stabilito alla fine dell'operazioneLo stato è definito prima dell'operazione (dalla Seal Definition dell'operazione precedente)

Stato globale

Lo Stato globale è spesso descritto come "nessuno possiede, tutti sanno". Contiene informazioni generali sul contratto, che sono pubblicamente visibili. Ad esempio, in un contratto di emissione di token, contiene potenzialmente :

Questo Stato globale può essere collocato su risorse pubbliche (siti web, IPFS, Nostr, Torrent, ecc.) e distribuito alla comunità. Inoltre, l'incentivo economico (la necessità di detenere e trasferire questi token, ecc.) spinge naturalmente gli utenti del contratto a mantenere e propagare questi dati da soli.

Incarichi

L'Assegnazione è la struttura di base per la definizione di :

Un Assignment può essere visto come l'analogo di un output di una transazione Bitcoin, ma con maggiore flessibilità. Qui sta la logica del trasferimento di proprietà: l'Assegnazione associa un particolare tipo di bene o diritto (AssignmentType) a un sigillo. Chiunque possieda la chiave privata dell'UTXO collegato a questo sigillo (o chiunque possa spendere questo UTXO) è considerato proprietario di questo Stato posseduto.

Uno dei grandi punti di forza di RGB è la possibilità di rivelare (rivelare) o nascondere (nascondere) i campi Definizione del sigillo e Stato di proprietà a piacimento. Ciò offre una potente combinazione di riservatezza e selettività. Ad esempio, è possibile dimostrare che una transizione è valida senza rivelare tutti i dati, fornendo la versione rivelata alla persona che deve convalidarla, mentre i terzi vedono solo la versione nascosta (un hash). In pratica, l'`OpId' di una transizione è sempre calcolato a partire dai dati nascosti.

RGB-Bitcoin

Definizione di sigillo

La Definizione di Sigillo, nella sua forma rivelata, ha quattro campi di base: txptr, vout, blinding e method :

La forma concelta della Seal Definition è un hash SHA256 (taggato) della concatenazione di questi 4 campi, con un tag specifico per RGB.

RGB-Bitcoin

Stati di proprietà

Il secondo componente di Assegnazione è lo Stato di proprietà. A differenza dello Stato globale, può esistere in forma pubblica o privata:

RGB definisce quattro possibili tipi di stato (StateTypes) per uno Stato di proprietà:

SHA-256(SHA-256(tag_data) || SHA-256(tag_data) || blob)

Con, ad esempio :

tag_data = urn:lnp-bp:rgb:state-data#2024-02-12
SHA-256(SHA-256(tag_attachment) || SHA-256(tag_attachment) || file_hash || media_type || salt)

Con, ad esempio :

tag_attachment = urn:rgb:state-attach#2024-02-12

Per riassumere, ecco i 4 possibili tipi di stato nella forma pubblica e nascosta:

State                      Concealed form                              Revealed form
+---------------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------+
|                                                                                |
Declarative        |                              < void >                                          |
|                                                                                |
+--------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+             +---------------------------------------+
| +----------------------+ |             |         +--------+ +----------+       |
Fungible           | | Pedersen Commitement | | <========== |         | Amount | | Blinding |       |
| +----------------------+ |             |         +--------+ +----------+       |
+--------------------------+             +---------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+             +---------------------------------------+
| +----------------------+ |             |         +--------------------+        |
Structured         | |     Tagged Hash      | | <========== |         |     Data Blob      |        |
| +----------------------+ |             |         +--------------------+        |
+--------------------------+             +---------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+             +---------------------------------------+
| +----------------------+ |             | +-----------+ +------------+ +------+ |
Attachments        | |     Tagged Hash      | | <========== | | File Hash | | Media Type | | Salt | |
| +----------------------+ |             | +-----------+ +------------+ +------+ |
+--------------------------+             +---------------------------------------+
ElementoDichiarativoFungibileStrutturatoAllegati
DatiNessunoIntero con segno o senza segno a 64 bitQualsiasi tipo di dati rigorosoQualsiasi file
Tipo di InfoNessunoCon segno o senza segnoTipi rigorosiTipo MIME
PrivacyNon richiestaPedersen commitmentHash con blindingIdentificatore di file con hash
Limiti di dimensioneN/A256 byteFino a 64 KBFino a ~500 GB

Ingressi

Gli ingressi di una Operazione contratto si riferiscono agli Assegnamenti che vengono spesi in questa nuova operazione. Un ingresso indica :

Gli ingressi non compaiono mai nella Genesi, poiché non esistono assegnazioni precedenti. Non compaiono nemmeno nelle Estensioni di stato (perché le Estensioni di stato non chiudono i sigilli, ma ridefiniscono nuovi sigilli in base alle Valenze).

Quando abbiamo Stati posseduti di tipo Fungibile, la logica di validazione (tramite lo script AluVM fornito nello Schema) controlla la consistenza delle somme: la somma dei token in entrata (Ingressi) deve essere uguale alla somma dei token in uscita (nei nuovi Assegnamenti).

Metadati

Il campo Metadata può avere una dimensione massima di 64 KiB ed è utilizzato per includere dati temporanei utili per la convalida, ma non integrati nello stato permanente del contratto. Ad esempio, le variabili di calcolo intermedie per gli script complessi possono essere memorizzate qui. Questo spazio non è destinato a essere memorizzato nella cronologia globale, motivo per cui non rientra nell'ambito degli Stati posseduti o dello Stato globale.

Valenze

Le valenze** sono un meccanismo originale del protocollo RGB. Si possono trovare in Genesi, Transizioni di Stato o Estensioni di Stato. Rappresentano diritti numerici che possono essere attivati da un'Estensione di Stato (tramite Redenzioni), quindi finalizzati da una successiva Transizione. Ogni Valenza è identificata da un ValencyType (16 bit). La sua semantica (diritto di riemissione, scambio di token, diritto di masterizzazione, ecc.) è definita nello Schema.

In concreto, potremmo immaginare una Genesi che definisca una valenza "diritto di riemissione". Un'Estensione di Stato la consumerà (Redimissione) se sono soddisfatte determinate condizioni, per introdurre una nuova quantità di gettoni. Poi, una Transizione di Stato emanata dal titolare del sigillo così creato può trasferire questi nuovi gettoni.

Riscatta

I riscatti sono l'equivalente delle valenze per le assegnazioni. Compaiono solo nelle Estensioni di stato, poiché è qui che viene attivata una Valenza definita in precedenza. Un Riscatto è composto da due campi:

Esempio: un Riscatto può corrispondere a un'esecuzione di CoinSwap, a seconda di quanto è stato codificato nella Valenza.

Caratteristiche di stato RGB

Ora analizzeremo alcune caratteristiche fondamentali dello stato in RGB. In particolare, esamineremo :

Come sempre, si tenga presente che tutto ciò che ha a che fare con lo stato del contratto viene convalidato dal lato del cliente secondo le regole di consenso stabilite nel protocollo, il cui riferimento crittografico ultimo è ancorato alle transazioni Bitcoin.

Sistema di tipi rigoroso

RGB utilizza uno Strict Type System e una modalità di serializzazione deterministica (Strict Encoding). Questa organizzazione è pensata per garantire una perfetta riproducibilità e precisione nella definizione, nel trattamento e nella convalida dei dati contrattuali.

In molti ambienti di programmazione (JSON, YAML...), la struttura dei dati può essere flessibile, persino troppo permissiva. In RGB, invece, la struttura e i tipi di ogni campo sono definiti con vincoli espliciti. Ad esempio :

Grazie a questo rigido protocollo di codifica :

In pratica, la struttura (Schema) e il codice risultante (Interfaccia e logica associata) vengono compilati. Si utilizza un linguaggio descrittivo per definire il contratto (tipi, campi, regole) e generare un formato binario rigoroso. Una volta compilato, il risultato è :

Il sistema di tipi rigoroso consente anche un monitoraggio preciso delle modifiche: qualsiasi modifica alla struttura (anche un cambio di nome di campo) è rilevabile e può portare a una variazione dell'impronta complessiva.

Infine, ogni compilazione produce un'impronta digitale, un identificatore crittografico che attesta l'esatta versione del codice (dati, regole, validazione). Ad esempio, un identificatore della forma :

BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana

In questo modo è possibile gestire il consenso o gli aggiornamenti delle implementazioni, garantendo al contempo una tracciabilità dettagliata delle versioni utilizzate nella rete.

Per evitare che lo stato di un contratto RGB diventi troppo complicato da convalidare sul lato client, una regola di consenso impone una dimensione massima di 2^16 byte (64 Kio) per qualsiasi dato coinvolto nei calcoli di convalida. Questo vale per ogni variabile o struttura: non più di 65536 byte, o l'equivalente in numeri (32768 interi a 16 bit, ecc.). Questo vale anche per le collezioni (liste, insiemi, mappe), che non possono superare i 2^16 elementi.

Questo limite garantisce :

Il paradigma Convalida = Proprietà

Una delle principali innovazioni di RGB è la rigida separazione tra due concetti:

La convalida** avviene a livello dello stack software RGB (librerie, protocollo impegni, ecc.). Il suo ruolo è quello di garantire che le regole interne del contratto (importi, autorizzazioni, ecc.) siano rispettate. Anche gli osservatori o altri partecipanti possono convalidare la cronologia dei dati.

La proprietà**, invece, si basa interamente sulla sicurezza di Bitcoin. Possedere la chiave privata di un UTXO significa controllare la capacità di avviare una nuova transizione (chiusura del sigillo monouso). Quindi, anche se qualcuno può vedere o convalidare i dati, non può cambiare lo stato se non possiede l'UTXO in questione.

RGB-Bitcoin

Questo approccio limita le classiche vulnerabilità riscontrate nelle blockchain più complesse (dove tutto il codice di uno smart contract è pubblico e modificabile da chiunque, cosa che a volte ha portato ad hackeraggi). Su RGB, un attaccante non può semplicemente interagire con lo stato della catena, poiché il diritto di agire sullo stato (proprietà) è protetto dal livello Bitcoin.

Inoltre, questo disaccoppiamento consente a RGB di integrarsi naturalmente con la rete Lightning. I canali Lightning possono essere utilizzati per coinvolgere e spostare le risorse RGB senza dover impegnare ogni volta gli impegni della catena. Nei capitoli successivi del corso esamineremo più da vicino l'integrazione di RGB con Lightning.

Sviluppi del consenso in RGB

Oltre al versioning semantico del codice, RGB include un sistema di evoluzione o aggiornamento delle regole di consenso di un contratto nel tempo. Esistono due forme principali di evoluzione:

Un avanzamento rapido si verifica quando una regola precedentemente non valida diventa valida. Ad esempio, se il contratto si evolve per consentire un nuovo tipo di AssignmentType o un nuovo campo :

Un push-back significa che una regola precedentemente valida diventa non valida. Si tratta quindi di un "indurimento" delle regole, ma non di un softfork in senso stretto:

In questo capitolo sulle operazioni di contratto RGB, abbiamo esplorato i principi fondamentali alla base di questo protocollo. Come avrete notato, la complessità intrinseca del protocollo RGB richiede l'uso di molti termini tecnici. Nel prossimo capitolo, quindi, vi fornirò un glossario che riassumerà tutti i concetti trattati in questa prima parte teorica, con le definizioni di tutti i termini tecnici relativi a RGB. Poi, nella prossima sezione, daremo uno sguardo pratico alla definizione e all'implementazione dei contratti RGB.

Glossario RGB

Se avete bisogno di tornare a questo breve glossario di termini tecnici importanti utilizzati nel mondo RGB (elencati in ordine alfabetico), lo troverete utile. Questo capitolo non è essenziale se avete già compreso tutto ciò che abbiamo trattato nella prima sezione.

AluVM

L'abbreviazione AluVM sta per "Algorithmic logic unit Virtual Machine", una macchina virtuale basata su registri progettata per la convalida di contratti smart e per il calcolo distribuito. È utilizzata (ma non esclusivamente riservata) per la convalida dei contratti RGB. Gli script o le operazioni incluse in un contratto RGB possono quindi essere eseguiti nell'ambiente AluVM.

Per ulteriori informazioni: Sito ufficiale di AluVM

Ancora

Un Anchor rappresenta un insieme di dati lato client utilizzati per dimostrare l'inclusione di un unico commitment in una transazione. Nel protocollo RGB, un Anchor è composto dai seguenti elementi:

Un Anchor serve quindi a stabilire un legame verificabile tra una specifica transazione Bitcoin e i dati privati convalidati dal protocollo RGB. Garantisce che questi dati siano effettivamente inclusi nella blockchain, senza che il loro contenuto esatto sia esposto pubblicamente.

Assegnazione

Nella logica di RGB, un Assignment è l'equivalente di un output di transazione che modifica, aggiorna o crea determinate proprietà all'interno dello stato di un contratto. Un Assignment comprende due elementi:

Un'assegnazione indica quindi che una parte dello stato (ad esempio, un bene) è ora assegnata a un particolare titolare, identificato tramite un sigillo monouso collegato a un UTXO.

Logica aziendale

La Business Logic raggruppa tutte le regole e le operazioni interne di un contratto, descritte dal suo schema (cioè la struttura del contratto stesso). Stabilisce come può evolvere lo stato del contratto e in quali condizioni.

Convalida lato client

La convalida lato client si riferisce al processo con cui ogni parte (client) verifica un insieme di dati scambiati privatamente, secondo le regole di un protocollo. Nel caso di RGB, questi dati scambiati sono raggruppati in quelli che sono noti come conferimenti. A differenza del protocollo Bitcoin, che richiede la pubblicazione di tutte le transazioni sulla catena, RGB consente di memorizzare pubblicamente solo gli impegni (ancorati in Bitcoin), mentre le informazioni essenziali del contratto (transizioni, attestazioni, prove) rimangono fuori dalla catena, condivise solo tra gli utenti interessati.

Impegno

Un impegno (in senso crittografico) è un oggetto matematico, indicato con C, derivato deterministicamente da un'operazione su dati strutturati m (il messaggio) e un valore casuale r. Scriviamo :

C = \text{commit}(m, r)

Questo meccanismo comprende due operazioni principali:

Un impegno deve rispettare due proprietà:

m' : \, | \, : m' \neq m \quad \text{and} \quad r' : \, | \, : r' \neq r \quad

Come ad esempio :

\text{verify}(m, r, C) = \text{verify}(m', r', C) \rightarrow \text{True}

Nel protocollo RGB, un impegno è incluso in una transazione Bitcoin per dimostrare l'esistenza di una certa informazione in un determinato momento, senza rivelare l'informazione stessa.

In conto vendita

Una Consegna raggruppa i dati scambiati tra le parti, soggetti a convalida lato cliente in RGB. Esistono due categorie principali di spedizioni:

Questi invii non vengono registrati pubblicamente sulla blockchain, ma vengono scambiati direttamente tra le parti interessate attraverso il canale di comunicazione di loro scelta.

Contratto

Un Contratto è un insieme di diritti eseguiti digitalmente tra diversi attori tramite il protocollo RGB. Ha uno stato attivo e una logica di business, definita da uno Schema, che specifica quali operazioni sono autorizzate (trasferimenti, estensioni, ecc.). Lo stato di un contratto, così come le sue regole di validità, sono espressi nello Schema. In qualsiasi momento, il contratto si evolve solo in base a quanto consentito da questo Schema e dagli script di validazione (eseguiti, ad esempio, in AluVM).

Operazione a contratto

Una Contract Operation è un aggiornamento dello stato del contratto eseguito secondo le regole di Schema. In RGB esistono le seguenti operazioni:

Ogni operazione modifica lo stato aggiungendo o sostituendo alcuni dati (Stato globale, Stato di proprietà...).

Partecipante al contratto

Un partecipante al contratto è un attore che prende parte alle operazioni relative al contratto. In RGB si distingue tra :

Diritti contrattuali

I diritti contrattuali si riferiscono ai vari diritti che possono essere esercitati dai soggetti coinvolti in un contratto RGB. Essi si dividono in diverse categorie:

Stato del contratto

Lo Stato del contratto corrisponde allo stato attuale di un contratto in un determinato momento. Può essere composto da dati pubblici e privati, che riflettono lo stato del contratto. RGB distingue tra :

Impegno deterministico di Bitcoin - DBC

Il Deterministic Bitcoin Commitment (DBC) è l'insieme di regole utilizzate per registrare in modo certo e univoco un impegno in una transazione Bitcoin. Nel protocollo RGB, esistono due forme principali di DBC:

Questi meccanismi definiscono con precisione il modo in cui l'impegno viene codificato nell'output o nella struttura di una transazione Bitcoin, per garantire che tale impegno sia deterministicamente tracciabile e verificabile.

Grafico aciclico diretto - DAG

Un DAG (o grafo guidato aciclico) è un grafo privo di cicli, che consente una programmazione topologica. Le blockchain, come gli shard dei contratti RGB, possono essere rappresentate da DAG.

Per ulteriori informazioni: Grafico Aciclico Diretto

Incisione

L'incisione è una stringa di dati opzionale che i proprietari successivi di un contratto possono inserire nella cronologia del contratto. Questa funzione esiste, ad esempio, nell'interfaccia RGB21 e consente di aggiungere informazioni commemorative o descrittive alla cronologia dei contratti.

Prova di transazione extra - ETP

L'ETP (Extra Transaction Proof) è la parte dell'Anchor che contiene i dati aggiuntivi necessari per convalidare un impegno di un Tapret (nel contesto di taproot). Include, tra l'altro, la chiave pubblica interna dello script taproot (internal PubKey) e informazioni specifiche del Script Path Spend.

Genesi

Genesis si riferisce all'insieme di dati, governati da uno Schema, che costituisce lo stato iniziale di qualsiasi contratto in RGB. Può essere paragonato al concetto di Blocco Genesi di Bitcoin, o al concetto di transazione di Coinbase, ma qui a livello di client-side e di token RGB.

Stato globale

Lo Stato globale è l'insieme delle proprietà pubbliche contenute nello Stato del contratto. È definito in Genesis e, a seconda delle regole del contratto, può essere aggiornato da transizioni autorizzate. A differenza degli Stati di proprietà, lo Stato globale non appartiene a un'entità particolare; è più vicino a un registro pubblico all'interno del contratto.

Interfaccia

L'interfaccia è l'insieme delle istruzioni utilizzate per decodificare i dati binari compilati in uno schema o nelle operazioni contrattuali e i loro stati, al fine di renderli leggibili per l'utente o il suo portafoglio. Agisce come un livello di interpretazione.

Implementazione dell'interfaccia

L'implementazione dell'interfaccia è l'insieme delle dichiarazioni che collegano una interfaccia a uno schema. Consente la traduzione semantica effettuata dall'Interfaccia stessa, in modo che i dati grezzi di un contratto possano essere compresi dall'utente o dal software coinvolto (i portafogli).

Fattura

Una fattura assume la forma di un URL codificato in base58, che incorpora i dati necessari per la costruzione di una Transizione di Stato (da parte del pagatore). In altre parole, è una fattura che consente alla controparte (pagatore) di creare la transizione corrispondente per trasferire il bene o aggiornare lo stato del contratto.

Rete di fulmini

La Lightning Network è una rete decentralizzata di canali di pagamento (o state channels) su Bitcoin, composta da 2/2 portafogli multi-firma. Consente transazioni off-chain veloci e a basso costo, affidandosi al livello 1 di Bitcoin per l'arbitrato (o la chiusura) quando necessario.

Per maggiori informazioni sul funzionamento di Lightning, vi consiglio di seguire quest'altro corso:

https://planb.network/courses/34bd43ef-6683-4a5c-b239-7cb1e40a4aeb

Impegno multiprotocollo - MPC

Multi Protocol Commitment (MPC) si riferisce alla struttura ad albero di Merkle utilizzata in RGB per includere, all'interno di una singola transazione Bitcoin, diversi Transition Bundles provenienti da contratti diversi. L'idea è quella di raggruppare diversi impegni (potenzialmente corrispondenti a diversi contratti o a diverse attività) in un unico punto di ancoraggio per ottimizzare l'occupazione dello spazio dei blocchi.

Stato di proprietà

Uno Stato di proprietà è la parte di uno Stato contrattuale racchiusa in un'assegnazione e associata a un particolare titolare (tramite un sigillo monouso che punta a un UTXO). Rappresenta, ad esempio, un bene digitale o uno specifico diritto contrattuale assegnato a quella persona.

Proprietà

La proprietà si riferisce alla capacità di controllare e spendere un UTXO a cui fa riferimento una Seal Definition. Quando uno Stato di proprietà è collegato a un UTXO, il proprietario di questo UTXO ha il diritto, potenzialmente, di trasferire o far evolvere lo Stato associato, secondo le regole del contratto.

Transazione Bitcoin parzialmente firmata - PSBT

Una PSBT (Partially Signed Bitcoin Transaction) è una transazione Bitcoin non ancora completamente firmata. Può essere condivisa tra diverse entità, ognuna delle quali può aggiungere o verificare alcuni elementi (firme, script...), finché la transazione non viene considerata pronta per la distribuzione sulla catena.

Per ulteriori informazioni: BIP-0174

Impegno di Pedersen

Un impegno Pedersen è un tipo di impegno crittografico con la proprietà di essere omorfo rispetto all'operazione di addizione. Ciò significa che è possibile convalidare la somma di due impegni senza rivelare i singoli valori.

Formalmente, se :

C1=\text{commit}(m1,r1) \quad C2=\text{commit}(m2,r2)

allora :

C3=C1⋅C2=\text{commit}(m1+m2, r1+r2)

Questa proprietà è utile, ad esempio, per nascondere le quantità di gettoni scambiati, pur potendo verificare i totali.

Ulteriori informazioni: Pedersen commitment

Riscatto

In un'Estensione di Stato, il Riscatto si riferisce all'azione di rivendicare (o sfruttare) una Valenza precedentemente dichiarata. Poiché una Valenza è un diritto pubblico, il Riscatto consente a un partecipante autorizzato di rivendicare una specifica estensione di stato del contratto.

Schema

Uno Schema in RGB è un pezzo di codice dichiarativo che descrive l'insieme di variabili, regole e logica aziendale (Business Logic) che regolano il funzionamento di un contratto. Lo schema definisce la struttura degli stati, i tipi di transizioni consentite e le condizioni di convalida.

Definizione di sigillo

La Definizione del sigillo è la parte di un'assegnazione che associa l'impegno a un UTXO di proprietà del nuovo titolare. In altre parole, indica dove si trova la condizione (in quale UTXO) e stabilisce la proprietà di un bene o di un diritto.

Frammento

Uno Shard rappresenta un ramo nel DAG della storia delle transizioni di stato di un contratto RGB. In altre parole, è un sottoinsieme coerente della storia complessiva del contratto, corrispondente, ad esempio, alla sequenza di transizioni necessarie per dimostrare la validità di un determinato bene fin dalla Genesi.

Sigillo monouso

Un sigillo monouso è una promessa crittografica di impegno per un messaggio ancora sconosciuto, che sarà rivelato solo una volta in futuro e deve essere conosciuto da tutti i membri di un pubblico specifico. Lo scopo è quello di impedire la creazione di più impegni concorrenti per lo stesso sigillo.

Stash

Lo Stash è l'insieme dei dati lato client che un utente memorizza per uno o più contratti RGB, ai fini della convalida (convalida lato client). Comprende la cronologia delle transizioni, gli invii, le prove di validità, ecc. Ogni titolare conserva solo le parti dello storico di cui ha bisogno (shard).

Estensione dello Stato

Un'Estensione di Stato è un'operazione contrattuale utilizzata per riattivare gli aggiornamenti di stato riscattando le Valenze precedentemente dichiarate. Per essere efficace, una State Extension deve essere chiusa da una State Transition (che aggiorna lo stato finale del contratto).

Transizione di stato

La transizione di stato è l'operazione che cambia lo stato di un contratto RGB in un nuovo stato. Può modificare i dati dello Stato globale e/o dello Stato di proprietà. In pratica, ogni transizione è verificata dalle regole dello Schema e ancorata alla blockchain Bitcoin tramite un commitment.

Radice di fittone

Si riferisce al formato di transazione Segwit v1 di Bitcoin, introdotto da BIP341 e BIP342. Taproot migliora la riservatezza e la flessibilità degli script, in particolare rendendo le transazioni più compatte e più difficili da distinguere l'una dall'altra.

Spedizione terminale - Punto finale di spedizione

Il Terminal Consignment (o Consignment Endpoint) è un trasferimento consignment contenente lo stato finale del contratto, inclusa la State Transition creata dalla Fattura del destinatario (pagatore). È quindi il punto finale di un trasferimento, con i dati necessari a dimostrare che la proprietà o lo stato sono stati trasferiti.

Pacchetto di transizione

Un pacchetto di transizioni è un insieme di transizioni di stato RGB (appartenenti allo stesso contratto) che sono tutte impegnate nella stessa transazione di testimonianza Bitcoin. Ciò consente di raggruppare diversi aggiornamenti o trasferimenti in un'unica ancora sulla catena.

UTXO

Un Bitcoin UTXO (Unspent Transaction Output) è definito dall'hash di una transazione e dall'indice di uscita (vout). A volte viene anche chiamato outpoint. Nel protocollo RGB, il riferimento a un UTXO (tramite una Seal Definition) consente di individuare lo Owned State, ossia la proprietà detenuta sulla blockchain.

Valenza

Una Valenza è un diritto pubblico che non richiede la conservazione dello Stato in quanto tale, ma che può essere riscattato tramite una Estensione di Stato. Si tratta quindi di una forma di possibilità aperta a tutti (o a determinati giocatori), dichiarata nella logica del contratto, al fine di effettuare una particolare estensione in una data successiva.

Testimonianza di transazione

La transazione del testimone è la transazione Bitcoin che chiude il sigillo monouso attorno a un messaggio contenente un impegno multiprotocollo (MPC). Questa transazione spende un UTXO o ne crea uno, in modo da sigillare l'impegno legato al protocollo RGB. Agisce come prova sulla catena che lo stato è stato impostato in un momento specifico.

Programmazione su RGB

Implementazione dei contratti RGB

In questo capitolo vedremo da vicino come viene definito e implementato un contratto RGB. Vedremo quali sono i componenti di un contratto RGB, quali sono i loro ruoli e come vengono costruiti.

I componenti di un contratto RGB

Finora abbiamo già parlato della Genesi, che rappresenta il punto di partenza di un contratto, e abbiamo visto come si inserisce nella logica di una Operazione di contratto e nello stato del protocollo. La definizione completa di un contratto RGB, tuttavia, non si limita alla sola Genesi: coinvolge tre componenti complementari che, insieme, costituiscono il cuore dell'implementazione.

Il primo componente è chiamato Schema. Si tratta di un file che descrive la struttura fondamentale e la logica aziendale (business logic) del contratto. Specifica i tipi di dati utilizzati, le regole di convalida, le operazioni consentite (ad esempio, l'emissione iniziale di token, i trasferimenti, le condizioni speciali e così via) - in breve, il quadro generale che detta il funzionamento del contratto.

Il secondo componente è l'interfaccia. Si concentra sul modo in cui gli utenti (e, per estensione, il software del portafoglio) interagiranno con questo contratto. Descrive la semantica, cioè la rappresentazione leggibile dei vari campi e delle azioni. Quindi, mentre lo Schema definisce come funziona tecnicamente il contratto, l'Interfaccia definisce come presentare ed esporre queste funzionalità: nomi dei metodi, visualizzazione dei dati, ecc.

Il terzo componente è l'Interface Implementation, che completa i due precedenti agendo come una sorta di ponte tra lo Schema e l'Interfaccia. In altre parole, associa la semantica espressa dall'Interfaccia alle regole sottostanti definite nello Schema. È questa implementazione che gestirà, ad esempio, la conversione tra un parametro inserito nel portafoglio e la struttura binaria imposta dal protocollo, o la compilazione delle regole di validazione in linguaggio macchina.

Questa modularità è una caratteristica interessante di RGB, in quanto consente a diversi gruppi di sviluppatori di lavorare separatamente su questi aspetti (Schema, Interfaccia, Implementazione), purché seguano le regole di consenso del protocollo.

In sintesi, ogni contratto è composto da :

RGB-Bitcoin

È importante notare che affinché un portafoglio possa gestire un asset RGB (sia esso un token fungibile o un diritto di qualsiasi tipo), deve avere tutti questi elementi compilati: Schema, Interfaccia, Implementazione dell'interfaccia e Genesi. Il tutto viene trasmesso tramite un invio di contratto, ovvero un pacchetto di dati contenente tutto ciò che serve per convalidare il contratto lato cliente.

Per chiarire queste nozioni, ecco una tabella riassuntiva che confronta i componenti di un contratto RGB con concetti già noti nella programmazione orientata agli oggetti (OOP) o nell'ecosistema Ethereum:

Componente del contratto RGBSignificatoEquivalente OOPEquivalente Ethereum
GenesisStato iniziale del contrattoCostruttore di classeCostruttore del contratto
SchemaLogica aziendale del contrattoClasseContratto
InterfaceSemantica del contrattoInterfaccia (Java) / Trait (Rust) / Protocollo (Swift)Standard ERC
Interface ImplementationMappatura della semantica e logicaImpl (Rust) / Implements (Java)Application Binary Interface (ABI)

La colonna di sinistra mostra gli elementi specifici del protocollo RGB. La colonna centrale mostra la funzione concreta di ciascun componente. Poi, nella colonna "equivalente OOP", troviamo il termine equivalente nella programmazione orientata agli oggetti:

Nel contesto di Ethereum, la Genesi è più vicina al costruttore del contratto, lo Schema alla definizione del contratto, l'Interfaccia a uno standard come ERC-20 o ERC-721 e l'Implementazione dell'Interfaccia all'ABI (Application Binary Interface), che specifica il formato delle interazioni con il contratto.

Il vantaggio della modularità di RGB risiede anche nel fatto che diverse parti interessate possono scrivere, ad esempio, la propria implementazione dell'interfaccia, purché rispettino la logica dello Schema e la semantica dell'Interfaccia. In questo modo, un emittente potrebbe sviluppare un nuovo front-end (interfaccia) più facile da usare, senza modificare la logica del contratto, o viceversa, si potrebbe estendere lo Schema per aggiungere funzionalità e fornire una nuova versione dell'implementazione dell'interfaccia adattata, mentre le vecchie implementazioni rimarrebbero valide per le funzionalità di base.

Quando compiliamo un nuovo contratto, generiamo una Genesi (il primo passo per l'emissione o la distribuzione dell'asset), nonché i suoi componenti (Schema, Interfaccia, Implementazione dell'interfaccia). Dopodiché, il contratto è pienamente operativo e può essere propagato ai portafogli e agli utenti. Questo metodo, in cui Genesis è combinato con questi tre componenti, garantisce un alto grado di personalizzazione (ogni contratto può avere una propria logica), decentralizzazione (tutti possono contribuire a un determinato componente) e sicurezza (la convalida rimane rigorosamente definita dal protocollo, senza dipendere da codice arbitrario sulla catena, come spesso accade su altre blockchain).

Vorrei ora dare un'occhiata più da vicino a ciascuno di questi componenti: lo Schema, l'Interfaccia e l'Implementazione dell'interfaccia.

Schema

Nella sezione precedente abbiamo visto che nell'ecosistema RGB un contratto è composto da diversi elementi: la Genesi, che stabilisce lo stato iniziale, e diversi altri componenti complementari. Lo scopo dello Schema è quello di descrivere in modo dichiarativo tutta la logica di business del contratto, ovvero la struttura dei dati, i tipi utilizzati, le operazioni consentite e le loro condizioni. È quindi un elemento molto importante per rendere operativo un contratto sul lato client, poiché ogni partecipante (un portafoglio, ad esempio) deve verificare che le transizioni di stato che riceve siano conformi alla logica definita nello Schema.

Uno schema può essere paragonato a una "classe" nella programmazione orientata agli oggetti (OOP). In generale, serve come modello che definisce i componenti di un contratto, come ad esempio :

RGB-Bitcoin

Quando l'emittente di un asset su RGB pubblica un contratto, fornisce la Genesi e lo Schema ad esso associato. Gli utenti o i portafogli che desiderano interagire con l'asset recuperano questo Schema per comprendere la logica alla base del contratto e per poter verificare in seguito che le transizioni a cui parteciperanno siano legittime.

Il primo passo, per chiunque riceva informazioni su un asset RGB (ad esempio un trasferimento di token), è quello di convalidare queste informazioni rispetto allo Schema. Ciò comporta l'utilizzo della compilazione dello Schema per :

In pratica, Schema non è codice eseguibile, come si può vedere nelle blockchain che memorizzano codice on-chain (EVM su Ethereum). Al contrario, RGB separa la logica aziendale (dichiarativa) dal codice eseguibile sulla blockchain (che è limitato alle ancore crittografiche). In questo modo, lo Schema determina le regole, ma l'applicazione di queste regole avviene al di fuori della blockchain, sul sito di ciascun partecipante, secondo il principio della Convalida lato client.

Uno schema deve essere compilato prima di poter essere utilizzato dalle applicazioni RGB. Questa compilazione produce un file binario (ad esempio .rgb) o un file binario criptato (.rgba). Quando il portafoglio importa questo file, sa che :

Come spiegato nei capitoli precedenti, il sistema di tipi severi ci fornisce un formato di codifica stabile e deterministico: tutte le variabili, siano esse Stati posseduti, Stati globali o Valenze, sono descritte con precisione (dimensione, limiti inferiori e superiori se necessario, tipo firmato o non firmato, ecc.) È anche possibile definire strutture annidate, ad esempio per supportare casi d'uso complessi.

Facoltativamente, lo schema può fare riferimento a uno SchemaId principale, che facilita il riutilizzo di una struttura di base esistente (un modello). In questo modo, è possibile evolvere un contratto o creare variazioni (ad esempio un nuovo tipo di token) da un modello già collaudato. Questa modularità evita la necessità di ricreare interi contratti e incoraggia la standardizzazione delle migliori pratiche.

Un altro punto importante è che la logica dell'evoluzione dello stato (trasferimenti, aggiornamenti, ecc.) è descritta nello Schema sotto forma di script, regole e condizioni. Quindi, se il progettista del contratto desidera autorizzare una riemissione o imporre un meccanismo di bruciatura (distruzione dei token), può specificare gli script corrispondenti per AluVM nella parte di validazione dello Schema.

Differenza rispetto alle blockchain on-chain programmabili

A differenza di sistemi come Ethereum, dove il codice dello smart contract (eseguibile) è scritto nella blockchain stessa, RGB memorizza il contratto (la sua logica) fuori dalla catena, sotto forma di documento dichiarativo compilato. Ciò implica che :

Utilizzo da parte dell'emittente e degli utenti

Quando un emittente crea un'attività (ad esempio, un gettone fungibile non inflazionistico), prepara :

Mette quindi a disposizione degli utenti lo Schema compilato (un file .rgb), in modo che chiunque riceva un trasferimento di questo token possa verificare localmente la coerenza dell'operazione. Senza questo Schema, un utente non sarebbe in grado di interpretare i dati di stato o di verificare la conformità alle regole del contratto.

Quindi, quando un nuovo portafoglio vuole supportare un asset, deve semplicemente integrare il relativo Schema. Questo meccanismo consente di aggiungere la compatibilità a nuovi tipi di asset RGB, senza modificare in modo invasivo il software di base del portafoglio: è sufficiente importare il binario dello Schema e comprenderne la struttura.

Lo Schema definisce la logica di business in RGB. Elenca le regole di evoluzione di un contratto, la struttura dei suoi dati (Stati di proprietà, Stato globale, Valenze) e gli script di validazione associati (eseguibili da AluVM). Grazie a questo documento dichiarativo, la definizione di un contratto (file compilato) è chiaramente separata dall'effettiva esecuzione delle regole (lato client). Questo disaccoppiamento conferisce a RGB una grande flessibilità, consentendo un'ampia gamma di casi d'uso (token fungibili, NFT, contratti più sofisticati) ed evitando al contempo la complessità e i difetti tipici delle blockchain programmabili on-chain.

Esempio di schema

Vediamo un esempio concreto di Schema per un contratto RGB. Si tratta di un estratto in Rust del file nia.rs (iniziali di "Non-Inflatable Assets"), che definisce un modello per i token fungibili che non possono essere riemessi oltre la loro fornitura iniziale (un asset non inflazionistico). Questo tipo di token può essere visto come l'equivalente, nell'universo RGB, dell'ERC20 di Ethereum, cioè token fungibili che rispettano alcune regole di base (ad esempio sui trasferimenti, sull'inizializzazione della fornitura, ecc.)

Prima di immergersi nel codice, vale la pena ricordare la struttura generale di uno schema RGB. C'è una serie di dichiarazioni che incorniciano :

RGB-Bitcoin

Il codice sottostante mostra la definizione completa dello schema di Rust. Lo commenteremo parte per parte, seguendo le annotazioni da (1) a (9):

// ===== PART 1: Function Header and SubSchema =====
fn nia_schema() -> SubSchema {
// definitions of libraries and variables
// ===== PART 2: General Properties (ffv, subset_of, type_system) =====
Schema {
ffv: zero!(),
subset_of: None,
type_system: types.type_system(),
// ===== PART 3: Global States =====
global_types: tiny_bmap! {
GS_NOMINAL => GlobalStateSchema::once(types.get("RGBContract.DivisibleAssetSpec")),
GS_DATA => GlobalStateSchema::once(types.get("RGBContract.ContractData")),
GS_TIMESTAMP => GlobalStateSchema::once(types.get("RGBContract.Timestamp")),
GS_ISSUED_SUPPLY => GlobalStateSchema::once(types.get("RGBContract.Amount")),
},
// ===== PART 4: Owned Types =====
owned_types: tiny_bmap! {
OS_ASSET => StateSchema::Fungible(FungibleType::Unsigned64Bit),
},
// ===== PART 5: Valencies =====
valency_types: none!(),
// ===== PART 6: Genesis: Initial Operations =====
genesis: GenesisSchema {
metadata: Ty::<SemId>::UNIT.id(None),
globals: tiny_bmap! {
GS_NOMINAL => Occurrences::Once,
GS_DATA => Occurrences::Once,
GS_TIMESTAMP => Occurrences::Once,
GS_ISSUED_SUPPLY => Occurrences::Once,
},
assignments: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
valencies: none!(),
},
// ===== PART 7: Extensions =====
extensions: none!(),
// ===== PART 8: Transitions: TS_TRANSFER =====
transitions: tiny_bmap! {
TS_TRANSFER => TransitionSchema {
metadata: Ty::<SemId>::UNIT.id(None),
globals: none!(),
inputs: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
assignments: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
valencies: none!(),
}
},
// ===== PART 9: Script AluVM and Entry Points =====
script: Script::AluVM(AluScript {
libs: confined_bmap! { alu_id => alu_lib },
entry_points: confined_bmap! {
EntryPoint::ValidateGenesis => LibSite::with(FN_GENESIS_OFFSET, alu_id),
EntryPoint::ValidateTransition(TS_TRANSFER) => LibSite::with(FN_TRANSFER_OFFSET, alu_id),
},
}),
}
}

La funzione nia_schema() restituisce un SubSchema, indicando che questo Schema può parzialmente ereditare da uno schema più generico. Nell'ecosistema RGB, questa flessibilità consente di riutilizzare alcuni elementi standard di uno schema principale, per poi definire regole specifiche per il contratto in questione. In questo caso, si sceglie di non abilitare l'ereditarietà, poiché subset_of sarà None.

La proprietà ffv corrisponde alla versione veloce del contratto. Un valore di zero!() indica che siamo alla versione 0 o alla versione iniziale di questo schema. Se in seguito si desidera aggiungere nuove funzionalità (nuovi tipi di operazioni, ecc.), si può incrementare questa versione per indicare una modifica del consenso.

La proprietà subset_of: None conferma l'assenza di ereditarietà. Il campo type_system si riferisce al sistema di tipi rigorosi già definito nella libreria types. Questa riga indica che tutti i dati utilizzati dal contratto utilizzano l'implementazione della serializzazione rigorosa fornita dalla libreria in questione.

Nel blocco global_types, si dichiarano quattro elementi. Utilizziamo la chiave, come GS_NOMINAL o GS_ISSUED_SUPPLY, per farvi riferimento in seguito:

La parola chiave once(...) significa che ognuno di questi campi può comparire una sola volta.

In owned_types, dichiariamo OS_ASSET, che descrive uno stato fungibile. Utilizziamo StateSchema::Fungible(FungibleType::Unsigned64Bit), indicando che la quantità di asset (token) è memorizzata come un intero a 64 bit senza segno. Pertanto, ogni transazione invierà una certa quantità di unità di questo token, che sarà convalidata in base a questa struttura numerica strettamente tipizzata.

Indichiamo tipi_di_valenza: nessuno!(), il che significa che non ci sono valenze in questo schema, in altre parole non ci sono diritti speciali o extra (come la riedizione, la masterizzazione condizionale, ecc.). Se uno schema ne includesse, sarebbero dichiarate in questa sezione.

Qui entriamo nella parte che dichiara le Operazioni contrattuali. La Genesi è descritta da :

In questo modo limitiamo la definizione dell'emissione iniziale del token: dobbiamo dichiarare l'offerta emessa (GS_ISSUED_SUPPLY), più almeno un possessore (un Owned State di tipo OS_ASSET).

Il campo estensioni: nessuna!() indica che in questo contratto non è prevista alcuna estensione di stato. Ciò significa che non esiste alcuna operazione per riscattare un diritto digitale (Valency) o per eseguire un'estensione di stato prima di una transizione. Tutto avviene tramite Genesi o Transizioni di Stato.

In transizioni', definiamo il tipo di operazioneTS_TRANSFER'. Spieghiamo che :

Questo modella il comportamento di un trasferimento di base, che consuma gettoni su un UTXO, quindi crea nuovi Stati Propri a favore dei destinatari, e quindi preserva l'uguaglianza dell'importo totale tra entrate e uscite.

Infine, si dichiara uno script AluVM (Script::AluVM(AluScript { ... })). Questo script contiene :

Questo codice di validazione è responsabile dell'applicazione della logica di business. Ad esempio, controllerà :

Se queste regole non vengono rispettate, la transizione sarà considerata non valida.

Questo esempio di schema "Asset fungibile non gonfiabile" ci permette di comprendere meglio la struttura di un semplice contratto di token fungibile RGB. Possiamo vedere chiaramente la separazione tra la descrizione dei dati (Stati globali e di proprietà), la dichiarazione delle operazioni (Genesi, Transizioni, Estensioni) e l'implementazione della validazione (script AluVM). Grazie a questo modello, un token si comporta come un classico token fungibile, ma rimane validato sul lato client e non dipende dall'infrastruttura on-chain per eseguire il suo codice. Solo gli impegni crittografici sono ancorati alla blockchain di Bitcoin.

Interfaccia

L'interfaccia è lo strato destinato a rendere un contratto leggibile e manipolabile, sia dagli utenti (lettura umana) che dai portafogli (lettura software). L'interfaccia svolge quindi un ruolo paragonabile a quello di un'interfaccia in un linguaggio di programmazione orientato agli oggetti (Java, Rust trait, ecc.), in quanto espone e chiarisce la struttura funzionale di un contratto, senza necessariamente rivelare i dettagli interni della logica aziendale.

A differenza di Schema, che è puramente dichiarativo e compilato in un file binario difficile da usare così com'è, Interface fornisce le chiavi di lettura necessarie per :

RGB-Bitcoin

Grazie all'interfaccia, è possibile, ad esempio, scrivere codice in un portafoglio che, invece di manipolare i campi, manipola direttamente le etichette come "numero di token", "nome dell'asset", ecc. In questo modo, la gestione di un contratto diventa più intuitiva. In questo modo, la gestione dei contratti diventa più intuitiva.

Funzionamento generale

Questo metodo presenta molti vantaggi:

Lo stesso tipo di contratto può essere supportato da un'interfaccia standard, condivisa da diverse implementazioni di portafogli. Questo facilita la compatibilità e il riutilizzo del codice.

Nella progettazione RGB, Schema (logica di business) e Interfaccia (presentazione e manipolazione) sono due entità indipendenti. Gli sviluppatori che scrivono la logica del contratto possono concentrarsi sullo Schema, senza preoccuparsi dell'ergonomia o della rappresentazione dei dati, mentre un altro team (o lo stesso team, ma con una tempistica diversa) può sviluppare l'Interfaccia.

L'interfaccia può essere modificata o aggiunta dopo l'emissione dell'asset, senza dover modificare il contratto stesso. Questa è una differenza sostanziale rispetto ad alcuni sistemi di smart contract on-chain, in cui l'interfaccia (spesso mescolata al codice di esecuzione) è congelata nella blockchain.

Lo stesso contratto potrebbe essere esposto attraverso diverse interfacce adatte a esigenze diverse: un'interfaccia semplice per l'utente finale, un'altra più avanzata per l'emittente che deve gestire operazioni di configurazione complesse. Il portafoglio può quindi scegliere quale Interfaccia importare, a seconda del suo utilizzo.

RGB-Bitcoin

In pratica, quando il portafoglio recupera un contratto RGB (tramite un file .rgb o .rgba), importa anche l'interfaccia associata, che viene anch'essa compilata. In fase di esecuzione, il portafoglio può, ad esempio :

Differenza con Ethereum e altri sistemi

Su Ethereum, l'interfaccia (descritta tramite l'ABI, Application Binary Interface) è generalmente derivata dal codice memorizzato sulla catena (lo smart contract). Può essere costoso o complicato modificare una parte specifica dell'interfaccia senza toccare il contratto stesso. Tuttavia, RGB si basa su una logica interamente fuori dalla catena, con dati ancorati in impegni su Bitcoin. Questo design consente di modificare l'interfaccia (o la sua implementazione) senza influire sulla sicurezza fondamentale del contratto, poiché la convalida delle regole commerciali rimane nello schema e nel codice AluVM di riferimento.

Compilazione dell'interfaccia

Come per gli schemi, l'interfaccia è definita nel codice sorgente (spesso in Rust) e compilata in un file .rgb o .rgba. Questo file binario contiene tutte le informazioni necessarie al portafoglio per :

Una volta importata l'interfaccia, il portafoglio può visualizzare correttamente il contratto e proporre interazioni all'utente.

Interfacce standardizzate dall'associazione LNP/BP

Nell'ecosistema RGB, un'Interfaccia viene utilizzata per dare un significato leggibile e manipolabile ai dati e alle operazioni di un contratto. L'Interfaccia integra quindi lo Schema, che descrive internamente la logica di business (tipi rigorosi, script di validazione, ecc.). In questa sezione, daremo un'occhiata alle Interfacce standard sviluppate dall'associazione LNP/BP per i tipi di contratto più comuni (token fungibili, NFT, ecc.).

Come promemoria, l'idea è che ogni Interfaccia descriva come visualizzare e manipolare un contratto dal lato del portafoglio, nominando chiaramente i campi (come spec, ticker, issuedSupply...) e definendo le possibili operazioni (come Transfer, Burn, Rename...). Diverse interfacce sono già operative, ma ce ne saranno altre in futuro.

Alcune interfacce pronte all'uso

RGB20 è l'interfaccia per gli asset fungibili, che può essere paragonata allo standard ERC20 di Ethereum. Tuttavia, si spinge oltre, offrendo funzionalità più ampie:

Ad esempio, l'interfaccia RGB20 può essere collegata allo schema Non-Inflatable Asset (NIA), che impone una fornitura iniziale non inflazionabile, o ad altri schemi più avanzati, a seconda delle esigenze.

RGB21 riguarda i contratti di tipo NFT o, più in generale, qualsiasi contenuto digitale unico, come la rappresentazione di media digitali (immagini, musica, ecc.). Oltre a descrivere l'emissione e il trasferimento di un singolo bene, include caratteristiche quali :

RGB25 è uno standard ibrido che combina aspetti fungibili e non fungibili. È stato progettato per asset parzialmente fungibili, come la tokenizzazione di immobili, in cui si desidera suddividere una proprietà mantenendo un collegamento a un singolo asset principale (in altre parole, si hanno pezzi fungibili di una casa, collegati a una casa non fungibile). Tecnicamente, questa interfaccia può essere collegata allo schema *Collectible Fungible Asset (CFA)**, che tiene conto della nozione di suddivisione, pur tracciando il bene originale.

Interfacce in fase di sviluppo

Altre interfacce sono previste per usi più specialistici, ma non sono ancora disponibili:

Naturalmente, a seconda della data di consultazione del corso, queste interfacce potrebbero essere già operative e accessibili.

Esempio di interfaccia

Questo frammento di codice di Rust mostra un'interfaccia RGB20 (risorsa fungibile). Questo codice è tratto dal file rgb20.rs della libreria standard RGB. Vediamolo per capire la struttura di un'interfaccia e come essa costituisca un ponte tra, da un lato, la logica aziendale (definita nello schema) e, dall'altro, le funzionalità esposte ai portafogli e agli utenti.

// ...
fn rgb20() -> Iface {
let types = StandardTypes::with(rgb20_stl());
Iface {
version: VerNo::V1,
name: tn!("RGB20"),
global_state: tiny_bmap! {
fname!("spec") => GlobalIface::required(types.get("RGBContract.DivisibleAssetSpec")),
fname!("data") => GlobalIface::required(types.get("RGBContract.ContractData")),
fname!("created") => GlobalIface::required(types.get("RGBContract.Timestamp")),
fname!("issuedSupply") => GlobalIface::one_or_many(types.get("RGBContract.Amount")),
fname!("burnedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")),
fname!("replacedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")),
},
assignments: tiny_bmap! {
fname!("inflationAllowance") => AssignIface::public(OwnedIface::Amount, Req::NoneOrMore),
fname!("updateRight") => AssignIface::public(OwnedIface::Rights, Req::Optional),
fname!("burnEpoch") => AssignIface::public(OwnedIface::Rights, Req::Optional),
fname!("burnRight") => AssignIface::public(OwnedIface::Rights, Req::NoneOrMore),
fname!("assetOwner") => AssignIface::private(OwnedIface::Amount, Req::NoneOrMore),
},
valencies: none!(),
genesis: GenesisIface {
metadata: Some(types.get("RGBContract.IssueMeta")),
global: tiny_bmap! {
fname!("spec") => ArgSpec::required(),
fname!("data") => ArgSpec::required(),
fname!("created") => ArgSpec::required(),
fname!("issuedSupply") => ArgSpec::required(),
},
assignments: tiny_bmap! {
fname!("assetOwner") => ArgSpec::many(),
fname!("inflationAllowance") => ArgSpec::many(),
fname!("updateRight") => ArgSpec::optional(),
fname!("burnEpoch") => ArgSpec::optional(),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_RESERVES
},
},
transitions: tiny_bmap! {
tn!("Transfer") => TransitionIface {
optional: false,
metadata: None,
globals: none!(),
inputs: tiny_bmap! {
fname!("previous") => ArgSpec::from_non_empty("assetOwner"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_non_empty("assetOwner"),
},
valencies: none!(),
errors: tiny_bset! {
NON_EQUAL_AMOUNTS
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("Issue") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.IssueMeta")),
globals: tiny_bmap! {
fname!("issuedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_non_empty("inflationAllowance"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_many("assetOwner"),
fname!("future") => ArgSpec::from_many("inflationAllowance"),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
ISSUE_EXCEEDS_ALLOWANCE,
INSUFFICIENT_RESERVES
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("OpenEpoch") => TransitionIface {
optional: true,
metadata: None,
globals: none!(),
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnEpoch"),
},
assignments: tiny_bmap! {
fname!("next") => ArgSpec::from_optional("burnEpoch"),
fname!("burnRight") => ArgSpec::required()
},
valencies: none!(),
errors: none!(),
default_assignment: Some(fname!("burnRight")),
},
tn!("Burn") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.BurnMeta")),
globals: tiny_bmap! {
fname!("burnedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnRight"),
},
assignments: tiny_bmap! {
fname!("future") => ArgSpec::from_optional("burnRight"),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_COVERAGE
},
default_assignment: None,
},
tn!("Replace") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.BurnMeta")),
globals: tiny_bmap! {
fname!("replacedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnRight"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_many("assetOwner"),
fname!("future") => ArgSpec::from_optional("burnRight"),
},
valencies: none!(),
errors: tiny_bset! {
NON_EQUAL_AMOUNTS,
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_COVERAGE
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("Rename") => TransitionIface {
optional: true,
metadata: None,
globals: tiny_bmap! {
fname!("new") => ArgSpec::from_required("spec"),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("updateRight"),
},
assignments: tiny_bmap! {
fname!("future") => ArgSpec::from_optional("updateRight"),
},
valencies: none!(),
errors: none!(),
default_assignment: Some(fname!("future")),
},
},
extensions: none!(),
error_type: types.get("RGB20.Error"),
default_operation: Some(tn!("Transfer")),
type_system: types.type_system(),
}
}

In questa interfaccia, notiamo delle somiglianze con la struttura dello Schema: troviamo una dichiarazione dello Stato globale, degli Stati posseduti, delle Operazioni contrattuali (Genesi e Transizioni), nonché la gestione degli errori. Ma l'Interfaccia si concentra sulla presentazione e sulla manipolazione di questi elementi per un portafoglio o per qualsiasi altra applicazione.

La differenza con Schema sta nella natura dei tipi. Schema utilizza tipi rigidi (come FungibleType::Unsigned64Bit) e identificatori più tecnici. L'interfaccia utilizza nomi di campi, macro (fname!(), tn!()) e riferimenti a classi di argomenti (ArgSpec, OwnedIface::Rights...). L'obiettivo è quello di facilitare la comprensione funzionale e l'organizzazione degli elementi per il portafoglio.

Inoltre, l'Interfaccia può introdurre funzionalità aggiuntive allo Schema di base (ad esempio, la gestione di un diritto burnEpoch), purché rimanga coerente con la logica finale convalidata sul lato client. La sezione "script" di AluVM nello Schema garantirà la validità crittografica, mentre l'Interfaccia descrive come l'utente (o il portafoglio) interagisce con questi stati e transizioni.

Stato globale e incarichi

Nella sezione global_state, troviamo campi come spec (descrizione dell'asset), data, created, issuedSupply, burnedSupply, replacedSupply. Si tratta di campi che il portafoglio può leggere e presentare. Ad esempio:

Nella sezione `assegnazioni' si definiscono vari ruoli o diritti. Ad esempio:

La parola chiave public o private (ad esempio AssignIface::public(...)) indica se questi stati sono visibili (public) o riservati (private). Per quanto riguarda Req::NoneOrMore, Req::Optional, indicano l'occorrenza prevista.

Genesi e transizioni

La parte genesi descrive come viene inizializzata la risorsa:

Poi, per ogni transizione (Transfer, Issue, Burn...), l'interfaccia definisce quali campi l'operazione si aspetta come input, quali campi l'operazione produrrà come output e gli eventuali errori che possono verificarsi. Per esempio:

Transizione :

Transizione Issue :

Transizione di fuoco :

Ogni operazione è quindi descritta in modo leggibile per un portafoglio. Ciò consente di visualizzare un'interfaccia grafica in cui l'utente può vedere chiaramente: "Hai il diritto di bruciare. Vuoi bruciare una certa quantità? Il codice sa che deve compilare un campo burnedSupply e verificare che il burnRight sia valido.

Per riassumere, è importante tenere presente che un'interfaccia, per quanto completa, non definisce da sola la logica interna del contratto. Il cuore del lavoro è svolto dallo Schema, che include tipi rigorosi, struttura di Genesis, transizioni e così via. L'interfaccia espone semplicemente questi elementi in modo più intuitivo e con un nome, per poterli utilizzare in un'applicazione.

Grazie alla modularità di RGB, l'interfaccia può essere aggiornata (ad esempio, aggiungendo una transizione Rename, correggendo la visualizzazione di un campo e così via) senza dover riscrivere l'intero contratto. Gli utenti di questa interfaccia possono quindi beneficiare immediatamente di questi miglioramenti, non appena aggiornano il file .rgb o .rgba.

Ma una volta dichiarata un'interfaccia, è necessario collegarla allo schema corrispondente. Ciò avviene tramite l'Interface Implementation, che specifica come mappare ogni campo denominato (come fname!("assetOwner")) all'ID rigoroso (come OS_ASSET) definito nello schema. Questo assicura, ad esempio, che quando un portafoglio manipola un campo burnRight, questo sia lo stato che, nello Schema, descrive la capacità di bruciare token.

Implementazione dell'interfaccia

Nell'architettura RGB, abbiamo visto che ogni componente (Schema, Interfaccia, ecc.) può essere sviluppato e compilato indipendentemente. Tuttavia, c'è ancora un elemento indispensabile che collega tra loro questi diversi blocchi costruttivi: l'Interface Implementation. È questa che mappa esplicitamente gli identificatori o i campi definiti nello Schema (dal lato della logica aziendale) ai nomi dichiarati nell'Interfaccia (dal lato della presentazione e dell'interazione con l'utente). In questo modo, quando un portafoglio carica un contratto, può capire esattamente a quale campo corrisponde cosa, e come un'operazione denominata nell'Interfaccia si riferisce alla logica dello Schema.

Un punto importante è che l'implementazione dell'interfaccia non è necessariamente destinata a esporre tutte le funzionalità dello schema, né tutti i campi dell'interfaccia: può essere limitata a un sottoinsieme. In pratica, ciò consente di limitare o filtrare alcuni aspetti dello schema. Ad esempio, si potrebbe avere uno Schema con quattro tipi di operazioni, ma un'Interfaccia di implementazione che ne mappa solo due in un determinato contesto. Al contrario, se un'interfaccia propone endpoint aggiuntivi, si può scegliere di non implementarli qui.

Ecco un classico esempio di implementazione dell'interfaccia, in cui associamo uno schema Non-Inflatable Asset (NIA) all'interfaccia RGB20:

fn nia_rgb20() -> IfaceImpl {
let schema = nia_schema();
let iface = Rgb20::iface();
IfaceImpl {
version: VerNo::V1,
schema_id: schema.schema_id(),
iface_id: iface.iface_id(),
script: none!(),
global_state: tiny_bset! {
NamedField::with(GS_NOMINAL, fname!("spec")),
NamedField::with(GS_DATA, fname!("data")),
NamedField::with(GS_TIMESTAMP, fname!("created")),
NamedField::with(GS_ISSUED_SUPPLY, fname!("issuedSupply")),
},
assignments: tiny_bset! {
NamedField::with(OS_ASSET, fname!("assetOwner")),
},
valencies: none!(),
transitions: tiny_bset! {
NamedType::with(TS_TRANSFER, tn!("Transfer")),
},
extensions: none!(),
}
}

In questa interfaccia di implementazione :

Il risultato dopo la compilazione è un file .rgb o .rgba separato, da importare nel portafoglio in aggiunta allo Schema e all'Interfaccia. In questo modo, il software sa come collegare concretamente questo contratto NIA (la cui logica è descritta dal suo Schema) all'Interfaccia "RGB20" (che fornisce nomi umani e una modalità di interazione per i gettoni fungibili), applicando questa Implementazione dell'Interfaccia come gateway tra i due.

Perché separare l'implementazione dell'interfaccia?

La separazione aumenta la flessibilità. Un singolo schema può avere diverse implementazioni di interfacce distinte, ognuna delle quali mapperà un diverso insieme di funzionalità. Inoltre, la stessa implementazione dell'interfaccia può evolversi o essere riscritta senza richiedere una modifica dello schema o dell'interfaccia. In questo modo si mantiene il principio di modularità di RGB: ogni componente (Schema, Interfaccia, Implementazione dell'Interfaccia) può essere modificato e aggiornato in modo indipendente, purché vengano rispettate le regole di compatibilità imposte dal protocollo (stessi identificatori, coerenza dei tipi, ecc.).

Nell'uso concreto, quando il portafoglio carica un contratto, deve :

Questa architettura modulare rende possibili scenari di utilizzo come :

Nel prossimo capitolo vedremo come funziona il trasferimento di un contratto e come vengono generate le fatture RGB.

Trasferimenti di contratti

In questo capitolo analizzeremo il processo di trasferimento di un contratto nell'ecosistema RGB. Per illustrarlo, prenderemo in considerazione Alice e Bob, i nostri soliti protagonisti, che desiderano scambiare un asset RGB. Mostreremo anche alcuni estratti di comandi dello strumento a riga di comando rgb, per vedere come funziona in pratica.

Comprendere il trasferimento del contratto RGB

Facciamo un esempio di trasferimento tra Alice e Bob. In questo esempio, ipotizziamo che Bob abbia appena iniziato a utilizzare RGB, mentre Alice possiede già asset RGB nel suo portafoglio. Vedremo come Bob configura il suo ambiente, importa il relativo contratto, richiede un trasferimento ad Alice e infine come Alice esegue la transazione effettiva sulla blockchain Bitcoin.

1) Installazione del portafoglio RGB

Prima di tutto, Bob deve installare un portafoglio RGB, cioè un software compatibile con il protocollo. All'inizio non contiene alcun contratto. Bob avrà anche bisogno di :

Come promemoria, gli Stati posseduti in RGB si riferiscono agli UTXO di Bitcoin. Dobbiamo quindi essere sempre in grado di gestire e spendere gli UTXO in una transazione Bitcoin che incorpora impegni crittografici (Tapret o Opret) che puntano ai dati RGB.

2) Acquisizione di informazioni sul contratto

Bob deve quindi recuperare i dati del contratto che gli interessano. Questi dati possono circolare attraverso qualsiasi canale: sito web, e-mail, applicazione di messaggistica... In pratica, vengono raggruppati in un incarico, cioè un piccolo pacchetto di dati contenente :

RGB-Bitcoin

La dimensione totale è spesso dell'ordine di pochi kilobyte, poiché ogni componente pesa generalmente meno di 200 byte. Può anche essere possibile trasmettere questo invio in Base58, tramite canali resistenti alla censura (come Nostr o la rete Lightning, ad esempio), o come codice QR.

3) Importazione e convalida del contratto

Una volta ricevuta la partita, Bob la importa nel suo portafoglio RGB. Questo poi :

Bob può ora vedere l'asset nel suo portafoglio (anche se non lo possiede ancora) e capire quali campi sono disponibili, quali operazioni sono possibili... A questo punto deve contattare la persona che possiede effettivamente l'asset da trasferire. Nel nostro esempio, si tratta di Alice.

Il processo di scoperta di chi detiene un determinato asset RGB è simile alla ricerca di un pagatore di Bitcoin. I dettagli di questa connessione dipendono dall'uso (marketplace, canali di chat privati, fatturazione, vendita di beni e servizi, stipendio...).

4) Emissione di una fattura

Per avviare il trasferimento di un bene RGB, Bob deve prima emettere una fattura. Questa fattura viene utilizzata per :

Bob utilizza lo strumento rgb alla riga di comando. Supponiamo che voglia 100 unità di un token il cui ContractId è noto, che voglia affidarsi a Tapret e che specifichi il suo UTXO (456e3..dfe1:0):

bob$ rgb invoice RGB20 100 <ContractId> tapret1st:456e3..dfe1:0

Alla fine di questo capitolo esamineremo più da vicino la struttura delle fatture RGB.

5) Trasmissione della fattura

La fattura generata (ad esempio come URL: rgb:2WBcas9.../RGB20/100+utxob:...) contiene tutte le informazioni necessarie ad Alice per preparare il trasferimento. Come per la spedizione, può essere codificata in modo compatto (Base58 o un altro formato) e inviata tramite un'applicazione di messaggistica, e-mail, Nostr...

RGB-Bitcoin

6) Preparazione della transazione sul lato Alice

Alice riceve la fattura di Bob. Nel suo portafoglio RGB ha uno stash contenente il bene da trasferire. Per spendere l'UTXO contenente il bene, deve prima generare una PSBT (Partially Signed Bitcoin Transaction), cioè una transazione Bitcoin incompleta, utilizzando l'UTXO in suo possesso:

alice$ wallet construct tx.psbt

Questa transazione di base (per il momento non firmata) sarà utilizzata per ancorare l'impegno crittografico legato al trasferimento a Bob. L'UTXO di Alice verrà quindi speso e, in uscita, verrà inserito l'impegno Tapret o Opret per Bob.

7) Generazione di partite di trasferimento

Successivamente, Alice costruisce il terminal consignment (talvolta chiamato "transfer consignment") tramite il comando :

alice$ rgb transfer tx.psbt <invoice> consignment.rgb

Questo nuovo file consignment.rgb contiene :

In questa fase, la transazione non è ancora trasmessa sulla rete Bitcoin. La partita è più grande di una partita di base, poiché include l'intera storia (catena di prova) per dimostrare la legittimità del bene.

8) Bob controlla e accetta la spedizione

Alice trasmette questo invio terminale a Bob. Bob quindi :

bob$ rgb accept consignment.rgb
sig:DbwzvSu4BZU81jEpE9FVZ3xjcyuTKWWy2gmdnaxtACrS
RGB-Bitcoin

9) Opzione: Bob invia la conferma ad Alice (borsa di pagamento)

Se Bob lo desidera, può inviare questa firma ad Alice. Questo indica che:

Questo non è obbligatorio, ma può dare ad Alice la certezza che non ci saranno controversie successive sul trasferimento.

10) Alice firma e pubblica la transazione

Alice può quindi :

alice$ rgb check <sig>
alice$ wallet sign —publish tx.psbt
RGB-Bitcoin

Una volta confermata, questa transazione segna la conclusione del trasferimento. Bob diventa il nuovo proprietario del bene: ora ha uno Stato di proprietà che punta all'UTXO che controlla, dimostrato dalla presenza dell'impegno nella transazione.

In sintesi, ecco il processo di trasferimento completo:

RGB-Bitcoin

Vantaggi dei trasferimenti RGB

Solo Alice e Bob hanno accesso a tutti i dati sulla transizione di stato. Essi si scambiano queste informazioni al di fuori della blockchain, attraverso le spedizioni. Gli impegni crittografici nella transazione Bitcoin non rivelano il tipo di bene o l'importo, il che garantisce una riservatezza molto maggiore rispetto ad altri sistemi di token on-chain.

Bob può verificare la coerenza del trasferimento confrontando il consignment con gli anchor della blockchain Bitcoin. Non ha bisogno di una convalida da parte di terzi. Alice non deve pubblicare l'intera cronologia sulla blockchain, il che riduce il carico del protocollo di base e migliora la riservatezza.

Scambi complessi (scambi atomici tra BTC e un asset RGB, ad esempio) possono essere effettuati all'interno di una singola transazione, evitando la necessità di script HTLC o PTLC. Se l'accordo non viene trasmesso, ognuno può riutilizzare i propri UTXO in altri modi.

Schema riassuntivo del trasferimento

Prima di esaminare le fatture in dettaglio, ecco un diagramma riassuntivo del flusso complessivo di un trasferimento RGB:

RGB-Bitcoin

Il trasferimento illustra tutta la potenza e la flessibilità del protocollo RGB: uno scambio privato, convalidato dal lato del cliente, ancorato in modo minimo e discreto alla blockchain Bitcoin e che conserva il meglio della sicurezza del protocollo (nessun rischio di doppia spesa). Ciò rende RGB un ecosistema promettente per trasferimenti di valore più riservati e scalabili rispetto alle blockchain programmabili on-chain.

Fatture RGB

In questa sezione spiegheremo in dettaglio come funzionano le fatture nell'ecosistema RGB e come consentono di effettuare operazioni (in particolare trasferimenti) con un contratto. In primo luogo, esamineremo gli identificatori utilizzati, poi il modo in cui sono codificati e infine la struttura di una fattura espressa come URL (un formato abbastanza pratico per l'uso nei portafogli).

Identificatori e codifica

Per ciascuno dei seguenti elementi viene definito un identificatore unico:

L'unicità è molto importante, poiché ogni componente del sistema deve essere distinguibile. Ad esempio, un contratto X non deve essere confuso con un altro contratto Y, e due interfacce diverse (RGB20 vs. RGB21, ad esempio) devono avere identificatori distinti.

Per rendere questi identificatori efficienti (dimensioni ridotte) e leggibili, utilizziamo il formato :

Per esempio, un ContractId potrebbe essere rappresentato da qualcosa come :

rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX

Il prefisso rgb: conferma che si tratta di un identificatore RGB e non di un link HTTP o di un altro protocollo. Grazie a questo prefisso, i portafogli sono in grado di interpretare correttamente la stringa.

Segmentazione degli identificatori

Gli identificatori RGB sono spesso molto lunghi, poiché la sicurezza (crittografica) sottostante può richiedere campi di 256 bit o più. Per agevolare la lettura e la verifica da parte dell'uomo, si suddividono queste stringhe in diversi blocchi separati da un trattino (-). Quindi, invece di avere una lunga stringa ininterrotta di caratteri, la dividiamo in blocchi più corti. Questa pratica è comune per i numeri di carta di credito o di telefono e si applica anche in questo caso per facilitare la verifica. Così, ad esempio, si può dire a un utente o a un partner: "Per favore, controlla che il terzo blocco sia 9GEgnyMj7", invece di doverlo confrontare tutto in una volta. L'ultimo blocco è spesso usato come checksum, per avere un sistema di rilevamento degli errori o dei refusi.

Ad esempio, un ContractId in base58 codificato e segmentato potrebbe essere :

2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX

Ognuno dei trattini spezza la stringa in sezioni. Questo non influisce sulla semantica del codice, ma solo sulla sua presentazione.

Utilizzo di URL per le fatture

Una fattura RGB viene presentata come un URL. Ciò significa che può essere cliccata o scansionata (come un codice QR) e un portafoglio può interpretarla direttamente per effettuare una transazione. Questa semplicità di interazione è diversa da quella di altri sistemi in cui è necessario copiare e incollare vari dati nei diversi campi del software.

Una fattura per un token fungibile (ad esempio un token RGB20) potrebbe avere il seguente aspetto:

rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/100+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb

Analizziamo questo URL:

Il fatto che tutto rientri in un unico URL semplifica la vita dell'utente: un semplice clic o una scansione nel portafoglio e l'operazione è pronta per essere eseguita.

Si potrebbero immaginare sistemi in cui al posto del ContractId si utilizzi un semplice ticker (ad esempio USDT). Tuttavia, questo solleverebbe grossi problemi di fiducia e sicurezza: un ticker non è un riferimento univoco (diversi contratti potrebbero affermare di chiamarsi USDT). Con RGB, vogliamo un identificatore crittografico unico e non ambiguo. Da qui l'adozione della stringa a 256 bit, codificata in base58 e segmentata. L'utente sa che sta manipolando proprio il contratto il cui ID è 2WBcas9-yjz... e non un altro.

Parametri URL aggiuntivi

È inoltre possibile aggiungere ulteriori parametri all'URL, come nel caso di HTTP, ad esempio :

rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/100+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb?sig=6kzbKKffP6xftkxn9UP8gWqiC41W16wYKE5CYaVhmEve

Prendiamo il caso di un NFT tramite l'interfaccia RGB21. Ad esempio, potremmo avere :

rgb:7BKsac8-beMNMWA8r-3GEprtFh7-bjzEvGufY-aNLuU4nSN-MRsLOIK/RGB21/DbwzvSu-4BZU81jEp-E9FVZ3xj-cyuTKWWy-2gmdnaxt-ACrS+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb

Qui vediamo :

L'idea è la stessa: trasmettere un link unico che il portafoglio possa interpretare, identificando chiaramente l'asset unico da trasferire.

Altre operazioni tramite URL

Gli URL RGB non sono utilizzati solo per richiedere un trasferimento. Possono anche codificare operazioni più avanzate, come l'emissione di nuovi token (emissione). Ad esempio:

rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/issue/100000+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb

Qui troviamo :

Ad esempio, il portafoglio potrebbe recitare: "Mi è stato chiesto di effettuare un'operazione di emissione dall'interfaccia RGB20, su tale e tale contratto, per 100.000 unità, a beneficio di tale e tale Sigillo monouso.*"

Dopo aver esaminato gli elementi principali della programmazione RGB, nel prossimo capitolo vi illustrerò come redigere un contratto RGB.

Redazione di contratti intelligenti

In questo capitolo, affronteremo passo dopo passo la scrittura di un contratto, utilizzando lo strumento a riga di comando rgb. L'obiettivo è mostrare come installare e manipolare la CLI, compilare uno Schema, importare l'Interfaccia e l'Implementazione dell'interfaccia, quindi emettere (emettere) una risorsa. Verrà esaminata anche la logica sottostante, compresa la compilazione e la convalida dello stato. Alla fine di questo capitolo, dovreste essere in grado di riprodurre il processo e creare i vostri contratti RGB.

Come promemoria, la logica interna di RGB è basata su librerie Rust che voi, come sviluppatori, potete importare nei vostri progetti per gestire la parte di validazione lato client. Inoltre, il team dell'associazione LNP/BP sta lavorando a legami per altre lingue, ma non sono ancora stati finalizzati. Inoltre, altre entità come Bitfinex stanno sviluppando i propri stack di integrazione (ne parleremo negli ultimi due capitoli del corso). Per il momento, quindi, la CLI rgb è il riferimento ufficiale, anche se rimane relativamente poco rifinita.

Installazione e presentazione dello strumento rgb

Il comando principale si chiama semplicemente rgb. È stato progettato per ricordare git, con una serie di sottocomandi per manipolare i contratti, invocarli, emettere beni e così via. Bitcoin Wallet non è attualmente integrato, ma lo sarà in una prossima versione (0.11). Questa prossima versione consentirà agli utenti di creare e gestire i loro portafogli (tramite descrittori) direttamente da rgb, compresa la generazione di PSBT, la compatibilità con l'hardware esterno (ad esempio un portafoglio hardware) per la firma e l'interoperabilità con software come Sparrow. Questo semplificherà l'intero scenario di emissione e trasferimento degli asset.

Installazione tramite Cargo

Installiamo lo strumento in Rust con :

cargo install rgb-contracts --all-features

(Nota: il crate si chiama rgb-contracts e il comando installato si chiamerà rgb. Se esisteva già un crate chiamato rgb, potrebbe esserci stata una collisione, da cui il nome)

L'installazione compila un gran numero di dipendenze (ad esempio, parsing dei comandi, integrazione di Electrum, gestione delle prove a conoscenza zero, ecc.)

Una volta completata l'installazione, il file :

rgb

L'esecuzione di rgb (senza argomenti) visualizza un elenco di sottocomandi disponibili, come interfacce, schema, importazione, esportazione, emissione, fattura, trasferimento, ecc. È possibile modificare la directory di archiviazione locale (una riserva che contiene tutti i log, gli schemi e le implementazioni), scegliere la rete (testnet, mainnet) o configurare il server Electrum.

RGB-Bitcoin

Prima panoramica dei controlli

Eseguendo il seguente comando, si noterà che un'interfaccia RGB20 è già integrata per impostazione predefinita:

rgb interfaces

Se questa interfaccia non è integrata, clonare il file :

git clone https://github.com/RGB-WG/rgb-interfaces

Compilare:

cargo run

Importare quindi l'interfaccia scelta:

rgb import interfaces/RGB20.rgb
RGB-Bitcoin

D'altra parte, ci viene detto che nessuno schema è stato ancora importato nel software. Non c'è nemmeno un contratto nella scorta. Per vederlo, eseguire il comando :

rgb schemata

È quindi possibile clonare il repository per recuperare determinati schemi:

git clone https://github.com/RGB-WG/rgb-schemata
RGB-Bitcoin

Questo repository contiene, nella sua directory src/, diversi file Rust (per esempio nia.rs) che definiscono gli schemi (NIA per "Non Inflatable Asset", UDA per "Unique Digital Asset", ecc.) Per la compilazione, è possibile eseguire :

cd rgb-schemata
cargo run

Questo genera diversi file .rgb e .rgba corrispondenti agli schemi compilati. Ad esempio, si trova NonInflatableAsset.rgb.

Importazione dello schema e dell'implementazione dell'interfaccia

Ora è possibile importare lo schema in rgb :

rgb import schemata/NonInflatableAssets.rgb
RGB-Bitcoin

Questo lo aggiunge allo stash locale. Se si esegue il comando seguente, si vede che ora lo schema appare:

rgb schemata

Creazione del contratto (emissione)

Esistono due approcci per creare una nuova risorsa:

Nella cartella examples si possono trovare degli esempi in Rust, che illustrano come costruire un ContractBuilder, compilare lo stato globale (nome dell'asset, ticker, fornitura, data, ecc.), definire lo Stato di proprietà (a quale UTXO è assegnato), quindi compilare il tutto in una partita di contratto che si può esportare, convalidare e importare in uno stash.

L'altro modo è quello di modificare manualmente un file YAML per personalizzare il ticker, il nome, la fornitura e così via. Supponiamo che il file si chiami RGB20-demo.yaml. È possibile specificare :

Ecco un esempio di file YAML da creare:

interface: RGB20Fixed
globals:
spec:
ticker: PBN
name: Plan B Network
details: "Pay attention: the asset has no value"
precision: 2
terms:
text: >
SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER. PROPERTY IS BEING SOLD “AS IS”...
media: ~
issuedSupply: 100000000
assignments:
assetOwner:
seal: tapret1st:b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1
amount: 100000000 # this is 1 million (we have two digits for cents)
RGB-Bitcoin

Quindi è sufficiente eseguire il comando :

rgb issue '<SchemaID>' ssi:<Issuer> rgb20-demo.yaml
RGB-Bitcoin

Nel mio caso, l'identificatore unico dello schema (da racchiudere tra virgolette singole) è RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k e non ho inserito alcun emittente. Quindi il mio ordine è :

rgb issue 'RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k' ssi:anonymous rgb20-demo.yaml

Se non si conosce l'ID dello schema, eseguire il comando :

rgb schemata

La CLI risponde che un nuovo contratto è stato emesso e aggiunto allo stash. Se digitiamo il comando seguente, vediamo che ora c'è un contratto aggiuntivo, corrispondente a quello appena emesso:

rgb contracts
RGB-Bitcoin

Quindi, il comando successivo visualizza gli stati globali (nome, ticker, fornitura...) e l'elenco degli Stati posseduti, cioè le allocazioni (ad esempio, 1 milione di gettoni PBN definiti in UTXO b449fea3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1).

rgb state '<ContractId>'
RGB-Bitcoin

Esportazione, importazione e convalida

Per condividere questo contratto con altri utenti, è possibile esportarlo dallo stash in un file :

rgb export '<ContractId>' myContractPBN.rgb
RGB-Bitcoin

Il file myContractPBN.rgb può essere passato a un altro utente, che può aggiungerlo alla sua scorta con il comando :

rgb import myContractPBN.rgb

Al momento dell'importazione, se si tratta di una semplice partita di contratto, si otterrà un messaggio "Importazione della partita rgb". Se si tratta di una partita di transizione di stato più grande, il comando sarà diverso (rgb accept).

Per garantire la validità, si può anche utilizzare la funzione di validazione locale. Ad esempio, si può eseguire :

rgb validate myContract.rgb

Utilizzo, verifica e visualizzazione dello Stash

Come promemoria, lo stash è un inventario locale di schemi, interfacce, implementazioni e contratti (Genesis + transizioni). Ogni volta che si esegue "import", si aggiunge un elemento allo stash. Questo stash può essere visualizzato in dettaglio con il comando :

rgb dump
RGB-Bitcoin

Questo genererà una cartella con i dettagli dell'intera scorta.

Trasferimento e PSBT

Per effettuare un trasferimento, è necessario manipolare un portafoglio Bitcoin locale per gestire gli impegni Tapret o Opret.

Generare una fattura

Nella maggior parte dei casi, l'interazione tra i partecipanti a un contratto (ad esempio, Alice e Bob) avviene attraverso la generazione di una fattura. Se Alice vuole che Bob esegua qualcosa (un trasferimento di token, una riemissione, un'azione in un DAO, ecc.), Alice crea una fattura che dettaglia le sue istruzioni a Bob. Quindi abbiamo :

A differenza di altri ecosistemi, una fattura RGB non si limita alla nozione di pagamento. Può incorporare qualsiasi richiesta legata al contratto: revocare una chiave, votare, creare un'incisione (incisione) su un NFT, ecc. L'operazione corrispondente può essere descritta nell'interfaccia del contratto. L'operazione corrispondente può essere descritta nell'interfaccia del contratto.

Il comando seguente genera una fattura RGB:

$ rgb invoice $CONTRACT -i $INTERFACE $ACTION $STATE $SEAL

Con :

Ad esempio, con i seguenti comandi

alice$ CONTRACT='iZgIN9EL-2H21UgQ-x!A3uJc-WwXhCSm-$9Lwcc1-v!mUkKY'
alice$ MY_UTXO=4960acc21c175c551af84114541eace09c14d3a1bb184809f7b80916f57f9ef8:1
alice$ rgb invoice $CONTRACT -i RGB20 --amount 100 $MY_UTXO

La CLI genererà una fattura come :

rgb:iZgIN9EL-2H21UgQ-x!A3uJc-WwXhCSm-$9Lwcc1-v!mUkKY/RGB20/100+utxob:zlVS28Rb-...

Può essere trasmesso a Bob tramite qualsiasi canale (testo, codice QR, ecc.).

Effettuare un trasferimento

Per trasferire da questa fattura :

bob$ rgb transfer tx.psbt $INVOICE consignment.rgb
alice$ rgb accept consignment.rgb
bob$ rgb check <sig> && wallet sign --publish tx.psbt

Nel prossimo capitolo vedremo da vicino l'integrazione di RGB nella rete Lightning.

RGB sulla rete Lightning

In questo capitolo propongo di esaminare come RGB possa essere utilizzato all'interno della Lightning Network, per integrare e muovere asset RGB (token, NFT, ecc.) attraverso canali di pagamento fuori dalla catena.

L'idea di base è che la transizione di stato RGB (Transizione di stato) può essere impegnata in una transazione Bitcoin che, a sua volta, può rimanere fuori dalla catena fino alla chiusura del canale Lightning. Quindi, ogni volta che il canale viene aggiornato, una nuova transizione di stato RGB può essere incorporata nella nuova transazione impegnata, che invalida la vecchia transizione. In questo modo, i canali Lightning possono essere utilizzati per trasferire beni RGB e possono essere instradati nello stesso modo dei pagamenti Lightning convenzionali.

Creazione di canali e finanziamenti

Per creare un canale Lightning che trasporta risorse RGB, abbiamo bisogno di due elementi:

In termini di Bitcoin, la transazione di finanziamento deve esistere per definire l'UTXO di riferimento, anche se contiene solo una piccola quantità di sats (si tratta solo di far sì che ogni uscita nelle future transazioni di impegno rimanga comunque al di sopra del limite di polvere). Ad esempio, Alice potrebbe decidere di fornire 10k sats e 500 USDT (emessi come asset RGB). Nella transazione di finanziamento, aggiungiamo un impegno (Opret o Tapret) che fissa la transizione di stato di RGB.

RGB-Bitcoin

Una volta che la transazione di finanziamento è stata preparata (ma non ancora trasmessa), vengono create transazioni di impegno in modo che una delle parti possa chiudere il canale unilateralmente in qualsiasi momento. Queste transazioni assomigliano alle transazioni di impegno classiche di Lightning, tranne per il fatto che aggiungiamo un'uscita supplementare contenente l'ancora RGB (OP_RETURN o Taproot) legata alla nuova transizione di stato.

La transizione di stato RGB sposta quindi le attività dal multisigma 2/2 del finanziamento agli output della transazione di impegno. Il vantaggio di questo processo è che la sicurezza dello stato RGB corrisponde esattamente alla meccanica punitiva di Lightning: se Bob trasmette uno stato di canale vecchio, Alice può punirlo e spendere l'output, per recuperare sia la saturazione che i gettoni RGB. L'incentivo è quindi ancora più forte che in un canale Lightning senza risorse RGB, poiché un attaccante può perdere non solo la saturazione, ma anche le risorse RGB del canale.

Una transazione di impegno firmata da Alice e inviata a Bob avrebbe quindi il seguente aspetto:

RGB-Bitcoin

La transazione di impegno che la accompagna, firmata da Bob e inviata ad Alice, avrà il seguente aspetto:

RGB-Bitcoin

Aggiornamento del canale

Quando si verifica un pagamento tra due partecipanti al canale (o questi desiderano modificare l'allocazione delle attività), essi creano una nuova coppia di transazioni di impegno. L'importo in sats di ciascuna uscita può rimanere invariato o meno, a seconda dell'implementazione, poiché il suo ruolo principale è quello di consentire la costruzione di UTXO validi. D'altra parte, l'uscita OP_RETURN (o Taproot) deve essere modificata per contenere la nuova ancora RGB, che rappresenta la nuova distribuzione degli asset nel canale.

Ad esempio, se Alice trasferisce 30 USDT a Bob nel canale, la nuova transizione di stato rifletterà un saldo di 400 USDT per Alice e 100 USDT per Bob. La transazione di commit viene aggiunta (o modificata) all'ancora OP_RETURN/Taproot per includere questa transizione. Si noti che, dal punto di vista di RGB, l'input della transizione rimane il multisig iniziale (dove le attività sulla catena sono effettivamente allocate fino alla chiusura del canale). Solo le uscite di RGB (allocazioni) cambiano, a seconda della ridistribuzione decisa.

La transazione di impegno firmata da Alice, pronta per essere distribuita da Bob :

RGB-Bitcoin

La transazione di impegno firmata da Bob, pronta per essere distribuita da Alice :

RGB-Bitcoin

Gestione HTLC

In realtà, la rete Lightning consente di instradare i pagamenti attraverso più canali, utilizzando gli HTLC (Hashed Time-Locked Contracts). È la stessa cosa con RGB: per ogni pagamento in transito attraverso il canale, viene aggiunto un output HTLC alla transazione che lo impegna e un'allocazione RGB collegata a questo HTLC. In questo modo, chi spende l'uscita HTLC (grazie al segreto o dopo la scadenza del timelock) recupera sia la saturazione che gli asset RGB associati. D'altra parte, è ovviamente necessario avere abbastanza denaro in circolazione sia in termini di sats che di asset RGB.

RGB-Bitcoin

Il funzionamento di RGB su Lightning deve quindi essere considerato in parallelo a quello della rete Lightning stessa. Se volete approfondire questo argomento, vi consiglio di dare un'occhiata a questo altro corso di formazione completo:

https://planb.network/courses/34bd43ef-6683-4a5c-b239-7cb1e40a4aeb

Mappa del codice RGB

Infine, prima di passare alla sezione successiva, vorrei fornire una panoramica del codice utilizzato in RGB. Il protocollo si basa su un insieme di librerie Rust e di specifiche open source. Ecco una panoramica dei principali repository e crate:

RGB-Bitcoin

Convalida lato client

Gestione della convalida fuori catena e della logica dei sigilli monouso.

Impegni deterministici di Bitcoin (DBC)

Gestione dell'ancoraggio deterministico nelle transazioni Bitcoin (Tapret, OP_RETURN, ecc.).

Impegno multiprotocollo (MPC)

Combinazioni di ingaggio multiple e integrazione con diversi protocolli.

Tipi rigorosi e codifica rigorosa

Il sistema di tipizzazione rigoroso e la serializzazione deterministica utilizzati per la validazione lato client.

Nucleo RGB

Il cuore del protocollo, che racchiude la logica principale della convalida RGB.

Libreria e portafoglio standard RGB

Implementazioni standard, gestione di stash e portafogli.

RGB CLI

La CLI rgb e il crate wallet, per la manipolazione dei contratti a riga di comando.

Schema RGB

Contiene esempi di schemi (NIA, UDA, ecc.) e delle loro implementazioni.

ALuVM

Macchina virtuale basata sul registro utilizzata per eseguire gli script di convalida.

Protocollo Bitcoin - BP

Componenti aggiuntivi per il supporto del protocollo Bitcoin (transazioni, bypass, ecc.).

Calcolo deterministico ubiquo - UBIDECO

Ecosistema legato agli sviluppi deterministici open-source.

Costruire su RGB

DIBA e il progetto Bitmask

Questa sezione finale del corso si basa sulle presentazioni fatte da vari relatori al bootcamp RGB. Include testimonianze e riflessioni su RGB e sul suo ecosistema, nonché presentazioni di strumenti e progetti basati sul protocollo. Questo primo capitolo è moderato da Hunter Beast e i due successivi da Frederico Tenga.

Da JavaScript a Rust e all'ecosistema Bitcoin

All'inizio, Hunter Beast lavorava principalmente in JavaScript. Poi ha scoperto Rust, la cui sintassi all'inizio sembrava poco attraente e frustrante. Tuttavia, ha imparato ad apprezzare la potenza del linguaggio, il controllo sulla memoria (heap e stack), la sicurezza e le prestazioni che ne derivano. Sottolinea che Rust è un'eccellente palestra per comprendere a fondo il funzionamento di un computer.

Hunter Beast racconta il suo passato in vari progetti dell'ecosistema altcoin, come Ethereum (con Solidity, TypeScript, ecc.) e successivamente Filecoin. Spiega di essere stato inizialmente colpito da alcuni protocolli, ma di aver finito per sentirsi disilluso dalla maggior parte di essi, non da ultimo a causa della loro tokenomica. Denuncia i dubbi incentivi finanziari, la creazione inflazionistica di token che diluisce gli investitori e l'aspetto potenzialmente di sfruttamento di questi progetti. Ha quindi finito per adottare una posizione Bitcoin massimalista, anche perché alcune persone gli hanno aperto gli occhi sui meccanismi economici più solidi del Bitcoin e sulla solidità di questo sistema.

Il fascino dell'RGB e della costruzione su livelli

Ciò che lo ha definitivamente convinto della rilevanza di Bitcoin, secondo le sue parole, è stata la scoperta di RGB e del concetto di livelli. Ritiene che le funzionalità esistenti su altre blockchain possano essere riprodotte su livelli superiori, al di sopra del Bitcoin, senza alterare il protocollo di base.

Nel febbraio 2022, si è unito a DIBA per lavorare specificamente su RGB, e in particolare sul portafoglio Bitmask. All'epoca, Bitmask era ancora alla versione 0.01 e RGB girava alla versione 0.4, solo per la gestione di singoli token. Egli osserva che questo sistema era meno orientato all'autocustodia rispetto a quello attuale, in quanto la logica era in parte basata su server. Da allora, l'architettura si è evoluta verso questo modello, molto apprezzato dai bitcoiners.

Le basi del protocollo RGB

Il protocollo RGB è l'incarnazione più recente e più avanzata del concetto di monete colorate, già esplorato intorno al 2012-2013. All'epoca, diversi team stavano cercando di associare diversi valori di bitcoin agli UTXO, il che ha portato a molteplici implementazioni sparse. Questa mancanza di standardizzazione e la scarsa domanda dell'epoca hanno impedito a queste soluzioni di prendere piede in modo duraturo.

Oggi, RGB si distingue per la sua solidità concettuale e per le specifiche unificate tramite l'associazione LNP/BP. Il principio si basa sulla validazione lato client. La blockchain Bitcoin memorizza solo gli impegni crittografici (commitments, tramite Taproot o OP_RETURN), mentre la maggior parte dei dati (definizioni dei contratti, cronologia dei trasferimenti, ecc.) viene memorizzata dagli utenti interessati. In questo modo, il carico di archiviazione è distribuito e la riservatezza degli scambi è rafforzata, senza appesantire la blockchain. Questo approccio consente di creare asset fungibili (standard RGB20) o unici (standard RGB21), in un quadro modulare e scalabile.

La funzione token (RGB20) e gli asset unici (RGB21)

Con RGB20, definiamo un token fungibile su Bitcoin. L'emittente sceglie una fornitura, una precisione e crea un contratto in cui può poi effettuare trasferimenti. Ogni trasferimento è riferito a un Bitcoin UTXO, che funge da sigillo monouso. Questa logica garantisce che l'utente non possa spendere due volte lo stesso bene, poiché solo la persona in grado di spendere l'UTXO possiede la chiave per aggiornare lo stato del contratto lato client.

RGB21 si rivolge ad asset unici (o "NFT"). L'asset ha una fornitura pari a 1 e può essere associato a metadati (file immagine, audio, ecc.) descritti tramite un campo specifico. A differenza degli NFT sulle blockchain pubbliche, i dati e i loro identificatori MIME possono rimanere privati, distribuiti peer-to-peer a discrezione del proprietario.

La soluzione Bitmask: un portafoglio per RGB

Per sfruttare le capacità di RGB nella pratica, il progetto DIBA ha progettato un portafoglio chiamato Bitmask. L'idea è quella di fornire uno strumento non custodiale, basato su Taproot, accessibile come applicazione web o estensione del browser. Bitmask gestisce beni sia RGB20 che RGB21 e integra diversi meccanismi di sicurezza:

Grazie a questa architettura, tutte le transazioni di asset avvengono sul lato client. Dall'esterno, la transazione Bitcoin non è altro che una classica transazione di spesa Taproot, che nessuno sospetterebbe essere anche un trasferimento di token fungibili o NFT. L'assenza di sovraccarico sulla catena (nessun metadato memorizzato pubblicamente) garantisce un certo grado di discrezione e rende più facile resistere a eventuali tentativi di censura.

Sicurezza e architettura distribuita

Poiché il protocollo RGB richiede che ogni partecipante conservi la cronologia delle transazioni (per dimostrare la validità dei trasferimenti ricevuti), si pone la questione dell'archiviazione. Bitmask propone di serializzare questa scorta a livello locale, per poi inviarla a diversi server o cloud (facoltativi). I dati rimangono criptati dall'utente tramite Carbonado, quindi un server non può leggerli. In caso di corruzione parziale, il livello di correzione degli errori può ricostituire il contenuto.

L'uso di CRDT (Conflict-free replicated data type) consente di unire diverse versioni dello stash, qualora dovessero divergere. Ognuno è libero di ospitare questi dati dove vuole, poiché nessun singolo nodo completo contiene tutte le informazioni legate alla risorsa. Questo riflette esattamente la filosofia della convalida lato cliente, in cui ogni proprietario è responsabile della conservazione delle prove della validità della propria risorsa RGB.

Verso un ecosistema più ampio: mercato, interoperabilità e nuove funzioni

L'azienda che sta dietro a Bitmask non si limita al semplice sviluppo di un portafoglio. DIBA intende sviluppare :

Allo stesso tempo, stiamo lavorando a WebBTC o WebLN (standard che consentono ai siti web di chiedere al portafoglio di firmare le transazioni Bitcoin o Lightning), nonché alla possibilità di "teleburnare" le voci Ordinals (se vogliamo rimpatriare gli Ordinals in un formato RGB più discreto e flessibile).

Conclusione

L'intero processo mostra come l'ecosistema RGB possa essere implementato e reso accessibile agli utenti finali attraverso solide soluzioni tecniche. Il passaggio da una prospettiva altcoin a una visione più Bitcoin-centrica, insieme alla scoperta della Client-side Validation, illustra un percorso abbastanza logico: abbiamo capito che è possibile implementare varie funzionalità (token fungibili, NFT, smart contract...) senza biforcare la blockchain, semplicemente sfruttando gli impegni crittografici sulle transazioni Taproot o OP_RETURN.

Il portafoglio Bitmask fa parte di questo approccio: dal lato della blockchain, tutto ciò che si vede è una normale transazione Bitcoin; dal lato dell'utente, si manipola un'interfaccia web in cui si creano, si scambiano e si memorizzano tutti i tipi di asset fuori dalla catena. Questo modello dissocia chiaramente l'infrastruttura monetaria (Bitcoin) dalla logica di emissione e trasferimento (RGB), garantendo al contempo un elevato livello di riservatezza e una migliore scalabilità.

Il lavoro di Bitfinex su RGB

In questo capitolo, basato su una presentazione di Frederico Tenga, esaminiamo una serie di strumenti e progetti creati dal team di Bitfinex dedicati a RGB, con l'obiettivo di favorire la nascita di un ecosistema ricco e diversificato intorno a questo protocollo. L'obiettivo iniziale del team non è quello di rilasciare un prodotto commerciale specifico, ma piuttosto di fornire blocchi software, contribuire al protocollo RGB stesso e proporre riferimenti concreti di implementazione come un portafoglio mobile (Iris Wallet) o un nodo Lightning compatibile con RGB.

Contesto e obiettivi

Dal 2022 circa, il team Bitfinex RGB si è concentrato sullo sviluppo dello stack tecnologico che consente di sfruttare e testare RGB in modo efficiente. Sono stati apportati diversi contributi:

Questo approccio mira a coprire l'intera catena di esigenze: dalla libreria di basso livello (RGBlib), che consente l'implementazione di un portafoglio, all'aspetto produttivo (un nodo Lightning, un portafoglio per Android, ecc.).

La libreria RGBlib: semplificazione dello sviluppo di applicazioni RGB

Un punto importante per democratizzare la creazione di portafogli e applicazioni RGB è quello di rendere disponibile un'astrazione abbastanza semplice in modo che gli sviluppatori non debbano imparare tutto sulla logica interna del protocollo. Questo è proprio l'obiettivo di RGBlib, scritto in Rust.

RGBlib funge da ponte tra i requisiti altamente flessibili (ma talvolta complessi) di RGB che abbiamo avuto modo di studiare nei capitoli precedenti e le esigenze concrete di uno sviluppatore di applicazioni. In altre parole, un portafoglio (o un servizio) che voglia gestire trasferimenti di token, emissione di asset, verifica, ecc. può affidarsi a RGBlib senza conoscere ogni dettaglio crittografico o ogni parametro RGB personalizzabile.

La libreria offre :

RGBlib si basa quindi su nozioni complesse specifiche di RGB (Client-side Validation, ancore Tapret/Opret), ma le incapsula in modo che l'applicazione finale non debba riprogrammare tutto o prendere decisioni rischiose. Inoltre, RGBlib è già legato a diversi linguaggi (Kotlin e Python), aprendo la porta a usi che vanno oltre il semplice universo di Rust.

Iris Wallet: un esempio di portafoglio RGB su Android

Per dimostrare l'efficacia di RGBlib, il team di Bitfinex ha sviluppato Iris Wallet, per ora esclusivamente su Android. Si tratta di un portafoglio mobile che illustra un'esperienza d'uso simile a quella di un normale portafoglio Bitcoin: è possibile emettere un asset, inviarlo, riceverlo e visualizzarne la cronologia, rimanendo su un modello di autodeposito.

Iris presenta una serie di caratteristiche interessanti:

Utilizzando un server Electrum:

Come ogni portafoglio, Iris ha bisogno di conoscere le conferme delle transazioni sulla blockchain. Piuttosto che incorporare un nodo completo, Iris utilizza per default un server Electrum gestito dal team di Bitfinex. Gli utenti possono tuttavia configurare il proprio server o un altro servizio di terze parti. In questo modo, le transazioni Bitcoin possono essere convalidate e le informazioni recuperate (indicizzazione) in modo modulare.

Il server proxy RGB:

A differenza di Bitcoin, RGB richiede lo scambio di metadati fuori catena (conferimenti) tra mittente e destinatario. Per semplificare questo processo, Iris offre una soluzione in cui la comunicazione avviene tramite un server proxy. Il portafoglio ricevente genera una fattura che indica dove il mittente deve inviare i dati sul lato cliente. Per impostazione predefinita, l'URL punta a un proxy ospitato dal team Bitfinex, ma è possibile cambiare questo proxy (o ospitarne uno proprio). L'idea è quella di tornare a un'esperienza utente familiare in cui il destinatario visualizza un codice QR e il mittente lo scansiona per effettuare la transazione, senza complesse manipolazioni aggiuntive.

**Backup continuo

In un contesto strettamente Bitcoin, il backup del seme è generalmente sufficiente (anche se al giorno d'oggi si consiglia di eseguire il backup del seme e dei descrittori). Con RGB, questo non è sufficiente: è necessario conservare anche la storia locale (i conferimenti) che dimostra che si possiede davvero un asset RGB. Ogni volta che si riceve una ricevuta, il dispositivo memorizza nuovi dati, essenziali per le spese successive. Iris gestisce automaticamente un backup criptato nel Google Drive dell'utente. Questo non richiede una particolare fiducia in Google, poiché il backup è criptato, e per il futuro sono previste opzioni più robuste (come un server personale) per evitare qualsiasi rischio di censura o cancellazione da parte di un operatore terzo.

Altre caratteristiche:

Nel complesso, Iris offre un'esperienza d'uso vicina a quella di un portafoglio Bitcoin classico, mascherando la complessità aggiuntiva (gestione delle scorte, cronologia degli incarichi, ecc.) grazie a RGBlib e all'uso di un server proxy.

Server proxy ed esperienza utente

Il server proxy introdotto in precedenza merita di essere illustrato in dettaglio, poiché è la chiave per un'esperienza utente senza problemi. Invece che il mittente debba trasmettere manualmente i conferimenti al destinatario, la transazione RGB avviene in background tramite un file :

In questo modo, il portafoglio si comporta quasi come un normale portafoglio. L'utente non è a conoscenza di tutti i passaggi intermedi. Certo, il proxy attuale non è né crittografato né autenticato (il che lascia dubbi sulla riservatezza e l'integrità), ma questi miglioramenti sono possibili nelle versioni successive. Il concetto di proxy rimane estremamente utile per ricreare l'esperienza "io invio un codice QR, tu lo scansioni per pagare".

Integrazione RGB sulla rete Lightning

Un altro punto chiave del lavoro del team di Bitfinex è quello di rendere la rete Lightning compatibile con gli asset RGB. L'obiettivo è quello di abilitare i canali Lightning in USDT (o qualsiasi altro token) e di beneficiare degli stessi vantaggi di bitcoin su Lightning (transazioni quasi istantanee, routing, ecc.). In concreto, si tratta di creare un nodo Lightning modificato in :

Questa soluzione, denominata "RGB Lightning Node", utilizza LDK (Lightning Dev Kit) come base e aggiunge i meccanismi necessari per iniettare token RGB nei canali. Gli impegni di Lightning mantengono la struttura classica (uscite perforabili, timelock...), e in aggiunta ancorano una transizione di stato RGB (tramite Opret o Tapret). Per l'utente, questo apre la strada ai canali Lightning in stablecoin o in qualsiasi altro asset emesso via RGB.

Potenziale di DEX e impatto su Bitcoin

Una volta che diversi asset sono gestiti tramite Lightning, diventa possibile immaginare uno scambio atomico su un singolo percorso di routing Lightning, utilizzando la stessa logica di segreti e timelock. Ad esempio, l'utente A possiede bitcoin su un canale Lightning e l'utente B possiede USDT RGB su un altro canale Lightning. Possono creare un percorso che colleghi i loro due canali e scambiare simultaneamente BTC con USDT, senza bisogno di fiducia. Questo non è altro che uno scambio atomico che si svolge in diversi hops, rendendo i partecipanti esterni quasi ignari del fatto che stanno effettuando uno scambio, non solo un instradamento. Questo approccio offre :

Possiamo quindi immaginare un ecosistema in cui i nodi Lightning offrono prezzi di scambio (fornendo liquidità). Ogni nodo, se lo desidera, può svolgere il ruolo di market maker, comprando e vendendo vari asset su Lightning. Questa prospettiva di un DEX layer-2 rafforza l'idea che non sia necessario effettuare fork o utilizzare blockchain di terze parti per ottenere scambi di asset decentralizzati.

L'impatto su Bitcoin potrebbe essere positivo: L'infrastruttura di Lightning (nodi, canali e servizi) sarebbe più utilizzata grazie ai volumi generati da queste stablecoin, derivati e altri token. I commercianti interessati ai pagamenti in USDT su Lightning scoprirebbero meccanicamente i pagamenti in BTC su Lightning (gestiti dallo stesso stack). Anche la manutenzione e il finanziamento dell'infrastruttura della rete Lightning potrebbero beneficiare della moltiplicazione di questi flussi non in BTC, a vantaggio indiretto degli utenti di Bitcoin.

Conclusioni e risorse

Il team di Bitfinex dedicato a RGB illustra, attraverso il suo lavoro, la diversità di ciò che si può fare con il protocollo. Da un lato, c'è RGBlib, una libreria che facilita la progettazione di portafogli e applicazioni. Dall'altro, c'è Iris Wallet, una dimostrazione pratica su Android di un'ottima interfaccia per l'utente finale. Infine, l'integrazione di RGB con Lightning dimostra che i canali stablecoin sono possibili e apre la strada a un potenziale DEX decentralizzato su Lightning.

Questo approccio rimane in gran parte sperimentale e continua ad evolversi: la libreria RGBlib viene perfezionata man mano, Iris Wallet riceve miglioramenti regolari e il nodo Lightning dedicato non è ancora un client Lightning mainstream.

Per coloro che desiderano saperne di più o contribuire, sono disponibili diverse risorse, tra cui :

Nel prossimo capitolo vedremo più da vicino come lanciare un nodo RGB Lightning.

RLN - Nodo fulmine RGB

In questo capitolo finale, Frederico Tenga vi guida passo dopo passo nella configurazione di un nodo Lightning RGB in un ambiente Regtest e vi mostra come creare token RGB su di esso. Avviando due nodi separati, scoprirete anche come aprire un canale Lightning tra di essi e scambiare asset RGB.

Questo video funge da esercitazione, simile a quella che abbiamo trattato in un capitolo precedente, ma questa volta è incentrato specificamente su Lightning!

La risorsa principale per questo video è il repository Github RGB Lightning Node, che consente di lanciare facilmente questa configurazione in Regtest.

Distribuzione di un nodo Lightning compatibile con RGB

Il processo riprende e mette in pratica tutti i concetti trattati nei capitoli precedenti:

Introduzione del nodo rgb-lightning

Il progetto rgb-lightning-node è un demone Rust basato su un fork di rust-lightning (LDK) modificato per tenere conto dell'esistenza di asset RGB in un canale. Quando si apre un canale, è possibile specificare la presenza di asset e ogni volta che lo stato del canale viene aggiornato, viene creata una transizione RGB che riflette la distribuzione dell'asset nelle uscite di Lightning. Questo permette di :

Il codice è ancora in fase alfa: si consiglia di utilizzarlo solo in regtest o su testnet.

Installazione dei nodi

Per compilare e installare il binario `rgb-lightning-node', si inizia clonando il repository e i suoi sottomoduli, quindi si esegue il comando :

git clone https://github.com/RGB-Tools/rgb-lightning-node --recurse-submodules --shallow-submodules
RGB-Bitcoin

Dalla root del progetto, eseguire il seguente comando per compilare e installare il binario :

cargo install --locked --debug --path .
RGB-Bitcoin

Al termine di questo comando, un eseguibile rgb-lightning-node' sarà disponibile nella cartellaCARGO_HOME/bin/`. Assicurarsi che questo percorso sia presente in `PATH`, in modo da poter invocare il comando da qualsiasi directory.

Requisiti di prestazione

Per funzionare, il demone rgb-lightning-node richiede la presenza e la configurazione di :

Ogni istanza RLN dovrà comunicare con bitcoind per trasmettere e monitorare le proprie transazioni sulla catena. Al demone dovranno essere forniti l'autenticazione (login/password) e l'URL (host/porta).

Il demone deve essere in grado di elencare ed esplorare le transazioni sulla catena, in particolare di trovare l'UTXO su cui è stata ancorata una risorsa. È necessario specificare l'URL del server Electrum o di Esplora.

Come visto nei capitoli precedenti, il proxy server è un componente (opzionale, ma altamente consigliato) per semplificare lo scambio di incarichi tra i peer di Lightning. Anche in questo caso, è necessario specificare un URL.

Gli ID e gli URL vengono inseriti quando il demone viene sbloccato tramite l'API. Per saperne di più, si veda più avanti.

Lancio di Regtest

Per un uso semplice, c'è uno script regtest.sh che avvia automaticamente, tramite Docker, un insieme di servizi: bitcoind, electrs (indicizzatore), rgb-proxy-server.

RGB-Bitcoin

Consente di avviare un ambiente locale, isolato e preconfigurato. Crea e distrugge i contenitori e le directory di dati a ogni riavvio. Inizieremo avviando il file :

./regtest.sh start

Questo script :

RGB-Bitcoin

Successivamente, lanceremo diversi nodi RLN. In shell separate, eseguire ad esempio (per lanciare 3 nodi RLN) :

# 1st shell
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
--ldk-peer-listening-port 9735 --network regtest
# 2nd shell
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
--ldk-peer-listening-port 9736 --network regtest
# 3rd shell
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
--ldk-peer-listening-port 9737 --network regtest
RGB-Bitcoin

È inoltre possibile eseguire comandi sui nodi RLN dal browser:

https://rgb-tools.github.io/rgb-lightning-node/

Perché un nodo possa aprire un canale, deve prima disporre di bitcoin su un indirizzo generato con il seguente comando (per il nodo n°1, ad esempio):

curl -X POST http://localhost:3001/address

La risposta vi fornirà un indirizzo.

RGB-Bitcoin

Nel Regtest bitcoind, stiamo per estrarre alcuni bitcoin. Eseguire :

./regtest.sh mine 101
RGB-Bitcoin

Inviare i fondi all'indirizzo del nodo generato sopra:

./regtest.sh sendtoaddress <address> <amount>
RGB-Bitcoin

Quindi, estrarre un blocco per confermare la transazione:

./regtest.sh mine 1
RGB-Bitcoin

Lancio di Testnet (senza Docker)

Se si vuole testare uno scenario più realistico, si possono lanciare 3 nodi RLN sulla Testnet piuttosto che in Regtest, puntando a servizi pubblici:

rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
--ldk-peer-listening-port 9735 --network testnet
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
--ldk-peer-listening-port 9736 --network testnet
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
--ldk-peer-listening-port 9737 --network testnet

Per impostazione predefinita, se non viene trovata alcuna configurazione, il demone cercherà di utilizzare il file :

Con il login :

È possibile personalizzare questi elementi anche tramite l'API init/unlock.

Emissione di un token RGB

Per emettere un token, inizieremo creando degli UTXO "colorabili":

curl -X POST -H "Content-Type: application/json" \
-d '{
"up_to": false,
"num": 4,
"size": 2000000,
"fee_rate": 4.2,
"skip_sync": false
}' \
http://localhost:3001/createutxos
RGB-Bitcoin

Naturalmente è possibile adattare l'ordine. Per confermare la transazione, viene emesso un :

./regtest.sh mine 1

Ora possiamo creare una risorsa RGB. Il comando dipende dal tipo di risorsa che si desidera creare e dai suoi parametri. Qui sto creando un token NIA (Non Inflatable Asset) chiamato "PBN" con una dotazione di 1000 unità. La precisione consente di definire la divisibilità delle unità.

curl -X POST -H "Content-Type: application/json" \
-d '{
"amounts": [
1000
],
"ticker": "PBN",
"name": "Plan B Network",
"precision": 0
}' \
http://localhost:3001/issueassetnia
RGB-Bitcoin

La risposta include l'ID della risorsa appena creata. Ricordarsi di annotare questo identificatore. Nel mio caso, è :

rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10
RGB-Bitcoin

È quindi possibile trasferirlo sulla catena o allocarlo in un canale Lightning. Questo è esattamente ciò che faremo nella prossima sezione.

Apertura di un canale e trasferimento di un asset RGB

È necessario prima collegare il proprio nodo a un peer sulla rete Lightning utilizzando il comando /connectpeer. Nel mio esempio, controllo entrambi i nodi. Quindi recupererò la chiave pubblica del mio secondo nodo Lightning con questo comando:

curl -X 'GET' \
'http://localhost:3002/nodeinfo' \
-H 'accept: application/json'

Il comando restituisce la chiave pubblica del mio nodo n°2 :

031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94
RGB-Bitcoin

Successivamente, apriremo il canale specificando la risorsa pertinente (PBN). Il comando /openchannel consente di definire la dimensione del canale in satoshi e di scegliere di includere l'asset RGB. Dipende da cosa si vuole creare, ma nel mio caso il comando è :

curl -X POST -H "Content-Type: application/json" \
-d '{
"peer_pubkey_and_opt_addr": "031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94@localhost:9736",
"capacity_sat": 1000000,
"push_msat": 10000000,
"asset_amount": 500,
"asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10",
"public": true,
"with_anchors": true,
"fee_base_msat": 1000,
"fee_proportional_millionths": 0,
"temporary_channel_id": "a8b60c8ce3067b5fc881d4831323e24751daec3b64353c8df3205ec5d838f1c5"
}' \
http://localhost:3001/openchannel

Per saperne di più, cliccate qui:

RGB-Bitcoin

Per confermare la transazione, vengono estratti 6 blocchi:

./regtest.sh mine 6
RGB-Bitcoin

Il canale Lightning è ora aperto e contiene anche 500 gettoni PBN dal lato del nodo n°1. Se il nodo n°2 desidera ricevere i token PBN, deve generare una fattura. Ecco come fare:

curl -X POST -H "Content-Type: application/json" \
-d '{
"amt_msat": 3000000,
"expiry_sec": 420,
"asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10",
"asset_amount": 100
}' \
http://localhost:3002/lninvoice

Con :

In risposta, si otterrà una fattura RGB (come descritto nei capitoli precedenti):

lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj
RGB-Bitcoin

Ora pagheremo questa fattura dal primo nodo, che detiene il denaro necessario con il token PBN:

curl -X POST -H "Content-Type: application/json" \
-d '{
"invoice": "lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj"
}' \
http://localhost:3001/sendpayment
RGB-Bitcoin

Il pagamento è stato effettuato. Questo può essere verificato eseguendo il comando :

curl -X 'GET' \
'http://localhost:3001/listpayments' \
-H 'accept: application/json'
RGB-Bitcoin

Ecco come distribuire un nodo Lightning modificato per trasportare risorse RGB. Questa dimostrazione si basa su :

Grazie a questo processo :

Il progetto rimane in fase alfa. Si raccomanda pertanto di limitarsi agli ambienti di prova (regtest, testnet).

Le opportunità aperte da questa compatibilità LN-RGB sono notevoli: monete stabili su Lightning, DEX layer-2, trasferimento di gettoni fungibili o NFT a costi molto bassi... I capitoli precedenti hanno delineato l'architettura concettuale e la logica di validazione. Ora avete una visione pratica di come ottenere un nodo di questo tipo e farlo funzionare, per i vostri futuri sviluppi o test.

Sezione finale

Recensioni e valutazioni

true

Conclusione

true