Como vimos os pagamentos da IoT em um hackathon em Hong Kong


10 de junho foi o terceiro dia de nossa climatização em Hong Kong. E nas últimas 26 horas que passamos quase sem dormir, desenvolvendo um projeto de protótipo com o nome de trabalho SensorPay na primeira etapa do hackathon da EOS Global, com um total de prêmios de um milhão e meio de dólares. O momento da demonstração do projeto diante dos juízes estava chegando.


Se você está ansioso para descobrir como essa história terminou, dê uma olhada na última parte imediatamente. Enquanto isso, começaremos a falar sistematicamente sobre as tecnologias de EOS e como chegamos à ideia de vincular pagamentos de IoT a EOS. Logo após, haverá uma descrição detalhada do material técnico do projeto.


0. Antecedentes


O EOS é um blockchain de nova geração, alguns até o consideram um assassino do Ethereum. Se de repente você não souber o que é um blockchain ou o Ethereum, o Google ajudará. E nós, por acaso, começamos a desenterrar a EOS cerca de um ano atrás, inclusive estudando os produtos anteriores de seus autores BitShares e Steem.


As vantagens do EOS em comparação com o Ethereum: o rendimento da transação é três ordens de magnitude maior; sistema de permissão desenvolvido para contratos inteligentes; a capacidade de restaurar o acesso perdido e corrigir erros no blockchain; gerenciamento de rede onchain. Fraquezas: preocupações com a centralização, consenso de DPoS potencialmente mais vulnerável, código bruto e uma curva de aprendizado mais acentuada para desenvolvedores.


Como gostamos dessa tecnologia há muito tempo e a consideramos promissora, não podemos desconsiderar a série de hackathons, que é apoiada pelos autores da EOS. Nós apenas queríamos estar lá, realizar nossas idéias nesse ambiente inspirador e compartilhá-las com um amplo público. Obviamente, a oportunidade de ganhar um bom dinheiro também se tornou um motivador agradável adicional.


Portanto, a EOS é a única solução funcional para o blockchain público que sabemos onde você pode realizar MUITAS transações. Onde é necessário? Claro que na Internet das coisas! De fato, se cada torradeira se tornar micropagamentos, ela pagará por cada pedaço de pão na geladeira (e isso é legal por padrão, como você entende), haverá muitas transações. Sem mencionar todos os tipos de outras aplicações na medicina, na indústria e na vida cotidiana.


Algumas semanas antes do hackathon, idéias alternativas surgiam periodicamente e pequenos brainstorms eram realizados. Comparamos as ideias com base em critérios de arbitragem conhecidos: aplicação dos recursos da EOS, criatividade, impacto social, escalabilidade. Como resultado, decidimos pela IoT + EOS - uma solução que pegava dados de sensores e enviava muitas transações de pagamento para a EOS.


A propósito, realmente queríamos contar aqui também como criamos nosso Block Producer para EOS; como eles planejaram liberar para ele o construtor de tokens do tipo ERC721 e suporte para funções constantes; como eles arquivaram o protocolo ACL da raiz de Merkle. Mas tudo isso não se encaixa no artigo, portanto, retornaremos ao nosso projeto principal.



1. Preparação


1.1 IoT


Preparar a parte IoT do projeto é escolher o hardware certo. No papel do leitor RFID, o RC522 operando no barramento SPI foi escolhido: é popular e fácil de usar.



Ao procurar o contador, focamos na presença de uma saída de pulso, pois ela permite a leitura de dados com muita simplicidade: um pulso é X kW⋅h (onde X depende do modelo); como resultado, paramos no contador Mercury 201.5.



O mais difícil foi decidir sobre o controlador, que deve coletar dados dos sensores, formar uma transação, assiná-lo com sua chave privada e enviá-lo à rede. Dessa forma, precisávamos de um dispositivo com um módulo de rede que pudesse assinar uma transação usando ECDSA (neste caso, na curva elíptica secp256k1, pois é usado no EOS para assinatura).


Inicialmente, a escolha recaiu sobre o microcontrolador ESP8266, possui um módulo Wi-Fi e todas as interfaces necessárias para conectar nossos sensores. Ao mesmo tempo, é muito compacto. Mas nenhum firmware possui uma implementação nativa de primitivas elípticas. É possível escrever sua própria implementação, mas isso não é uma tarefa para o hackathon. Como resultado, o Raspberry Pi 3 B foi escolhido para o protótipo e a biblioteca eosjs foi usada para gerar e assinar transações.



1.2 A infraestrutura


Alguns dias antes da hackathon, preparamos localmente e no servidor eos-hackathon.smartz.io um assembly EOS ( fonte ). A instalação, montagem e testes de dependência foram surpreendentemente tranqüilos para um projeto tão jovem (usando a documentação ). Não havia tempo suficiente para outra preparação da infraestrutura, e eu já tinha que lidar com isso durante o hackathon.


1.3 Arquitetura


Na véspera do hackathon, discutimos a arquitetura e esclarecemos os detalhes do produto. Iríamos implementar os seguintes casos principais: pagamentos por eletricidade e pagamento por compras marcadas com etiquetas RFID. Eles também planejavam tornar o produto facilmente extensível e usá-lo em outras áreas.



A idéia da arquitetura é que o provedor de serviços (Produtor) crie um contrato - o ponto central da interação entre o fornecedor e os consumidores. Cada consumidor tem seu próprio saldo, que pode ser reabastecido, e os fundos são debitados com base nos sinais dos sensores. Todos os dados - usuários, sensores, estatísticas - são armazenados no contrato do fornecedor.


As preferências do usuário estão associadas ao consumidor ou sinalizadores (por exemplo, uma categoria preferencial do usuário) - user_meta . Vários sensores podem ser conectados ao consumidor, para cada um deles são indicados um contrato e configurações de cobrança ( billing_meta ). Assim, você pode obter um contrato de faturamento apátrida imutável, usado para um grande número de consumidores; os dados necessários aparecerão durante a chamada do método de bill(payload, user_meta, billing_meta) . Além disso, é apresentada a possibilidade de uma lógica de faturamento diferente, ou seja, contratos diferentes: por exemplo, um considera eletricidade, o outro - bens. Cada sensor tem um "ponteiro" para seu contrato de cobrança.


Supõe-se que o consumidor confie no fabricante do sensor, mas não confie necessariamente no provedor de serviços. A interface de interação com o sensor é extremamente simples: é uma chamada ao método de contrato do fornecedor com um parâmetro numérico, que será transferido para o faturamento. O provedor de serviços inicia consumidores, sensores, contratos de cobrança e seus relacionamentos no contrato, usando transações de controle - setters primitivos. Quando uma transação é recebida do sensor, os dados são verificados, os dados para cobrança são gerados, a cobrança é chamada, o pagamento é registrado e as estatísticas são registradas.


Talvez, acima de tudo, tenhamos discutido os seguintes problemas que são importantes para a aplicabilidade do produto no mundo real:


  • Adiantamentos ou pós-pagamento? Reabasteça sua conta e use-a (como uma conexão de celular) - ou use-a e depois pague (como a AWS)? Não há resposta certa ou errada aqui: empresas diferentes preferem modelos diferentes. Por uma questão de simplicidade, decidimos fazer pagamentos antecipados.
  • O usuário deve manter uma conta separada para cada fornecedor ou todas as cobranças são provenientes de uma conta? Novamente - não há decisão certa e errada; além disso, a resposta está intimamente relacionada à resposta à pergunta anterior. Os adiantamentos são bons amigos de contas de consumidores individuais - eles foram feitos.
  • Cobrar uma taxa no EOS, um token de um provedor de serviços ou moeda estável (vinculada à moeda fiduciária)? Naturalmente, outras opções que não a moeda estável são inconvenientes para o consumidor devido à volatilidade, e a moeda estável no âmbito do EOS ainda não existe. Naquela época, nem a principal rede EOS estava lá! Por simplicidade, eles receberam um token condicional.

2. Codificação


Primeiro, eles especificaram a API e a estrutura do contrato do fornecedor para iniciar simultaneamente o desenvolvimento do frontend, código do dispositivo, cobrança e contrato principal ( fonte ).


2.1 IoT


O primeiro a implementar um código para ler pulsos de um contador. Para trabalhar com o GPIO (pinos de uso geral), a biblioteca JS onoff foi usada. Mais tarde, dois LEDs foram adicionados ao circuito para maior clareza: o primeiro piscou quando um sinal foi recebido do contador e o segundo quando uma resposta sobre uma transação bem-sucedida veio do nó EOS. Da mesma forma, desenvolvemos um esquema e código para a leitura de tags RFID, com a única diferença: a leitura ocorreu no barramento SPI usando a biblioteca MFRC522-python. Como se viu, a configuração SPI para o Raspberry Pi 3 é diferente da configuração nos modelos anteriores de placa; Esta instrução nos ajudou a entender.


Os dispositivos foram alimentados pelo banco de potência, que foi apresentado com sucesso a todos os participantes do hackathon, e eles tiveram que compartilhar a Internet com o iPhone 5, já que o Wi-Fi do hackathon funcionava exclusivamente a 5 GHz, isso não funcionava para o Raspberry Pi.


2.2 Infraestrutura e Utilitários


Os organizadores aconselharam tirar a imagem do dock do eos-dev , mas ficamos confusos com a falta de descrição e documentação da imagem. No servidor, eles continuaram trabalhando com a montagem preparada e, localmente, para evitar a instalação sistemática do EOS, eles usaram o eos-dev.


Imediatamente precisava urgentemente da capacidade de construir e testar rapidamente. Ideal: criar e executar um arquivo executável localmente. No entanto, era impossível ignorar o fato de que, após a montagem, a saída exigia o WebAssembly e, no ambiente EOS, com os correspondentes impulsionadores, bibliotecas e contratos do sistema. As opções de compilação necessárias podem ser vistas em eosiocpp.in , no entanto, decidimos não jogar este jogo. O resultado previsto, embora um pouco mais lento, é mais importante do que uma solução rápida com um potencial rake. Portanto, para a montagem, pegamos o eoscpp, que está no contêiner eos-dev.


Acabou sendo mais difícil com o lançamento, tive que aumentar a blockchain da EOS local e, novamente, não havia solução pronta. Somente software. Então a primeira versão da infraestrutura de lançamento apareceu. A idéia é ocultar as nuances de montagem e configuração e obter um conjunto auto-consistente de quatro a cinco "botões" para ações típicas. Menos controle, mas menos chance de erro, além de economia de tempo.


Os principais componentes do EOS incluem os nodeos, keosd daemons, o utilitário cleos console e o compilador eoscpp:


  • nodeos - nó EOS, daemon - participante da rede, fornece acesso ao blockchain e, opcionalmente, produz novos blocos;
  • keosd - um daemon para gerenciar carteiras locais que armazenam pares de chaves;
  • O cleos fornece comandos desde a obtenção de informações sobre transações até o trabalho com chaves; é implementado com base em chamadas em nodeos e keosd através da API HTTP;
  • O eoscpp compila contratos no WebAssembly e também permite que você obtenha a Interface binária do aplicativo com base no código-fonte.

Imediatamente ficou claro que os comandos cleos relacionados às chamadas keosd não funcionavam. Como foi emitido um erro indicando inacessibilidade da rede keosd, passamos um tempo diagnosticando problemas de rede na rede docker. No entanto, o strace mostrou que não era a rede: os cleos acessavam o endereço errado, sempre para o host local (e, no caso de nossa infraestrutura, daemons diferentes têm endereços de rede diferentes em uma rede docker separada). Um bug foi diagnosticado no cleos: a verificação da disponibilidade do keosd, que é executada antes de qualquer comando relacionado às carteiras, leva em consideração a porta transmitida nos argumentos, mas não leva em consideração o endereço. Sob o hackathon, mudamos para a rede host no docker como uma solução alternativa.


A próxima etapa foi o utilitário de compilação do contrato usando o compilador no contêiner ( confirmação ). Diretórios de entrada e saída foram montados. E, finalmente, a capacidade de fazer upload de um contrato para o blockchain e enviar transações ( confirmação ). Novamente - utilitários em um estilo consistente, simples "botões". Isso encerrou a infraestrutura básica, mas as surpresas continuaram: deparamos com o problema das funções C para trabalhar com memória (em mais detalhes abaixo).


Em conclusão, eles começaram a configurar contas em um arquivo (cada contrato e participante exigem contas separadas) junto com pares de chaves criados automaticamente quando o blockchain é iniciado, para que uma equipe possa elevar o ambiente de teste. Uma cópia desse ambiente foi implantada no eos-hackathon.smartz.io.


2.3 Contratos inteligentes


2.3.1 Contrato de fornecedor e cobrança de energia elétrica


Após o início do hackathon, começamos a definir a estrutura dos contratos de acordo com o esquema acima. O sistema consistia nos seguintes contratos:


  • contrato supplier - supplier ;
  • billing_electricity - um contrato para calcular o pagamento de eletricidade para cada tick do medidor.

No contrato do supplier , a maior parte do trabalho é realizada por operações CRUD comuns: adição de usuários, tarifas, contadores, aumento ou diminuição do saldo do usuário. Métodos mais complexos foram responsáveis ​​por receber dados do medidor, abrir um contrato para calcular um pagamento (cobrança), debitar a conta pessoal de um usuário após um retorno de chamada de um contrato de cobrança. O contrato de cobrança necessário foi determinado com base na tarifa do usuário.


Após a chamada no contrato para cobrança, o pagamento foi calculado e o método foi chamado para debitar o pagamento da conta pessoal do usuário. Tendo jogado a lógica principal, até pensamos se estávamos fazendo contratos muito simples. Um pouco depois, após a implantação dos contratos no nó e seus testes, ficou claro que os contratos podem ser simples, mas há nuances. :)


Após a implantação, verificou-se que as chamadas de contrato esperadas entre si não funcionavam. Direitos insuficientes. Diferentemente dos contratos inteligentes no Ethereum, onde um contrato é chamado de um contrato em nome do contrato de chamada, no EOS, toda a cadeia começa com o iniciador da transação. Quando um contrato é chamado de um contrato, é verificado se o iniciador permitiu que o contrato fizesse isso.


Os mentores imediatamente sugeriram como agir em um caso simples. Os direitos são adicionados da seguinte forma (através da chamada do contrato inteligente do sistema eosio):


 ./cleos push action eosio updateauth '{"account":"electricity","permission":"active","parent":"owner","auth":{"keys":[{"key":"EOS7oPdzdvbHcJ4k9iZaDuG4Foh9YsjQffTGniLP28FC8fbpCDgr5","weight":1}],"threshold":1,"accounts":[{"permission":{"actor":"supplier","permission":"eosio.code"},"weight":1}],"waits":[]}}' -p electricity 

Nesse caso, a conta de electricity permite que o contrato do supplier chame outros contratos em seu nome. Você pode ler mais sobre direitos no Technical WP EOS . Em nosso país, o contrato do supplier causou o contrato de billing e, por sua vez, novamente chamou o supplier . A adição por analogia de direitos neste formulário não funcionou:


 ./cleos push action eosio updateauth '{"account":"electricity","permission":"active","parent":"owner","auth":{"keys":[{"key":"EOS7oPdzdvbHcJ4k9iZaDuG4Foh9YsjQffTGniLP28FC8fbpCDgr5","weight":1}],"threshold":1,"accounts":[{"permission":{"actor":"supplier","permission":"eosio.code"},"weight":1},{"permission":{"actor":"billelectro","permission":"eosio.code"},"weight":1}],"waits":[]}}' -p electricity 

Um erro foi emitido: autoridade inválida. Aqui os mentores não podiam mais nos ajudar: eles disseram que eles mesmos não fizeram isso. E quem fez? Talvez apenas Dan Larimer. Não conseguimos encontrar rapidamente a causa do erro no código EOS e já começamos a considerar opções alternativas, sem uma cadeia de chamadas. Impediu lindamente que o mecanismo de convocação de outros contratos no EOS também seja diferente do éter. Quando outro contrato é chamado, esta chamada fica na fila e só será concluída após a conclusão da chamada atual. Não funcionará para chamar o contrato e após a chamada para ler os dados registrados por este contrato.


Mais tarde, afinal, eles encontraram no código EOS o motivo do erro ao definir os direitos para dois contratos. Acontece que as contas na lista de direitos devem ser classificadas por conta: Garante que todas as chaves sejam únicas e classificadas e que todas as permissões da conta sejam únicas e classificadas ( Authority.hpp ). Após alterar a ordem das contas, a atualização dos direitos funcionou - e nosso sistema de contratos começou a operar.


2.3.2 O problema das funções C com memória


É ridículo dizer, mas no final não conseguimos usar as funções prontas para analisar números (!) Para ler a configuração de cobrança. Após std::istringstream função std::istringstream foi std::istringstream que é bastante estranho. E ao usar atof e similares, assim como sscanf - env.realloc apertado. Por alguma razão, as funções mencionadas de trabalhar com a memória da biblioteca C padrão não foram encontradas durante o carregamento de código nos nós. As funções C ++ que trabalham com memória funcionaram.


Obviamente, ao executar o contrato do WebAssembly, não é usado um alocador de memória padrão, mas sua própria caixa de proteção, que é fornecida a cada transação sob determinadas condições. Além disso, o suporte às funções C do trabalho com memória em cima dessa caixa de proteção foi implementado por um longo tempo, sua implementação está em contratos EOS padrão . Provavelmente algo deu errado no estágio de vinculação.


Depois de passar cerca de uma hora procurando uma saída, inclusive com a ajuda de um dos mentores, decidimos não continuar e fazer uma solução alternativa: escreva nosso próprio código que resolva o problema de analisar números. O mecanismo EOS do fluxo de dados não nos convinha: requeria a capacidade de salvar pacotes de dados de estruturas diferentes em um campo e criá-los manualmente (as próprias configurações de cobrança).


2.3.3 Faturamento do Shopping


No segundo vento, que foi aberto pelos engenheiros de energia ou pelo café da manhã, eles escreveram faturamento para compras na loja. O esquema geral de trabalho é o seguinte:


  1. O fornecedor cria um contrato de faturamento e o prescreve em seu contrato geral.
  2. Na saída da loja, o fornecedor estabelece estruturas que podem ler RFID, interagir com o EOS e ter suas próprias contas prescritas no contrato de cobrança.
  3. Cada produto na loja está equipado com uma etiqueta RFID, todas as etiquetas são registradas no contrato de cobrança.
  4. O comprador paga pelas mercadorias digitalizando seu RFID e as mercadorias são removidas do contrato de cobrança.
  5. Na saída da loja, os quadros também lêem compras de RFID. Se as mercadorias ainda estiverem na loja, a transação não passa e o quadro deve soar o alarme (sim, de fato, você não pode nem enviar a transação, mas apenas ler a tabela).

Não faz sentido insistir no próprio código do contrato: esse é o C ++ 14 padrão com algumas construções e bibliotecas específicas do EOS. Melhor dito no Wiki do EOSIO e no Portal do desenvolvedor do EOSIO .


2.3.4 Frontend


A parte frontend do projeto foi implementada usando o React. Em vez do habitual, muitos Redux decidiram usar o MobX, que acelera significativamente o desenvolvimento e permite gerenciar o status global sem dor de cabeça.


A fase de integração front-blockchain não correu tão bem quanto o esperado. O pacote eosjs está sendo finalizado de forma muito ativa, seguido pela carteira EOS para o navegador Scatter . Nesse grupo, isso geralmente causa problemas. E não o fato de que o código que funcionou ontem funcionará bem hoje. Nós pisamos neste rake (e não na primeira vez). Uma hora tentando e depurando em um estado sonolento - o problema está resolvido.


Considere um diagrama simplificado da interação do lado do cliente do aplicativo com o eos. Para fazer isso, você precisa da biblioteca eosjs e da extensão do navegador Scatter.


Lembramos você! O Scatter é atualizado ativamente após o eosjs, não se esqueça de atualizar a biblioteca.


Em seguida, uma breve olhada em leitura e escrita. Existem duas maneiras de se comunicar com contratos inteligentes no EOS: enviar transações (faz com que o blockchain seja modificado, sem valores de retorno fornecidos) e ler tabelas (ação somente leitura).


Considere o código de envio da transação:


  sendTransaction(funcName, data) { return this.scatter .suggestNetwork(this.network) .then(() => this.scatter.getIdentity({ accounts: [this.network] })) .then((identity) => { let accountName = this.getAccountName(identity); // wrap eos instance const eos = this.scatter.eos(this.network, Eos, this.configEosInstance); return eos.transaction(accountName, (contract) => { contract[funcName](data, { authorization: accountName }); }); }); } 

Argumentos de entrada: nome da função e objeto, seus valores são argumentos dessa função. Terceira linha: confirmamos a rede através da qual interagimos com o EOS. Quarta linha: obtemos identity , o parâmetro é um objeto com o campo de accounts (para esta rede). A função getAccountName retorna a primeira conta da lista de contas recebidas (no objeto de identity ).


Neste exemplo, o Scatter é usado para assinar uma transação. Scatter é um wrapper sobre uma instância da classe Eos . Na linha 9, chamamos o método eos , seus parâmetros:


  1. this.network - um objeto com parâmetros de rede.
  2. Eos é uma instância do eosjs.
  3. this.configEosInstance - um objeto com parâmetros para uma instância do Eos (consulte dock eosjs).

O último método de transaction aceita accountName e callback como uma entrada; o argumento de callback é um contrato localizado na conta accountName . No callback , chamamos o método do contrato recebido com o objeto, suas chaves são os argumentos do método chamado.


Considere o método de leitura de tabelas:


  readTable(data) { this.eos = this.scatter.eos(this.network, Eos, this.configEosInstance); return this.eos.getTableRows({ json: true, limit: 1, ...data, }); } 

Aqui para leitura, precisamos apenas de uma instância eos .


Para projetar a interface, lançamos Materialize, Semantic e Ant, criamos os próprios estilos. Nas últimas horas do hackathon, uma idéia apareceu para reviver a interface do usuário, adicionar uma visualização do processo. Destacou as novas linhas da tabela por dois segundos em verde e obteve um efeito interessante à cotação das ações. A melhoria aumentou significativamente a atratividade do projeto e se tornou o estágio final da criação da interface do usuário.


3. Montagem


Três horas antes do final do tempo, tínhamos um Raspberry Pi com o medidor de eletricidade Mercury e um leitor RFID conectado a ele, além de uma indicação luminosa. Toda a eletricidade da mesa passou pelo Mercúrio. Para cada 0,3125 Wh / h gasto, bem como para cada "compra", o Raspberry Pi enviava transações para nossa blockchain, e o provedor de serviços podia gerenciar usuários, sensores, cobrança e ver estatísticas de consumo.



Por mais uma hora, calmamente nos envolvemos em verificações e adicionamos os retoques finais. Duas horas antes do final dos tempos, recebemos um produto completo com dois casos implementados, ilustrando completamente o conceito e até mesmo sem confirmação nos últimos minutos!


4. Demonstração


As demonstrações de projetos (também conhecidos como arremessos) consistiram em duas etapas. Na primeira etapa, 69 equipes participantes foram divididas em quatro grupos, cada um deles alimentado separadamente na frente de dois juízes e sem espectadores. Os juízes deram notas (quatro critérios de 5 pontos cada) e, com base nessas notas, as 10 melhores equipes foram selecionadas para a segunda etapa. Essas equipes tiveram a oportunidade de realizar um projeto em um grande palco diante da platéia e dos oito juízes.


Acabamos no primeiro grupo, nossos juízes eram o CEO e o presidente (imagino como essas posições diferem) da Everipedia. Três minutos foram alocados para o desempenho, eles foram rigorosamente monitorados pelo timer. Terminamos nossa inconsistência, mas pedimos para impressionar o discurso 30 segundos antes do previsto. Os juízes perguntaram algo superficialmente e em pouco tempo, e a manifestação terminou.


Nós, ingênuos, ficamos surpresos por não prestarmos atenção à capacidade real de trabalho do produto e, mais ainda, ao código do juiz. Questões técnicas de implementação não lhes interessavam nem um pouco. Poderíamos mostrar as lâmpadas piscantes do Raspberry Pi e a foto na frente.


Havia a sensação de que, com a apresentação do projeto, fracassamos, porque esperávamos impressionar com uma solução real, um protótipo e não apenas uma descrição colorida de um projeto socialmente significativo e ambicioso. Tudo foi tocado como se fosse anotações: descrevemos o problema, a dor, nossa solução, mostramos como ele funciona e descrevemos os planos de desenvolvimento do projeto. Conhecendo antecipadamente os métodos de julgamento, teríamos feito muito diferente.


Os juízes das quatro séries do primeiro turno reduziram suas pontuações e trocaram de opinião 15 minutos após o final dos arremessos. Após o anúncio dos vencedores começou. Uma atmosfera nervosa reinou no salão: cansada após a maratona de 26 horas, as pessoas queriam vencer, havia muitos times fortes e sabiam que podiam reivindicar a vitória. E sabíamos disso - e esperamos pelos resultados.


Para impedir que os espectadores relaxem, os resultados foram anunciados em três partes. Os quatro primeiros finalistas, depois mais três, depois outros três. Entre anúncios e no final - performances. Não entramos no top 10 e não tivemos a oportunidade de entrar no grande palco. Duas equipes de língua russa chegaram ao top 10, uma das quais acabou se tornando a terceira. Parabéns aos vencedores, eles merecem seus prêmios.


5. Conclusão e planos


AngelHack . , . — , , . , , , — .


26 IoT- EOS. , .


— UI ( — -- Smartz ), . - , blockchain-ready , , — . :)



, , «», «» . . 5 . , 100 , . SensorPay !


:


Yuvasee (entrepreneur)
algs (hardware & backend developer)
therealal (architect, backend developer, devops)
bolbu (frontend developer)
quantum (blockchain & backend developer)

Source: https://habr.com/ru/post/pt414803/


All Articles