[RECAPTULAÇAO]
Fig. 2: TIPOS BASICOS E PRIMITIVOS DE LEDGER
executado e a transação só é considerada válida se a execução do script retornar verdadeiro. UMA
o script de política de forja é executado em um contexto que fornece acesso aos principais componentes do
transação de forja, os UTXOs que ela gasta e o ID da política. A passagem do contexto fornece uma
peça crucial do quebra-cabeça em relação à auto-identificação: inclui o próprio PolicyID do script, que
evita o problema de tentar incluir o hash de um script dentro de si.
Intervalos de validade.
O campo de intervalo de validade de uma transação contém um intervalo de tiques (monotonicamente
unidades crescentes de “tempo”, de [5]). O intervalo de validade afirma que a transação deve apenas
ser validado se o tique atual estiver dentro do intervalo. O intervalo de validade, em vez do real
valor atual da escala da cadeia, deve ser usado para validação do script. Em uma transação válida de outra forma,
UTXOma: UTXO com suporte para vários ativos
INICIO PT2
unspentTxOutputs: Tx → Definir [OutputRef]
unspentTxOutputs (t) = {(txId (t), 1),. . . , (txId (id), | t.outputs |)}
unspentOutputs: Ledger → Definir [OutputRef]
unspentOutputs () = {}
unspentOutputs (t :: l) = (unspentOutputs (l) \ t.inputs) ∪ unspentTxOutputs (t)
getSpentOutput: Entrada × Razão → Saída
getSpentOutput (i, l) = lookupTx (l, i.outputRef .id) .outputs [i.outputRef .index]
Fig. 3: FUNÇOES AUXILIARES DE VALIDAÇAO
Passar o tique atual para o avaliador pode resultar em resultados de validação de script diferentes em
diferentes ticks, o que seria problemático.
Orações de linguagem. Em nossa escolha do conjunto de predicados p1, …, pn para incluir na definição da linguagem de script, aderimos à seguinte heurística: só admitimos predicados com quantificação
sobre estruturas finitas passadas para o avaliador nos dados específicos da transação, ou seja, conjuntos, mapas e
listas. Os cálculos que permitimos nos próprios predicados são funções computáveis bem conhecidas,
como hash, verificação de assinatura, operações aritméticas, comparações, etc.
A gama de políticas expressas no modelo que propomos aqui é totalmente determinada pela
coleção de predicados, reunidos em um único script por conectivos lógicos &&, || e Not. Apesar de
sendo composta apenas de predicados e conectivos embutidos em código, as políticas resultantes podem ser bastante
expressivo, como demonstraremos na próxima seção de inscrições. Ao especificar forjamento
predicados, usamos tx. notação para acessar os campos de uma transação.
3.2 VALIDADE DA TRANSAÇÃO
A Figura 4 define o que significa para uma transação t ser válida para um razão válido L durante o tick
currentTick, usando algumas funções auxiliares da Figura 3. Um razão l é válido se l estiver vazio ou
l tem a forma t :: l0 com l0 válido e t válido para l0.
As regras seguem a estrutura usual para um razão UTXO, com uma série de modificações e
aditivos. A nova regra de falsificação (Regra 8) implementa o suporte para políticas de falsificação, exigindo
que a política de falsificação da moeda está incluída na transação - junto com a Regra 9, que garante
que eles são realmente executados! Os argumentos aos quais um script é aplicado são aqueles discutidos anteriormente.
Quando os scripts de política de forja são executados, eles são fornecidos com os dados de transação apropriados,
o que lhes permite impor condições. Em particular, eles podem inspecionar o campo de forja na
transação, e assim um script de política de falsificação pode identificar quanto de sua própria moeda foi falsificada,
o que normalmente é uma consideração importante para permitir a transação.
Também precisamos ter cuidado para garantir que as transações em nosso novo sistema preservem o valor corretamente.
Existem dois aspectos a considerar:
- Generalizamos o tipo de valor para Quantidades. No entanto, uma vez que Quantities é um monóide (consulte a Seção 3), a Regra 4 é (quase) idêntica à do modelo UTXO original, simplesmente com um
monóide diferente. Concretamente, isso equivale a preservar as quantidades de cada um dos indivíduos
classes de token na transação. - Permitimos a falsificação de novos tokens, incluindo o campo forjar no saldo na Regra.
O tique atual está dentro do intervalo de validade
currentTick ∈ t.validityInterval
2. Todas as saídas têm valores não negativos
Para todas as saídas off, o.value ≥ 0
3. Todas as entradas referem-se a saídas não gastas
{i.outputRef: i ∈ t.inputs} ⊆ unspentOutputs (l).
4. O valor é preservado
t.forge + X
i∈t.inputs
getSpentOutput (i, l) =
X
o∈t.outputs
o.value
5. Nenhuma saída é gasta o dobro
Se i1, i ∈ t.inputs e i1.outputRef = i.outputRef então i1 = i.
6. Todas as entradas são validadas
Para todos os i ∈ t.inputs, Ji.validator K (scriptAddr (i.validator), t, {getSpentOutput (i, l) | i ∈ t.inputs}) = verdadeiro
7. Os scripts do validador correspondem aos endereços de saída
Para todos os i ∈ t.inputs, scriptAddr (i.validator) = getSpentOutput (i, l) .addr
- FORJAMENTO
Uma transação com um campo forja diferente de zero só é válida se:
(a) o razão l está vazio (isto é, se for a transação inicial).
(b) para cada chave h ∈ supp (t.forge), existe s ∈ t.scripts com h = scriptAddr (s).
9. Todos os scripts são validados
Para todos os s ∈ t.scripts, JsK (scriptAddr (s), t, {getSpentOutput (i, l) | i ∈ t.inputs}) = verdadeiro
Fig. 4: Validade de uma transação t em um razão l
4 UMA LINGUAGEM DE POLÍTICA DE FORJA SEM ESTADO
A linguagem específica do domínio para forjar políticas atinge um equilíbrio entre expressividade e
simplicidade. Em particular, é sem estado e de complexidade computacional limitada. No entanto,
é suficiente para suportar os aplicativos descritos na Seção 5.
Nomes de tokens semânticos significativos. O ID da política está associado a um script de política (é o
hash), portanto, tem um significado semântico que é identificado com o do script. Nas cláusulas de
nossa linguagem, damos significado semântico aos nomes dos tokens também. Isso nos permite fazer
alguns julgamentos sobre eles de forma programática, além de confirmar que a preservação de
o valor é válido, ou quais são fungíveis entre si. Por exemplo, o construtor FreshTokens
JJustMSig(msig)K(h, tx, utxo) = checkMultiSig(msig, tx)
JSpendsOutput(o)K(h, tx, utxo) = o ∈ { i.outputRef : i ∈ tx.inputs }
JTickAfter(tick1)K(h, tx, utxo) = tick1 ≤ min(tx.validityInterval)
JForges(tkns)K(h, tx, utxo) = (h 7→ tkns ∈ tx.forge) && (h 7→ tkns ≥ 0)
JBurns(tkns)K(h, tx, utxo) = (h 7→ tkns ∈ tx.forge) && (h 7→ tkns ≤ 0)
JFreshTokens
K(h, tx, utxo) =
∀ pid 7→ tkns
∈ tx.forge, pid == h ⇒
∀ t 7→ q ∈ tkns,
t == hash(indexof(t, tkns), tx.inputs) && q == 1
JAssetToAddress(addr)
K(h, tx, utxo) =
∀ pid 7→ tkns ∈ utxo.balance, pid == h
⇒
addr == _ ⇒ (h, pid 7→ tkns) ∈ utxo
∧ addr 6= _ ⇒ (addr, pid 7→ tkns) ∈ utxo
JDoForgeK(h, tx, utxo) = h ∈ supp(tx.forge)
JSignedByPIDToken
K(h, tx, utxo) =
∀ pid 7→ tkns ∈ utxo.balance, pid == h ⇒
∀ s ∈ tx.sigs, ∃ t ∈ supp(tkns),
isSignedBy(tx, s, t)
JSpendsCur(pid)
K(h, tx, utxo) =
pid == _ ⇒
h ∈ supp(utxo.balance)
∧ pid 6= _ ⇒ pid ∈ supp(utxo.balance)
Fig. 5: LINGUAGEM DE POLÍTICA DE FALSIFICAÇAO
nos dá uma maneira de gerar nomes de token programaticamente que, por construção, significa que esses
os tokens são exclusivos, sem nunca verificar o estado do razão global.
Forjar scripts de política como scripts de bloqueio de saída. Tal como acontece com a moeda no mundo não digital, é
um problema mais difícil de controlar a transferência de ativos, uma vez que eles entraram em circulação (ver também
Seção 7). Podemos, no entanto, especificar diretamente na política de falsificação que os ativos sendo falsificados
deve ser bloqueado por um script de saída de nossa escolha. Além disso, uma vez que os endereços de saída e
as políticas são hashes de scripts, podemos usar o ID da política do ativo e o endereço de forma intercambiável.
A cláusula AssetToAddress é usada para essa finalidade.
Orações de linguagem. As várias cláusulas do validador e linguagem da política de falsificação são conforme descrito
abaixo, com sua semântica formal como na Figura 5. Nesta figura, usamos a notação x 7 → y para
representam um único par de valores-chave de um mapa finito. Lembre-se da Regra 9 que os argumentos foram passados para
a função de validação JsK h são: o hash do script de forjamento (ou bloqueio de saída) sendo validado,
a transação tx sendo validada, e as saídas do razão que a transação
tx está gastando
(denotamos esses utxo aqui).
-
JustMSig (msig) verifica se as assinaturas m-out-of-n exigidas por s estão no conjunto de assinaturas
fornecido pela transação. Não fornecemos os detalhes do avaliador de script de múltiplas assinaturas, pois este
é um conceito comum e assume que existe um procedimento checkMultiSig. -
SpendsOutput (o) verifica se a transação gasta a saída referenciada por o no UTXO.
-
TickAfter (tick1) verifica se o intervalo de validade da transação atual começa após o tempo
tick1. -
Forges (tkns) verifica se a transação forja exatamente tkns do ativo com o ID da política
que está sendo validado. -
Burns (tkns) verifica se a transação queima exatamente tkns do ativo com o ID da política
que está sendo validado. -
FreshTokens verifica se todos os tokens do ativo que está sendo falsificado não são fungíveis.
Este script deve verificar se os nomes dos tokens neste pacote de tokens são gerados por
hashing de alguns dados exclusivos. Esses dados devem ser exclusivos da própria transação e do
token dentro do ativo que está sendo forjado. Em particular, podemos hash um par de
- alguma saída no UTXO que a transação consome, e
- o índice do nome do token no (a representação de lista do) mapa de tokens sendo forjados
(de acordo com a política específica, por esta transação). Denotamos a função que obtém o índice
de uma chave em um mapa de valor-chave por indexof.
- AssetToAddress (addr) verifica se todos os tokens associados ao ID da política são iguais
para o hash do script que está sendo executado são enviados para um UTXO com o endereço addr. Dentro do estojo
que nenhum valor addr é fornecido (representado por), usamos o valor addr passado para o avaliador
como o hash da política do ativo que está sendo falsificado. - DoForge verifica se esta transação forja tokens no pacote controlado pelo ID da política
que é passado para o avaliador de script FPS (aqui, novamente, fazemos uso da passagem separada de
o script FPS e o ID da política). - SignedByPIDToken (pid) verifica o hash de cada chave que assinou a transação.
- SpendsCur (pid) verifica se a transação está gastando ativos no pacote de tokens com política
ID pid (que é especificado como parte do construtor e pode ser diferente do ID da política
passado para o avaliador).
5 APPS
UTXOma é capaz de oferecer suporte a um grande número de casos de uso padrão para livros de vários ativos, bem como
alguns novos. Nesta seção, fornecemos uma seleção de exemplos. Existem alguns temas comuns:
(1) Tokens como recursos podem ser usados para reificar muitas coisas não óbvias, o que os torna de primeira classe
itens negociáveis; (2) tokens baratos nos permitem resolver muitos pequenos problemas com mais tokens; e (3)
o poder da linguagem de script afeta quais exemplos podem ser implementados.
5.1 EMISSAO DE TOKEN UNICO SIMPLES
Para criar um SimpleCoin de moeda simples com um suprimento fixo de s = 1000 tokens SimpleCoins, nós
pode tentar usar o script de política simples Forges (s) com uma únic
Em outras palavras, precisamos garantir que só possa haver uma única transação no razão
que forja o SimpleCoin com sucesso. Podemos conseguir isso exigindo que a transação de falsificação
consome um UTXO específico. Como os UTXOs têm a garantia de ser (1) exclusivo e (2) ser gasto apenas uma vez,
temos a garantia de que a política de falsificação só pode ser usada uma vez para falsificar tokens. Podemos usar
o script:
simple_policy (o, v) = SpendsOutput (o) && Forges (v)
onde o é uma saída que criamos especificamente para este propósito em uma transação de configuração anterior,
e v = s.
5.2 REFLEXOA DE ATIVOS FORA DO LIVRO
Muitos tokens são usados para representar (ser lastreados por) ativos fora do razão no razão. Um importante
exemplo disso são os stablecoins. Outros exemplos dignos de nota de tais ativos incluem videogame
tokens, bem como tokens de serviço (que representam as obrigações do provedor de serviço).
Um projeto típico para tal sistema é que uma parte confiável (o “emissor”) é responsável por
criação e destruição dos tokens de ativos no razão. O emissor é confiável para manter um dos
fazer backup de ativos fora do livro-razão para cada token que existe no livro-razão, portanto, a única função que o
a política pode jogar é verificar se a falsificação do token é assinada pelo emissor confiável. Isso pode
ser implementado com uma política de falsificação que impõe um esquema de múltiplas assinaturas m-out-of-n, e não
cláusulas adicionais:
trust_issuer (msig) = JustMSig (msig)
5.3 VESTING
Um desejo comum é liberar um estoque de algum ativo em alguma programação. Os exemplos incluem aquisição
esquemas de ações e lançamentos em etapas de tokens recém-cunhados. Isso parece complicado em nosso simples
modelo: como a política de falsificação deve saber quais tranches já foram liberadas
sem algum tipo de estado global que os rastreia? No entanto, este é um problema que podemos resolver
com mais tokens. Começamos a construir essa política seguindo o esquema de emissor único, mas precisamos
para expressar mais.
Dada uma saída específica o, e duas tranches de tokens tr1 e tr2 que devem ser liberados
após tick1 e tick2, podemos escrever uma política de falsificação como:
vesting = SpendsOutput (o) && Forges ({“tr1” 7 → 1, “tr2” 7 → 1})
|| TickAfter (tick1) && Forges (tr1bundle) && Burns ({“tr1” 7 → 1})
|| TickAfter (tick2) && Forges (tr2bundle) && Burns ({“tr2” 7 → 1})
Esta disjunção tem três cláusulas:
- Uma vez, você pode forjar dois tokens exclusivos, tranche1 e tranche2.
- Se você gastar e queimar tr1 e for depois de tick1, você pode forjar todos os tokens em tr1bundle.
- Se você gastar e queimar tr2 e for depois de tick2, você pode forjar todos os tokens em tr2bundle.
Ao reificar as tranches como tokens, garantimos que sejam exclusivas e possam ser usadas exatamente uma vez.
Como bônus, os tokens da tranche são, eles próprios, negociáveis.
Rastreador de inventário: tokens como estado
Podemos usar tokens para transportar alguns dados para nós ou para representar o estado. Um exemplo simples é o estoque
rastreamento, onde a lista de inventário só pode ser modificada por um conjunto de partes confiáveis. Rastrear
estoque na cadeia, queremos ter uma única saída contendo todos os tokens de um "estoque
rastreamento ”ativo. Se as chaves confiáveis são representadas pelo msig com várias assinaturas, o inventário
tokens de rastreador sempre devem ser mantidos em uma entrada UTXO com a seguinte saída:
(hash (msig), {hash (msig) 7 → {chapéus 7 → 3, espadas 7 → 1, corujas 7 → 2}})
O rastreador de estoque é um exemplo de ativo que deve ser controlado indefinidamente por um
script específico (que garante que apenas usuários autorizados possam atualizar o inventário), e aplicamos isso
condição no próprio script de forjamento:
inventário_tracker (msig) = JustMSig (msig) && AssetToAddress (_)
Nesse caso, o rastreador de inventário (msig) é o script de forjamento e o script de bloqueio de saída.
O valor em branco fornecido como argumento significa que o ID da política (e também o endereço) são ambos
assumido como sendo o hash do script do rastreador de inventário (msig). Definido desta forma, nosso script é executado
no momento da forja inicial e sempre que o inventário for atualizado. Cada vez, ele só valida se todos os
tokens de rastreamento de estoque nas saídas da transação são sempre bloqueados por este script de saída exato.
5.5 TOKENS NAO FUNGIVES
Um caso comum é desejar um grupo de ativos em que todos os tokens não sejam fungíveis. Uma maneira simples de
fazer isso é simplesmente ter uma política de ativos diferente para cada token, cada um dos quais só pode ser executado
uma vez, exigindo que um UTXO específico seja gasto. No entanto, isso é desajeitado e normalmente queremos
ter um conjunto de tokens não fungíveis, todos controlados pela mesma política. Podemos fazer isso com o
Cláusula FreshTokens. Se a política sempre afirma que os nomes dos tokens são hashes de dados exclusivos para
a transação e o token, então os tokens sempre serão distintos.
5.6 PERMISSAO REVOGAVEL
Um exemplo em que empregamos essa natureza de duplo propósito de scripts é a permissão revogável. Vamos
expressar permissões como um token de credencial.
A lista de usuários (como uma lista de hashes de suas chaves públicas) em um token de credencial é composta
por alguma autoridade central de acreditação. Os usuários geralmente confiam que esta autoridade verificou alguns
dados da vida real, por exemplo que uma autoridade de acreditação KYC verificou fora da cadeia se aqueles que ela acredita
atendem a alguns padrões. Observe aqui que simplificamos significativamente a função das credenciais KYC para
brevidade do nosso exemplo.
Por exemplo, suponha que as trocas só estão dispostas a transferir fundos para aqueles que comprovaram
que são credenciados pela KYC.
Neste caso, a autoridade de acreditação pode emitir um ativo que se pareça com
{KYC_accr_authority 7 → {accr_key_1 7 → 1, accr_key_2 7 → 1, accr_key_3 7 → 1}}
7 KYC significa “conheça seu cliente”, que é o processo de verificar a identidade de um cliente antes
permitindo que o cliente use o serviço de uma empresa.
onde os nomes dos tokens são as chaves públicas dos usuários credenciados. Gostaríamos de ter certeza de que
- apenas a autoridade tem o poder de forjar ou queimar tokens controlados por esta política, e
pode fazer isso a qualquer momento, - todos os usuários com chaves listadas são capazes de gastar este ativo como prova na cadeia de que são KYC�acreditados, e
- assim que um usuário puder provar que possui as credenciais, ele deve ter permissão para receber fundos
de uma troca.
Conseguimos isso com um script da seguinte forma:
credential_token (msig) = JustMSig (msig) && DoForge
|| AssetToAddress () && Not DoForge && SignedByPIDToken ()
Aqui, as falsificações (ou seja, atualizações para tokens de credencial) só podem ser feitas pela autoridade msig, mas
cada usuário cujo hash de chave está incluído nos nomes de token pode gastar com este script, desde que
retorne o ativo para o mesmo script. Fazer um script que só permita gastar dele se o usuário
fazendo isso está na lista de hashes de chave no token de credencial feito pelo msig, escrevemos
must_be_on_list (msig) = SpendsCur (credential_token (msig))
Em nossa definição de token de credencial, usamos todas as estratégias que discutimos acima
para estender a expressividade de uma linguagem FPS. Ainda não estamos usando o modelo UTXO em sua totalidade
potencial, já que estamos apenas usando o UTXO para armazenar algumas informações que não podem ser negociadas. Contudo,
poderíamos considerar a atualização de nossa política de uso de token de credencial para associar o gasto com outra
ação, como adicionar uma cláusula pay-per-use. Essa mudança realmente depende do modelo UTXO.
6 TRABALHOS RELACIONADOS
Ethereum. Os padrões de token ERC da Ethereum [15,8] são uma das mais conhecidas implementações de múltiplos ativos. Eles são uma implementação não nativa e, portanto, vêm com um conjunto de desvantagens, como
como ter que implementar a funcionalidade do razão (como transferências de ativos) usando contratos inteligentes, em vez
do que usar o razão subjacente.
Aumentando o livro razão Ethereum com funcionalidade semelhante à do modelo que apresentamos
aqui provavelmente seria possível. Além disso, o acesso ao estado do contrato global tornaria mais fácil
definir políticas forjadas que se preocupam com informações globais, como o fornecimento total de um ativo.
Waves. Waves [16] é um livro razão de múltiplos ativos baseado em contas, suportando sua própria linguagem de contrato inteligente. No Waves, as contas e os próprios ativos podem ser associados a contratos. Em ambos
casos, a associação é feita adicionando o script associado ao estado da conta (ou o estado de
a conta que contém o ativo). Um script associado a um ativo impõe condições sobre o uso
deste ativo, incluindo restrições de cunhagem e queima, bem como restrições de transferência.
Estelar. Stellar [13] é um sistema multi-ativo nativo baseado em conta voltado para rastrear a propriedade de itens do mundo real por meio de tokens blockchain associados. Stellar é otimizado para permitir um emissor de token
para manter um nível de controle sobre o uso de seu token, mesmo quando ele muda de mãos. O Blockchain Stellar
também apresenta uma lista de troca distribuída, que é usada para facilitar a correspondência (por preço)
trocas entre tokens diferentes.