Esse artigo foi escrito por: Ben Guidarelli e traduzido por Dimitris Calixto, artigo original disponível aqui
Olá Desenvolvedor
Se você já escreveu e implantou um Contrato Inteligente para Algorand usando PyTeal antes de hoje, você provavelmente mastigou muito vidro para fazer isso, muito bem feito!
Tenha coragem; a equipe Algorand tem trabalhado duro para melhorar a experiência de desenvolvimento.
Antes de mergulharmos nas melhorias, vamos rever algumas coisas comuns com as quais as pessoas lutam enquanto desenvolvem.
Organização do Código
Quando você começa a escrever um contrato, como você estrutura a lógica do programa? Como você lida com as entradas e saídas do contrato?
Um padrão muito comum para escrever o programa de aprovação em PyTeal é algo parecido com:
def approval():
#...
return Cond(
# Inferir que isto é criado
[Txn.application_id() == Int(0), do_create_method()],
# Verificação manual completa
[Txn.on_complete() == OnComplete.UpdateApplication, do_update()],
# Use alguma const que você tem que comunicar de alguma forma ao _caller_
# para encaminhar para o método certo, depois descobre como analisar o resto
# dos argumentos do app
[Txn.application_args[0] == "do_the_thing", do_the_thing()],
#...
)
# ...
approval_teal = compileTeal(approval(), mode=Mode.Application, version=6)
Isto funciona, mas é difícil de entender para um recém-chegado.
Interagindo com a Aplicação
Para implantar um aplicativo on-chain, você submete uma transação de criação de aplicativo. Nesta transação, você especifica os programas TEAL compilados, o esquema de aplicação ("Quantos uints globais eu preciso novamente?"), e páginas extras do programa.
A chamada de um aplicativo on-chain envolve a criação de transações de chamada de aplicativo com o roteamento apropriado e argumentos de dados se não usar a ABI.
Mesmo quando se usa a ABI, os métodos de chamada envolvem a importação da descrição do contrato JSON e a construção de uma AtomicTransactionComposer, passando argumentos como uma lista sem contexto sobre o que eles devem ser.
Gerenciando o estado
O gerenciamento do esquema de estado da aplicação é muitas vezes feito manualmente com constantes para as chaves e lembrando-se de qual deve ser o tipo associado.
A criação da aplicação exige que você saiba o número e o tipo de cada valor de estado que não tem uma maneira fácil de obter automaticamente.
Depurando
A depuração pode ser um pesadelo ao tentar descobrir uma mensagem de erro como assert failed: pc=XXX
Testando
Os contratos de teste podem ser difíceis e pouca orientação é fornecida. Muitas vezes é necessário reconstruir grande parte da infra-estrutura do frontend para testar diferentes entradas/saídas.
Os devs fizeram algo
Agora, vamos ver como as coisas mudaram.
ABI
A ABI fornece padrões para tipos de codificação, descrevendo métodos e chamadas de métodos de roteamento interno para a lógica apropriada.
Com a ABI, temos agora uma maneira padrão de organizar o código e interagir com a aplicação.
Mais detalhes sobre a ABI estão disponíveis aqui
Compositor de Transações Atômicas
Usando o compositor de transações atômicas e as especificações da ABI para seu contrato, você pode facilmente compor transações de grupo atômico e ter os argumentos codificados e os valores de retorno decodificados para você!
Pyteal ABI
PyTeal agora trata da codificação/decodificação de tipos de dados em um contrato. A classe PyTeal Router
oferece até mesmo uma maneira de lidar com a lógica de roteamento de métodos, passando os tipos decodificados diretamente para um método, e fornece as especificações do contrato ABI.
Por exemplo, se você quiser um método que acrescenta 1 a um uint8, você pode escrevê-lo assim:
@router.method
def increment_my_number(input: abi.Uint8, *, output: abi.Uint8):
return output.set(input.get() + Int(1))
Muito. Mais agradável.
Para mais informações, veja o post do blog aqui
Para documentação detalhada sobre a PyTeal ABI veja a documentação aqui
Mapas de origem
O mapeamento de um pc
retornado de uma mensagem de erro ficou muito mais fácil. Agora você pode compilar TEAL com a flag sourcemap
ativada. O mapa resultante volta de acordo com esta especificação e pode ser decodificado com qualquer um dos SDKs usando o novo objeto SourceMap
.
Isto significa que você pode associar um pc diretamente à linha TEAL de origem, com todos os nomes familiares e formatação que você está acostumado a ver.
Olá Beaker
Hoje estamos compartilhando o Beaker, um framework de desenvolvimento de contratos inteligentes destinado a melhorar ainda mais a experiência de desenvolvimento.
O Beaker aproveita as melhorias citadas acima, nos permitindo fornecer muito mais estruturas às aplicações.
No entanto, ainda é experimental.
Toda a documentação está aqui.
Vamos ver como Beaker resolve nossos problemas.
Organização do código
Beaker fornece uma maneira padrão de organizar o código usando uma classe para encapsular a funcionalidade.
from beaker import Application, external
class MyApp(Application):
@external
def add(self, a: abi.Uint64, b: abi.Uint64, *, output: abi.Uint64):
return output.set(a.get() + b.get())
Esta é uma aplicação completa! Tem um programa de aprovação
, um limpar programa
, um estado
implicitamente vazio. Os métodos definidos são fornecidos em um contrato
da ABI para exportar para outros clientes.
O @external decorator do método expõe nosso método definido aos chamadores e fornece roteamento com base em sua assinatura do método
. A assinatura do método resultante deste método é add(uint64,uint64)uint64
.
O método add
é um método PyTeal ABI (em sua maioria) válido. A exceção que o torna mais válido aqui, é que o Beaker permite que você passe self
, permitindo referências a variáveis de instância.
Há muito mais que você pode fazer, incluindo; controle de acesso, mudando quais tipos OnComplete
podem ser usados para chamá-lo, ou marcando-o como um método read-only
.
Para mais informações, consulte a documentação do Decorator
Interagindo com a aplicação
Beaker fornece um ApplicationClient
para lidar com necessidades comuns como a criação/opção de métodos de chamada.
Ele usa sua definição de Application
para fornecer o contexto como o esquema ou os argumentos necessários para os métodos que estão sendo chamados.
from beaker import sandbox, client
# obtém o primeiro acct no sandbox
acct = sandbox.get_accts().pop()
# cria um cliente de aplicação
app_client = client.ApplicationClient(
client=sandbox.get_algod_client(),
app=MyApp(),
signer=acct.signer
)
# implanta o aplicativo on-chain
app_client.create()
# chama o método
result = app_client.call(MyApp.add, a=32, b=10)
print(result.return_value) # 42
# agora vá lá fora e toque em um pouco de grama porque você está pronto
Para mais informações, veja a documentação do ApplicationClient
Gerenciando Estado
O Beaker permite declarar valores de estado tipados como variáveis de classe
from beaker import Application, ApplicationStateValue, external
class CounterApp(Application):
counter = ApplicationStateValue(TealType.uint64)
@external
def incr_counter(self, incr_amt: abi.Uint64):
self.counter.set(self.counter + incr_amt.get())
Podemos até inspecionar nossa aplicação para ver quais são os requisitos de seu esquema!
app = CounterApp()
print(app.app_state.schema())
Para mais informações, veja a documentação de Estado
Depurando
Beaker melhora a mensagem de erro pc=xxx
usando o ponto final do mapa de origem durante a compilação e mapeando o pc de volta para o teal de origem. O LogicException
resultante permite que você veja o número exato da linha Teal da fonte com todos os nomes úteis de sub-rotinas e quaisquer comentários no teal da fonte.
Abaixo está o resultado de uma simples impressão de uma LogicException
me dizendo exatamente onde meu programa falhou. Mais importante ainda, ele fornece o contexto da fonte TEAL mostrando-me por que ele falhou.
Txn WWVF5P2BXRNQDFFSGAGMCXJNDMZ224RJUGSMVPJVTBCVHEZMOMNA had error 'assert failed pc=883' at PC 883 and Source Line 579:
store 50
store 49
store 48
store 47
// correct asset a
load 50
txnas Assets
bytec_0 // "a"
app_global_get
==
assert <-- Error
// correct asset b
load 51
txnas Assets
bytec_1 // "b"
app_global_get
==
assert
// correct pool token
load 49
Também estamos trabalhando para fazer com que este mapeamento volte à fonte PyTeal com este problema
Testando
Inicialmente o Beaker fornece auxiliares para:
Recuperar e comparar saldos de contas. Útil para garantir que as quantidades corretas de algos ou Tokens foram transferidas de ou para as contas relevantes.
Funcionalidade de teste de unidade passando por entradas e comparando com as saídas esperadas. Útil para testar comportamentos pequenos e autocontidos.
Para mais informações, consulte a documentação de teste.
Mais
Há muito mais que não foi abordado aqui e ainda há muito a ser feito. O Beaker precisa de sua ajuda para melhorar!
Veja a documentação https://beaker.algo.xyz
O código aqui https://github.com/algorand-devrel/beaker. Por favor, sinta-se à vontade para abrir uma issue ou PRs!
E para qualquer pergunta, marque @barnji no canal #beaker no discord do Algorand
Top comments (0)