name: O protocolo RGB, da teoria à prática goal: Adquirir as competências necessárias para compreender e utilizar o RGB objectives:


Descobrir o protocolo RGB

Mergulhe no mundo do RGB, um protocolo concebido para implementar e fazer cumprir direitos digitais, sob a forma de contratos e activos, com base nas regras de consenso e operações da cadeia de blocos Bitcoin. Este curso de formação abrangente guia-o através dos fundamentos técnicos e práticos do RGB, desde os conceitos de "Validação do lado do cliente" e "Selos de utilização única", até à implementação de contratos inteligentes avançados.

Através de um programa estruturado e passo a passo, descobrirá os mecanismos de validação do lado do cliente, compromissos determinísticos no Bitcoin e padrões de interação entre utilizadores. Aprenderá a criar, gerir e transferir RGB tokens em Bitcoin ou na Lightning Network.

Quer seja um programador, um entusiasta do Bitcoin ou simplesmente um curioso para saber mais sobre esta tecnologia, este curso de formação irá fornecer-lhe as ferramentas e os conhecimentos necessários para dominar o RGB e criar soluções inovadoras no Bitcoin.

O curso baseia-se num seminário ao vivo organizado pela Fulgur'Ventures e ministrado por três professores de renome e especialistas em RGB.

Introdução

Apresentação do curso

Olá a todos, e bem-vindos a este curso de formação dedicado ao RGB, um sistema de contrato inteligente validado do lado do cliente que funciona com Bitcoin e a Lightning Network. A estrutura deste curso foi concebida para permitir uma exploração aprofundada deste assunto complexo. Veja como o curso está organizado:

**Secção 1: Teoria

A primeira secção é dedicada aos conceitos teóricos necessários para compreender os fundamentos da validação do lado do cliente e do RGB. Como você descobrirá neste curso, o RGB introduz uma série de conceitos técnicos que não são normalmente vistos no Bitcoin. Nesta seção, você também encontrará um glossário que fornece definições para todos os termos específicos do protocolo RGB.

**Secção 2: Prática

A segunda secção centrar-se-á na aplicação dos conceitos teóricos vistos na secção 1. Aprenderemos a criar e a manipular contratos RGB. Veremos também como programar com estas ferramentas. Estas duas primeiras secções são apresentadas por Maxim Orlovsky.

**Secção 3: Aplicações

A secção final é conduzida por outros oradores que apresentam aplicações concretas baseadas em RGB, para realçar casos de utilização reais.


Este curso de formação surgiu originalmente de um bootcamp de desenvolvimento avançado de duas semanas em Viareggio, Toscana, organizado pela Fulgur'Ventures. A primeira semana, focada em Rust e SDKs, pode ser encontrada neste outro curso:

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

Neste curso, concentramo-nos na segunda semana do bootcamp, que se centra no RGB.

Semana 1 - LNP402:

RGB-Bitcoin

Semana 2 - Formação atual CSV402:

RGB-Bitcoin

Muito obrigado aos organizadores destes cursos em direto e aos 3 professores que participaram:

A versão escrita deste curso de formação foi elaborada com base em dois recursos principais:

Pronto para mergulhar no universo complexo e fascinante do RGB? Vamos lá!

RGB em teoria

Introdução aos conceitos de computação distribuída

O RGB é um protocolo concebido para aplicar e fazer cumprir direitos digitais (sob a forma de contratos e activos) de forma escalável e confidencial, com base nas regras e operações de consenso da cadeia de blocos Bitcoin. O objetivo deste primeiro capítulo é apresentar os conceitos básicos e a terminologia em torno do protocolo RGB, destacando em particular as suas ligações estreitas com conceitos básicos de computação distribuída, como a validação do lado do cliente e os selos de utilização única.

Neste capítulo, exploraremos os fundamentos dos sistemas de consenso distribuído e veremos como o RGB se encaixa nessa família de tecnologias. Apresentaremos também os princípios principais que nos ajudam a compreender por que razão o RGB pretende ser extensível e independente do mecanismo de consenso do Bitcoin, embora dependa dele quando necessário.

Introdução

A computação distribuída, um ramo específico da ciência da computação, estuda os protocolos utilizados para fazer circular e processar informações numa rede de nós. No seu conjunto, estes nós e as regras do protocolo constituem o que se designa por sistema distribuído. Entre as propriedades essenciais que caracterizam um sistema deste tipo contam-se :

Em particular, a noção de consenso num sistema distribuído abrange dois aspectos:

A primeira implementação funcional e sem permissões de um mecanismo de consenso distribuído foi introduzida por Satoshi Nakamoto com a Bitcoin, graças à utilização combinada de uma estrutura de dados de cadeia de blocos e de um algoritmo de prova de trabalho (PoW). Neste sistema, a credibilidade do historial do bloco depende do poder de computação que lhe é dedicado pelos nós (mineiros). A Bitcoin é, por conseguinte, um exemplo histórico e importante de um sistema de consenso distribuído aberto a todos (sem permissões).

No mundo do blockchain e da computação distribuída, podemos distinguir dois paradigmas fundamentais: blockchain no sentido tradicional, e canais de estado, cujo melhor exemplo em produção é a Lightning Network. A blockchain é definida como um registo de eventos ordenados cronologicamente, replicados por consenso numa rede aberta e sem permissões. Os canais de estado, por outro lado, são canais peer-to-peer que permitem a dois (ou mais) participantes manter um estado atualizado fora da cadeia, utilizando a cadeia de blocos apenas quando abrem e fecham esses canais.

No contexto da Bitcoin, está sem dúvida familiarizado com os princípios de mineração, descentralização e finalidade das transacções na blockchain, bem como com o funcionamento dos canais de pagamento. Com o RGB, estamos a introduzir um novo paradigma chamado Client-side Validation, que, ao contrário do blockchain ou do Lightning, consiste em armazenar e validar localmente (do lado do cliente) as transições de estado de um contrato inteligente. Também difere de outras técnicas "DeFi" (rollups, plasma, ARK, etc.), na medida em que a validação do lado do cliente se baseia na blockchain para evitar gastos duplos e para ter um sistema de marcação de tempo, mantendo o registo de estados e transições fora da cadeia, apenas com os participantes em causa.

RGB-Bitcoin

Mais adiante, introduziremos também um termo importante: a noção de "stash", que se refere ao conjunto de dados do lado do cliente necessários para preservar o estado de um contrato, uma vez que estes dados não são replicados globalmente na rede. Por fim, analisaremos a lógica subjacente ao RGB, um protocolo que tira partido da validação do lado do cliente, e a razão pela qual complementa as abordagens existentes (blockchain e canais de estado).

Trilemas na computação distribuída

Para entender como a validação do lado do cliente e o RGB abordam problemas não resolvidos pelo blockchain e pelo Lightning, vamos descobrir três grandes "trilemas" na computação distribuída:

1. Escalabilidade, descentralização e confidencialidade

A cadeia de blocos é altamente descentralizada, mas não é muito escalável. Além disso, como tudo está num registo global e público, a confidencialidade é limitada. Podemos tentar melhorar a confidencialidade com tecnologias de conhecimento zero (transacções confidenciais, esquemas mimblewimble, etc.), mas a cadeia pública não pode esconder o gráfico da transação.

Os canais estatais (como a Lightning Network) são mais escaláveis e mais privados do que a cadeia de blocos, uma vez que as transacções têm lugar fora da cadeia. No entanto, a obrigação de anunciar publicamente certos elementos (transacções de financiamento, topologia da rede) e a monitorização do tráfego da rede podem comprometer parcialmente a confidencialidade. A descentralização também é afetada: o encaminhamento é intensivo em dinheiro e os nós principais podem tornar-se pontos de centralização. É precisamente este o fenómeno a que começamos a assistir no Lightning.

Este novo paradigma é ainda mais escalável e mais confidencial, porque não só podemos integrar técnicas de prova de conhecimento de divulgação zero, como também não existe um gráfico global de transacções, uma vez que ninguém detém o registo completo. Por outro lado, também implica um certo compromisso em relação à descentralização: o emissor de um contrato inteligente pode ter um papel central (como um "implantador de contrato" no Ethereum). No entanto, ao contrário da blockchain, com a Validação do lado do cliente, apenas armazena e valida os contratos que lhe interessam, o que melhora a escalabilidade ao evitar a necessidade de descarregar e verificar todos os estados existentes.

RGB-Bitcoin

2. Teorema CAP (Consistência, Disponibilidade, Tolerância de Partição)

O teorema CAP sublinha que é impossível um sistema distribuído satisfazer simultaneamente a consistência (Consistência), a disponibilidade (Disponibilidade) e a tolerância de partição (Tolerância de partição).

A cadeia de blocos favorece a consistência e a disponibilidade, mas não se dá bem com o particionamento da rede: se não se consegue ver um bloco, não se pode atuar e ter a mesma visão que toda a rede.

Um sistema de canais de estado tem disponibilidade e tolerância de partição (uma vez que dois nós podem permanecer ligados um ao outro mesmo que a rede esteja fragmentada), mas a consistência global depende da abertura e fecho de canais na cadeia de blocos.

Um sistema como o RGB oferece consistência (cada participante valida os seus dados localmente, sem ambiguidade) e tolerância de partição (o utilizador mantém os seus dados de forma autónoma), mas não garante a disponibilidade global (cada um tem de se certificar de que possui os elementos relevantes do historial e alguns participantes podem não publicar nada ou deixar de partilhar determinadas informações).

RGB-Bitcoin

3. Trilema CIA (Confidencialidade, Integridade, Disponibilidade)

Este trilema recorda-nos que a confidencialidade, a integridade e a disponibilidade não podem ser optimizadas ao mesmo tempo. Blockchain, Lightning e Validação do lado do cliente caem de forma diferente neste equilíbrio. A ideia é que nenhum sistema pode fornecer tudo; é necessário combinar várias abordagens (o registo de tempo da blockchain, a abordagem síncrona da Lightning e a validação local com RGB) para obter um pacote coerente que ofereça boas garantias em cada dimensão.

RGB-Bitcoin

O papel da cadeia de blocos e a noção de fragmentação

O blockchain (neste caso, o Bitcoin) serve principalmente como um mecanismo de time-stamping e proteção contra gastos duplos. Em vez de inserir os dados completos de um contrato inteligente ou de um sistema descentralizado, incluímos simplesmente compromissos criptográficos (compromissos) para as transacções (no sentido da validação do lado do cliente, a que chamaremos "transições de estado"). Assim :

O sharding é um conceito que teve origem nas bases de dados distribuídas (por exemplo, MySQL para redes sociais como o Facebook ou o Twitter). Para resolver o problema do volume de dados e das latências de sincronização, a base de dados é segmentada em shards (EUA, Europa, Ásia, etc.). Cada segmento é localmente consistente e apenas parcialmente sincronizado com os outros.

Para os contratos inteligentes do tipo RGB, fragmentamos de acordo com os próprios contratos. Cada contrato é um shard independente. Por exemplo, se só tiver tokens USDT, não precisa de armazenar ou validar todo o histórico de outro token como o USDC. No Bitcoin, a blockchain não faz sharding: tem um conjunto global de UTXOs. Com a validação do lado do cliente, cada participante retém apenas os dados do contrato que detém ou utiliza.

Podemos, portanto, imaginar o ecossistema da seguinte forma:

RGB-Bitcoin

Estes três elementos formam um todo triangular, em vez de uma pilha linear de "camada 2", "camada 3" e assim por diante. O Lightning pode ligar-se diretamente à Bitcoin ou ser associado a transacções Bitcoin que incorporem dados RGB. Do mesmo modo, uma utilização "BiFi" (finanças em Bitcoin) pode compor-se com a cadeia de blocos, com Lightning e com RGB de acordo com as necessidades de confidencialidade, escalabilidade ou lógica de contrato.

RGB-Bitcoin

A noção de transições de estado

Em qualquer sistema distribuído, o objetivo do mecanismo de validação é poder determinar a validade e a ordem cronológica das mudanças de estado. O objetivo é verificar se as regras do protocolo foram respeitadas e provar que estas alterações de estado se sucedem numa ordem definitiva e inatacável.

Para compreender como funciona esta validação no contexto da Bitcoin e, de uma forma mais geral, para compreender a filosofia subjacente à validação do lado do cliente, vamos primeiro analisar os mecanismos da blockchain da Bitcoin, antes de ver como a validação do lado do cliente difere deles e quais as optimizações que torna possíveis.

RGB-Bitcoin

No caso da cadeia de blocos Bitcoin, a validação da transação baseia-se numa regra simples:

RGB-Bitcoin

No entanto, este modelo tem dois grandes inconvenientes:

RGB-Bitcoin

Na prática, este modelo funciona para a Bitcoin como camada de base (camada 1), mas pode tornar-se insuficiente para utilizações mais complexas que exijam simultaneamente um elevado débito de transacções e um certo grau de confidencialidade.

A validação do lado do cliente baseia-se na ideia oposta: em vez de exigir que toda a rede valide e armazene todas as transacções, cada participante (cliente) validará apenas a parte do histórico que lhe diz respeito:

RGB-Bitcoin

Ao mesmo tempo, para que o resto da rede (ou, mais precisamente, a camada subjacente, como a Bitcoin) possa bloquear o estado final sem ver os detalhes desses dados, a validação do lado do cliente baseia-se na noção de compromisso.

Um compromisso é um compromisso criptográfico, normalmente um hash (SHA-256, por exemplo) inserido numa transação Bitcoin, que prova que foram incluídos dados privados, sem revelar esses dados.

Graças a estes compromissos, podemos provar:

No entanto, o conteúdo exato não é revelado, preservando assim a sua confidencialidade.

Em termos concretos, eis como funciona uma transição de estado RGB:

RGB-Bitcoin

A validação do lado do cliente oferece duas grandes vantagens:

Os compromissos (compromissos) incluídos na cadeia de blocos são pequenos (da ordem de algumas dezenas de bytes). Isso garante que o espaço do bloco não seja saturado, pois apenas o hash precisa ser incluído. Também permite a evolução do protocolo fora da cadeia, uma vez que cada utilizador só tem de armazenar o seu fragmento de história (o seu stash).

As transacções propriamente ditas (ou seja, o seu conteúdo detalhado) não são publicadas na cadeia. Apenas as suas impressões digitais (hash) o são. Assim, os valores, endereços e lógica de contrato permanecem privados, e o recetor pode verificar, localmente, a validade do seu fragmento inspeccionando todas as transições anteriores. Não há razão para o recetor tornar estes dados públicos, exceto em caso de disputa ou quando é necessária uma prova.

Num sistema como o RGB, múltiplas transições de estado de diferentes contratos (ou diferentes activos) podem ser agregadas numa única transação Bitcoin através de um único commitment. Este mecanismo estabelece uma ligação determinística, com registo de data e hora, entre a transação na cadeia e os dados fora da cadeia (as transições validadas do lado do cliente), e permite que vários fragmentos sejam simultaneamente registados num único ponto de ancoragem, reduzindo ainda mais o custo e a pegada na cadeia.

Na prática, quando esta transação Bitcoin é validada, "bloqueia" permanentemente o estado dos contratos subjacentes, uma vez que se torna impossível modificar o hash já inscrito na cadeia de blocos.

RGB-Bitcoin

O conceito de esconderijo

Um stash é o conjunto de dados do lado do cliente que um participante deve absolutamente reter para manter a integridade e o histórico de um contrato inteligente RGB. Ao contrário de um canal Lightning, onde certos estados podem ser reconstruídos localmente a partir de informações compartilhadas, o stash de um contrato RGB não é replicado em outro lugar: se você o perder, ninguém será capaz de restaurá-lo para você, pois você é responsável por sua parte do histórico. É por isso que é necessário adotar um sistema com procedimentos de cópia de segurança fiáveis em RGB.

RGB-Bitcoin

Selo de utilização única: origens e funcionamento

Ao aceitar um ativo como uma moeda, são essenciais duas garantias:

Para activos físicos, como uma nota de banco, a presença física é suficiente para provar que não foi duplicada. No entanto, no mundo digital, onde os activos são puramente informativos, esta verificação é mais complexa, uma vez que a informação pode facilmente multiplicar-se e ser duplicada.

Como vimos anteriormente, o facto de o remetente revelar o histórico das transições de estado permite-nos garantir a autenticidade de um token RGB. Ao ter acesso a todas as transacções desde a transação de génese, podemos confirmar a autenticidade do token. Este princípio é semelhante ao da Bitcoin, em que o histórico das moedas pode ser rastreado até à transação original da coinbase para verificar a sua validade. No entanto, ao contrário da Bitcoin, este historial de transições de estado na RGB é privado e mantido no lado do cliente.

Para evitar o gasto duplo de fichas RGB, utilizamos um mecanismo denominado "Selo de utilização única". Este sistema garante que cada ficha, uma vez utilizada, não pode ser reutilizada de forma fraudulenta uma segunda vez.

Os selos de utilização única são primitivos criptográficos, propostos em 2016 por Peter Todd, semelhantes ao conceito de selos físicos: uma vez colocado um selo num contentor, torna-se impossível abri-lo ou modificá-lo sem quebrar irreversivelmente o selo.

RGB-Bitcoin

Esta abordagem, transposta para o mundo digital, permite provar que uma sequência de eventos teve efetivamente lugar e que já não pode ser alterada a posteriori. Os selos de utilização única ultrapassam assim a lógica simples de hash + timestamp, acrescentando a noção de um selo que pode ser fechado uma única vez.

RGB-Bitcoin

Para que os selos de uso único funcionem, é necessário um meio de prova de publicação capaz de provar a existência ou ausência de uma publicação e difícil (se não impossível) de falsificar depois de a informação ter sido disseminada. Uma blockchain (como a Bitcoin) pode desempenhar esse papel, assim como um jornal em papel de circulação pública, por exemplo. A ideia é a seguinte:

Uma cadeia de blocos presta-se idealmente a este papel: assim que uma transação é incluída num bloco, toda a rede tem a mesma prova infalsificável da sua existência e do seu conteúdo (pelo menos em parte, uma vez que o compromisso pode esconder os pormenores ao mesmo tempo que prova a autenticidade da mensagem).

Um selo de utilização única pode, portanto, ser visto como uma promessa formal de publicar uma mensagem (ainda desconhecida nesta fase) uma vez e apenas uma vez, de uma forma que possa ser verificada por todas as partes interessadas.

Ao contrário dos compromissos simples (hash) ou dos carimbos de data/hora, que atestam uma data de existência, um selo de utilização única oferece a garantia adicional de que nenhum compromisso alternativo pode coexistir: não se pode fechar o mesmo selo duas vezes, nem tentar substituir a mensagem selada.

A comparação que se segue ajuda a compreender este princípio:

Compromisso simples (digest/hash)TimestampsSelos de uso único
A publicação do compromisso não revela a mensagemSimSimSim
Prova da data do compromisso / existência da mensagem antes de uma determinada dataImpossívelPossívelPossível
Prova de que nenhum outro compromisso alternativo pode existirImpossívelImpossívelPossível

Os selos de utilização única funcionam em três fases principais:

Definição de vedação :

RGB-Bitcoin

Fechamento do selo :

RGB-Bitcoin

Verificação da selagem :

O processo pode ser resumido da seguinte forma:

# 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)

No entanto, a validação do lado do cliente vai um passo mais além: se a definição de um selo permanecer fora da cadeia de blocos, é possível (em teoria) que alguém conteste a existência ou a legitimidade do selo em questão. Para ultrapassar este problema, é utilizada uma cadeia de selos de utilização única interligados:

É exatamente isso que o sistema RGB faz:

Em suma:

Esta singularidade é importante para a validação do lado do cliente: quando valida uma transição de estado, verifica se esta corresponde a um UTXO único, não gasto anteriormente num compromisso concorrente. É isto que garante a ausência de gastos duplos em contratos inteligentes fora da cadeia.

Múltiplos compromissos e raízes

Um contrato inteligente RGB pode precisar gastar vários selos de uso único (vários UTXOs) simultaneamente. Além disso, uma única transação Bitcoin pode fazer referência a vários contratos distintos, cada um selando a sua própria transição de estado. Isto requer um mecanismo de multi-compromisso para provar, de forma determinística e única, que nenhum dos compromissos existe em duplicado. É aqui que a noção de anchor entra em jogo no RGB: uma estrutura especial que liga uma transação Bitcoin e um ou mais compromissos do lado do cliente (transições de estado), cada um potencialmente pertencente a um contrato diferente. Iremos analisar este conceito mais detalhadamente no próximo capítulo.

RGB-Bitcoin

Dois dos principais repositórios GitHub do projeto (sob a organização LNPBP) agrupam as implementações básicas destes conceitos estudados no primeiro capítulo:

RGB-Bitcoin

Note-se que estes blocos de software são agnósticos em relação à Bitcoin; em teoria, poderiam ser aplicados a qualquer outro meio de prova de publicação (outro registo, um jornal, etc.). Na prática, o RGB depende do Bitcoin pela sua robustez e consenso alargado.

RGB-Bitcoin

Perguntas do público

Para uma utilização mais alargada dos selos de utilização única

Peter Todd também criou o protocolo Open Timestamps, e o conceito de Single-use Seal é uma extensão natural destas ideias. Para além do RGB, podem ser previstos outros casos de utilização, como a construção de sidechains sem recorrer ao merge mining ou a propostas relacionadas com drivechains como o BIP300. Qualquer sistema que exija um único compromisso pode, em princípio, explorar esta primitiva criptográfica. Atualmente, o RGB é a primeira grande implementação em grande escala.

Problemas de disponibilidade de dados

Uma vez que, na validação do lado do cliente, cada utilizador armazena a sua própria parte do histórico, a disponibilidade dos dados não é garantida globalmente. Se o emitente de um contrato retiver ou revogar determinadas informações, o utilizador pode não ter conhecimento da evolução real da oferta. Nalguns casos (como o das stablecoins), espera-se que o emitente mantenha dados públicos que comprovem o volume em circulação, mas não existe qualquer obrigação técnica de o fazer. Por conseguinte, é possível conceber contratos deliberadamente opacos com oferta ilimitada, o que levanta questões de confiança.

Fragmentação e isolamento de contratos

Cada contrato representa um shard isolado: O USDT e o USDC, por exemplo, não têm de partilhar os seus históricos. As trocas atómicas continuam a ser possíveis, mas isso não implica a fusão dos seus registos. Tudo é feito através de um compromisso criptográfico, sem revelar todo o histórico a cada participante.

Conclusão

Vimos onde o conceito de Validação do lado do cliente se encaixa com blockchain e state channels, como ele responde a trilemas de computação distribuída, e como ele alavanca o blockchain do Bitcoin exclusivamente para evitar gastos duplos e para time-stamping. A ideia baseia-se na noção de Selo de utilização única, permitindo a criação de compromissos únicos que não podem ser reutilizados à vontade. Desta forma, cada participante carrega apenas o histórico estritamente necessário, aumentando a escalabilidade e a confidencialidade dos contratos inteligentes, mantendo a segurança do Bitcoin como pano de fundo.

O próximo passo será explicar com mais detalhes como esse mecanismo de Single-use Seal é aplicado no Bitcoin (via UTXOs), como as âncoras são criadas e validadas e, em seguida, como contratos inteligentes completos são construídos em RGB. Em particular, analisaremos a questão dos compromissos múltiplos, o desafio técnico de provar que uma transação Bitcoin sela simultaneamente várias transições de estado em diferentes contratos, sem introduzir vulnerabilidades ou compromissos duplos.

Antes de mergulhar nos detalhes mais técnicos do segundo capítulo, não hesite em reler as principais definições (validação do lado do cliente, selo de utilização única, âncoras, etc.) e tenha em mente a lógica geral: estamos a tentar conciliar os pontos fortes da cadeia de blocos Bitcoin (segurança, descentralização, registo de data e hora) com os das soluções fora da cadeia (velocidade, confidencialidade, escalabilidade), e é precisamente isto que o RGB e a validação do lado do cliente estão a tentar alcançar.

A camada de compromisso

Neste capítulo, veremos a implementação da validação do lado do cliente e dos selos de uso único dentro da blockchain do Bitcoin. Apresentaremos os principais princípios da camada de compromisso (camada 1) da RGB, com um foco particular no esquema TxO2, que a RGB usa para definir e fechar um selo em uma transação Bitcoin. De seguida, discutiremos dois pontos importantes que ainda não foram abordados em pormenor:

É a combinação destes conceitos que nos permite sobrepor vários sistemas ou contratos a um único UTXO e, por conseguinte, a uma única cadeia de blocos.

Recorde-se que as operações criptográficas descritas podem ser aplicadas, em termos absolutos, a outras blockchains ou meios de publicação, mas as caraterísticas da Bitcoin (em termos de descentralização, resistência à censura e abertura a todos) fazem dela a base ideal para o desenvolvimento de uma programação avançada como a exigida pela RGB.

Esquemas de compromisso na Bitcoin e a sua utilização pela RGB

Como vimos no primeiro capítulo do curso, Selos de uso único são um conceito geral: fazemos uma promessa de incluir um compromisso (compromisso) em um local específico de uma transação, e esse local atua como um selo que fechamos em uma mensagem. No entanto, na blockchain do Bitcoin, existem várias opções para escolher onde colocar esse compromisso.

Para entender a lógica, vamos relembrar o princípio básico: para fechar um selo de uso único, gastamos a área selada inserindo o compromisso numa determinada mensagem. Em Bitcoin, isso pode ser feito de várias maneiras:

Podemos decidir que uma chave pública ou endereço específico é o selo de utilização única. Assim que esta chave ou endereço aparece na cadeia numa transação, significa que o selo foi fechado com uma determinada mensagem.

Isto significa que um selo de utilização única é definido como um ponto de saída preciso (um par TXID + número de saída). Assim que este ponto de saída é gasto, o selo é fechado.

Enquanto trabalhávamos no RGB, identificámos pelo menos 4 formas diferentes de implementar estes selos na Bitcoin:

Nome do esquemaDefinição do seloFechamento do seloRequisitos adicionaisAplicação principalEsquemas de compromisso possíveis
PkOValor da chave públicaSaída de transaçãoP2(W)PKHNenhuma no momentoKeytweak, taptweak, opret
TxO2Saída de transaçãoSaída de transaçãoExige compromissos determinísticos em BitcoinRGBv1 (universal)Keytweak, tapret, opret
PkIValor da chave públicaEntrada de transaçãoSomente Taproot & não compatível com carteiras antigasIdentidades baseadas em BitcoinSigtweak, witweak
TxO1Saída de transaçãoEntrada de transaçãoSomente Taproot & não compatível com carteiras antigasNenhuma no momentoSigtweak, witweak

Não entraremos em detalhes sobre cada uma dessas configurações, pois no RGB optamos por usar um outpoint como definição do selo, e colocar o commitment na saída da transação que gasta esse outpoint. Podemos assim introduzir os seguintes conceitos para a sequência:

Este esquema foi selecionado pela sua compatibilidade com a arquitetura RGB, mas outras configurações podem ser úteis para diferentes utilizações.

O "O2" em "TxO2" recorda-nos que tanto a definição como o encerramento se baseiam na despesa (ou criação) de um resultado de transação.

Exemplo de diagrama TxO2

Como lembrete, a definição de um selo de utilização única não requer necessariamente a publicação de uma transação na cadeia. É suficiente que Alice, por exemplo, já tenha um UTXO não gasto. Ela pode decidir: "Este outpoint (já existente) é agora o meu selo". Ela regista este facto localmente (client-side), e até que este UTXO seja gasto, o selo é considerado aberto.

RGB-Bitcoin

No dia em que pretende fechar o selo (para assinalar um acontecimento ou para ancorar uma determinada mensagem), gasta este UTXO numa nova transação (esta transação é frequentemente designada por "transação de testemunho" (não tem qualquer relação com segwit, é apenas o termo que lhe damos). Esta nova transação conterá o compromisso com a mensagem.

RGB-Bitcoin

Note-se que neste exemplo :

Para ilustrar este esquema TxO2, podemos utilizar um selo de utilização única como mecanismo de revogação de uma chave PGP. Em vez de publicar um certificado de revogação nos servidores, Alice pode dizer: "Esta saída de Bitcoin, se gasta, significa que a minha chave PGP está revogada".

Alice tem, por conseguinte, um UTXO específico, ao qual está associado localmente (no lado do cliente) um determinado estado ou dados (que só ela conhece).

Alice informa Bob que se este UTXO for gasto, um determinado evento será considerado como tendo ocorrido. Do lado de fora, tudo o que vemos é uma transação de Bitcoin; mas o Bob sabe que esta despesa tem um significado oculto.

RGB-Bitcoin

Quando Alice gasta este UTXO, ela fecha o selo numa mensagem indicando a sua nova chave, ou simplesmente a revogação da antiga. Desta forma, qualquer pessoa que esteja a monitorizar a cadeia verá que o UTXO foi gasto, mas apenas aqueles com a prova completa saberão que é precisamente a revogação da chave PGP.

RGB-Bitcoin

Para que Bob ou qualquer outra pessoa envolvida possa verificar a mensagem oculta, Alice deve fornecer-lhe informações fora da cadeia.

RGB-Bitcoin

Alice deve, portanto, fornecer a Bob :

RGB-Bitcoin

Os terceiros não têm esta informação. Apenas vêem que foi gasto um UTXO. A confidencialidade é assim assegurada.

Para clarificar a estrutura, vamos resumir o processo em duas transacções:

RGB-Bitcoin RGB-Bitcoin

Por conseguinte, designamos a segunda transação por "transação de testemunha".

Para ilustrar isto de outro ângulo, podemos representar duas camadas:

RGB-Bitcoin

Mas, ao fechar o selo, coloca-se a questão de saber onde deve ser inserido o "compromisso

Na secção anterior, mencionámos brevemente como o modelo de validação do lado do cliente pode ser aplicado ao RGB e a outros sistemas. Aqui, abordamos a parte sobre compromissos Bitcoin determinísticos e como integrá-los em uma transação. A ideia é perceber por que razão estamos a tentar inserir um único compromisso na transacção de testemunho e, acima de tudo, como garantir que não pode haver outros compromissos concorrentes não revelados.

Locais de compromisso numa transação

Quando se dá a alguém uma prova de que uma determinada mensagem está incorporada numa transação, é necessário poder garantir que não existe outra forma de compromisso (uma segunda mensagem oculta) na mesma transação que não lhe tenha sido revelada. Para que a validação do lado do cliente se mantenha robusta, é necessário um mecanismo determinístico para colocar um único compromisso na transação que fecha o selo de utilização única.

A transacção testemunha gasta o famoso UTXO (ou definição do selo) e esta despesa corresponde ao fecho do selo. Tecnicamente, sabemos que cada ponto de saída só pode ser gasto uma vez. É precisamente isto que está na base da resistência do Bitcoin ao duplo gasto. Mas a transação de despesa pode ter vários inputs, vários outputs, ou ser composta de forma complexa (coinjoins, canais Lightning, etc.). Por conseguinte, é necessário definir claramente onde inserir o commitment nesta estrutura, de forma inequívoca e uniforme.

Qualquer que seja o método (PkO, TxO2, etc.), o compromisso pode ser inserido :

RGB-Bitcoin

Eis os pormenores de cada método:

RGB-Bitcoin

Sig tweak (sign-to-contract) :

Um esquema anterior envolvia a exploração da parte aleatória de uma assinatura (ECDSA ou Schnorr) para incorporar o compromisso: esta é a técnica conhecida como "Sign-to-contract". Substitui-se o nonce gerado aleatoriamente por um hash que contém os dados. Desta forma, a assinatura revela implicitamente o seu compromisso, sem qualquer espaço adicional na transação. Esta abordagem tem uma série de vantagens:

No entanto, surgiram dois grandes inconvenientes:

Na prática, o sig tweak também não é muito compatível com o hardware (carteiras de hardware) e os formatos existentes (Lightning, etc.). Por isso, esta grande ideia é difícil de pôr em prática.

Ajustamento da chave (pagamento por contrato) :

O ajuste da chave retoma o conceito histórico de pagar-para-contratar. Pegamos na chave pública X e alteramo-la adicionando o valor H(mensagem). Especificamente, se X = x * G e h = H(mensagem), então a nova chave será X' = X + h * G. Esta chave modificada esconde o compromisso com a mensagem. O detentor da chave privada original pode, ao adicionar h à sua chave privada x, provar que tem a chave para gastar a saída. Em teoria, isto é elegante, porque :

Na prática, porém, deparamo-nos com as seguintes dificuldades:

No contexto do RGB, esta via estava prevista até 2021, mas revelou-se demasiado complicada para funcionar com as normas e infra-estruturas actuais.

Ajuste da testemunha :

Uma outra ideia, que certos protocolos como inscriptions Ordinals puseram em prática, consiste em colocar os dados diretamente na secção "testemunha" da transação (daí a expressão "witness tweak"). No entanto, este método :

Além disso, o testemunho foi concebido para ser podável em determinados contextos, o que pode tornar mais complicada a obtenção de provas robustas.

Abertura-retorno (opret) :

Muito simples no seu funcionamento, um OP_RETURN permite-lhe armazenar um hash ou uma mensagem num campo especial da transação. Mas é imediatamente detetável: todos vêem que há um compromisso na transação, e pode ser censurado ou descartado, bem como adicionar uma saída extra. Uma vez que isto aumenta a transparência e o tamanho, é considerado menos satisfatório do ponto de vista de uma solução de validação do lado do cliente.

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

Tapret

A última opção é a utilização do Taproot (introduzido com o BIP341) com o esquema Tapret. Tapret é uma forma mais complexa de compromisso determinístico, que traz melhorias em termos de footprint na blockchain e confidencialidade para operações de contrato. A ideia principal é esconder o compromisso na parte Script Path Spend de uma [transação taproot] (https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki).

RGB-Bitcoin

Antes de descrever como o compromisso é inserido numa transação taproot, vejamos a forma exacta do compromisso, que deve imperativamente corresponder a uma cadeia de 64 bytes construída da seguinte forma:

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

Assim, o método Tapret de 64 bytes parece um Opret ao qual prefixámos 29 bytes de OP_RESERVED e adicionámos um byte extra como Nonce.

Para manter a flexibilidade em termos de implementação, confidencialidade e escalonamento, o esquema Tapret tem em conta vários casos de utilização, consoante os requisitos:

Vejamos mais detalhadamente cada um destes dois cenários.

Incorporação de Tapret sem Caminho de Script existente

Neste primeiro caso, começamos a partir de uma chave de saída taproot (Taproot Output Key) Q que contém apenas a chave pública interna P (Internal Key), sem nenhum caminho de script associado (Script Path) :

RGB-Bitcoin

Para incluir uma autorização Tapret, adicione um Script Path Spend com um script único, como se segue:

RGB-Bitcoin

A prova de inclusão e unicidade na árvore de raiz principal resume-se aqui à única chave pública interna P.

Integração de Tapret num Script Path pré-existente

O segundo cenário diz respeito a uma saída Q taproot** mais complexa, que já contém vários scripts. Por exemplo, temos uma árvore de 3 scripts:

RGB-Bitcoin

Para acrescentar o compromisso Tapret, é necessário inserir um script não gastável no primeiro nível da árvore, deslocando os scripts existentes um nível abaixo. Visualmente, a árvore torna-se :

RGB-Bitcoin

De acordo com as regras da raiz principal, cada ramo/folha deve ser combinado de acordo com uma ordem de hash lexicográfica. Há dois casos possíveis:

Exemplo visual para o primeiro caso (tHABC < tHT):

RGB-Bitcoin

Exemplo para o segundo caso (tHABC > tHT):

RGB-Bitcoin

Otimização com o nonce

Para melhorar a confidencialidade, podemos "minerar" (um termo mais preciso seria "fazer força bruta") o valor do <Nonce> (o último byte do Tapret de 64 bytes) na tentativa de obter um hash tHT tal que tHABC < tHT. Neste caso, o compromisso é colocado à direita, poupando o utilizador de ter de divulgar todo o conteúdo de scripts existentes para provar a unicidade do Tapret.

Em suma, o Tapret oferece uma forma discreta e determinística de incorporar um compromisso numa transação de raiz principal, respeitando o requisito de unicidade e inequivocidade essencial para a lógica de validação do lado do cliente e do selo de utilização única da RGB.

Saídas válidas

Para as transacções de compromisso RGB, o principal requisito para um esquema de compromisso Bitcoin válido é o seguinte: A transação (transação testemunha) deve conter comprovadamente um único compromisso. Este requisito impossibilita a construção de um histórico alternativo para dados validados do lado do cliente dentro da mesma transação. Isto significa que a mensagem em torno da qual o single-use seal se fecha é única.

Para satisfazer este princípio, e independentemente do número de saídas numa transação, exigimos que uma e apenas uma saída possa conter um compromisso (compromisso). Para cada um dos esquemas utilizados (Opret ou Tapret), as únicas saídas válidas que podem conter um compromisso RGB são :

Note-se que é perfeitamente possível que uma transação contenha um único compromisso Opret e um único compromisso Tapret em duas saídas separadas. Graças à natureza determinística da Definição de Selo, estes dois compromissos correspondem então a dois dados distintos validados no lado do cliente.

Análise e opções práticas em RGB

Quando criámos o RGB, analisámos todos estes métodos para determinar onde e como colocar um compromisso numa transação de forma determinística. Definimos alguns critérios:

MétodoRastro e tamanho on-chainTamanho do lado do clienteIntegração com carteiraCompatibilidade de hardwareCompatibilidade com LightningCompatibilidade com Taproot
Keytweak (P2C determinístico)🟢🟡🔴🟠🔴 BOLT, 🔴 Bifrost🟠 Taproot, 🟢 MuSig
Sigtweak (S2C determinístico)🟢🟢🟠🔴🔴 BOLT, 🔴 Bifrost🟠 Taproot, 🔴 MuSig
Opret (OP_RETURN)🔴🟢🟢🟠🔴 BOLT, 🟠 Bifrost-
Algoritmo Tapret: nó superior esquerdo🟠🔴🟠🟢🔴 BOLT, 🟢 Bifrost🟢 Taproot, 🟢 MuSig
Algoritmo Tapret #4: qualquer nó + prova🟢🟠🟠🟢🔴 BOLT, 🟢 Bifrost🟢 Taproot, 🟢 MuSig
Esquema de compromisso determinísticoPadrãoCusto on-chainTamanho da prova no lado do cliente
Keytweak (P2C determinístico)LNPBP-1, 20 bytes33 bytes (chave não ajustada)
Sigtweak (S2C determinístico)WIP (LNPBP-39)0 bytes0 bytes
Opret (OP_RETURN)-36 (v)bytes (TxOut adicional)0 bytes
Algoritmo Tapret: nó superior esquerdoLNPBP-632 bytes no witness (8 vbytes) para qualquer multisig n-of-m e gasto via caminho de script0 bytes nos scriptless scripts taproot ~270 bytes para um único script, ~128 bytes se houver vários scripts
Algoritmo Tapret #4: qualquer nó + prova de unicidadeLNPBP-632 bytes no witness (8 vbytes) para casos de script único, 0 bytes no witness na maioria dos outros casos0 bytes nos scriptless scripts taproot, 65 bytes até que o Taptree tenha uma dúzia de scripts
CamadaCusto on-chain (bytes/vbytes)Custo on-chain (bytes/vbytes)Custo on-chain (bytes/vbytes)Custo on-chain (bytes/vbytes)Custo on-chain (bytes/vbytes)Custo lado cliente (bytes)Custo lado cliente (bytes)Custo lado cliente (bytes)Custo lado cliente (bytes)Custo lado cliente (bytes)
TipoTapretTapret #4KeytweakSigtweakOpretTapretTapret #4KeytweakSigtweakOpret
Single-sig00003200320?0
MuSig (n-of-n)0000320032? > 00
Multi-sig 2-of-332/832/8 ou 00n/a32~2706532n/a0
Multi-sig 3-of-532/832/8 ou 00n/a32~3406532n/a0
Multi-sig 2-of-3 com timeouts32/800n/a32646532n/a0
CamadaCusto on-chain (vbytes)Custo on-chain (vbytes)Custo on-chain (vbytes)Custo no cliente (bytes)Custo no cliente (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
Ramificação MuSig / Multi_a (n-of-m)1+16n+8n+8xlog(n)806465
Com timeouts (n-of-m)1+16n+8n+8xlog(n)806465
MétodoPrivacidade e EscalabilidadeInteroperabilidadeCompatibilidadePortabilidadeComplexidade
Keytweak (P2C determinístico)🟢🔴🔴🟡🟡
Sigtweak (S2C determinístico)🟢🔴🔴🟢🔴
Opret (OP_RETURN)🔴🟠🔴🟢🟢
Algo Tapret: Nó superior esquerdo🟠🟢🟢🔴🟠
Algo Tapret #4: Qualquer nó + prova🟢🟢🟢🟠🔴

No decurso do estudo, tornou-se claro que nenhum dos esquemas de compromisso era totalmente compatível com a atual norma Lightning (que não emprega Taproot, muSig2 ou suporte adicional de commitment). Estão a ser desenvolvidos esforços para modificar a construção de canais do Lightning (BiFrost) para permitir a inserção de compromissos RGB. Esta é outra área em que precisamos de rever a estrutura da transação, as chaves e a forma como as actualizações do canal são assinadas.

A análise mostrou que, de facto, outros métodos (key tweak, sig tweak, witness tweak, etc.) apresentavam outras formas de complicação:

Para RGB, destacam-se dois métodos em particular: Opret e Tapret, ambos classificados como "Transaction Output" e compatíveis com o modo TxO2 utilizado pelo protocolo.

Compromissos multiprotocolo - MPC

Nesta secção, vamos ver como o RGB lida com a agregação de vários contratos (ou, mais precisamente, os seus transition bundles) dentro de um único compromisso (commitment) registado numa transação Bitcoin através de um esquema determinístico (de acordo com Opret ou Tapret). Para isso, a ordem de Merkelização dos vários contratos ocorre numa estrutura chamada MPC Tree (Multi Protocol Commitment Tree). Nesta secção, veremos a construção desta Árvore MPC, como obter a sua raiz e como vários contratos podem partilhar a mesma transação de forma confidencial e sem ambiguidades.

O Compromisso Multiprotocolo (MPC) foi concebido para satisfazer duas necessidades:

Em termos concretos, cada transition bundle pertence a um determinado contrato. Toda esta informação é inserida numa Árvore MPC, cuja raiz (mpc::Root) é depois novamente hashada para dar o mpc::Commitment. É este último hash que é colocado na transação Bitcoin (witness transaction), de acordo com o método determinístico escolhido.

RGB-Bitcoin

Hash de raiz MPC

O valor efetivamente escrito na cadeia (em Opret ou Tapret) é chamado mpc::Commitment. Este é calculado na forma de BIP-341, de acordo com a fórmula :

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

em que :

RGB-Bitcoin

Construção de árvores MPC

Para construir esta árvore MPC, temos de garantir que cada contrato corresponde a uma única posição de folha. Suponhamos que temos :

Construímos então uma árvore de largura w e profundidade d tal que 2^d = w, com w > C, de modo a que cada contrato possa ser colocado numa folha separada. A posição pos(c_i) de cada contrato na árvore é determinada por :

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

em que o cofator é um número inteiro que aumenta a probabilidade de obter posições distintas para cada contrato. Na prática, a construção segue um processo iterativo:

O objetivo é evitar as árvores demasiado altas, reduzindo ao mínimo o risco de colisão. Note-se que o fenómeno da colisão segue uma lógica de distribuição aleatória, ligada ao [Paradoxo do Aniversário] (https://en.wikipedia.org/wiki/Birthday_problem).

Folhas habitadas

Depois de terem sido obtidas C posições distintas pos(c_i) para os contratos i = {0,1,...,C-1}, cada folha é preenchida com uma função hash (tagged hash):

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

em que :

Folhas desabitadas

As restantes folhas, não atribuídas a um contrato (ou seja, as folhas w - C), são preenchidas com um valor "fictício" (folha de entropia):

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

em que :

Nós MPC

Depois de gerar as w folhas (habitadas ou não), procede-se à merkelização. Todos os nós internos são transformados em hash da seguinte forma:

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

em que :

Progredindo desta forma, obtemos a raiz mpc::Root. Podemos então calcular mpc::Commitment (como explicado acima) e inseri-lo na cadeia.

Para ilustrar isto, vamos imaginar um exemplo em que C=3 (três contratos). As suas posições são supostas ser pos(c_0)=7, pos(c_1)=4, pos(c_2)=2. As outras folhas (posições 0, 1, 3, 5, 6) são folhas de entropia. O diagrama abaixo mostra a sequência de hashes para a raiz com :

O resultado final é o mpc::Root, depois o mpc::Commitment.

RGB-Bitcoin

Verificação do veio MPC

Quando um verificador deseja garantir que um contrato c_i (e seu BundleId) está incluído no mpc::Commitment final, ele simplesmente recebe uma prova de Merkle. Esta prova indica os nós necessários para rastrear as folhas (neste caso, a folha de contrato de c_i) até a raiz. Não é necessário revelar toda a árvore MPC: isto protege a confidencialidade de outros contratos.

No exemplo, um verificador c_2 precisa apenas de um hash intermediário (tH_MPC_LEAF(D)), dois tH_MPC_BRANCH(...), a prova de posição pos(c_2) e o valor cofator. Ele pode então reconstruir localmente a raiz, recalcular o mpc::Commitment e compará-lo com o que foi escrito na transação Bitcoin (dentro de Opret ou Tapret).

RGB-Bitcoin

Este mecanismo garante que :

Resumo da estrutura do CPM

O Multi Protocol Commitment* (MPC) é o princípio que permite à RGB agregar vários contratos numa única transação Bitcoin, mantendo a unicidade dos compromissos e a confidencialidade em relação aos outros participantes. Graças à construção determinística da árvore, a cada contrato é atribuída uma posição única, e a presença de folhas "fictícias" (Entropy Leaves) oculta parcialmente o número total de contratos que participam na transação.

A árvore Merkle completa nunca é armazenada no cliente. Limitamo-nos a gerar um Merkle path para cada contrato em causa, a transmitir ao destinatário (que pode então validar o compromisso). Em alguns casos, pode haver vários activos que passaram pelo mesmo UTXO. É possível fundir vários Merkle paths num chamado multi-protocol commitment block, para evitar a duplicação de muitos dados.

Cada prova de Merkle é, portanto, leve, tanto mais que a profundidade da árvore não ultrapassa 32 em RGB. Existe também uma noção de "bloco de Merkle", que retém mais informações (secção transversal, entropia, etc.), útil para combinar ou separar vários ramos.

É por isso que demorou tanto tempo para finalizar o RGB. Tínhamos a visão geral desde 2019: colocar tudo no lado do cliente, circulando tokens fora da cadeia. Mas para detalhes como sharding para vários contratos, a estrutura da árvore Merkle, como lidar com colisões e provas de fusão ... tudo isso exigiu iterações.

Âncoras: uma assembleia mundial

Na sequência da construção dos nossos compromissos (Opret ou Tapret) e do nosso MPC (Multi Protocol Commitment), precisamos de abordar a noção de Anchor no protocolo RGB. Uma âncora é uma estrutura validada do lado do cliente que reúne os elementos necessários para verificar se um compromisso Bitcoin contém efetivamente informações contratuais específicas. Por outras palavras, uma âncora resume todos os dados necessários para validar os compromissos descritos acima.

Uma âncora é constituída por três campos ordenados:

Cada um destes campos desempenha um papel no processo de validação, quer se trate de reconstruir a transação Bitcoin subjacente ou de provar a existência de um compromisso oculto (particularmente no caso do Tapret).

TxId

O campo Txid corresponde ao identificador de 32 bytes da transação Bitcoin que contém o compromisso Opret ou Tapret.

Em teoria, seria possível encontrar este Txid rastreando a cadeia de transições de estado que apontam para cada transação testemunha, seguindo a lógica dos selos de utilização única. No entanto, para facilitar e acelerar a verificação, este Txid é simplesmente incluído na Âncora, evitando assim que o validador tenha de percorrer todo o historial fora da cadeia.

Prova de MPC

O segundo campo, MPC Proof, refere-se à prova de que este contrato específico (por exemplo, c_i) está incluído no Multi Protocol Commitment. É uma combinação de :

Este mecanismo foi descrito na secção anterior sobre a construção da árvore MPC, onde cada contrato obtém uma folha única graças ao :

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

Em seguida, um esquema determinístico de merkelização é utilizado para agregar todas as folhas (contratos + entropia). No final, o MPC Proof permite que a raiz seja reconstruída localmente e comparada com o mpc::Commitment incluído na cadeia.

Prova de transação extra - ETP

O terceiro campo, o ETP, depende do tipo de compromisso utilizado. Se o compromisso for do tipo Opret, nenhuma prova adicional é necessária. O validador inspeciona a primeira saída OP_RETURN da transação e encontra o mpc::Commitment diretamente lá.

Se o compromisso for do tipo Tapret, deve ser apresentada uma prova adicional denominada Extra Transaction Proof - ETP. Esta prova contém :

Esta prova adicional é essencial porque, ao contrário do Opret, o compromisso Tapret está integrado na estrutura de um script taproot, o que requer a revelação de parte da árvore taproot para validar corretamente a localização do compromisso.

RGB-Bitcoin

Os Anchors encapsulam, portanto, todas as informações necessárias para validar um compromisso Bitcoin no contexto do RGB. Elas indicam tanto a transação relevante (Txid) quanto a prova de posicionamento do contrato (MPC Proof), enquanto gerenciam a prova adicional (ETP) no caso do Tapret. Desta forma, uma Âncora protege a integridade e a unicidade do estado fora da cadeia, assegurando que a mesma transação não pode ser reinterpretada para outros dados contratuais.

Conclusão

Neste capítulo, abordamos :

Na prática, a implementação técnica está dividida entre várias crates Rust dedicadas (em client_side_validation, commit-verify, bp_core, etc.). As noções fundamentais estão lá:

RGB-Bitcoin

No próximo capítulo, veremos o componente puramente fora da cadeia do RGB, ou seja, a lógica do contrato. Veremos como os contratos RGB, organizados como máquinas de estado infinito parcialmente replicadas, alcançam uma expressividade muito maior do que os scripts Bitcoin, preservando a confidencialidade de seus dados.

Introdução aos contratos inteligentes e aos seus estados

Neste e no próximo capítulo, analisaremos a noção de contrato inteligente no ambiente RGB e exploraremos as diferentes formas como estes contratos podem definir e fazer evoluir o seu estado. Veremos porque é que a arquitetura RGB, utilizando a sequência ordenada de selos de utilização única, permite executar vários tipos de operações contratuais de forma escalável e sem passar por um registo centralizado. Veremos também o papel fundamental da Lógica de Negócios no enquadramento da evolução do estado do contrato.

Contratos inteligentes e direitos digitais ao portador

O objetivo da RGB é fornecer uma infraestrutura para a implementação de contratos inteligentes na Bitcoin. Por "contrato inteligente" entende-se um acordo entre várias partes que é aplicado de forma automática e computacional, sem intervenção humana para fazer cumprir as cláusulas. Por outras palavras, a lei do contrato é aplicada pelo software e não por um terceiro de confiança.

Esta automatização levanta a questão da descentralização: como podemos libertar-nos de um registo centralizado (por exemplo, uma plataforma ou base de dados central) para gerir a propriedade e a execução dos contratos? A ideia original, retomada pela RGB, é regressar a um modo de propriedade conhecido como "instrumentos ao portador". Historicamente, certos títulos (obrigações, acções, etc.) eram emitidos ao portador, permitindo a qualquer pessoa que possuísse fisicamente o documento fazer valer os seus direitos.

RGB-Bitcoin

O RGB aplica este conceito ao mundo digital: os direitos (e obrigações) são encapsulados em dados que são manipulados fora da cadeia e o estado destes dados é validado pelos próprios participantes. Isto permite, a priori, um grau de confidencialidade e independência muito maior do que o oferecido por outras abordagens baseadas em registos públicos.

Introdução ao estado RGB do contrato inteligente

Um contrato inteligente em RGB pode ser visto como uma máquina de estado, definida por :

RGB-Bitcoin

É importante compreender que estes contratos não se limitam à simples transferência de tokens. Podem incorporar uma grande variedade de aplicações: desde activos tradicionais (tokens, acções, obrigações) a mecanismos mais complexos (direitos de utilização, condições comerciais, etc.). Ao contrário de outras cadeias de blocos, em que o código do contrato é acessível e executável por todos, a abordagem da RGB compartimenta o acesso e o conhecimento do contrato pelos participantes ("participantes do contrato"). Existem vários papéis:

Esta separação de papéis contribui para a resistência à censura, garantindo que apenas pessoas autorizadas possam interagir com o estado contratual. Também dá à RGB a capacidade de escalar horizontalmente: a maioria das validações ocorre fora da blockchain, e apenas as âncoras criptográficas (os compromissos) são inscritas no Bitcoin.

Estado e lógica empresarial em RGB

De um ponto de vista prático, a Lógica Comercial do contrato assume a forma de regras e guiões, definidos naquilo a que a RGB chama um Esquema. O esquema codifica :

Ao mesmo tempo, o Estado Contratual divide-se frequentemente em duas componentes:

Como veremos nos próximos capítulos, qualquer atualização de status (Contract Operation) deve ser atrelada a um Bitcoin commitment (via Opret ou Tapret) e obedecer aos scripts de Business Logic para ser considerada válida.

Operações contratuais: criação e evolução do Estado

No universo RGB, uma Operação de Contrato é qualquer evento que altere o contrato de um estado antigo para um estado novo. Estas operações seguem a seguinte lógica:

RGB-Bitcoin

O resultado final é um contrato atualizado, agora com um estado diferente. Esta transição não requer que toda a rede Bitcoin se preocupe com os detalhes, uma vez que apenas uma pequena impressão digital criptográfica (o compromisso) é registada na blockchain. A sequência de selos de uso único impede qualquer gasto duplo ou uso duplo do Estado.

Cadeia de operações: da génese ao estado terminal

Para colocar isto em perspetiva, um contrato inteligente RGB começa com uma Génese, o primeiro estado. A partir daí, várias operações de contrato sucedem-se, formando um DAG (Direted Acyclic Graph) de operações:

RGB-Bitcoin

Esta topologia DAG (em vez de uma simples cadeia linear) reflecte a possibilidade de diferentes partes do contrato evoluírem em paralelo, desde que não se contradigam. A RGB encarrega-se então de evitar quaisquer incoerências através da verificação do lado do cliente de cada participante envolvido.

Resumo

Os contratos inteligentes na RGB introduzem um modelo de instrumentos digitais ao portador, descentralizados mas ancorados na Bitcoin para marcar o tempo e garantir a ordem das transacções. A execução automatizada destes contratos baseia-se em :

No próximo capítulo, entraremos em mais detalhes sobre a representação concreta desses estados e transições de estado no nível fora da cadeia, e como eles se relacionam com os UTXOs e Selos de uso único embutidos no Bitcoin. Esta será uma oportunidade para ver como a mecânica interna do RGB, baseada na validação do lado do cliente, consegue manter a consistência dos contratos inteligentes, preservando a confidencialidade dos dados.

Operações de contrato RGB

Neste capítulo, veremos como funcionam as operações em contratos inteligentes e as transições de estado, mais uma vez no âmbito do protocolo RGB. O objetivo será também compreender como vários participantes cooperam para transferir a propriedade de um ativo.

Transições de estado e sua mecânica

O princípio geral continua a ser o da validação do lado do cliente, em que os dados de estado são detidos pelo proprietário e validados pelo destinatário. No entanto, a especificidade da RGB reside no facto de Bob, enquanto destinatário, pedir a Alice que incorpore determinadas informações nos dados do contrato para ter um controlo real sobre o bem recebido, através de uma referência oculta a um dos seus UTXO.

Para ilustrar o processo de uma transição de estado (que é uma das operações contratuais fundamentais em RGB), vejamos um exemplo passo a passo de uma transferência de activos entre Alice e Bob:

**Situação inicial

A Alice tem um stash RGB de dados validados localmente (client-side). Este stash refere-se a um dos seus UTXOs no Bitcoin. Isto significa que uma definição de selo nestes dados aponta para um UTXO pertencente a Alice. A ideia é permitir-lhe transferir certos direitos digitais associados a um ativo (por exemplo, tokens RGB) para o Bob.

RGB-Bitcoin

O Bob também tem UTXOs :

O Bob, por outro lado, tem pelo menos um UTXO próprio, sem ligação direta ao da Alice. No caso de o Bob não ter um UTXO, é ainda possível fazer a transferência para ele utilizando a própria transação de testemunho: o resultado desta transação incluirá então o compromisso (commitment) e associará implicitamente a propriedade do novo contrato ao Bob.

RGB-Bitcoin

Construção do novo imóvel (Novo Estado) :

O Bob envia à Alice informação codificada sob a forma de uma fatura (entraremos em mais pormenores sobre a construção de facturas em capítulos posteriores), pedindo-lhe que crie um novo estado que esteja em conformidade com as regras do contrato. Este estado incluirá uma nova definição de selo apontando para um dos UTXOs do Bob. Desta forma, o Bob passa a ser proprietário dos activos definidos neste novo estado, por exemplo, uma certa quantidade de fichas RGB.

RGB-Bitcoin

Preparação da transação modelo:

Alice então cria uma transação Bitcoin gastando o UTXO referenciado no selo anterior (aquele que a legitimou como titular). Na saída desta transação, um compromisso (via Opret ou Tapret) é inserido para ancorar o novo estado RGB. Os compromissos Opret ou Tapret são derivados de uma árvore MPC (como visto nos capítulos anteriores), que pode agregar várias transições de diferentes contratos.

Transmissão de Consignação para Bob:

Antes de transmitir a transação, Alice envia a Bob uma Consignment contendo todos os dados necessários do lado do cliente (o seu stash) e a nova informação de estado a favor de Bob. Nesta altura, o Bob aplica as regras de consenso RGB:

Conclusão da transição:

Se o Bob estiver satisfeito, pode dar a sua aprovação (por exemplo, assinando a consignação). A Alice pode então transmitir a transação de amostra preparada. Uma vez confirmada, esta transação encerra o selo anteriormente detido por Alice e formaliza a propriedade por Bob. A segurança anti-gastos duplos baseia-se então no mesmo mecanismo que no Bitcoin: o UTXO é gasto, provando que Alice já não o pode reutilizar.

RGB-Bitcoin

O novo estado agora faz referência ao UTXO de Bob, dando a Bob a propriedade anteriormente detida por Alice. A saída Bitcoin onde os dados RGB estão ancorados torna-se a prova irrevogável da transferência de propriedade.

Um exemplo de um DAG (Direted Acyclic Graph) mínimo que inclui duas operações de contrato (uma Génese e depois uma Transição de Estado) pode ilustrar a forma como o estado RGB (camada do lado do cliente, a vermelho) se liga à cadeia de blocos Bitcoin (camada de compromisso, a laranja).

RGB-Bitcoin

Mostra que um Génesis define um selo (definição de selo), depois uma transição de estado fecha este selo para criar um novo num outro UTXO.

Neste contexto, eis algumas chamadas de atenção para a terminologia:

As Transições de Estado**, descritas no capítulo anterior, são a principal forma de operação de contrato. Referem-se a um ou mais estados anteriores (do Génesis ou de outra Transição de Estado) e actualizam-nos para um novo estado.

RGB-Bitcoin

Este diagrama mostra como, num State Transition Bundle, vários selos podem ser fechados numa única transação de amostra, abrindo simultaneamente novos selos. De facto, uma caraterística interessante do protocolo RGB é a sua capacidade de escalar: várias transições podem ser agregadas num Transition Bundle, sendo cada agregação associada a uma folha distinta da árvore MPC (um identificador de bundle único). Graças ao mecanismo Deterministic Bitcoin Commitment (DBC), toda a mensagem é inserida numa saída Tapret ou Opret, fechando os selos anteriores e possivelmente definindo novos selos. O `Anchor* serve de ligação direta entre o compromisso armazenado na blockchain e a estrutura de validação do lado do cliente (client-side).

Nos capítulos seguintes, veremos todos os componentes e processos envolvidos na construção e validação de uma Transição de Estado. A maioria destes elementos faz parte do consenso RGB, implementado na RGB Core Library.

Pacote de transição

Na RGB, é possível agrupar diferentes Transições de Estado pertencentes ao mesmo contrato (ou seja, partilhando o mesmo ContractId, derivado do OpId do Genesis). No caso mais simples, como entre Alice e Bob no exemplo acima, um Transition Bundle contém apenas uma transição. Mas o suporte para operações multi-pagador (tais como coinjoins, aberturas de canais Lightning, etc.) significa que vários utilizadores podem combinar as suas Transições de Estado num único pacote.

Uma vez recolhidas, estas transições são ancoradas (pelo mecanismo MPC + DBC) numa única transação Bitcoin:

Em termos técnicos, o BundleId inserido na folha MPC é obtido a partir de um hash marcado aplicado à serialização estrita do campo InputMap do pacote:

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

Em que bundle_tag = urn:lnp-bp:rgb:bundle#2024-02-03 por exemplo.

O InputMap é uma estrutura de dados que enumera, para cada entrada i da transação-modelo, a referência ao OpId da transição de estado correspondente. Por exemplo:

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

Ao fazer referência a cada entrada apenas uma vez e de forma ordenada, evitamos que o mesmo selo seja gasto duas vezes em duas Transições de Estado simultâneas.

Geração de estados e estado ativo

As transições de estado podem, portanto, ser utilizadas para transferir a propriedade de um ativo de uma pessoa para outra. No entanto, estas não são as únicas operações possíveis no protocolo RGB. O protocolo define três operações contratuais :

Entre estas, Génese e Extensão de estados são por vezes chamadas "operações de Geração de estados", porque criam novos estados sem fechar imediatamente nenhum. Este é um ponto muito importante: Genesis e State Extension não implicam o fecho de um selo. Em vez disso, definem um novo selo, que deve então ser gasto por uma Transição de estado subsequente para ser verdadeiramente validado no histórico da blockchain.

RGB-Bitcoin

O Estado Ativo de um contrato é frequentemente definido como o conjunto dos últimos estados resultantes do histórico (o DAG) das transacções, começando com o Genesis e seguindo todas as âncoras na blockchain Bitcoin. Quaisquer estados antigos que já estejam obsoletos (ou seja, ligados a UTXOs gastos) já não são considerados activos, mas continuam a ser essenciais para verificar a consistência do histórico.

Génesis

O Génesis é o ponto de partida de cada contrato RGB. É criado pelo emitente do contrato e define os parâmetros iniciais, em conformidade com o Esquema. No caso de um token RGB, o Genesis pode especificar, por exemplo, :

Sendo a primeira transação do contrato, a Génesis não faz referência a qualquer estado anterior, nem fecha qualquer selo. No entanto, para aparecer no histórico e ser validado, o Génesis deve ser consumido (fechado) por uma primeira Transição de Estado (frequentemente uma transação de digitalização/auto-despesa para o próprio emissor, ou a distribuição inicial aos utilizadores).

Extensão do Estado

As Extensões de Estado** oferecem uma caraterística original aos contratos inteligentes. Permitem resgatar certos direitos digitais (Valências) previstos na definição do contrato, sem fechar imediatamente o selo. Na maioria das vezes, trata-se de :

Tecnicamente, uma Extensão de Estado faz referência a um Redeem (um tipo particular de entrada RGB) que corresponde a uma Valência definida anteriormente (por exemplo, no Génesis ou noutra Transição de Estado). Define um novo selo, disponível para a pessoa ou condição que dele beneficia. Para que este selo se torne efetivo, deve ser gasto por uma Transição de Estado posterior.

RGB-Bitcoin

Por exemplo: o Génesis cria um direito de emissão (Valência). Este pode ser exercido por um ator autorizado, que constrói então uma Extensão de Estado:

Componentes de uma operação contratual

Gostaria agora de analisar detalhadamente cada um dos elementos constituintes de uma Operação de Contrato em RGB. Uma operação contratual é a ação que modifica o estado de um contrato e que é validada do lado do cliente, de forma determinística, pelo destinatário legítimo. Em particular, veremos como a operação contratual tem em conta, por um lado, o estado antigo (Estado antigo) do contrato e, por outro, a definição de um novo estado (Novo estado).

+---------------------------------------------------------------------------------------------------------------------+
|  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 observarmos o diagrama acima, podemos ver que uma operação de contrato inclui elementos referentes ao novo estado e outros referentes ao antigo estado atualizado.

Os elementos do Estado Novo são :

O Old State é referenciado através de :

Além disso, uma Operação de contrato inclui campos mais gerais específicos da operação:

Finalmente, todos estes campos são condensados por um processo de hashing personalizado, para produzir uma impressão digital única, o OpId. Este OpId é então integrado no Transition Bundle, permitindo-lhe ser autenticado e validado no âmbito do protocolo.

Cada operação de contrato é, portanto, identificada por um hash de 32 bytes denominado OpId. Este hash é calculado através de um hash SHA256 de todos os elementos que compõem a operação. Por outras palavras, cada Contract Operation tem o seu próprio compromisso criptográfico, que inclui todos os dados necessários para verificar a autenticidade e a consistência da operação.

Um contrato RGB é então identificado por um ContractId, derivado do OpId do Genesis (uma vez que não existe uma operação anterior ao Genesis). Em termos concretos, pegamos no OpId do Genesis, invertemos a ordem dos bytes e aplicamos uma codificação Base58. Esta codificação torna o ContractId mais fácil de manusear e reconhecer.

Métodos e regras de atualização do estado

O Estado do contrato representa o conjunto de informações que o protocolo RGB deve seguir para um determinado contrato. É composto por :

RGB-Bitcoin

O Estado global é diretamente incluído na Operação contratual como um bloco único. Os Owned States são definidos em cada Assignment, juntamente com a Seal Definition.

Uma das principais caraterísticas do RGB é a forma como o Estado Global e os Estados Próprios são modificados. Existem geralmente dois tipos de comportamento:

Se, no contrato, um elemento de estado não for definido como mutável ou cumulativo, este elemento permanecerá vazio para as operações subsequentes (por outras palavras, não existem novas versões para este campo). É o esquema do contrato (ou seja, a lógica comercial codificada) que determina se um estado (global ou próprio) é mutável, cumulativo ou fixo. Uma vez definido o Génesis, estas propriedades só podem ser modificadas se o próprio contrato o permitir, por exemplo, através de uma Extensão de Estado específica.

A tabela abaixo ilustra como cada tipo de Operação de contrato pode manipular (ou não) o Estado global e o Estado próprio:

GêneseExtensão de EstadoTransição de Estado
Adição de Global State+-+
Mutação de Global Staten/a-+
Adição de Owned State+-+
Mutação de Owned Staten/aNão+
Adição de Valencies+++

+ : ação possível se o esquema do contrato o permitir.

-: a operação deve ser confirmada por uma transição de estado subsequente (a extensão de estado, por si só, não fecha o selo de utilização única).

Além disso, o âmbito temporal e os direitos de atualização de cada tipo de dados podem ser distinguidos no quadro seguinte:

MetadadosEstado GlobalEstado Possuído
EscopoDefinido para uma única Operação de ContratoDefinido globalmente para o contratoDefinido para cada selo (Assignment)
Quem pode atualizá-lo?Não atualizável (dados efêmeros)Operação emitida por atores (emissor, etc.)Depende do detentor legítimo que possui o selo (quem pode gastá-lo em uma transação seguinte)
Escopo TemporalApenas para a operação atualO estado é estabelecido ao final da operaçãoO estado é definido antes da operação (pela Seal Definition da operação anterior)

Estado global

O Estado Global é frequentemente descrito como "ninguém é dono, toda a gente sabe". Contém informações gerais sobre o contrato, que são visíveis publicamente. Por exemplo, num contrato de emissão de tokens, contém potencialmente :

Este Estado Global pode ser colocado em recursos públicos (sítios Web, IPFS, Nostr, Torrent, etc.) e distribuído à comunidade. Além disso, o incentivo económico (a necessidade de manter e transferir estes tokens, etc.) leva naturalmente os utilizadores contratuais a manterem e propagarem eles próprios estes dados.

Atribuições

A Atribuição é a estrutura básica para definir :

Uma Assignment pode ser vista como o análogo de uma saída de transação Bitcoin, mas com mais flexibilidade. É aqui que reside a lógica da transferência de propriedade: a Assignment associa um determinado tipo de bem ou direito (AssignmentType) a um selo. Quem possuir a chave privada do UTXO associado a este selo (ou quem puder gastar este UTXO) é considerado o proprietário deste Owned State.

Um dos grandes pontos fortes do RGB reside na capacidade de revelar (revelar) ou ocultar (ocultar) os campos Definição de Selo e Estado de Propriedade à vontade. Isto oferece uma poderosa combinação de confidencialidade e seletividade. Por exemplo, é possível provar que uma transição é válida sem revelar todos os dados, fornecendo a versão revelada à pessoa que tem de a validar, enquanto terceiros apenas vêem a versão oculta (um hash). Na prática, o OpId de uma transição é sempre calculado a partir dos dados ocultos.

RGB-Bitcoin

Definição do selo

A Definição de Selo, na sua forma revelada, tem quatro campos básicos: txptr, vout, blinding e method :

A forma oculta da definição do selo é um hash SHA256 (etiquetado) da concatenação destes 4 campos, com uma etiqueta específica para RGB.

RGB-Bitcoin

Estados de propriedade

O segundo componente da Atribuição é o Estado Próprio. Ao contrário do Estado Global, este pode existir sob a forma pública ou privada:

A RGB define quatro tipos de estado possíveis (StateTypes) para um estado próprio:

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

Com, por exemplo :

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)

Com, por exemplo :

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

Para resumir, eis os 4 tipos possíveis de estado na forma pública e oculta:

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 | |
| +----------------------+ |             | +-----------+ +------------+ +------+ |
+--------------------------+             +---------------------------------------+
ElementoDeclarativoFungívelEstruturadoAnexos
DadosNenhumNúmero inteiro de 64 bits assinado ou não assinadoQualquer tipo de dado estritoQualquer arquivo
Tipo de InfoNenhumAssinado ou não assinadoTipos estritosTipo MIME
PrivacidadeNão requeridaPedersen commitmentHash com blindingIdentificador de arquivo com hash
Limites de TamanhoN/A256 bytesAté 64 KBAté ~500 GB

Entradas

As entradas de uma operação contratual referem-se às atribuições que estão a ser gastas nesta nova operação. Uma entrada indica :

As entradas nunca aparecem na Génese, uma vez que não existem Atribuições anteriores. Também não aparecem nas Extensões de Estado (porque as Extensões de Estado não fecham selos; em vez disso, redefinem novos selos com base em Valências).

Quando temos Owned States do tipo Fungible, a lógica de validação (através do script AluVM fornecido no Schema) verifica a consistência das somas: a soma dos tokens de entrada (Inputs) deve ser igual à soma dos tokens de saída (no novo Assignments).

Metadados

O campo Metadata pode ter um máximo de 64 KiB e é utilizado para incluir dados temporários úteis para a validação, mas não integrados no estado permanente do contrato. Por exemplo, podem ser armazenadas aqui variáveis de cálculo intermédias para scripts complexos. Este espaço não se destina a ser armazenado no historial global, razão pela qual está fora do âmbito dos Estados Próprios ou do Estado Global.

Valências

As valências** são um mecanismo original do protocolo RGB. Podem ser encontradas em Génesis, Transições de Estado ou Extensões de Estado. Representam direitos numéricos que podem ser activados por uma Extensão de Estado (via Redeems), e depois finalizados por uma Transição subsequente. Cada Valência é identificada por um ValencyType (16 bits). A sua semântica (direito de reemissão, troca de fichas, direito de queima, etc.) é definida no Schema.

Em termos concretos, poderíamos imaginar um Génesis que define uma valência "direito de reemissão". Uma Extensão de Estado consumi-la-á (Redeem) se certas condições estiverem reunidas, a fim de introduzir uma nova quantidade de fichas. Em seguida, uma Transição de Estado que emana do detentor do selo assim criado pode transferir essas novas fichas.

Resgata

Os resgates são o equivalente em valência das entradas para atribuições. Só aparecem nas Extensões de Estado, pois é aqui que se ativa uma Valência previamente definida. Um Resgate é composto por dois campos:

Exemplo: um Resgate pode corresponder a uma execução CoinSwap, dependendo do que foi codificado na Valência.

Caraterísticas do estado RGB

Vamos agora dar uma vista de olhos a várias caraterísticas fundamentais do estado em RGB. Em particular, veremos :

Como sempre, tenha em conta que tudo o que tem a ver com o estado do contrato é validado do lado do cliente, de acordo com as regras de consenso definidas no protocolo, e cuja referência criptográfica final está ancorada nas transacções Bitcoin.

Sistema de tipos rigoroso

A RGB utiliza um Strict Type System e um modo de serialização determinístico (Strict Encoding). Esta organização foi concebida para garantir uma perfeita reprodutibilidade e precisão na definição, tratamento e validação dos dados contratuais.

Em muitos ambientes de programação (JSON, YAML...), a estrutura de dados pode ser flexível, ou mesmo demasiado permissiva. Em RGB, por outro lado, a estrutura e os tipos de cada campo são definidos com restrições explícitas. Por exemplo :

Graças a este protocolo de codificação rigoroso :

Na prática, a estrutura (Esquema) e o código resultante (Interface e lógica associada) são compilados. É utilizada uma linguagem descritiva para definir o contrato (tipos, campos, regras) e gerar um formato binário rigoroso. Quando compilado, o resultado é :

O sistema de tipos rigoroso permite também um controlo preciso das alterações: qualquer modificação da estrutura (mesmo uma alteração do nome do campo) é detetável e pode levar a uma alteração da pegada global.

Finalmente, cada compilação produz uma impressão digital, um identificador criptográfico que atesta a versão exacta do código (dados, regras, validação). Por exemplo, um identificador do tipo :

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

Isto permite gerir actualizações de consenso ou de implementação, assegurando ao mesmo tempo uma rastreabilidade detalhada das versões utilizadas na rede.

Para evitar que o estado de um contrato RGB se torne demasiado complicado de validar do lado do cliente, uma regra de consenso impõe um tamanho máximo de 2^16 bytes (64 Kio) para qualquer dado envolvido nos cálculos de validação. Isto aplica-se a cada variável ou estrutura: não mais de 65536 bytes, ou o equivalente em números (32768 números inteiros de 16 bits, etc.). Isto também se aplica a colecções (listas, conjuntos, mapas), que não podem exceder 2^16 elementos.

Este limite garante :

O paradigma Validação != Propriedade

Uma das principais inovações da RGB é a separação rigorosa entre dois conceitos:

A validação** efectua-se ao nível da pilha de software RGB (bibliotecas, protocolo compromissos, etc.). O seu papel consiste em garantir o respeito das regras internas do contrato (montantes, autorizações, etc.). Os observadores ou outros participantes podem igualmente validar o historial dos dados.

A propriedade**, por outro lado, depende inteiramente da segurança do Bitcoin. Possuir a chave privada de um UTXO significa controlar a capacidade de lançar uma nova transição (fechar o selo de utilização única). Assim, mesmo que alguém possa ver ou validar os dados, não pode alterar o estado se não possuir o UTXO em causa.

RGB-Bitcoin

Esta abordagem limita as vulnerabilidades clássicas encontradas em cadeias de blocos mais complexas (em que todo o código de um contrato inteligente é público e modificável por qualquer pessoa, o que por vezes levou a piratarias). Na RGB, um atacante não pode simplesmente interagir com o estado da cadeia, pois o direito de agir sobre o estado (propriedade) é protegido pela camada Bitcoin.

Além disso, esse desacoplamento permite que o RGB se integre naturalmente com a Lightning Network. Os canais Lightning podem ser usados para envolver e mover ativos RGB sem envolver * compromissos * na cadeia todas as vezes. Examinaremos mais de perto essa integração do RGB no Lightning nos capítulos posteriores do curso.

Evolução do consenso na RGB

Para além do controlo de versões do código semântico, a RGB inclui um sistema de evolução ou atualização das regras de consenso de um contrato ao longo do tempo. Existem duas formas principais de evolução:

Um avanço rápido ocorre quando uma regra anteriormente inválida se torna válida. Por exemplo, se o contrato evoluir para permitir um novo tipo de AssignmentType ou um novo campo :

Um push-back significa que uma regra anteriormente válida se torna inválida. Trata-se, portanto, de um "endurecimento" das regras, mas não de um softfork propriamente dito:

Neste capítulo sobre as operações do contrato RGB, explorámos os princípios fundamentais subjacentes a este protocolo. Como deve ter reparado, a complexidade inerente ao protocolo RGB exige a utilização de muitos termos técnicos. Por isso, no próximo capítulo, apresentarei um glossário que resumirá todos os conceitos abordados nesta primeira parte teórica, com definições de todos os termos técnicos relacionados com a RGB. Em seguida, na próxima secção, vamos analisar de forma prática a definição e a implementação de contratos RGB.

Glossário RGB

Se precisar de voltar a este pequeno glossário de termos técnicos importantes utilizados no mundo RGB (listados por ordem alfabética), vai achá-lo útil. Este capítulo não é essencial se já tiver compreendido tudo o que foi abordado na primeira secção.

AluVM

A abreviatura AluVM significa "Algorithmic logic unit Virtual Machine", uma máquina virtual baseada em registos concebida para a validação de contratos inteligentes e a computação distribuída. É utilizada (mas não exclusivamente reservada) para a validação dos contratos RGB. Os scripts ou operações incluídos num contrato RGB podem assim ser executados no ambiente AluVM.

Para mais informações: Sítio Web oficial do AluVM

Âncora

Uma âncora representa um conjunto de dados do lado do cliente utilizados para provar a inclusão de um compromisso único numa transação. No protocolo RGB, uma âncora é constituída pelos seguintes elementos:

Uma âncora serve, portanto, para estabelecer uma ligação verificável entre uma transação Bitcoin específica e os dados privados validados pelo protocolo RGB. Garante que estes dados estão efetivamente incluídos na cadeia de blocos, sem que o seu conteúdo exato seja exposto publicamente.

Atribuição

Na lógica da RGB, uma atribuição é o equivalente a uma saída de transação que modifica, actualiza ou cria determinadas propriedades no estado de um contrato. Uma atribuição é composta por dois elementos:

Uma Atribuição indica, portanto, que uma parte do estado (por exemplo, um ativo) está agora atribuída a um determinado titular, identificado através de um Selo de Utilização Única ligado a um UTXO.

Lógica empresarial

A lógica comercial agrupa todas as regras e operações internas de um contrato, descritas pelo seu esquema (ou seja, a estrutura do próprio contrato). Determina a forma como o estado do contrato pode evoluir e em que condições.

Validação do lado do cliente

A validação do lado do cliente refere-se ao processo pelo qual cada parte (cliente) verifica um conjunto de dados trocados em privado, de acordo com as regras de um protocolo. No caso do RGB, esses dados trocados são agrupados no que é conhecido como consignações. Ao contrário do protocolo Bitcoin, que exige que todas as transacções sejam publicadas na cadeia, a RGB permite que apenas os compromissos (ancorados na Bitcoin) sejam armazenados em público, enquanto as informações essenciais do contrato (transições, atestados, provas) permanecem fora da cadeia, partilhadas apenas entre os utilizadores em causa.

Compromisso

Um compromisso (no sentido criptográfico) é um objeto matemático, denotado C, derivado deterministicamente de uma operação sobre dados estruturados m (a mensagem) e um valor aleatório r. Escrevemos :

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

Este mecanismo compreende duas operações principais:

Um compromisso deve respeitar duas propriedades:

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

Tais como :

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

No protocolo RGB, um compromisso é incluído numa transação Bitcoin para provar a existência de uma determinada informação num determinado momento, sem revelar a informação em si.

Consignação

Uma Consignação agrupa os dados trocados entre as partes, sujeitos à validação do lado do cliente em RGB. Existem duas categorias principais de consignação:

Estas remessas não são registadas publicamente na cadeia de blocos; são trocadas diretamente entre as partes interessadas através do canal de comunicação da sua escolha.

Contrato

Um contrato é um conjunto de direitos executados digitalmente entre vários actores através do protocolo RGB. Tem um estado ativo e uma lógica comercial, definida por um esquema, que especifica as operações autorizadas (transferências, extensões, etc.). O estado de um contrato, bem como as suas regras de validade, são expressos no esquema. A qualquer momento, o contrato evolui apenas de acordo com o que é permitido por esse esquema e por scripts de validação (executados, por exemplo, no AluVM).

Operação do contrato

Uma operação de contrato é uma atualização do estado do contrato executada de acordo com as regras do esquema. Existem as seguintes operações no RGB:

Cada operação modifica o estado, acrescentando ou substituindo certos dados (Estado global, Estado próprio...).

Participante no contrato

Um participante no contrato é um ator que toma parte nas operações relacionadas com o contrato. Na RGB, é feita uma distinção entre :

Direitos contratuais

Os direitos contratuais referem-se aos vários direitos que podem ser exercidos pelas pessoas envolvidas num contrato RGB. Estes direitos dividem-se em várias categorias:

Estado do contrato

O Estado do contrato corresponde ao estado atual de um contrato num determinado momento. Pode ser constituído por dados públicos e privados, reflectindo o estado do contrato. A RGB distingue entre :

Compromisso determinístico de Bitcoin - DBC

Deterministic Bitcoin Commitment (DBC) é o conjunto de regras utilizadas para registar de forma comprovada e única um commitment numa transação Bitcoin. No protocolo RGB, existem duas formas principais de DBC:

Estes mecanismos definem com precisão a forma como o compromisso é codificado no resultado ou na estrutura de uma transação Bitcoin, para garantir que este compromisso é deterministicamente rastreável e verificável.

Gráfico Acíclico Dirigido - DAG

Um DAG (ou Acyclic Guided Graph) é um gráfico sem ciclos, que permite o escalonamento topológico. As cadeias de blocos, como os shards dos contratos RGB, podem ser representadas por DAGs.

Para mais informações: [Direted Acyclic Graph] (https://en.wikipedia.org/wiki/Directed_acyclic_graph)

Gravação

A gravação é uma cadeia de dados opcional que os sucessivos proprietários de um contrato podem introduzir no historial do contrato. Esta caraterística existe, por exemplo, na interface RGB21 e permite acrescentar informações comemorativas ou descritivas ao historial do contrato.

Prova de transação extra - ETP

A ETP (Extra Transaction Proof) é a parte da Âncora que contém os dados adicionais necessários para validar um Tapret compromisso (no contexto de taproot). Inclui, entre outras coisas, a chave pública interna do script taproot (internal PubKey) e informações específicas do Script Path Spend.

Génesis

Genesis refere-se ao conjunto de dados, regido por um Schema, que forma o estado inicial de qualquer contrato em RGB. Pode ser comparado com o conceito de Genesis Block da Bitcoin, ou com o conceito de transação da Coinbase, mas aqui ao nível do client-side e do token RGB.

Estado global

O Estado global é o conjunto das propriedades públicas contidas no Estado do contrato. É definido no Génesis e, em função das regras do contrato, pode ser atualizado por transições autorizadas. Ao contrário dos Estados Próprios, o Estado Global não pertence a uma entidade específica; está mais próximo de um registo público dentro do contrato.

Interface

A interface é o conjunto de instruções utilizadas para descodificar os dados binários compilados num esquema ou em operações contratuais e respectivos estados, de modo a torná-los legíveis para o utilizador ou para a sua carteira. Actua como uma camada de interpretação.

Implementação da interface

A Implementação da Interface é o conjunto de declarações que ligam uma Interface a um Esquema. Permite a tradução semântica realizada pela própria Interface, de modo a que os dados brutos de um contrato possam ser compreendidos pelo utilizador ou pelo software envolvido (as carteiras).

Fatura

Uma Fatura assume a forma de um URL codificado em base58, que incorpora os dados necessários para a construção de uma Transição de Estado (pelo pagador). Por outras palavras, é uma fatura que permite à contraparte (pagador) criar a transição correspondente para transferir o ativo ou atualizar o estado do contrato.

Rede Lightning

A Lightning Network é uma rede descentralizada de canais de pagamento (ou state channels) no Bitcoin, composta por 2/2 carteiras multi-assinatura. Ela permite transações rápidas e de baixo custo off-chain, enquanto conta com a Camada 1 do Bitcoin para arbitragem (ou fechamento) quando necessário.

Para obter mais informações sobre o funcionamento do Lightning, recomendo que faça este outro curso:

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

Compromisso multiprotocolo - MPC

Multi Protocol Commitment (MPC) refere-se à estrutura de árvore Merkle utilizada no RGB para incluir, numa única transação Bitcoin, vários Transition Bundles de diferentes contratos. A ideia é agrupar vários compromissos (potencialmente correspondentes a diferentes contratos ou diferentes activos) num único ponto de ancoragem, de forma a otimizar a ocupação do espaço do bloco.

Estado de propriedade

Um Estado Proprietário é a parte de um Estado Contratual que está incluída numa Atribuição e associada a um determinado titular (através de um Selo de Utilização Única que aponta para um UTXO). Isto representa, por exemplo, um ativo digital ou um direito contratual específico atribuído a essa pessoa.

Propriedade

A propriedade refere-se à capacidade de controlar e gastar um UTXO referenciado por uma Definição de Selo. Quando um Estado de Propriedade está ligado a uma UTXO, o proprietário desta UTXO tem o direito, potencialmente, de transferir ou evoluir o Estado associado, de acordo com as regras do contrato.

Transação Bitcoin parcialmente assinada - PSBT

Uma PSBT (Partially Signed Bitcoin Transaction) é uma transação Bitcoin que ainda não está totalmente assinada. Pode ser partilhada entre várias entidades, cada uma das quais pode adicionar ou verificar certos elementos (assinaturas, scripts...), até que a transação seja considerada pronta para distribuição na cadeia.

Para mais informações: [BIP-0174] (https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki)

Compromisso Pedersen

Um compromisso Pedersen é um tipo de compromisso criptográfico com a propriedade de ser homomórfico relativamente à operação de adição. Isto significa que é possível validar a soma de dois compromissos sem revelar os valores individuais.

Formalmente, se :

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

depois :

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

Esta propriedade é útil, por exemplo, para ocultar as quantidades de tokens trocadas, enquanto ainda é possível verificar os totais.

Para mais informações: Pedersen commitment

Resgatar

Numa Extensão de Estado, um Resgate refere-se à ação de reclamar (ou explorar) uma Valência previamente declarada. Como uma Valência é um direito público, o Resgate permite a um participante autorizado reivindicar uma extensão de estado de contrato específica.

Esquema

Um esquema em RGB é uma parte declarativa do código que descreve o conjunto de variáveis, regras e lógica comercial (Lógica comercial) que regem o funcionamento de um contrato. O esquema define a estrutura do estado, os tipos de transições permitidas e as condições de validação.

Definição do selo

A Definição do Selo é a parte de uma Cessão que associa o compromisso a um UTXO propriedade do novo titular. Por outras palavras, indica onde se encontra a condição (em que UTXO) e estabelece a propriedade de um bem ou direito.

Fragmento

Um fragmento representa um ramo no DAG do historial das transições de estado de um contrato RGB. Por outras palavras, é um subconjunto coerente do histórico global do contrato, correspondendo, por exemplo, à sequência de transições necessárias para provar a validade de um determinado ativo desde a Génese.

Selo de utilização única

Um selo de uso único é uma promessa criptográfica de compromisso com uma mensagem ainda desconhecida, que será revelada apenas uma vez no futuro e deve ser conhecida por todos os membros de um público específico. O objetivo é evitar a criação de múltiplos compromissos concorrentes para o mesmo selo.

Coleção

O Stash é o conjunto de dados do lado do cliente que um utilizador armazena para um ou mais contratos RGB, para efeitos de validação (Validação do lado do cliente). Inclui o historial de transições, as remessas, as provas de validade, etc. Cada titular conserva apenas as partes do historial de que necessita (shards).

Extensão do Estado

Uma extensão de estado é uma operação de contrato utilizada para voltar a desencadear actualizações de estado através do resgate de Valências previamente declaradas. Para ser eficaz, uma Extensão de estado deve ser encerrada por uma Transição de estado (que actualiza o estado final do contrato).

Transição de estado

A Transição de estado é a operação que altera o estado de um contrato RGB para um novo estado. Pode modificar os dados do Estado Global e/ou do Estado Próprio. Na prática, cada transição é verificada por regras de esquema e ancorada no blockchain do Bitcoin por meio de um commitment.

Raiz da torneira

Refere-se ao formato de transação Segwit v1 da Bitcoin, introduzido por BIP341 e BIP342. O Taproot melhora a confidencialidade e a flexibilidade dos scripts, em particular ao tornar as transacções mais compactas e mais difíceis de distinguir umas das outras.

Consignação terminal - Ponto final de consignação

A consignação terminal (ou Consignment Endpoint) é uma consignação de transferência que contém o estado final do contrato, incluindo a transição de estado criada a partir da fatura do destinatário (payee). Por conseguinte, é o ponto final de uma transferência, com os dados necessários para provar que a propriedade ou o estado foi transferido.

Pacote de transição

Um Transition Bundle é um conjunto de Transições de Estado RGB (pertencentes ao mesmo contrato) que estão todas envolvidas na mesma transação de testemunho Bitcoin. Isto torna possível agrupar várias actualizações ou transferências numa única âncora na cadeia.

UTXO

Um Bitcoin UTXO (Unspent Transaction Output) é definido pelo hash de uma transação e o índice de saída (vout). Também é por vezes chamado de outpoint. No protocolo RGB, a referência a um UTXO (através de uma Seal Definition) permite a localização do Owned State, ou seja, a propriedade mantida na blockchain.

Valência

Uma Valência é um direito público que não necessita de armazenamento estatal enquanto tal, mas que pode ser resgatado através de uma Extensão estatal. É, portanto, uma forma de possibilidade aberta a todos (ou a certos jogadores), declarada na lógica do contrato, para efetuar uma determinada extensão numa data posterior.

Transação de testemunhas

A transação testemunha é a transação Bitcoin que fecha o selo de utilização única em torno de uma mensagem que contém um compromisso multiprotocolo (MPC). Esta transação gasta um UTXO ou cria um, de modo a selar o compromisso ligado ao protocolo RGB. Funciona como uma prova na cadeia de que o estado foi definido num determinado momento.

Programação em RGB

Implementação de contratos RGB

Neste capítulo, analisaremos em pormenor a forma como um contrato RGB é definido e implementado. Veremos quais são os componentes de um contrato RGB, quais são as suas funções e como são construídos.

Os componentes de um contrato RGB

Até agora, já falámos da Génese, que representa o ponto de partida de um contrato, e vimos como se enquadra na lógica de uma Operação de Contrato e no estado do protocolo. A definição completa de um contrato RGB, no entanto, não se limita apenas ao Génesis: envolve três componentes complementares que, em conjunto, formam o coração da implementação.

O primeiro componente é designado por Esquema. Trata-se de um ficheiro que descreve a estrutura fundamental e a lógica comercial (lógica comercial) do contrato. Especifica os tipos de dados utilizados, as regras de validação, as operações permitidas (por exemplo, emissão inicial de fichas, transferências, condições especiais, etc.), em suma, o quadro geral que determina o funcionamento do contrato.

A segunda componente é a Interface. Centra-se na forma como os utilizadores (e, por extensão, o software da carteira) irão interagir com este contrato. Descreve a semântica, ou seja, a representação legível dos vários campos e acções. Assim, enquanto o Esquema define o funcionamento técnico do contrato, a Interface define a forma de apresentar e expor estas funcionalidades: nomes dos métodos, visualização dos dados, etc.

O terceiro componente é a Interface Implementation, que complementa os dois anteriores, actuando como uma espécie de ponte entre o Esquema e a Interface. Por outras palavras, associa a semântica expressa pela Interface com as regras subjacentes definidas no Esquema. É esta implementação que vai gerir, por exemplo, a conversão entre um parâmetro introduzido na carteira e a estrutura binária imposta pelo protocolo, ou a compilação das regras de validação em linguagem de máquina.

Esta modularidade é uma caraterística interessante do RGB, pois permite que diferentes grupos de programadores trabalhem separadamente nestes aspectos (Esquema, Interface, Implementação), desde que sigam as regras de consenso do protocolo.

Em suma, cada contrato é composto por :

RGB-Bitcoin

É importante notar que, para que uma carteira possa gerir um ativo RGB (seja ele um token fungível ou um direito de qualquer tipo), deve ter todos estes elementos compilados: Schema, Interface, Interface Implementation e Genesis. Estes elementos são transmitidos através de uma remessa de contrato, ou seja, um pacote de dados que contém todos os elementos necessários para validar o contrato do lado do cliente.

Para ajudar a clarificar estas noções, eis um quadro recapitulativo que compara os componentes de um contrato RGB com conceitos já conhecidos da programação orientada para os objectos (OOP) ou do ecossistema Ethereum:

Componente do contrato RGBSignificadoEquivalente OOPEquivalente Ethereum
GenesisEstado inicial do contratoConstrutor de classeConstrutor de contrato
SchemaLógica de negócios do contratoClasseContrato
InterfaceSemântica do contratoInterface (Java) / Trait (Rust) / Protocolo (Swift)Padrão ERC
Interface ImplementationMapeamento de semântica e lógicaImpl (Rust) / Implements (Java)Application Binary Interface (ABI)

A coluna da esquerda apresenta os elementos específicos do protocolo RGB. A coluna do meio mostra a função concreta de cada componente. Em seguida, na coluna "equivalente OOP", encontramos o termo equivalente em programação orientada para objectos:

No contexto do Ethereum, a Génese está mais próxima do construtor do contrato, o Esquema da definição do contrato, a Interface de uma norma como a ERC-20 ou a ERC-721 e a Implementação da Interface da ABI (Interface Binária da Aplicação), que especifica o formato das interações com o contrato.

A vantagem da modularidade da RGB reside também no facto de diferentes partes interessadas poderem escrever, por exemplo, a sua própria implementação de interface, desde que respeitem a lógica do esquema e a semântica da interface. Assim, um emitente pode desenvolver um novo front-end (Interface) mais fácil de utilizar, sem modificar a lógica do contrato, ou, pelo contrário, pode alargar o Esquema para acrescentar funcionalidades e fornecer uma nova versão da Implementação de Interface adaptada, enquanto as implementações antigas permaneceriam válidas para a funcionalidade básica.

Quando compilamos um novo contrato, geramos um Génesis (o primeiro passo na emissão ou distribuição do ativo), bem como os seus componentes (Esquema, Interface, Implementação de Interface). Depois disso, o contrato está totalmente operacional e pode ser propagado para carteiras e utilizadores. Este método, em que o Génesis é combinado com estes três componentes, garante um elevado grau de personalização (cada contrato pode ter a sua própria lógica), descentralização (todos podem contribuir para um determinado componente) e segurança (a validação permanece estritamente definida pelo protocolo, sem depender de código arbitrário na cadeia, como é frequentemente o caso noutras cadeias de blocos).

Gostaria agora de analisar mais detalhadamente cada um destes componentes: o Esquema, a Interface e a Implementação da Interface.

Esquema

Na secção anterior, vimos que, no ecossistema RGB, um contrato é composto por vários elementos: o Genesis, que estabelece o estado inicial, e vários outros componentes complementares. O objetivo do Esquema é descrever de forma declarativa toda a lógica comercial do contrato, ou seja, a estrutura dos dados, os tipos utilizados, as operações permitidas e as suas condições. Trata-se, por conseguinte, de um elemento muito importante para tornar um contrato operacional do lado do cliente, uma vez que cada participante (uma carteira, por exemplo) deve verificar se as transições de estado que recebe estão em conformidade com a lógica definida no esquema.

Um esquema pode ser comparado a uma "classe" na programação orientada para objectos (OOP). De um modo geral, serve como um modelo que define os componentes de um contrato, tais como :

RGB-Bitcoin

Quando o emissor de um ativo no RGB publica um contrato, fornece o Génesis e o Esquema a ele associado. Os utilizadores ou as carteiras que desejam interagir com o ativo recuperam este esquema para compreender a lógica subjacente ao contrato e para poderem verificar mais tarde se as transições em que vão participar são legítimas.

O primeiro passo, para qualquer pessoa que receba informações sobre um ativo RGB (por exemplo, uma transferência de token), é validar essas informações com base no esquema. Isto implica utilizar a compilação do esquema para :

Na prática, o esquema não é um código executável, como se pode ver nas cadeias de blocos que armazenam código na cadeia (EVM no Ethereum). Pelo contrário, o RGB separa a lógica comercial (declarativa) do código executável na cadeia de blocos (que se limita às âncoras criptográficas). Assim, o esquema determina as regras, mas a aplicação destas regras tem lugar fora da cadeia de blocos, no sítio de cada participante, de acordo com o princípio da validação do lado do cliente.

Um Schema deve ser compilado antes de poder ser utilizado por aplicações RGB. Esta compilação produz um ficheiro binário (por exemplo, .rgb) ou um ficheiro binário encriptado (.rgba). Quando a carteira importa este arquivo, ela sabe que o :

Como explicado nos capítulos anteriores, o sistema de tipos estritos dá-nos um formato de codificação estável e determinista: todas as variáveis, quer sejam Estados Próprios, Estados Globais ou Valências, são descritas com precisão (tamanho, limites inferior e superior, se necessário, tipo assinado ou não assinado, etc.). Também é possível definir estruturas aninhadas, por exemplo, para suportar casos de utilização complexos.

Opcionalmente, o esquema pode fazer referência a um SchemaId de raiz, o que facilita a reutilização de uma estrutura de base existente (um modelo). Desta forma, é possível evoluir um contrato ou criar variações (por exemplo, um novo tipo de token) a partir de um modelo já comprovado. Esta modularidade evita a necessidade de recriar contratos inteiros e incentiva a normalização das melhores práticas.

Outro ponto importante é que a lógica da evolução do estado (transferências, actualizações, etc.) é descrita no esquema sob a forma de scripts, regras e condições. Assim, se o autor do contrato pretender autorizar uma reemissão ou impor um mecanismo de queima (destruição de fichas), pode especificar os guiões correspondentes para o AluVM na parte de validação do esquema.

Diferença em relação às cadeias de blocos programáveis na cadeia

Ao contrário de sistemas como o Ethereum, em que o código do contrato inteligente (executável) é escrito na própria cadeia de blocos, o RGB armazena o contrato (a sua lógica) fora da cadeia, sob a forma de um documento declarativo compilado. Isto implica que :

Utilização pelo emitente e pelos utilizadores

Quando um emissor cria um ativo (por exemplo, uma ficha fungível não inflacionista), prepara :

Em seguida, disponibiliza o esquema compilado (um ficheiro `.rgb') aos utilizadores, para que qualquer pessoa que receba uma transferência deste token possa verificar localmente a coerência da operação. Sem este esquema, um utilizador não poderia interpretar os dados de estado ou verificar a sua conformidade com as regras do contrato.

Assim, quando uma nova carteira quiser suportar um ativo, basta integrar o esquema relevante. Este mecanismo torna possível adicionar compatibilidade a novos tipos de activos RGB, sem alterar de forma invasiva a base de software da carteira: tudo o que é necessário é importar o binário Schema e compreender a sua estrutura.

O Schema define a lógica comercial em RGB. Enumera as regras de evolução de um contrato, a estrutura dos seus dados (Estados Próprios, Estado Global, Valências) e os scripts de validação associados (executáveis pelo AluVM). Graças a este documento declarativo, a definição de um contrato (ficheiro compilado) está claramente separada da execução efectiva das regras (lado do cliente). Esta dissociação confere à RGB uma grande flexibilidade, permitindo uma vasta gama de casos de utilização (tokens fungíveis, NFT, contratos mais sofisticados), evitando ao mesmo tempo a complexidade e as falhas típicas das cadeias de bloqueio programáveis on-chain.

Exemplo de esquema

Vejamos um exemplo concreto de Schema para um contrato RGB. Este é um extrato em Rust do ficheiro nia.rs (iniciais de "Non-Inflatable Assets"), que define um modelo para tokens fungíveis que não podem ser reemitidos para além do seu fornecimento inicial (um ativo não inflacionário). Este tipo de token pode ser visto como o equivalente, no universo RGB, do ERC20 no Ethereum, ou seja, tokens fungíveis que respeitam certas regras básicas (por exemplo, em transferências, inicialização de fornecimento, etc.).

Antes de mergulhar no código, vale a pena recordar a estrutura geral de um esquema RGB. Existe uma série de declarações que enquadram :

RGB-Bitcoin

O código abaixo mostra a definição completa do esquema Rust. Vamos comentá-lo parte por parte, seguindo as anotações (1) a (9) abaixo:

// ===== 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),
},
}),
}
}

A função nia_schema() devolve um SubSchema, indicando que este esquema pode herdar parcialmente de um esquema mais genérico. No ecossistema RGB, esta flexibilidade permite reutilizar certos elementos padrão de um esquema mestre, e depois definir regras específicas para o contrato em questão. Aqui, optámos por não permitir a herança, uma vez que subset_of será None.

A propriedade ffv corresponde à versão fast-forward do contrato. Um valor de zero!() indica que estamos na versão 0 ou na versão inicial deste esquema. Se mais tarde pretender acrescentar novas funcionalidades (novo tipo de operação, etc.), pode incrementar esta versão para indicar uma alteração consensual.

A propriedade subset_of: None confirma a ausência de herança. O campo type_system refere-se ao sistema de tipos estritos já definido na biblioteca types. Esta linha indica que todos os dados utilizados pelo contrato utilizam a implementação de serialização estrita fornecida pela biblioteca em questão.

No bloco global_types, declaramos quatro elementos. Utilizamos a chave, como GS_NOMINAL ou GS_ISSUED_SUPPLY, para referenciá-los posteriormente:

A palavra-chave once(...) significa que cada um destes campos só pode aparecer uma vez.

Em owned_types, declaramos OS_ASSET, que descreve um estado fungível. Usamos StateSchema::Fungible(FungibleType::Unsigned64Bit), indicando que a quantidade de activos (tokens) é armazenada como um inteiro sem sinal de 64 bits. Assim, qualquer transação enviará uma certa quantidade de unidades deste token, que será validado de acordo com esta estrutura numérica estritamente tipificada.

Indicamos valency_types: none!(), o que significa que não há valências neste esquema, ou seja, não há direitos especiais ou extra (como reemissão, queima condicional, etc.). Se um esquema incluísse valências, estas seriam declaradas nesta secção.

Aqui entramos na parte que declara as Operações do Contrato. A Génese é descrita por :

É assim que limitamos a definição da emissão inicial de fichas: devemos declarar a oferta emitida (GS_ISSUED_SUPPLY), mais pelo menos um detentor (um Estado Proprietário do tipo OS_ASSET).

O campo extensions: none!() indica que não está prevista qualquer extensão de estado neste contrato. Isto significa que não existe nenhuma operação para resgatar um direito digital (Valência) ou para efetuar uma extensão de estado antes de uma Transição. Tudo é feito através da Génese ou das Transições de Estado.

Em transições, definimos o tipo de operação TS_TRANSFER. Explicamos que :

Isto modela o comportamento de uma transferência básica, que consome tokens num UTXO, depois cria novos Estados Próprios a favor dos destinatários, e assim preserva a igualdade do montante total entre entradas e saídas.

Finalmente, declaramos um script AluVM (Script::AluVM(AluScript { ... })). Este script contém :

Este código de validação é responsável pela aplicação da lógica comercial. Por exemplo, ele verificará :

Se estas regras não forem respeitadas, a transição será considerada inválida.

Este exemplo de um esquema "Non Inflatable Fungible Asset" dá-nos uma melhor compreensão da estrutura de um contrato simples de token fungível RGB. Podemos ver claramente a separação entre a descrição dos dados (Global e Owned States), a declaração das operações (Genesis, Transitions, Extensions) e a implementação da validação (scripts AluVM). Graças a este modelo, um token comporta-se como um token fungível clássico, mas permanece validado do lado do cliente e não depende da infraestrutura na cadeia para executar o seu código. Apenas os compromissos criptográficos estão ancorados na cadeia de blocos Bitcoin.

Interface

A interface é a camada destinada a tornar um contrato legível e manipulável, tanto pelos utilizadores (leitura humana) como pelas carteiras (leitura informática). A interface desempenha, portanto, um papel comparável ao de uma interface numa linguagem de programação orientada para os objectos (Java, Rust trait, etc.), na medida em que expõe e clarifica a estrutura funcional de um contrato, sem revelar necessariamente os pormenores internos da lógica comercial.

Ao contrário do Schema, que é puramente declarativo e compilado num ficheiro binário difícil de utilizar, a Interface fornece as chaves de leitura necessárias para :

RGB-Bitcoin

Graças à Interface, é possível, por exemplo, escrever código numa carteira que, em vez de manipular campos, manipula diretamente etiquetas como "número de tokens", "nome do ativo", etc. Desta forma, a gestão de um contrato torna-se mais intuitiva. Desta forma, a gestão dos contratos torna-se mais intuitiva.

Funcionamento geral

Este método tem muitas vantagens:

O mesmo tipo de contrato pode ser suportado por uma interface normalizada, partilhada por várias implementações de carteiras. Isto facilita a compatibilidade e a reutilização do código.

Na conceção RGB, o esquema (lógica comercial) e a interface (apresentação e manipulação) são duas entidades independentes. Os programadores que escrevem a lógica do contrato podem concentrar-se no Esquema, sem se preocuparem com a ergonomia ou a representação dos dados, enquanto outra equipa (ou a mesma equipa, mas com um calendário diferente) pode desenvolver a Interface.

A Interface pode ser modificada ou adicionada depois de o ativo ter sido emitido, sem ter de alterar o próprio contrato. Esta é uma grande diferença em relação a alguns sistemas de contratos inteligentes na cadeia, onde a Interface (muitas vezes misturada com o código de execução) é congelada na cadeia de blocos.

O mesmo contrato pode ser exposto através de diferentes interfaces adaptadas a necessidades distintas: uma interface simples para o utilizador final, outra mais avançada para o emitente que necessita de gerir operações de configuração complexas. A carteira pode então escolher qual a interface a importar, consoante a sua utilização.

RGB-Bitcoin

Na prática, quando a carteira obtém um contrato RGB (através de um arquivo .rgb ou .rgba), ela também importa a Interface associada, que também é compilada. Em tempo de execução, a carteira pode, por exemplo, :

Diferença em relação ao Ethereum e a outros sistemas

No Ethereum, a Interface (descrita através da ABI, Application Binary Interface) é geralmente derivada do código armazenado na cadeia (o contrato inteligente). Pode ser dispendioso ou complicado modificar uma parte específica da interface sem tocar no próprio contrato. No entanto, o RGB é baseado numa lógica totalmente fora da cadeia, com dados ancorados em compromissos no Bitcoin. Esta conceção torna possível modificar a interface (ou a sua implementação) sem afetar a segurança fundamental do contrato, uma vez que a validação das regras de negócio permanece no esquema e no código AluVM referenciado.

Compilação de interfaces

Assim como o Schema, a Interface é definida em código fonte (geralmente em Rust) e compilada em um arquivo .rgb ou .rgba. Este arquivo binário contém todas as informações necessárias para que a carteira :

Uma vez importada a interface, a carteira pode apresentar corretamente o contrato e propor interações ao utilizador.

Interfaces normalizadas pela associação LNP/BP

No ecossistema RGB, uma Interface é utilizada para dar um significado legível e manipulável aos dados e às operações de um contrato. A Interface complementa assim o Esquema, que descreve internamente a lógica comercial (tipos estritos, scripts de validação, etc.). Nesta secção, vamos analisar as interfaces normalizadas desenvolvidas pela associação LNP/BP para tipos de contratos comuns (fichas fungíveis, NFT, etc.).

Para relembrar, a ideia é que cada Interface descreva como apresentar e manipular um contrato do lado da carteira, nomeando claramente os campos (tais como spec, ticker, issuedSupply...) e definindo as operações possíveis (tais como Transfer, Burn, Rename...). Várias Interfaces já estão operacionais, mas haverá mais e mais no futuro.

Algumas interfaces prontas a utilizar

RGB20 é a interface para activos fungíveis, que pode ser comparada à norma ERC20 da Ethereum. No entanto, vai um passo mais além, oferecendo uma funcionalidade mais alargada:

Por exemplo, a interface RGB20 pode ser ligada ao regime Non-Inflatable Asset (NIA), que impõe um fornecimento inicial não inflacionável, ou a outros regimes mais avançados, conforme necessário.

o RGB21 diz respeito a contratos do tipo NFT ou, de um modo mais geral, a qualquer conteúdo digital único, como a representação de suportes digitais (imagens, música, etc.). Para além de descrever a emissão e a transferência de um único ativo, inclui caraterísticas como :

o RGB25 é uma norma híbrida que combina aspectos fungíveis e não fungíveis. Foi concebida para activos parcialmente fungíveis, como a tokenização de bens imobiliários, em que se pretende dividir uma propriedade, mantendo uma ligação a um único ativo de raiz (por outras palavras, tem partes fungíveis de uma casa, ligadas a uma casa não fungível). Tecnicamente, esta interface pode ser ligada ao esquema *Collectible Fungible Asset (CFA)**, que tem em conta a noção de divisão enquanto rastreia o ativo original.

Interfaces em desenvolvimento

Estão previstas outras interfaces para utilizações mais especializadas, mas ainda não estão disponíveis:

É claro que, dependendo da data em que consultar este curso, estas interfaces podem já estar operacionais e acessíveis.

Exemplo de interface

Este trecho de código Rust mostra uma Interface RGB20 (ativo fungível). Este código foi retirado do arquivo rgb20.rs da biblioteca padrão do RGB. Vamos dar uma vista de olhos para compreender a estrutura de uma Interface e como ela faz a ponte entre, por um lado, a lógica de negócio (definida no Schema) e, por outro, as funcionalidades expostas às carteiras e aos utilizadores.

// ...
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(),
}
}

Nesta interface, notamos semelhanças com a estrutura do Esquema: encontramos uma declaração de Estado Global, Estados Próprios, Operações de Contrato (Génese e Transições), bem como tratamento de erros. Mas a Interface foca-se na apresentação e manipulação destes elementos para uma carteira ou qualquer outra aplicação.

A diferença em relação ao Schema reside na natureza dos tipos. Schema utiliza tipos estritos (como FungibleType::Unsigned64Bit) e identificadores mais técnicos. A Interface utiliza nomes de campos, macros (fname!(), tn!()), e referências a classes de argumentos (ArgSpec, OwnedIface::Rights...). O objetivo aqui é facilitar a compreensão funcional e a organização dos elementos para a carteira.

Além disso, a Interface pode introduzir funcionalidades adicionais ao Schema básico (por exemplo, gerenciamento de um direito burnEpoch), desde que isso permaneça consistente com a lógica final validada do lado do cliente. A secção "script" do AluVM no Schema assegurará a validade criptográfica, enquanto a Interface descreve a forma como o utilizador (ou a carteira) interage com estes estados e transições.

Estado global e atribuições

Na secção global_state, encontramos campos como spec (descrição do ativo), data, created, issuedSupply, burnedSupply, replacedSupply. Estes são campos que a carteira pode ler e apresentar. Por exemplo:

Na secção atribuições, definimos várias funções ou direitos. Por exemplo:

A palavra-chave public ou private (por exemplo, AssignIface::public(...)) indica se estes estados são visíveis (public) ou confidenciais (private). Quanto a Req::NoneOrMore, Req::Optional, indicam a ocorrência esperada.

Génese e transições

A parte genesis descreve como o ativo é inicializado:

Depois, para cada Transição (Transfer, Issue, Burn...), a Interface define os campos que a operação espera como entrada, os campos que a operação produzirá como saída e quaisquer erros que possam ocorrer. Por exemplo:

Transição :

Transição Issue :

Transição de queima :

Assim, cada operação é descrita de forma legível para uma carteira. Isto permite apresentar uma interface gráfica onde o utilizador pode ver claramente: "Tem o direito de queimar. Quer queimar uma determinada quantia? O código sabe preencher um campo burnedSupply e verificar se o burnRight é válido.

Em suma, é importante ter em conta que uma Interface, por mais completa que seja, não define por si só a lógica interna do contrato. O coração do trabalho é feito pelo Esquema, que inclui tipos estritos, estrutura Genesis, transições e assim por diante. A Interface simplesmente expõe estes elementos de uma forma mais intuitiva e nomeada, para utilização numa aplicação.

Graças à modularidade do RGB, a Interface pode ser actualizada (por exemplo, adicionando uma transição Rename, corrigindo a exibição de um campo, etc.) sem ter que reescrever todo o contrato. Os utilizadores desta Interface podem então beneficiar imediatamente destas melhorias, assim que actualizarem o ficheiro .rgb ou .rgba.

Mas uma vez declarada uma Interface, é necessário ligá-la ao Schema correspondente. Isto é feito através da Interface Implementation, que especifica como mapear cada campo nomeado (como fname!("assetOwner")) para o ID estrito (como OS_ASSET) definido no Schema. Isto garante, por exemplo, que quando uma carteira manipula um campo burnRight, este é o estado que, no Schema, descreve a capacidade de queimar tokens.

Implementação da interface

Na arquitetura RGB, vimos que cada componente (esquema, interface, etc.) pode ser desenvolvido e compilado de forma independente. No entanto, existe ainda um elemento indispensável que liga estes diferentes blocos de construção: a Interface Implementation. É esta que mapeia explicitamente os identificadores ou campos definidos no Esquema (do lado da lógica empresarial) para os nomes declarados na Interface (do lado da apresentação e da interação com o utilizador). Assim, quando uma carteira carrega um contrato, pode compreender exatamente que campo corresponde a quê, e como uma operação designada na Interface se relaciona com a lógica do Esquema.

Um ponto importante é que a implementação da interface não se destina necessariamente a expor todas as funcionalidades do esquema, nem todos os campos da interface: pode ser limitada a um subconjunto. Na prática, isto permite restringir ou filtrar certos aspectos do esquema. Por exemplo, pode ter um esquema com quatro tipos de operação, mas uma interface de implementação que mapeia apenas dois deles num determinado contexto. Por outro lado, se uma Interface propuser pontos finais adicionais, podemos optar por não os implementar aqui.

Eis um exemplo clássico de implementação de interface, em que associamos um esquema Non-Inflatable Asset (NIA) à interface 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!(),
}
}

Nesta interface de implementação :

O resultado após a compilação é um ficheiro .rgb ou .rgba separado, a ser importado para a carteira, para além do Esquema e da Interface. Assim, o software sabe como ligar concretamente este contrato NIA (cuja lógica é descrita pelo seu Esquema) à Interface "RGB20" (que fornece nomes humanos e um modo de interação para tokens fungíveis), aplicando esta Implementação de Interface como uma porta de entrada entre os dois.

Porquê separar a implementação da interface?

A separação aumenta a flexibilidade. Um único esquema pode ter várias implementações de interface distintas, cada uma delas mapeando um conjunto diferente de funcionalidades. Além disso, a própria implementação da interface pode evoluir ou ser reescrita sem que seja necessário alterar o esquema ou a interface. Mantém-se assim o princípio de modularidade da RGB: cada componente (Esquema, Interface, Implementação de Interface) pode ser versionado e atualizado independentemente, desde que as regras de compatibilidade impostas pelo protocolo sejam respeitadas (mesmos identificadores, consistência de tipos, etc.).

Na utilização concreta, quando a carteira carrega um contrato, deve :

Esta arquitetura modular torna possíveis cenários de utilização como :

No próximo capítulo, veremos como funciona uma transferência de contrato e como são geradas as facturas RGB.

Transferências de contratos

Neste capítulo, vamos analisar o processo de transferência de um contrato no ecossistema RGB. Para o ilustrar, vamos ver a Alice e o Bob, os nossos protagonistas habituais, que desejam trocar um ativo RGB. Vamos também mostrar alguns excertos de comandos da ferramenta de linha de comando rgb, para ver como funciona na prática.

Compreender a transferência de contratos RGB

Vejamos um exemplo de uma transferência entre Alice e Bob. Neste exemplo, assumimos que Bob está apenas a começar a utilizar RGB, enquanto Alice já possui activos RGB na sua carteira. Veremos como Bob configura seu ambiente, importa o contrato relevante, solicita uma transferência de Alice e, finalmente, como Alice realiza a transação real no blockchain do Bitcoin.

1) Instalar a carteira RGB

Em primeiro lugar, Bob precisa de instalar uma carteira RGB, ou seja, um software compatível com o protocolo. Esta não contém, à partida, quaisquer contratos. O Bob também precisa de :

Como lembrete, Owned States em RGB referem-se a Bitcoin UTXOs. Portanto, devemos sempre ser capazes de gerenciar e gastar UTXOs em uma transação Bitcoin que incorpora compromissos criptográficos (Tapret ou Opret) apontando para dados RGB.

2) Aquisição de informações sobre os contratos

O Bob precisa então de obter os dados do contrato que lhe interessam. Estes dados podem circular através de qualquer canal: sítio Web, correio eletrónico, aplicação de mensagens... Na prática, são agrupados numa consignação, ou seja, um pequeno pacote de dados contendo :

RGB-Bitcoin

O tamanho total é muitas vezes da ordem de alguns kilobytes, uma vez que cada componente pesa geralmente menos de 200 bytes. Também pode ser possível transmitir esta remessa em Base58, através de canais resistentes à censura (como Nostr ou através da Lightning Network, por exemplo), ou como um código QR.

3) Importação e validação de contratos

Depois de Bob ter recebido a remessa, ele importa-a para a sua carteira RGB. Isto irá então :

O Bob pode agora ver o ativo na sua carteira (mesmo que ainda não o possua) e perceber que campos estão disponíveis, que operações são possíveis... Depois, precisa de contactar a pessoa que possui o ativo a transferir. No nosso exemplo, trata-se da Alice.

O processo de descobrir quem detém um determinado ativo RGB é semelhante ao de encontrar um pagador de Bitcoin. Os pormenores desta ligação dependem da utilização (mercados, canais de conversação privados, faturação, venda de bens e serviços, salário...).

4) Emissão de uma fatura

Para iniciar a transferência de um ativo RGB, o Bob deve primeiro emitir uma fatura. Esta fatura é utilizada para :

Bob utiliza a ferramenta rgb na linha de comando. Suponha que ele quer 100 unidades de um token cujo ContractId é conhecido, quer confiar em Tapret, e especifica seu UTXO (456e3..dfe1:0) :

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

No final deste capítulo, analisaremos mais detalhadamente a estrutura das facturas RGB.

5) Transmissão de facturas

A fatura gerada (por exemplo, como URL: rgb:2WBcas9.../RGB20/100+utxob:...) contém todas as informações de que Alice necessita para preparar a transferência. Tal como a remessa, pode ser codificada de forma compacta (Base58 ou outro formato) e enviada através de uma aplicação de mensagens, correio eletrónico, Nostr...

RGB-Bitcoin

6) Preparação da transação no lado da Alice

A Alice recebe a fatura do Bob. Na sua carteira RGB, ela tem um stash que contém o ativo a ser transferido. Para gastar o UTXO que contém o ativo, ela deve primeiro gerar uma PSBT (Partially Signed Bitcoin Transaction), ou seja, uma transação Bitcoin incompleta, utilizando o UTXO que possui:

alice$ wallet construct tx.psbt

Esta transação básica (por enquanto não assinada) será usada para ancorar o compromisso criptográfico ligado à transferência para o Bob. O UTXO de Alice será assim gasto, e na saída, colocaremos o compromisso Tapret ou Opret para Bob.

7) Geração de remessa de transferência

Em seguida, Alice constrói a remessa de terminal (por vezes chamada "remessa de transferência") através do comando :

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

Este novo ficheiro consignment.rgb contém :

Nesta fase, a transação ainda não é transmitida na rede Bitcoin. A consignação é maior do que uma consignação básica, pois inclui todo o histórico (cadeia de prova) para provar a legitimidade do ativo.

8) Bob verifica e aceita a remessa

Alice transmite esta remessa terminal a Bob. O Bob irá então :

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

9) Opção: O Bob envia a confirmação de volta à Alice (pagamento)

Se o Bob quiser, pode enviar esta assinatura de volta para a Alice. Isto indica:

Não é obrigatório, mas pode dar a Alice a garantia de que não haverá litígios posteriores sobre a transferência.

10) Alice assina e publica a transação

Alice pode então :

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

Uma vez confirmada, esta transação marca a conclusão da transferência. O Bob torna-se o novo proprietário do ativo: tem agora um Estado de Propriedade que aponta para o UTXO que controla, comprovado pela presença do compromisso na transação.

Para resumir, eis o processo de transferência completo:

RGB-Bitcoin

Vantagens das transferências RGB

Apenas Alice e Bob têm acesso a todos os dados de transição de estado. Eles trocam essas informações fora da blockchain, por meio de consignações. Os compromissos criptográficos na transação Bitcoin não revelam o tipo de ativo ou o montante, o que garante uma confidencialidade muito maior do que outros sistemas de token na cadeia.

Bob pode verificar a consistência da transferência comparando a consignação com as âncoras na blockchain do Bitcoin. Ele não precisa de validação de terceiros. Alice não precisa de publicar o histórico completo na blockchain, o que reduz a carga sobre o protocolo de base e melhora a confidencialidade.

As trocas complexas (swaps atómicos entre BTC e um ativo RGB, por exemplo) podem ser efectuadas numa única transação, evitando a necessidade de scripts HTLC ou PTLC. Se o acordo não for difundido, todos podem reutilizar os seus UTXOs de outras formas.

Diagrama sintético de transferência

Antes de analisar as facturas em mais pormenor, eis um diagrama sumário do fluxo geral de uma transferência RGB:

RGB-Bitcoin

A transferência ilustra todo o poder e flexibilidade do protocolo RGB: uma troca privada, validada no lado do cliente, ancorada de forma mínima e discreta na blockchain da Bitcoin, e retendo o melhor da segurança do protocolo (sem risco de gasto duplo). Isto faz do RGB um ecossistema promissor para transferências de valor mais confidenciais e escaláveis do que as cadeias de blocos programáveis na cadeia.

Facturas RGB

Nesta secção, explicaremos em pormenor como funcionam as facturas no ecossistema RGB e como permitem realizar operações (em particular transferências) com um contrato. Primeiro, veremos os identificadores utilizados, depois a forma como são codificados e, por fim, a estrutura de uma fatura expressa como URL (um formato suficientemente prático para ser utilizado em carteiras).

Identificadores e codificação

É definido um identificador único para cada um dos seguintes elementos:

Esta unicidade é muito importante, uma vez que cada componente do sistema deve ser distinguível. Por exemplo, um contrato X não pode ser confundido com outro contrato Y, e duas interfaces diferentes (RGB20 vs. RGB21, por exemplo) devem ter identificadores distintos.

Para tornar estes identificadores eficientes (tamanho reduzido) e legíveis, utilizamos :

Por exemplo, um ContractId pode ser representado por algo como :

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

O prefixo rgb: confirma que se trata de um identificador RGB e não de uma ligação HTTP ou outro protocolo. Graças a este prefixo, as carteiras são capazes de interpretar a cadeia corretamente.

Segmentação de identificadores

Os identificadores RGB são frequentemente bastante longos, uma vez que a segurança (criptográfica) subjacente pode exigir campos de 256 bits ou mais. Para facilitar a leitura e verificação humanas, dividimos estas cadeias em vários blocos separados por um hífen (-). Assim, em vez de termos uma cadeia de caracteres longa e ininterrupta, dividimo-la em blocos mais curtos. Esta prática é comum para números de cartão de crédito ou de telefone, e também se aplica aqui para facilitar a verificação. Assim, por exemplo, pode ser dito a um utilizador ou parceiro: "Por favor, verifique se o terceiro bloco é 9GEgnyMj7", em vez de ter de comparar tudo de uma só vez. O último bloco é frequentemente utilizado como checksum, para ter um sistema de deteção de erros ou gralhas.

A título de exemplo, um ContractId em base58 codificado e segmentado poderia ser :

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

Cada um dos traços divide a cadeia em secções. Isto não afecta a semântica do código, apenas a sua apresentação.

Utilização de URLs para facturas

Uma fatura RGB é apresentada como um URL. Isto significa que pode ser clicado ou digitalizado (como um código QR) e que uma carteira pode interpretá-lo diretamente para efetuar uma transação. Esta simplicidade de interação difere de alguns outros sistemas em que é necessário copiar e colar vários dados em diferentes campos do software.

Uma fatura para uma ficha fungível (por exemplo, uma ficha RGB20) pode ter o seguinte aspeto:

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

Vamos analisar este URL:

O facto de tudo caber num único URL facilita a vida ao utilizador: um simples clique ou scan na carteira e a operação está pronta a ser executada.

Poder-se-ia imaginar sistemas em que, em vez do ContractId, fosse utilizado um simples ticker (por exemplo, USDT). No entanto, isso levantaria grandes problemas de confiança e segurança: um ticker não é uma referência única (vários contratos poderiam reivindicar o nome USDT). Com o RGB, pretendemos um identificador criptográfico único e não ambíguo. Daí a adoção da cadeia de 256 bits, codificada em base58 e segmentada. O utilizador sabe que está a manipular precisamente o contrato cujo ID é 2WBcas9-yjz... e não qualquer outro.

Parâmetros URL adicionais

Também é possível acrescentar parâmetros adicionais ao URL, da mesma forma que com HTTP, como por exemplo :

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

Vejamos o caso de um NFT através da interface RGB21. Por exemplo, poderíamos ter :

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

Aqui vemos :

A ideia é a mesma: transmitir uma ligação única que a carteira possa interpretar, identificando claramente o ativo único a transferir.

Outras operações via URL

Os URLs RGB não são usados apenas para solicitar uma transferência. Eles também podem codificar operações mais avançadas, como a emissão de novos tokens (issuance). Por exemplo:

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

Aqui encontramos :

Por exemplo, a carteira pode ter a seguinte redação "Pediram-me para efetuar uma operação de emissão a partir da interface RGB20, num contrato tal e tal, para 100.000 unidades, em benefício de tal e tal Selo de Utilização Única*"

Agora que já analisámos os principais elementos da programação RGB, passo ao capítulo seguinte sobre a elaboração de um contrato RGB.

Elaboração de contratos inteligentes

Neste capítulo, vamos abordar passo-a-passo a escrita de um contrato, usando a ferramenta de linha de comando rgb. O objetivo é mostrar como instalar e manipular o CLI, compilar um Esquema, importar a Interface e a Interface Implementation, e depois emitir (emitir) um ativo. Também veremos a lógica subjacente, incluindo compilação e validação de estado. No final deste capítulo, deverá ser capaz de reproduzir o processo e criar os seus próprios contratos RGB.

Relembrando, a lógica interna do RGB baseia-se em bibliotecas Rust que os programadores podem importar para os seus projectos para gerir a parte da validação do lado do cliente. Além disso, a equipa da Associação LNP/BP está a trabalhar em ligações para outras línguas, mas isto ainda não foi finalizado. Além disso, outras entidades, como a Bitfinex, estão a desenvolver as suas próprias pilhas de integração (falaremos sobre elas nos últimos 2 capítulos do curso). Por enquanto, portanto, o rgb CLI é a referência oficial, mesmo que permaneça relativamente pouco polido.

Instalação e apresentação da ferramenta rgb

O comando principal é simplesmente chamado rgb. Ele foi projetado para ser uma reminiscência do git, com um conjunto de sub-comandos para manipular contratos, invocá-los, emitir ativos e assim por diante. A Bitcoin Wallet não está integrada atualmente, mas estará em uma versão iminente (0.11). Esta próxima versão permitirá aos utilizadores criar e gerir as suas carteiras (através de descritores) diretamente a partir do rgb, incluindo a geração de PSBT, compatibilidade com hardware externo (por exemplo, uma carteira de hardware) para assinatura, e interoperabilidade com software como o Sparrow. Isto simplificará todo o cenário de emissão e transferência de activos.

Instalação via Cargo

Instalamos a ferramenta em Rust com :

cargo install rgb-contracts --all-features

(Nota: o crate é chamado rgb-contracts, e o comando instalado será chamado rgb. Se uma crate chamada rgb já existia, pode ter havido uma colisão, daí o nome)

A instalação compila um grande número de dependências (por exemplo, análise de comandos, integração Electrum, gestão de provas de conhecimento zero, etc.).

Quando a instalação estiver concluída, o ficheiro :

rgb

Executando rgb (sem argumentos) mostra uma lista de sub-comandos disponíveis, tais como interfaces, schema, import, export, issue, invoice, transfer, etc. Você pode mudar o diretório de armazenamento local (um esconderijo que guarda todos os logs, esquemas e implementações), escolher a rede (testnet, mainnet) ou configurar seu servidor Electrum.

RGB-Bitcoin

Primeira visão geral dos controlos

Quando executar o seguinte comando, verá que uma interface RGB20 já está integrada por defeito:

rgb interfaces

Se esta interface não estiver integrada, clone o ficheiro :

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

Compilar:

cargo run

Em seguida, importe a interface da sua escolha:

rgb import interfaces/RGB20.rgb
RGB-Bitcoin

Por outro lado, é-nos dito que ainda não foi importado nenhum esquema para o software. Também não existe nenhum contrato na reserva. Para o ver, execute o comando :

rgb schemata

Pode então clonar o repositório para obter determinados esquemas:

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

Este repositório contém, no seu diretório src/, vários ficheiros Rust (por exemplo nia.rs) que definem esquemas (NIA para "Non Inflatable Asset", UDA para "Unique Digital Asset", etc.). Para compilar, pode então executar :

cd rgb-schemata
cargo run

Isso gera vários arquivos .rgb e .rgba correspondentes aos esquemas compilados. Por exemplo, você encontrará NonInflatableAsset.rgb.

Importação de esquema e implementação de interface

Agora é possível importar o esquema para o rgb :

rgb import schemata/NonInflatableAssets.rgb
RGB-Bitcoin

Isto adiciona-o ao stock local. Se executarmos o seguinte comando, vemos que o esquema aparece agora:

rgb schemata

Criação de contratos (emissão)

Existem duas abordagens para criar um novo ativo:

Pode encontrar exemplos em Rust na pasta examples, que ilustram como construir um ContractBuilder, preencher o estado global (nome do ativo, ticker, abastecimento, data, etc.), definir o Estado de Propriedade (a que UTXO está atribuído), e depois compilar tudo isto numa consignação de contrato que pode exportar, validar e importar para um esconderijo.

A outra maneira é editar manualmente um arquivo YAML para personalizar o ticker, o nome, o fornecimento, e assim por diante. Suponha que o arquivo se chame RGB20-demo.yaml. Você pode especificar :

Eis um exemplo de um ficheiro YAML a criar:

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

Em seguida, basta executar o comando :

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

No meu caso, o identificador único do esquema (que deve ser colocado entre aspas simples) é RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k e não coloquei nenhum emitente. Portanto, o meu pedido é :

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

Se não souber o ID do esquema, execute o comando :

rgb schemata

O CLI responde que um novo contrato foi emitido e adicionado ao stash. Se digitarmos o seguinte comando, vemos que existe agora um contrato adicional, correspondente ao que acabou de ser emitido:

rgb contracts
RGB-Bitcoin

Em seguida, o comando seguinte apresenta os estados globais (nome, ticker, oferta...) e a lista de Estados Próprios, ou seja, as atribuições (por exemplo, 1 milhão de fichas PBN definidas no UTXO b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1).

rgb state '<ContractId>'
RGB-Bitcoin

Exportação, importação e validação

Para partilhar este contrato com outros utilizadores, pode ser exportado do esconderijo para um ficheiro :

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

O arquivo myContractPBN.rgb pode ser passado para outro usuário, que pode adicioná-lo ao seu estoque com o comando :

rgb import myContractPBN.rgb

Aquando da importação, se se tratar de uma simples contratação de consignação, será apresentada a mensagem "Importing consignment rgb". Se se tratar de uma consignação de transição de estado de maior dimensão, o comando será diferente (rgb accept).

Para garantir a validade, também é possível utilizar a função de validação local. Por exemplo, é possível executar :

rgb validate myContract.rgb

Utilização, verificação e visualização de stocks

Para relembrar, o stash é um inventário local de esquemas, interfaces, implementações e contratos (Genesis + transições). Cada vez que executa "import", adiciona um elemento ao stash. Este stash pode ser visto em pormenor com o comando :

rgb dump
RGB-Bitcoin

Isto irá gerar uma pasta com detalhes de todo o stock.

Transferência e PSBT

Para efetuar uma transferência, é necessário manipular uma carteira Bitcoin local para gerir os compromissos Tapret ou Opret.

Gerar uma fatura

Na maioria dos casos, a interação entre os participantes num contrato (por exemplo, Alice e Bob) ocorre através da geração de uma fatura. Se a Alice quiser que o Bob execute algo (uma transferência de fichas, uma reemissão, uma ação num DAO, etc.), a Alice cria uma fatura que detalha as suas instruções ao Bob. Assim, temos :

Ao contrário de outros ecossistemas, uma fatura RGB não se limita à noção de pagamento. Pode incluir qualquer pedido ligado ao contrato: revogar uma chave, votar, criar uma gravação (gravação) num NFT, etc. A operação correspondente pode ser descrita na interface do contrato. A operação correspondente pode ser descrita na interface do contrato.

O seguinte comando gera uma fatura RGB:

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

Com :

Por exemplo, com os seguintes comandos

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

O CLI gerará uma fatura como :

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

Pode ser transmitida ao Bob através de qualquer canal (texto, código QR, etc.).

Efetuar uma transferência

Para transferir a partir desta fatura :

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

No próximo capítulo, analisaremos mais detalhadamente a integração do RGB na rede Lightning.

RGB na rede Lightning

Neste capítulo, proponho-me examinar a forma como o RGB pode ser utilizado na Lightning Network, para integrar e movimentar activos RGB (tokens, NFTs, etc.) através de canais de pagamento fora da cadeia.

A ideia básica é que a transição de estado RGB (Transição de estado) pode ser comprometida com uma transação Bitcoin que, por sua vez, pode permanecer fora da cadeia até que o canal Lightning seja fechado. Assim, cada vez que o canal é atualizado, uma nova transição de estado RGB pode ser incorporada na nova transação de confirmação, o que invalida a transição antiga. Desta forma, os canais Lightning podem ser utilizados para transferir activos RGB e podem ser encaminhados da mesma forma que os pagamentos Lightning convencionais.

Criação e financiamento de canais

Para criar um canal Lightning que transporta activos RGB, precisamos de dois elementos:

Em termos de Bitcoin, a transação de financiamento deve existir para definir o UTXO de referência, mesmo que contenha apenas uma pequena quantidade de sats (é apenas uma questão de cada saída em futuras transacções de compromisso permanecer acima do limite de poeira). Por exemplo, Alice pode decidir fornecer 10k sats e 500 USDT (emitidos como um ativo RGB). Na transação de financiamento, adicionamos um compromisso (Opret ou Tapret) que ancora a transição do estado RGB.

RGB-Bitcoin

Depois de a transação de financiamento ter sido preparada (mas ainda não transmitida), são criadas transacções de compromisso para que qualquer uma das partes possa fechar o canal unilateralmente a qualquer momento. Estas transacções assemelham-se às transacções de compromisso clássicas do Lightning, exceto pelo facto de acrescentarmos uma saída adicional que contém a âncora RGB (OP_RETURN ou Taproot) ligada à nova transição de estado.

A transição de estado RGB move então os activos do multisig 2/2 do financiamento para os outputs da transação de compromisso. A vantagem deste processo é que a segurança do estado RGB corresponde exatamente à mecânica punitiva do Lightning: se Bob transmitir um estado de canal antigo, Alice pode puni-lo e gastar o output, de modo a recuperar tanto os sats como os tokens RGB. O incentivo é, portanto, ainda mais forte do que num canal Lightning sem activos RGB, uma vez que um atacante pode perder não só os sats, mas também os activos RGB do canal.

Uma transação de compromisso assinada por Alice e enviada a Bob teria, portanto, o seguinte aspeto

RGB-Bitcoin

E a transação de compromisso que a acompanha, assinada por Bob e enviada a Alice, terá o seguinte aspeto:

RGB-Bitcoin

Atualização do canal

Quando ocorre um pagamento entre dois participantes do canal (ou estes pretendem alterar a afetação de activos), criam um novo par de transacções de compromisso. O montante em sats de cada saída pode ou não permanecer inalterado, consoante a implementação, uma vez que a sua principal função é permitir a construção de UTXOs válidas. Por outro lado, a saída OP_RETURN (ou Taproot) deve ser modificada para conter a nova âncora RGB, que representa a nova distribuição dos activos no canal.

Por exemplo, se Alice transferir 30 USDT para Bob no canal, a nova transição de estado reflectirá um saldo de 400 USDT para Alice e 100 USDT para Bob. A transação de confirmação é adicionada à (ou modificada pela) âncora OP_RETURN/Taproot para incluir esta transição. Note-se que, do ponto de vista da RGB, a entrada para a transição continua a ser o multisig inicial (onde os activos na cadeia são realmente alocados até o canal fechar). Apenas os outputs do RGB (alocações) mudam, dependendo da redistribuição decidida.

A transação de compromisso assinada por Alice, pronta a ser distribuída por Bob :

RGB-Bitcoin

A transação de compromisso assinada por Bob, pronta a ser distribuída por Alice :

RGB-Bitcoin

Gestão de HTLC

Na realidade, a Lightning Network permite que os pagamentos sejam encaminhados através de múltiplos canais, utilizando HTLCs (Hashed Time-Locked Contracts). O mesmo se passa com o RGB: para cada pagamento em trânsito no canal, é adicionado um output HTLC à transação de confirmação e uma alocação RGB ligada a este HTLC. Assim, quem gasta a saída HTLC (graças ao segredo ou após a expiração do timelock) recupera tanto os sats como os activos RGB associados. Por outro lado, é óbvio que é necessário ter dinheiro suficiente na estrada, tanto em termos de sats como de activos RGB.

RGB-Bitcoin

O funcionamento do RGB no Lightning deve, portanto, ser considerado em paralelo com o da própria rede Lightning. Se quiser aprofundar este assunto, recomendo vivamente que dê uma vista de olhos a este outro curso de formação completo:

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

Mapa de código RGB

Finalmente, antes de passar à secção seguinte, gostaria de dar uma visão geral do código utilizado no RGB. O protocolo baseia-se num conjunto de bibliotecas Rust e especificações de código aberto. Eis um resumo dos principais repositórios e caixas:

RGB-Bitcoin

Validação do lado do cliente

Gestão da validação fora da cadeia e da lógica dos selos de utilização única.

Compromissos determinísticos de Bitcoin (DBC)

Gestão da ancoragem determinística nas transacções Bitcoin (Tapret, OP_RETURN, etc.).

Compromisso multiprotocolo (MPC)

Múltiplas combinações de compromissos e integração com diferentes protocolos.

Tipos estritos e codificação estrita

O sistema de tipagem rigoroso e a serialização determinística utilizados para a validação do lado do cliente.

Núcleo RGB

O núcleo do protocolo, que engloba a lógica principal da validação RGB.

Biblioteca e carteira padrão RGB

Implementações normalizadas, gestão de stocks e carteiras.

RGB CLI

O rgb CLI e crate wallet, para manipulação de contratos em linha de comando.

Esquema RGB

Contém exemplos de esquemas (NIA, UDA, etc.) e respectivas implementações.

ALuVM

Máquina virtual baseada no registo utilizada para executar scripts de validação.

Protocolo Bitcoin - BP

Add-ons para suportar o protocolo Bitcoin (transacções, desvios, etc.).

Computação Ubíqua Determinística - UBIDECO

Ecossistema ligado a desenvolvimentos determinísticos de fonte aberta.

Baseando-se no RGB

DIBA e o projeto Bitmask

Esta última secção do curso baseia-se nas apresentações feitas por vários oradores no bootcamp RGB. Inclui testemunhos e reflexões sobre o RGB e o seu ecossistema, bem como apresentações de ferramentas e projectos baseados no protocolo. Este primeiro capítulo é moderado por Hunter Beast e os dois seguintes por Frederico Tenga.

Do JavaScript para o Rust e para o ecossistema Bitcoin

No início, Hunter Beast trabalhava principalmente em JavaScript. Depois descobriu Rust, cuja sintaxe parecia pouco atraente e frustrante no início. No entanto, acabou por apreciar o poder da linguagem, o controlo sobre a memória (heap e stack), a segurança e o desempenho que lhe estão associados. Ele enfatiza que Rust é um excelente campo de treinamento para uma compreensão profunda de como um computador funciona.

Hunter Beast conta a sua experiência em vários projectos do ecossistema altcoin, como o Ethereum (com Solidity, TypeScript, etc.) e, mais tarde, o Filecoin. Explica que ficou inicialmente impressionado com alguns dos protocolos, mas que acabou por ficar desiludido com a maior parte deles, nomeadamente devido à sua tokenomics. Denuncia os incentivos financeiros duvidosos, a criação inflacionária de tokens que dilui os investidores e o aspeto potencialmente explorador destes projectos. Assim, acabou por adotar uma postura Bitcoin maximalista, até porque algumas pessoas lhe abriram os olhos para os mecanismos económicos mais sólidos do Bitcoin e para a robustez deste sistema.

O atrativo do RGB e a construção em camadas

O que o convenceu definitivamente da relevância do Bitcoin, nas suas palavras, foi a descoberta do RGB e o conceito de camadas. Ele acredita que as funcionalidades existentes em outros blockchains poderiam ser reproduzidas em camadas superiores, acima do Bitcoin, sem alterar o protocolo básico.

Em fevereiro de 2022, juntou-se à DIBA para trabalhar especificamente no RGB e, em particular, na carteira Bitmask. Na altura, a Bitmask ainda estava na versão 0.01 e executava o RGB na versão 0.4, apenas para a gestão de tokens individuais. Ele observa que isso era menos orientado para a autocustódia do que hoje, já que a lógica era parcialmente baseada no servidor. Desde então, a arquitetura evoluiu para este modelo, muito apreciado pelos bitcoiners.

As bases do protocolo RGB

O protocolo RGB é a mais recente e mais avançada concretização do conceito de colored coins, já explorado por volta de 2012-2013. Na altura, várias equipas procuravam associar diferentes valores de bitcoin aos UTXOs, o que levou a múltiplas implementações dispersas. Esta falta de padronização e a baixa procura na altura impediram que estas soluções ganhassem uma posição duradoura.

Atualmente, a RGB destaca-se pela sua robustez concetual e especificações unificadas através da associação LNP/BP. O princípio baseia-se na validação do lado do cliente. A blockchain Bitcoin apenas armazena compromissos criptográficos (commitments, via Taproot ou OP_RETURN), enquanto a maioria dos dados (definições de contratos, históricos de transferências, etc.) é armazenada pelos utilizadores em causa. Desta forma, a carga de armazenamento é distribuída e a confidencialidade das trocas é reforçada, sem sobrecarregar a cadeia de blocos. Esta abordagem permite a criação de activos fungíveis (norma RGB20) ou únicos (norma RGB21), num quadro modular e escalável.

A função de ficha (RGB20) e os activos únicos (RGB21)

Com RGB20, definimos um token fungível no Bitcoin. O emissor escolhe uma oferta, uma precisão, e cria um contrato no qual pode então efetuar transferências. Cada transferência é referenciada a um Bitcoin UTXO, que actua como um Selo de utilização única. Esta lógica garante que o utilizador não poderá gastar o mesmo ativo duas vezes, uma vez que apenas a pessoa capaz de gastar o UTXO detém a chave para atualizar o estado do contrato do lado do cliente.

RGB21 visa activos únicos (ou "NFT"). O ativo tem um fornecimento de 1, e pode ser associado a metadados (ficheiro de imagem, áudio, etc.) descritos através de um campo específico. Ao contrário dos NFTs em cadeias de blocos públicas, os dados e os seus identificadores MIME podem permanecer privados, distribuídos ponto a ponto à discrição do proprietário.

A solução Bitmask: uma carteira para RGB

Para explorar as capacidades do RGB na prática, o projeto DIBA concebeu uma carteira chamada Bitmask. A ideia é fornecer uma ferramenta sem custódia, baseada no Taproot, acessível como uma aplicação web ou extensão do browser. A Bitmask gere activos RGB20 e RGB21 e integra vários mecanismos de segurança:

Graças a esta arquitetura, todas as transacções de activos têm lugar no lado do cliente. Do lado de fora, a transação Bitcoin não é mais do que uma transação clássica de gastos Taproot, que ninguém suspeitaria que também transporta uma transferência de tokens fungíveis ou NFTs. A ausência de sobrecarga na cadeia (sem metadados armazenados publicamente) garante um certo grau de discrição e facilita a resistência a possíveis tentativas de censura.

Segurança e arquitetura distribuída

Na medida em que o protocolo RGB exige que cada participante conserve o seu histórico de transacções (para provar a validade das transferências que recebe), coloca-se a questão do armazenamento. A Bitmask propõe serializar localmente este stash e depois enviá-lo para vários servidores ou nuvens (opcional). Os dados permanecem encriptados pelo utilizador através do Carbonado, pelo que um servidor não os pode ler. Em caso de corrupção parcial, a camada de correção de erros pode reconstituir o conteúdo.

A utilização de CRDT (Conflict-free replicated data type) permite a fusão de diferentes versões do stash, caso estas divirjam. Cada um é livre de alojar estes dados onde quiser, uma vez que nenhum nó completo contém toda a informação relacionada com o ativo. Isto reflecte exatamente a filosofia Client-side Validation, em que cada proprietário é responsável por armazenar provas da validade do seu ativo RGB.

Rumo a um ecossistema mais vasto: mercado, interoperabilidade e novas funções

A empresa por detrás da Bitmask não se limita ao simples desenvolvimento de uma carteira. A DIBA pretende desenvolver :

Ao mesmo tempo, estamos a trabalhar em WebBTC ou WebLN (normas que permitem que os sites peçam à carteira para assinar transacções Bitcoin ou Lightning), bem como na capacidade de "telequeimar" entradas Ordinals (se quisermos repatriar Ordinals para um formato RGB mais discreto e flexível).

Conclusão

Todo este processo mostra como o ecossistema RGB pode ser implementado e tornado acessível aos utilizadores finais através de soluções técnicas robustas. A transição de uma perspetiva altcoin para uma visão mais centrada no Bitcoin, associada à descoberta da Client-side Validation, ilustra um caminho bastante lógico: compreendemos que é possível implementar várias funcionalidades (tokens fungíveis, NFT, contratos inteligentes...) sem bifurcar a blockchain, simplesmente tirando partido dos compromissos criptográficos nas transacções Taproot ou OP_RETURNs.

A carteira Bitmask faz parte desta abordagem: do lado da blockchain, tudo o que vê é uma transação Bitcoin normal; do lado do utilizador, manipula uma interface web onde cria, troca e armazena todo o tipo de activos fora da cadeia. Este modelo dissocia claramente a infraestrutura monetária (Bitcoin) da lógica de emissão e de transferência (RGB), garantindo simultaneamente um elevado nível de confidencialidade e uma melhor escalabilidade.

Trabalho da Bitfinex sobre RGB

Neste capítulo, com base numa apresentação de Frederico Tenga, analisamos um conjunto de ferramentas e projectos criados pela equipa da Bitfinex dedicados ao RGB, com o objetivo de fomentar a emergência de um ecossistema rico e diversificado em torno deste protocolo. O objetivo inicial da equipa não é lançar um produto comercial específico, mas sim fornecer blocos de construção de software, contribuir para o próprio protocolo RGB e propor referências concretas de implementação, como uma carteira móvel (Iris Wallet) ou um nó Lightning compatível com o RGB.

Antecedentes e objectivos

Desde cerca de 2022, a equipa Bitfinex RGB tem vindo a concentrar-se no desenvolvimento da pilha de tecnologia que permite que o RGB seja explorado e testado de forma eficiente. Várias contribuições foram feitas:

Esta abordagem visa cobrir toda a cadeia de necessidades: desde a biblioteca de baixo nível (RGBlib), que permite a implementação de uma carteira, até ao aspeto da produção (um nó Lightning, uma carteira para Android, etc.).

A biblioteca RGBlib: simplificar o desenvolvimento de aplicações RGB

Um ponto importante na democratização da criação de carteiras e aplicações RGB é disponibilizar uma abstração simples o suficiente para que os desenvolvedores não tenham que aprender tudo sobre a lógica interna do protocolo. Este é precisamente o objetivo da RGBlib, escrita em Rust.

O RGBlib atua como uma ponte entre os requisitos altamente flexíveis (mas às vezes complexos) do RGB que pudemos estudar nos capítulos anteriores e as necessidades concretas de um desenvolvedor de aplicativos. Por outras palavras, uma carteira (ou serviço) que pretenda gerir transferências de tokens, emissão de activos, verificação, etc., pode confiar no RGBlib sem conhecer todos os detalhes criptográficos ou todos os parâmetros RGB personalizáveis.

A livraria oferece :

O RGBlib, portanto, se baseia em noções complexas específicas do RGB (validação do lado do cliente, âncoras Tapret/Opret), mas as encapsula para que a aplicação final não tenha que reprogramar tudo ou tomar decisões arriscadas. Além disso, o RGBlib já está ligado a várias linguagens (Kotlin e Python), abrindo a porta a utilizações que vão para além de um simples universo Rust.

Iris Wallet: um exemplo de uma carteira RGB no Android

Para provar a eficácia do RGBlib, a equipa da Bitfinex desenvolveu a Iris Wallet, exclusivamente para Android nesta fase. É uma carteira móvel que ilustra uma experiência de utilizador semelhante à de uma carteira Bitcoin normal: pode emitir um ativo, enviá-lo, recebê-lo e ver o seu histórico, mantendo-se num modelo de auto-custódia.

O Iris tem uma série de caraterísticas interessantes:

Utilizando um servidor Electrum:

Como qualquer carteira, a Iris precisa de saber sobre as confirmações de transacções na cadeia de bloqueio. Em vez de incorporar um nó completo, o Iris usa como padrão um servidor Electrum mantido pela equipa da Bitfinex. Os utilizadores podem, no entanto, configurar o seu próprio servidor ou outro serviço de terceiros. Desta forma, as transacções Bitcoin podem ser validadas e a informação recuperada (indexação) de uma forma modular.

O servidor proxy RGB:

Ao contrário do Bitcoin, o RGB requer a troca de metadados fora da cadeia (consignments) entre o emissor e o recetor. Para simplificar este processo, a Iris oferece uma solução em que a comunicação é efectuada através de um servidor proxy. A carteira recetora gera uma fatura que menciona para onde o remetente deve enviar os dados do lado do cliente. Por defeito, o URL aponta para um proxy alojado pela equipa Bitfinex, mas é possível alterar este proxy (ou alojar o seu próprio). A ideia é voltar a uma experiência de utilizador familiar em que o destinatário apresenta um código QR e o remetente digitaliza este código para a transação, sem quaisquer manipulações adicionais complexas.

Cópia de segurança contínua:

Num contexto estritamente Bitcoin, fazer o backup da sua semente é geralmente suficiente (embora hoje em dia recomendamos fazer o backup da semente e dos descritores). Com a RGB, isso não é suficiente: é preciso também manter o histórico local (as consignações), provando que você realmente possui um ativo RGB. Cada vez que recebe um recibo, o dispositivo armazena novos dados, essenciais para as despesas posteriores. O Iris gere automaticamente uma cópia de segurança encriptada no Google Drive do utilizador. Não é necessária qualquer confiança especial no Google, uma vez que a cópia de segurança é encriptada, e estão previstas para o futuro opções mais robustas (como um servidor pessoal) para evitar qualquer risco de censura ou eliminação por um operador terceiro.

Outras caraterísticas:

Em suma, o Iris oferece uma experiência de utilizador próxima da de uma carteira Bitcoin clássica, mascarando a complexidade adicional (gestão de stash, histórico de consignações, etc.) graças à RGBlib e à utilização de um servidor proxy.

Servidor proxy e experiência do utilizador

O servidor proxy introduzido acima merece ser detalhado, pois é a chave para uma experiência de utilizador sem problemas. Em vez de o remetente ter de transmitir manualmente as consignações para o destinatário, a transação RGB tem lugar em segundo plano através de um ficheiro :

Desta forma, a carteira comporta-se quase como uma carteira normal. O utilizador não tem conhecimento de todos os passos intermédios. É certo que o proxy atual não é encriptado nem autenticado (o que deixa dúvidas quanto à confidencialidade e integridade), mas estas melhorias são possíveis em versões posteriores. O conceito de proxy continua a ser extremamente útil para recriar a experiência "Eu envio um código QR, tu digitalizas para pagar".

Integração RGB na rede Lightning

Outro ponto-chave do trabalho da equipa da Bitfinex é tornar a Lightning Network compatível com os activos RGB. O objetivo é permitir canais Lightning em USDT (ou qualquer outro token) e beneficiar das mesmas vantagens que a bitcoin na Lightning (transacções quase instantâneas, encaminhamento, etc.). Em termos concretos, trata-se de criar um nó Lightning modificado para :

Esta solução, apelidada de "RGB Lightning Node", usa o LDK (Lightning Dev Kit) como base, e adiciona os mecanismos necessários para injetar tokens RGB nos canais. Os compromissos Lightning mantêm a estrutura clássica (saídas pontuáveis, timelock...) e, além disso, ancoram uma transição de estado RGB (via Opret ou Tapret). Para o usuário, isso abre o caminho para os canais Lightning em stablecoins ou em qualquer outro ativo emitido via RGB.

Potencial e impacto da DEX na Bitcoin

Uma vez que vários ativos são gerenciados via Lightning, torna-se possível imaginar uma troca atômica em um único caminho de roteamento Lightning, usando a mesma lógica de segredos e timelocks. Por exemplo, o utilizador A detém bitcoin num canal Lightning e o utilizador B detém USDT RGB noutro canal Lightning. Eles podem construir um caminho ligando seus dois canais e simultaneamente trocar BTC por USDT, sem a necessidade de confiança. Isto não é mais do que uma troca atómica que ocorre em vários saltos, tornando os participantes externos quase alheios ao facto de estarem a fazer uma troca e não apenas um encaminhamento. Esta abordagem oferece :

Podemos então imaginar um ecossistema onde os nós Lightning oferecem preços de swap (fornecendo liquidez). Cada nó, se o desejar, pode desempenhar o papel de market maker, comprando e vendendo vários activos no Lightning. Esta perspetiva de uma DEX layer-2 reforça a ideia de que não é necessário bifurcar ou utilizar blockchains de terceiros para obter trocas de activos descentralizadas.

O impacto na Bitcoin poderia ser positivo: A infraestrutura da Lightning (nós, canais e serviços) seria mais bem utilizada graças aos volumes gerados por estas stablecoins, derivados e outros tokens. Os comerciantes interessados em pagamentos em USDT no Lightning descobririam mecanicamente pagamentos em BTC no Lightning (geridos pela mesma pilha). A manutenção e o financiamento da infraestrutura da rede Lightning poderiam também beneficiar da multiplicação destes fluxos não BTC, o que beneficiaria indiretamente os utilizadores de Bitcoin.

Conclusão e recursos

A equipa da Bitfinex dedicada ao RGB ilustra, através do seu trabalho, a diversidade do que pode ser feito em cima do protocolo. Por um lado, temos a RGBlib, uma biblioteca que facilita a conceção de carteiras e aplicações. Por outro lado, temos a Iris Wallet, uma demonstração prática no Android de uma interface de utilizador final elegante. Finalmente, a integração do RGB com o Lightning mostra que os canais de stablecoin são possíveis e abre o caminho para um potencial DEX descentralizado no Lightning.

Esta abordagem continua a ser em grande parte experimental e continua a evoluir: a biblioteca RGBlib está a ser aperfeiçoada à medida que avançamos, a Iris Wallet está a receber melhorias regulares e o nó Lightning dedicado ainda não é um cliente Lightning convencional.

Para aqueles que desejam saber mais ou contribuir, estão disponíveis vários recursos, incluindo :

No próximo capítulo, veremos mais detalhadamente como lançar um nó de iluminação RGB.

RLN - Nó de iluminação RGB

Neste capítulo final, Frederico Tenga leva-o passo a passo através da configuração de um nó Lightning RGB num ambiente Regtest, e mostra-lhe como criar tokens RGB nele. Ao lançar dois nós separados, você também descobrirá como abrir um canal Lightning entre eles e trocar ativos RGB.

Este vídeo serve como um tutorial, semelhante ao que abordámos num capítulo anterior, mas desta vez centrado especificamente no Lightning!

O principal recurso para este vídeo é o repositório do Github [RGB Lightning Node] (https://github.com/RGB-Tools/rgb-lightning-node), que facilita o lançamento dessa configuração no Regtest.

Implantação de um nó do Lightning compatível com RGB

O processo retoma e põe em prática todos os conceitos abordados nos capítulos anteriores:

Apresentação do nó de iluminação rgb

O projeto rgb-lightning-node é um daemon Rust baseado em um fork rust-lightning (LDK) modificado para levar em conta a existência de assets RGB em um canal. Quando um canal é aberto, a presença de ativos pode ser especificada, e cada vez que o estado do canal é atualizado, uma transição RGB é criada, refletindo a distribuição do ativo nas saídas do Lightning. Isso permite :

O código ainda está em fase alfa: recomendamos a sua utilização apenas em regtest ou na testnet.

Instalação do nó

Para compilar e instalar o binário rgb-lightning-node, começamos por clonar o repositório e seus sub-módulos, depois executamos o comando :

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

A partir da raiz do projeto, execute o seguinte comando para compilar e instalar o binário :

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

No final deste comando, um executável rgb-lightning-node estará disponível no seu $CARGO_HOME/bin/. Certifique-se que este caminho está no seu $PATH para que você possa invocar o comando de qualquer diretório.

Requisitos de desempenho

Para funcionar, o daemon rgb-lightning-node requer a presença e configuração do :

Cada instância RLN precisará se comunicar com bitcoind para transmitir e monitorar suas transações on-chain. Autenticação (login/password) e URL (host/porta) terão de ser fornecidos ao daemon.

O daemon deve ser capaz de listar e explorar transacções na cadeia, em particular para encontrar o UTXO no qual um ativo foi ancorado. Terá de especificar o URL do seu servidor Electrum ou Esplora.

Como visto em capítulos anteriores, o servidor proxy é um componente (opcional, mas altamente recomendado) para simplificar a troca de consignações entre pares Lightning. Mais uma vez, um URL deve ser especificado.

Os IDs e URLs são introduzidos quando o daemon é desbloqueado através da API. Mais sobre isso mais tarde.

Lançamento do Regtest

Para uso simples, há um script regtest.sh que inicia automaticamente, via Docker, um conjunto de serviços: bitcoind, electrs (indexador), rgb-proxy-server.

RGB-Bitcoin

Isto permite-lhe lançar um ambiente local, isolado e pré-configurado. Cria e destrói contentores e diretórios de dados em cada reinicialização. Começaremos iniciando o arquivo :

./regtest.sh start

Este script irá :

RGB-Bitcoin

De seguida, vamos lançar vários nós RLN. Em shells separados, execute, por exemplo (para lançar 3 nós 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

Também pode executar comandos nos seus nós RLN a partir do seu browser:

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

Para que um nó possa abrir um canal, deve primeiro ter bitcoins num endereço gerado com o seguinte comando (para o nó n.º 1, por exemplo):

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

A resposta fornecer-lhe-á um endereço.

RGB-Bitcoin

No Regtest bitcoind, nós vamos minerar alguns bitcoins. Executar :

./regtest.sh mine 101
RGB-Bitcoin

Enviar os fundos para o endereço do nó gerado acima:

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

Em seguida, extrai um bloco para confirmar a transação:

./regtest.sh mine 1
RGB-Bitcoin

Lançamento da Testnet (sem Docker)

Se quiser testar um cenário mais realista, pode lançar 3 nós RLN na Testnet em vez de na Regtest, apontando para serviços públicos:

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

Por defeito, se não for encontrada nenhuma configuração, o daemon tentará utilizar o ficheiro :

Com o login :

Também é possível personalizar estes elementos através da API init/unlock.

Emissão de um token RGB

Para emitir um token, começaremos por criar UTXOs "coloríveis":

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

Pode, evidentemente, adaptar a encomenda. Para confirmar a transação, extraímos um :

./regtest.sh mine 1

Agora, podemos criar um ativo RGB. O comando dependerá do tipo de ativo que pretende criar e dos respectivos parâmetros. Aqui estou a criar um token NIA (Non Inflatable Asset) chamado "PBN" com um fornecimento de 1000 unidades. O parâmetro precision permite-lhe definir a divisibilidade das unidades.

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

A resposta inclui o ID do ativo recentemente criado. Não se esqueça de anotar este identificador. No meu caso, é :

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

Pode então transferi-lo para a cadeia ou alocá-lo num canal Lightning. É exatamente isso que vamos fazer na próxima secção.

Abrir um canal e transferir um ativo RGB

Você deve primeiro conectar seu nó a um par na rede Lightning usando o comando /connectpeer. No meu exemplo, eu controlo ambos os nós. Então, vou recuperar a chave pública do meu segundo nó do Lightning com este comando:

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

O comando devolve a chave pública do meu nó n.º 2:

031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94
RGB-Bitcoin

Em seguida, abriremos o canal especificando o ativo relevante (PBN). O comando /openchannel permite-lhe definir o tamanho do canal em satoshis e optar por incluir o ativo RGB. Depende do que se pretende criar, mas no meu caso, o 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

Saiba mais aqui:

RGB-Bitcoin

Para confirmar a transação, são extraídos 6 blocos:

./regtest.sh mine 6
RGB-Bitcoin

O canal Lightning está agora aberto e também contém 500 tokens PBN do lado do nó nº 1. Se o nó nº 2 desejar receber tokens PBN, deve gerar uma fatura. Veja como fazer isso:

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

Com :

Em resposta, obterá uma fatura RGB (como descrito nos capítulos anteriores):

lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj
RGB-Bitcoin

Vamos agora pagar esta fatura a partir do primeiro nó, que detém o dinheiro necessário com o token PBN:

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

O pagamento foi efectuado. Este facto pode ser verificado através da execução do comando :

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

Eis como implementar um nó Lightning modificado para transportar activos RGB. Esta demonstração é baseada em :

Graças a este processo :

O projeto continua na fase alfa. Por conseguinte, recomenda-se vivamente que se limite aos ambientes de teste (regtest, testnet).

As oportunidades abertas por esta compatibilidade LN-RGB são consideráveis: stablecoins na Lightning, DEX layer-2, transferência de tokens fungíveis ou NFTs a um custo muito baixo... Os capítulos precedentes apresentaram a arquitetura concetual e a lógica de validação. Agora tem uma visão prática de como colocar um nó deste tipo em funcionamento, para os seus futuros desenvolvimentos ou testes.

Seção final

Comentários e classificações

true

Conclusão

true