O ano passado foi um ótimo período de expansão para o software Ledger Live. Passamos de 3 para 9 famílias de moedas suportadas e enviamos recursos como Secure Swap for Staking (delegação Tezos, votos Tron, validação Cosmos, Algorand staking e, muito recentemente, Polkadot)…
À medida que a lista de novos recursos e moedas suportadas na Ledger Live crescia, percebemos rapidamente que nosso fluxo de teste não seria dimensionado. Anteriormente, nossa equipe de controle de qualidade precisava testar todos os recursos diferentes para cada moeda manualmente. Com ambos aumentando em número, o processo estava se tornando mais longo e tedioso. Foi quando decidimos resolver esse problema com uma nova abordagem: automatizar o teste de ponta a ponta para cada família de moedas junto com seus respectivos recursos!
Vamos retroceder um pouco e dar uma olhada no contexto aqui. Estamos falando de testes de ponta a ponta em diferentes blockchains. Blockchains são imutáveis por design. Depois que uma operação é transmitida, não há como voltar a um estado anterior do blockchain. Isso significa que não poderíamos reproduzir nenhum caso de teste ou cenário.
Em certo momento, chegamos a cogitar as blockchains testnet, mas elas ainda não podem produzir o mesmo resultado que uma mainnet.
Então, com o contexto e as condições da vida real em mente, decidimos criar o Ledger Live Bot.
O que é o Ledger Live Bot?
O Ledger Live Bot é um framework que construímos internamente para permitir a automação de testes de transação em todas as moedas e recursos suportados pela Ledger Live, em uma abordagem mais completa possível.
A Ledger Live Bot testa implicitamente muitas coisas com um arquivo de especificação muito simples.
=> INSERIR SCREENSHOT EM UM RELATÓRIO DE TESTE DE COMMIT
Filosofia
Quando construímos o bot, definimos alguns princípios que nos ajudariam a torná-lo a ferramenta de que precisávamos.
Sem Estado : Meu estado é a blockchain.
Sem configuração : Eu só preciso de uma pasta seed e coinapps.
Autônomo : Eu simplesmente restauro minhas contas usando as seeds e continuo à partir dali.
Generativo : envio fundos para contas irmãs, criando novas contas e fazendo a rotação dos fundos. Meus únicos custos são taxas da rede.
Orientado a Dados : Meu mecanismo é simples e faço ações com base em especificações de dados que impulsionam meus recursos.
De ponta a ponta: Eu confio na "stack Ledger" inteira:
- live-common: a biblioteca por trás da lógica da Ledger Live (contas derivadas, lógica de transação…) (código aberto)
- Speculos: o emulador de dispositivos Ledger (código aberto)
- coinapps: uma pasta contendo os aplicativos necessários para Speculos (código fechado)
Realista : Estou muito próximo do fluxo usado pelos usuários da Ledger Live e do que eles fazem com seus dispositivos. Eu posso até pressionar os botões dos dispositivos.
Completude : tecnicamente posso fazer qualquer coisa que um usuário possa fazer na Ledger Live com sua conta (o envio, mas também qualquer outro recurso da Leger Live, como delegações, congelar, apostar…), mas faço isso mais rápido 🤖
Automatizado : posso rodar no Github Actions (runners) e comentar nos Pull Requests e Commits.
Como automatizar o teste de dispositivos com Speculos, o emulador de carteira de hardware Ledger
Um dos nossos principais gargalos é obviamente o uso de dispositivos físicos reais para passar por todos os diferentes fluxos e transações.
Para isso, contamos com uma tecnologia desenvolvida na Ledger e lançada em 2019: Speculos.
Agora equipado com uma versão "software" do nosso dispositivo que pode ser pilotado por uma API, estávamos prontos para começar a trabalhar no bot.
Aqui estão alguns exemplos de como construímos nossas interações com o Speculos.
A primeira iteração parecia algo assim:
functiondeviceActionAcceptBitcoin({
// transport é um objeto que representa a conexão
// com um dispositivo
transport,
// eventos são recebidos do Specculos e nos dão o que é
// atualmente exibido no dispositivo, permitindo-nos
// reagir aos diferentes estados
event,
}:{
transport:Transport\<\*\>&{button:(string)=>void},
event:{type:string,text:string},
}){
// É aqui que reagimos ao que está na tela
if(event.text.startsWith("Accept")){
// Usando a API do Speculos para acionar ações de botão,
// como um usuário real! Aqui nós pressionamos os dois botões
transport.button("LRlr");
}elseif(
// O mesmo aqui, reagimos a certas palavras-chave exibidas no
// dispositivo
event.text.startsWith("Review")||
event.text.startsWith("Amount")||
event.text.startsWith("Address")||
event.text.startsWith("Confirm")||
event.text.startsWith("Fees")
){
// E acionamos o botão direito
transport.button("Rr");
}
}
Mesmo sendo funcional, nós o adaptamos para que também pudéssemos fazer afirmações sobre o que o dispositivo exibe.
constacceptTransaction:DeviceAction\<Transaction,\*\>=deviceActionFlow({
// Matriz de `steps` que são basicamente as
// diferentes telas exibidas no dispositivo
steps:[
// Aqui temos um formato mais conciso e unificado
// para todos os passos
{
// Texto exibido no dispositivo
title: "Amount",
// Qual botão apertar
button: "Rr",
// E aqui está a parte interessante onde
// podemos fazer asserção com os dados fornecidos
// pelo dispositivo E os dados da conta/status
// vinculado às transações
expectedValue:({account,status})=>...,
},
{
title: "Fees",
button: "Rr",
expectedValue:({account,status})=>...,
},
{
title: "Address",
button: "Rr",
expectedValue:...,
},
{
title: "Review",
button: "Rr",
},
{
title: "Confirm",
button: "Rr",
},
{
title: "Accept",
button: "LRlr",
},
],
});
A moeda spec , ou a espinha dorsal de nossos testes
Para tornar nosso botinteligente em seu processo de tomada de decisão, contamos com arquivos de specs. Uma moeda spec define todas as mutações possíveis no blockchain (suportado pela Ledger Live), bem como a expectativa após a transmissão da mutação. É aqui que as coisas ficam divertidas: como dissemos anteriormente, não há como "reproduzir" cenários na blockchain. Para compensar essas limitações, criamos uma nova maneira, focando no estado da conta, antes e depois das mutações.
Aqui está um exemplo de uma moeda spec:
// Como convenção, chamamos as specs: [coin]Spec**
const dogecoinSpec:AppSpec <*> = {
// Nome da moeda que estamos testando
name : " DogeCoin" ,
currency :getCryptoCurrencyById(" dogecoin"),
// A dependência está relacionada ao aplicativo do dispositivo (aqui dogecoin) e se ele
// requer qualquer outro aplicativo instalado para funcionar
dependency :"Bitcoin",
// Metadados usados para gerar o emulador**
appQuery : {
model :"nanoS",
appName :" Dogecoin",
firmware: "1.6.0",
appVersion:"1.3.x",
},
// É aqui que está a verdadeira diversão. A matriz de mutações é uma lista
// de possíveis mutações que podem ser aplicadas à conta**
// se todas as condições forem válidas
mutations :[
{
// Nome da mutação
name: "send max",
// A transação é onde usaremos a lógica `live-common` para
// criar o tipo de transação que desejamos testar**
transaction :({account, siblings,bridge})=> {
// invariáveis são `condições` que precisam ser verdadeiras para a
// mutação ser considerada ao executar o bot
invariant (account.balance.gt(100000),"balance is too low");
// Criamos uma nova transação
let t =bridge.createTransaction(account);
// Escolhemos uma conta de irmã (ou criamos uma)**
// para que os fundos permaneçam na mesma _seed _
const sibling =pickSiblings(siblings);
constrecipient=sibling.freshAddress;
// Atualizamos a transação e a retornamos
t= bridge.updateTransaction ( t, { useAllAmount :true , recipient});
return t ;
},
// Aqui nós conectamos uma `deviceAction` que cuidará das vários
// telas exibidas no dispositivo
deviceAction : deviceActionAcceptBitcoin ,
// E finalmente, a afirmação
// Aqui obtemos muitas informações sobre a conta estado anterior e atual
// assim como transação e alguns outros dados que
// podemos usar para fazer algumas afirmações
test:({
account,
accountBeforeTransaction ,
transaction,
optimisticOperation,
operation ,
})=> {
// É aqui que precisamos ser criativos:
// como os cenários não podem ser reproduzidos, descrevemos nossos testes
// para ser algum tipo de asserção de "meta".
expect ( account.balance.toString()).toBe("0");
},
},
],
};
A lógica do _ bot _
Agora que temos uma API para controlar uma versão de software do nosso dispositivo e os arquivos de especificações, como o bot funciona?
Quando executamos os testes (atualmente em execução dentro do Jest runner), geramos um emulador com os metadados do [coin]Spec, que nos fornece uma versão de firmware e uma versão da aplicação para a família/moeda que queremos testar. Em seguida, o bot processa a especificação e cria uma lista de possíveis mutações para cada conta disponível. Em seguida, ele escolherá aleatoriamente uma das mutações da lista e tentará reproduzi-la (enviar, delegar…). Depois disso, o bot tenta esperar até que a transação recém-criada apareça na blockchain, e então tenta fazer a asserção. Decidimos adotar essa abordagem para que o bot se comporte de modo um pouco mais "humano", alternando entre os diferentes tipos de operações. Sabemos que não cobrimos todos os casos possíveis em cada execução. Esta é uma escolha que fizemos quando decidimos analisar esses testes com uma filosofia de Long Tail (depois de muitas execuções, eventualmente cobriremos todos os cenários possíveis).
Como o bot é apenas um script que é executado em um executor de testes, podemos automatizar facilmente suas execuções com o Github Action (executando como um cronjob). Isso nos dá a oportunidade de comentar os Pull Requests e Commits automaticamente, publicando relatórios de cada uma de suas execuções. É uma ótima ferramenta para entender quando as coisas dão errado para nós. É um problema com a blockchain? Com a versão do dispositivo? Talvez a versão do aplicativo instalada no dispositivo? Ou algo totalmente diferente?
Não importa qual seja a causa raiz, o Ledger Live Bot é uma ótima fonte para entender nosso ecossistema e definitivamente tem sido um grande suporte para nossa equipe de controle de qualidade e engenharia no ano passado.
O que vem a seguir?
Então, o que vem a seguir? Agora que o Ledger Live Bot é um projeto sólido com boas bases, estamos olhando para o que vem a seguir.
Um dos grandes recursos do Ledger Live é a capacidade de swap entre criptomoedas. Podemos replicar isso com o bot? O bot pode ser usado como uma ferramenta de transação automatizada? Podemos dar-lhe regras para agir por conta própria? Pode se tornar um bot de negociação….
Este artigo foi escrito por Gaëtan Renaudeau e Valentin De Almeida, com tradução feita por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.
Latest comments (0)