Capítulo 7

Integração do Monero para desenvolvedores

Esse capítulo cobre os padrões e protocolos que desenvolvedores podem usar para interagir com o Monero e construir novas ferramentas. Primeiro, os formatos OpenAlias e Monero URI são apresentados como formas efetivas de comunicar endereços e outros detalhes importantes. O restante do capítulo discute chamadas remotas de procedimento com exemplos de integração usando C++ e Python.

7.1 OpenAlias: endereços convenientes em texto (para humanos)

É extremamente complicado para qualquer pessoa ler ou memorizar endereços de criptomoedas, a não ser que ela tenha memória fotográfica. Endereços na vida real como “Rua Principal, 123” ou um e-mail como “donate@masteringmonero.com” são muito mais fáceis de interpretar e lembrar do que um endereço Monero, como por exemplo: “45ttEikQEZWN1m7VxaVN9rjQkpSdmpGZ82GwUps66neQ1PqbQMno4wMY8F5jiDt2GoHzCtMwa7PDPJUJYb1GYrMP4CwAwNp”.

Esses endereços de criptomoedas contém muitas informações, mas são complexos demais para humanos. Na verdade, existe um trilema famoso conhecido como “triângulo de Zooko” que descreve a dificuldade inerente de se projetar sistemas de nomes que simultaneamente atendam três critérios: segurança, descentralização e que “faça algum sentido para humanos”.

O endereço Monero mostrado acima não faz nenhum sentido para humanos, porém atende os outros dois critérios com sucesso. Endereços públicos do Monero contém ao menos 95 caracteres, o que os tornam difíceis de ler e impossíveis de memorizar. Certamente deve existir uma forma de simplificar os destinos de pagamento!

A Equipe Core do Monero lançou o padrão OpenAlias para “contornar” o triângulo de Zooko criando uma forma legível por humanos para comunicar endereços. O padrão OpenAlias é um registro DNS de texto em um Nome de Domínio Completamente Qualificado (Fully Qualified Domain Name (FQDN), em inglês). Cada registro de texto só precisa conter duas informações: o prefixo e o endereços de destino. Um par chave-valor recipient_name também pode ser adicionado, mas ele é opcional.

Um registo de texto OpenAlias típico se parece com isso:

oa1:xmr

recipient_address=45ttEikQEZWN1m7VxaVN9rjQkpSdmpGZ82GwUps66neQ1PqbQMno4wMY8F5jiDt2GoHzCtMwa7PDPJUJYb1GYrMP4CwAwNp

recipient_name=MoneroFFS

A porção “oa1:xmr” indica que o registro é baseado no OpenAlias Versão 1 e que o destino é um endereço Monero. Um nome para o destinatário pode ser especificado, neste caso “MoneroFFS”.

Nome Tamanho Descrição
oa1: 4 O registro sempre começa com “oa1:”, indicando que este é um registro OpenAlias Versão 1. Se o prefixo não estiver presente, nós ignoramos o registro, já que ele pode ser um registro SPF ou alguma outra coisa que não nos interessa.
symbol 3 O código da criptomoeda. Os códigos devem seguir a norma ISO 4217: por exemplo, para a criptomoeda Monero, o símbolo é xmr e para o Bitcoin, o símbolo é btc.
recipient_address = endereço; 17 + endereço + 1 O endereço de destino. O formato é recipient_address = seu_endereço; onde seu_endereço é seu endereço de criptomoeda. Para o Monero, ele será uma sequência de 95 caracteres. Pares de chave-valor são separados por ponto-e-vírgula e, opcionalmente, um espaço para facilitar a leitura. Essa chave-valor deve existir. O OpenAlias existe para associar FQDNs a um “endereço” de qualquer tipo, que é expresso neste valor.
recipient_name = descrição; 14 + descrição + 1 Esta entrada não é necessária, embora seja útil para o propósito de confirmar o destinatário correto ou para oferecer ao usuário a opção de adicionar uma nota ou nome à lista de endereços.

O padrão OpenAlias é extensível para desenvolvedores, intuitivo para usuários e interoperável entre sistemas de domínio centralizados e descentralizados. O padrão pode ser utilizado com qualquer criptomoeda e já foi implementado pelo Monero, Bitcoin (Electrum) e HyperStake.

Figura 7.1

Figura 7.1 – O termo legível donate.getmonero.org é revolvido pelo servidor DNS, que retorna o endereço de destino 44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A.

7.2 Monero_URI: informações convenientes em texto (para computadores)

O padrão de Identificador Uniforme de Recurso do Monero (Uniform Resource Identifier (URI), em inglês) descreve um formato para comunicar, de forma inequívoca, campos de dados importantes para faturas e transações. Esses URIs são especialmente úteis para fins comerciais, como a geração de códigos QR para pagamentos, por exemplo.

A sintaxe URI do Monero segue a RFC 3986, e os espaços precisam ser no formato x-www-urlencoded, na forma %20. O URI abaixo mostra um exemplo de texto que codifica a requisição de um pagamento de 0,0413 XMR para o endereço 4BKq…feW5 para o “Livro Mastering Monero”.

monero:4BKjy1uVRTPiz4pHyaXXawb82XpzLiowSDd8rEQJGqvN6AD6kWosLQ6VJXW9sghopxXgQSh1RTd54JdvvCRsXiF41xvfeW5?tx_amount=0.0413&tx_description=Livro%20Mastering%20Monero
Parâmetro Tipo Descrição
address Texto O endereço em si
tx_payment_id Texto A ID do pagamento proposta para a transação (se mencionada)
recipient_name Texto O nome do contato de destino proposto (se mencionado)
tx_amount Float O valor proposto para a transação em unidades atômicas
tx_description Texto Descreve a transação que deve ser inicializada

7.3 Monero RPC

Desenvolvedores integrando o Monero podem escolher entre utilizar a API C++ do Monero (C/C++) ou a interface de chamadas remotas de procedimento (RPC). Os métodos RPC podem ser acessados por qualquer linguagem de programação que tenha o recurso de realizar requisições HTTP, então aproveitaremos essa flexibilidade e incluiremos códigos de exemplo para algumas das atividades mais comuns.

O daemon do Monero (monerod) é acessível via RPC para atividades essenciais como verificar saldos ou enviar fundos. A carteira Monero RPC (monero-wallet-RPC) permite que você gerencie todas as funções da carteira através de chamadas JSON.

A RPC expressa as quantidades de Monero em “unidades atômicas”, que referem-se a menor fração que uma moeda Monero é reconhecida pela implementação atual do monerod. Você pode converter facilmente entre formatos utilizando a notação:

1 XMR = 1x10^12 unidades atômicas

7.3.1 Inicialização e configuração (configurar e proteger)

Primeiro, execute a carteira Monero RPC especificando a porta e o caminho do arquivo da sua carteira:

$ ./monero-wallet-rpc --rpc-bind-port 18082 --disable-rpc-login --log-level 2 --wallet-file arquivo-da-sua-carteira --prompt-for-password

Se você deseja utilizar um nó remoto, basta adicionar a flag --daemon-addess seguida pelo endereço, por exemplo:

--daemon-address node.moneroworld.com:18089

Já que a monero-wallet-rpc não vincula seu endereço IP e porta por padrão, você deve especificar --rpc-bind-ip seuIP para conectar-se remotamente.

Algumas medidas de segurança são recomendadas, já que colocar o sistema em produção com uma interface RPC aberta é como ir a um safári sem nenhuma proteção! Certifique-se de configurar um nome de usuário e senha antes de expor seu nó. Se você seguir esses passos para configurar as proteções adequadas, sua API estará segura.

A flag --restriced-rpc é extremamente útil para limitar os privilégios RPC e evitar potenciais abusos. Por exemplo, o modo restrito garante que seu nó não retornará dados sensíveis e privados via RPC, e previne que usuários externos ativem a mineração em seus dispositivos.

7.3.2 Formato JSON RPC

JSON-RPC é um protocolo RPC leve e sem estado que utiliza o formato de dados JSON RFC 4672. A especificação primariamente define diversas estruturas de dados e as regras para processá-las. O protocolo é agnóstico ao transporte, o que significa que ele funciona independentemente do mecanismo de transporte utilizado. Assim, os mesmos conceitos podem ser aplicados dentro de determinado processo, seja usando soquetes, conexões HTTP ou qualquer outro meio de comunicação.

Para receber qualquer informação da carteira RPC, você deve enviar uma mensagem pelo método POST. A API JSON-RPC aceita mensagens no formato:

{ “jsonrpc” : versão , “method” : método, “params”: parâmetros, “id”: id }

usando entradas descritas por:

Campo Descrição
version Versão do protocolo JSON-RPC (O Monero suporta a v2.0)
method Declara qual funcionalidade é chamada
params Especifica informações adicionais necessárias para o método desejado
id Número para acompanhar as respostas (inteiros partindo do 0)

7.3.3 Exemplos de chamadas RPC

A RPC do Monero pode ser acessada diretamente de um terminal, como mostrado nos exemplos a seguir. O site do Monero contém a documentação completa descrevendo as especificações e todas as funcionalidades da carteira RPC e do daemon RPC.

7.3.3.1 Obter saldo

O saldo da carteira pode ser requisitado pelo método getbalance:

$ curl -X POST 127.0.0.1:18082/json_rpc -d '{“jsonrpc”:”2.0”,”id”:”0”,”method”:”getbalance”}' -H 'Content-Type: application/json'

que retorna duas saídas: o saldo [total] e o saldo desbloqueado, que inclui somente transações “profudas” o suficiente na blockchain para serem consideradas “seguras” (por exemplo, confirmadas como disponíveis após 6 blocos).

{“id”: “0”,“jsonrpc”: “2.0”, “result”: {  “balance”: 140000000000, “unlocked_balance”: 84000000000} }

Neste caso, a carteira contém 0,14 XMR e somente 0,084 XMR desbloqueados.

7.3.3.2 Obter endereço

Para requisitar o endereço da carteira:

$ curl -X POST 127.0.0.1:18082/json_rpc -d '{“jsonrpc”:”2.0”,”id”:”0”,”method”:”getaddress”}' -H 'Content-Type: application/json'

que retorna:

{“id”: 0,“jsonrpc”: “2.0”,“result”: {“address”: “42uMGYwvLuUGJzqdWZvr47CGCBz1qNNExZeegcjLPMbaFkBb3XG g6Y1bUwaMbovzGWDXtaASxSBYtaiBB4wuDmrAMCygexH”, “addresses”: [{ “address”:  “42uMGYwvLuUGJzqdWZvr47CGCBz1qNNExZeegcjLPMbaFkBb3XG g6Y1bUwaMbovzGWDXtaASxSBYtaiBB4wuDmrAMCygexH”, “address_index”: 0, “label”: “Primary account”,“used”: false
 },
 {
     “address”: “894PaGJyxRjZU8nP7Dh4FuAyzr2dK3VT9ZZX95MxdAGP3HoHEpA bNb8Htgp5LKzc1pXQ8zhpokTZtcUTnzeU823oUPUGSpv”,
     “address_index”: 1,
     “label”: “”,
     “used”: false
 },
             ]}}

7.3.3.3 Criar endereço

Para criar um novo endereço para uma conta. E opcionalmente, rotular o novo endereço.

$ curl -X POST 127.0.0.1:18082/json_rpc -d '{“jsonrpc”:”2.0”,”id”:”0”,”method”:”create_address”, “params” : “{“account_index:0,”label”:”Secondary account”}}' -H 'Content-Type: application/json'

que retorna:

{ “id”: 0, “jsonrpc”: “2.0”, “result”: {“address”: “86KoCQsZHQvSUnp9fFn92e5QGUiZtH1qZ1nNx1Jv5eJs94ywbLR2k 11CjZTq5o4v8j9bx3CEAturCheJqJR7cYdQKT4xE3w”, “address_index”: 9 }}

7.3.3.4 Criar conta

Para criar uma conta:

$ curl -X POST 127.0.0.1:18082/json_rpc -d '{“jsonrpc”:”2.0”,”id”:”0”,”method”:”create_account”,  “params”:{“label”:”Secondary account”}}' -H 'Content-Type: application/json'

que retorna:

{ “id”: “0”, “jsonrpc”: “2.0”, “result”: {“account_index”: 1, “address”: “88bV1uo76AaKZaWD389kCf5EfPxKFYEKUQbs9ZRJm23E2X2oYgV9bQ54FiY6hAB83aDXMUSZF6KWyfeQqzLqaAeeFrk9iic” } }

7.3.3.5 Transferir

Para transferir (enviar) uma quantidade de Monero, especificada em unidades atômicas.

$ curl -X POST http://127.0.0.1:18082/json_rpc -d ' {“jsonrpc”:”2.0”, ”id”:”0”, ”method”:”transfer”, ”params”:{“destinations”: [{“amount”:100000000, ”address”:”9wNgSYy2F9qPZu7KBjvsFgZLTKE2TZgEpNFbGka9gA5 zPmAXS35QzzYaLKJRkYTnzgArGNX7TvSqZC87tBLwtaC5RQgJ8rm” }, {“amount”:200000000,  ”address”:”9vH5D7Fv47mbpCpdcthcjU34rqiiAYRCh1tYywmhqnE k9iwCE9yppgNCXAyVHG5qJt2kExa42TuhzQfJbmbpeGLkVbg8xit” }],”mixin”:4,”get_tx_key”: true}}' -H 'Content-Type: application/json'

que retorna:

{ “id”: “0”, “jsonrpc”: “2.0”, “result”: { “fee”: 48958481211, “tx_hash”: “985180f468637bc6d2f72ee054e1e34b8d5097988bb29a2e0cb 763e4464db23c”, “tx_key”: “8d62e5637f1fcc9a8904057d6bed6c697618507b193e956f77c 31ce662b2ee07”, “amount”: 300000000, “tx_blob”: “”, “tx_metadata”: “”, “multisig_txset”: “” } }

7.4 A integração do Monero na prática (Tutoriais em Python e C++)

Escolher uma linguagem de programação para estes exemplos é complicado, já que qualquer desenvolvedor sabe que não existe uma linguagem de programação universal e perfeita. Todavia, o Python é bastante apropriado para o livro Mastering Monero, já que ele é uma linguagem gratuita e de código-aberto relativamente acessível e compreensível para iniciantes.

Os exemplos a seguir utilizam a versão mais recente, Python 3. A maioria das distribuições Linux baseadas no Debian já possuem as versões Python 2 e Python 3 pré-instaladas. Antes de começar, atualize seus softwares e sistema para garantir que os recursos necessários sejam os mais recentes:

$ sudo apt-get update && sudo apt-get -y upgrade

Os códigos para os tutoriais a seguir estão disponíveis gratuitamente em um repositório público. Você poderá baixar os exercícios através do poderoso sistema de controle de versão “git” utilizando o comando fornecido abaixo.

Cada tutorial está salvo em uma pasta. Por exemplo, a pasta do “Tutorial 1” será tutorial-1. Para baixar os recursos pelo sistema de versão Git, basta executar:

$ git clone https://github.com/monerobook/code

7.4.1 Tutorial 1 – Obter seu saldo

Esse programa irá conectar-se ao daemon via RPC, depois requisitar e imprimir o saldo da conta. Você deve se lembrar da função getbalance (também responde à get_balance) da seção que apresentou a RPC.

Começaremos importando duas bibliotecas do Python bastante úteis para realizar requisições POST: requests e json.

# Mastering Monero Tutorial. This is a comment
import requests
import json

## Import Setup variables
## Url for JSON RPC interface. We assume that your RPC interface is running on localhost port 18082
url = “http://localhost:18082/json_rpc”

## JSON headers . Required
headers = {'content-type': 'application/json'}

## RPC input . Adding method name , at the moment we don't need variables.

rpc_fields = {
  “method” : “get_balance”
}

Relembre os campos JSON padrão que devem ser incluídos em uma chamada RPC:

# Adding the JSON RPC version and id. Id is a int variable which should be incremented each request. First request is 0 , second is one and ...

rpc_fields.update({“jsonrpc”: “2.0”, “id”: “0”})

Agora que tudo está preparado, só resta uma coisa a fazer! Enviar todas as variáveis para a interface JSON-RPC utilizando o método POST HTTP:

# execute the rpc request
response = requests.post(url,data=json.dumps(rpc_input),headers=headers)

# print the response as JSON
print(json.dumps(response.json()))

Salve todo o código acima como tutorial.py (ou qualquer nome que queira) e execute:

$ python tutorial.py

Seu script deverá imprimir no terminal a saída da chamada getbalance:

{
  “id”: “0”,
  “jsonrpc”: “2.0”,
  “result”: {
      “balance”: 0,
      “multisig_import_needed”: false,
      “unlocked_balance”: 0 }
}

Embora a saída contenha todas as informações que precisamos, a sintaxe RPC não está formatada para uma fácil leitura por humanos. Olhar para muitos símbolos {} pode te deixar confuso depois de um tempo!

Para uma saída mais limpa, podemos adicionar algumas linhas de código ao final do script do tutorial para que ele imprima somente o saldo (ou o saldo desbloqueado, se preferir):

# Get the balance from response array and convert to a string.
balance = str(response.json().get('result').get('balance'))

print(“Balance is “ + balance )

Agora, executando:

$ python tutorial.py

Deverá retornar simplesmente:

Balance is 426700000

Você pode usar métodos RPC como esse para desenvolver seu próprio cliente para a carteira Monero!

7.4.2 Tutorial 2 – Como gerar um endereço pseudoaleatório

No Capítulo 5, apresentamos o conceito de geração de endereços pseudoaleatórios. Para complementar a explicação matemática, segue uma implementação em Python para você acompanhar.

Primeiro, importe as bibliotecas necessárias e adicione-as à pasta (path).

# Import libraries. Hexlify for hex code, utils for the utility, etc.
import os, sys
from binascii import hexlify, unhexlify
sys.path.append('../libraries')
import utils
import ed25519
import base58

Para programar a função generate_random_address, vários passos precisarão ser executados:

  1. Criar sua semente gerando um número de 32 bytes (256-bit) de forma pseudoaleatória. Utilize a biblioteca hexlify para converter sua semente em uma sequência em codificação hex e armazene-a na variável seed.

  2. Armazenar sua chave secreta de gasto reduzindo a semente para um escalar válido na curva elíptica Ed25519. Sua chave secreta de gasto é simplesmente a representação da sua semente. Essa verificação requer a função sc_reduce32 da biblioteca utils.

  3. Calcular sua chave secreta de visualização como sendo o hash reduzido da chave secreta de gasto. A função hash_to_scalar executa o hash da entrada, depois a converte para um escalar válido na curva elíptica Ed25519.

  4. Derivar as chaves públicas usando a função publickey_to_private_key para multiplicar suas chaves privadas pelo ponto gerador. Sua chave secreta de gasto produz sua chave pública de gasto e, da mesma forma, sua chave secreta de visualização é usada para derivar sua chave pública de visualização.

  5. Começar a formar seu endereço concatenando o byte da rede (0x12 para os endereços públicos Monero), a chave pública de gasto e a chave pública de visualização. Essas são as informações essenciais incluídas em todos endereços Monero.

  6. Calcular a soma de verificação que será anexada à sequência de caracteres acima, pegando os 4 primeiros bytes (8 caracteres hex) de seu hash Keccak-256.

  7. Codifiquar as informações + soma de verificação em Base58 para uma representação legível por humanos. E isso é tudo! Conforme discutido no Capítulo 5, endereços Monero consistem de:

[byte da rede + chave pública de gasto + chave pública de visualização + soma de verificação]

def generate_random_address():
        ## Generate 32 bytes (256 bits) of pseudo-random data
        seed = hexlify(os.urandom(32))

        ## Reduce random data to make it a valid ed25519 scalar
        secret_spend_key = utils.sc_reduce32(seed)

        ## Use a reduced hash of the secret spend key for the deterministic secret view key
        secret_view_key = utils.hash_to_scalar(secret_spend_key)

        ## multiply by the generator point to get public keys from private keys
        public_spend_key = utils.publickey_to_privatekey(secret_spend_key)
        public_view_key  = utils.publickey_to_privatekey(secret_ view_key)
        ## the network byte, public spend key, and public view key are all concatenated together
        ## 0x12 is the Monero mainnet network byte
        network_byte = “12”
        ## Concatenate the three strings
        data = network_byte + public_spend_key + public_view_key
        hash = utils.keccak_256(data)
        ## checksum is the first 4 bytes (8 hex characters) of the hash of the previous data
        checksum = hash[0:8]
        address = base58.encode(data + checksum)

        ## Printing the keys

        print(“Secret_spend_key : “ + secret_spend_key)
        print(“Secret_view_key : “ + secret_view_key)
        print(“Public_spend_key : “ + public_spend_key)
        print(“Public_view_key : “ + public_view_key)

        ## Returning address generated
        return address

7.4.3 Tutorial 3 – Gerador de endereços “customizados”

Endereços “customizados” referem-se a endereços de criptomoedas que são gerados para ter algum prefixo em particular que você escolhe. Se você quer um endereço com a palavra “gato”, você pode usar esse método para gerar um endereço público começando com “4gato”. Existem algumas limitações devido ao formato do endereço Monero: você não pode remover o 4 inicial (o byte da rede em codificação hex, 0x12) e a codificação Base58 exclui alguns caracteres (I, l, 0, O).

Nunca confie em um site ou terceiro para gerar endereços customizados para você. Não há nenhuma forma de saber se essas chaves foram geradas de maneira segura ou se elas foram copiadas pelo serviço ou por um alguém.

Aqui está um script em Python que você pode verificar por si mesmo e usar para gerar seus próprios endereços customizados em segurança. A abordagem é simples: gerar endereços repetidamente até que um dos resultados coincidam com seu critério. Recomenda-se usar textos curtos já que o tempo necessário para gerar um endereço qualificado usando força bruta aumenta drasticamente conforme o tamanho do texto desejado.

A maior parte do código está dentro de um while(1), um loop infinito que será executado até que um endereço coincidente seja descoberto. Em cada iteração no loop, o código chama a função generate_random_address do exemplo anterior para gerar um novo endereço.

Assim que o endereço é criado, o script verifica se os primeiros caracteres coincidem com o texto desejado pelo usuário. Quando um endereço pertinente é descoberto, o script imprime tal endereço e finaliza, quebrando o loop do while.

import sys
sys.path.append('../libraries')
import address

if (len(sys.argv) != 2):
        print(“usage: python vanity_address.py [desired_prefix]”)
        exit()

if (sys.argv[1][0] != “4”):
        print “Monero addresses must start with the character 4”
        exit()

## create random addresses until one of them matches the desired prefix
## bruteforcing takes a while
while(1):
        rand_address = address.generate_random_address()
        if (rand_address[0:len(sys.argv[1])] == sys.argv[1]):
        print(rand_address)
        exit()
else:
  print(“searching”)

7.4.4 Tutorial 4 – Como criar um endereço sigiloso

O método para geração de um endereço sigiloso explicado no Capítulo 5 é um tanto complexo, assim, incluímos uma implementação em Python para servir de apoio. Programar todo o processo passo-a-passo pode ser muito útil para interpretar e internalizar o conceito matemático.

O objetivo deste tutorial é gerar um endereço sigiloso usando: uma chave pública de visualização, uma chave pública de gasto e uma chave privada da transação aleatória (escalar de 256-bit).

Primeiro, as dependências necessárias são importadas da pasta de bibliotecas:

import os, sys
# library for hex
from binascii import hexlify, unhexlify
sys.path.append('../libraries')
# utils and ed25519 libraries
import utils
import ed25519

A função generate_stealth_address é definida, encarregando-se das operações matemáticas necessárias para criar o endereço não associável a partir das chaves públicas e algumas informações aleatórias.

def generate_stealth_address(publicViewKey, privateTxKey,  publicSpendKey, index):

## multiply r*A
derivation = utils.generate_key_derivation(publicViewKey, privateTxKey)

## concatenate index to derivation then hash and reduce
## Hs(rA|i)
scalar = utils.derivation_to_scalar(derivation, index)

## multiply by base point
## Hs(rA|i)G
sG = ed25519.scalarmultbase(utils.hex2int(scalar))
## interpret the public spend key as a point on the curve
pubPoint  = ed25519.decodepoint(unhexlify(publicSpendKey))

## add the public spend key to the previously calculated point
## Hs(rA|i)G + B
output = ed25519.edwards(pubPoint, sG)
## convert the point to a hex encoded public key
return hexlify(ed25519.encodepoint(output))

O código por ser chamado dessa forma:

print(generate_stealth_address(“be90718b250a06b4bcffca6af948240ad6d8951b730a9711f78d4c9decefb4bd”, “12b793b002ed168f36c9dc8d13c0e820546359452f67136f03087eb18208710e”, “6b48d1c30a640b0b33d0062188df2edd4e6acac7282b215e86701a644a9f70ba”, “01”))

Endereços sigilosos são gerados de forma não determinística, dado que alguns dados aleatórios são misturados também. Por exemplo, uma saída será parecida com isso:

a2bd788a63555e0847800b56051072db3558ac2f97b58b8021e57c67125b4411

7.5 API C++ do Monero

Embora interagir com o Monero através da interface RPC seja simples e fácil de implementar, existem também algumas desvantagens. Você pode gerar endereços e subendereços, e até transferir fundos. Contudo, os métodos RPC não escalam de forma efetiva e podem gerar gargalos em grandes aplicações empresariais.

Existe uma alternativa? Sim! O Monero possui uma API C++ que pode lidar com todas as funcionalidades, incluindo gerenciar carteiras e enviar transações.

A API C++ é um pouco mais complicada de usar do que a interface RPC, então talvez você não queira “brincar” com ela em um ambiente de produção, a não ser que você já esteja bastante familiarizado com integração do Monero. Quaisquer erros ou problemas ao longo do caminho podem prejudicar sua segurança e privacidade.

7.5.1 Bibliotecas do Monero

Monero Core é uma coleção de várias bibliotecas simples que são necessárias ou úteis para atividades relacionadas ao Monero – como Boost, Ed25519 e o algoritmo CryptoNight.

Elas foram reunidas para simplificar processos comuns para desenvolvedores; por exemplo, um programador pode simplesmente chamar base58_decode das bibliotecas do Monero Core ao invés de precisar criar a função do zero.

Primeiro, você precisa compilar as bibliotecas do Monero Core. Uma vez que uma biblioteca está compilada, um arquivo de saída é criado com a extensão .a ou .so.

7.5.2 Primeiros passos com C++

Para integrar o código Monero Core, primeiramente você deve compilar suas bibliotecas. Basta seguir as instruções abaixo e verificar a tabela de dependências no Capítulo 6. Familiaridade com C++ (especialmente os fundamentos do padrão C++11) será muito útil para acompanhar o tutorial.

7.5.3 Tutorial 5 – Recuperando todas as chaves a partir da chave privada de gasto

Esse tutorial mostra como recuperar todas as chaves Monero a partir da chave privada de gasto, utilizando a API C++ e o método CMake. Esse guia é voltado para plataformas baseadas no Linux, já que Apple e Windows implementaram suas próprias bibliotecas (por exemplo, OpenSSL ou Boost).

Primeiramente, configure todas as bibliotecas e variáveis do ambiente em um arquivo chamado CMakeLists.txt. Nesse tutorial, compilaremos o Monero Core na pasta /opt/monero.

cmake_minimum_required(VERSION 3.5)

set(PROJECT_NAME tutorial-5)

project(${PROJECT_NAME})

set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -std=c++11 -ldl”)

if (NOT MONERO_DIR)
        # Path of Monero source code
        set(MONERO_DIR ~/monero)
endif()

message(STATUS MONERO_DIR “: ${MONERO_DIR}”)

set(MONERO_SOURCE_DIR ${MONERO_DIR} CACHE PATH “Path to the root directory for Monero”)

# set location of Monero build tree
set(MONERO_BUILD_DIR ${MONERO_SOURCE_DIR}/build/Linux/master/release/ CACHE PATH “Path to the build directory for Monero”)

set(MY_CMAKE_DIR “${CMAKE_CURRENT_LIST_DIR}/cmake” CACHE PATH “The path to the cmake directory of the current project”)
list(APPEND CMAKE_MODULE_PATH “${MY_CMAKE_DIR}”)

set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} “${MONERO_BUILD_DIR}” CACHE PATH “Add Monero directory for library searching”)

# find boost
find_package(Boost COMPONENTS
    system
    filesystem
    thread
    date_time
    chrono
    regex
    serialization
    program_options
    date_time
    REQUIRED)

# include boost headers
include_directories(
    ${Boost_INCLUDE_DIRS}
)

include_directories(
    ${MONERO_SOURCE_DIR}/src
    ${MONERO_SOURCE_DIR}/external
    ${MONERO_SOURCE_DIR}/build
    ${MONERO_SOURCE_DIR}/external/easylogging++
    ${MONERO_SOURCE_DIR}/contrib/epee/include
    ${MONERO_SOURCE_DIR}/version
    ${MONERO_SOURCE_DIR}/external/db_drivers/liblmdb)
# Specify source files
set(SOURCE_FILES main.cpp)

# Make executable
add_executable(${PROJECT_NAME} ${SOURCE_FILES})

set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)

set(LIBRARIES        
    wallet
    blockchain_db
    cryptonote_core
    cryptonote_protocol
    cryptonote_basic
    daemonizer
    cncrypto
    blocks
    lmdb
    ringct
    device
    common
    mnemonics
    epee
    easylogging
    device
    pcsclite
    sodium
    ${Boost_LIBRARIES}
    pthread
    unbound
    crypto
    ringct_basic)

if (Xmr_CHECKPOINTS_LIBRARIES)
 set(LIBRARIES ${LIBRARIES} checkpoints)
endif()

set(LIBS common; blocks; cryptonote_basic; cryptonote_core; cryptonote_protocol; daemonizer; mnemonics; epee; lmdb; device; blockchain_db; ringct; wallet; cncrypto; easylogging; version; checkpoints; ringct_basic; )

foreach (l ${LIBS})
    string(TOUPPER ${l} L)
    find_library(Xmr_${L}_LIBRARY
        NAMES ${l}
        PATHS ${CMAKE_LIBRARY_PATH}
        PATH_SUFFIXES “/src/${l}” “/src/ringct” “/src/” “/external/db_drivers/lib${l}” “/lib” “/src/crypto” “/contrib/epee/src” “/external/easylogging++/”
        NO_DEFAULT_PATH
        )

set(Xmr_${L}_LIBRARIES ${Xmr_${L}_LIBRARY})

message(STATUS “ Xmr_${L}_LIBRARIES ${Xmr_${L}_LIBRARY}”)
add_library(${l} STATIC IMPORTED)
set_property(TARGET ${l} PROPERTY IMPORTED_LOCATION ${Xmr_${L}_LIBRARIES})
endforeach()
target_link_libraries(${PROJECT_NAME} ${LIBRARIES})

Agora que as bibliotecas foram adicionadas, é hora de desenvolver nosso programa especificamente. A derivação de todas as chaves a partir da chave privada de gasto é uma tarefa comum, necessária para gerar ou restaurar carteiras.

Código Main.cpp

Para compilar o código, acesse o diretório e execute cmake. Se você estiver na pasta raiz do código do tutorial, execute:

$ cd tutorial-5 && cmake .

Os resultados deverão ser semelhantes a:

$ cd tutorial-5 && cmake .
-- The C compiler identification is GNU 6.3.0
-- The CXX compiler identification is GNU 6.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
.....

-- Configuring done
-- Generating done
-- Build files have been written to: /code/tutorial-5

e

$ make
Scanning dependencies of target tutorial-5
[ 50%] Building CXX object CMakeFiles/tutorial-5.dir/main.cpp.o
[100%] Linking CXX executable tutorial-5
[100%] Built target tutorial-5

Se você encontrar algum erro, por favor, primeiro verifique se você possui a versão CMake correta (>= v3.5.2) e GCC (>= v5). O programa CMake irá criar um arquivo makefile para você, depois basta executar o comando abaixo.

Por fim, execute o programa com ./tutorial-5

Private spend key : <f8f2fba1da00643bbf11ffec355a808d2d8ca4e4de14a10476e116abd8dd7f02>
Public spend key : <fffb624bd31dfafb015b01cbeaef28cbff3b2d77af01c54b77d6e1cef04d5f1e>
Private view key : <9227a05c665f684f5b8fef815cedd8a911b426c9fa07554c70daacf87757b302>
Public view key : <d79eaf3acfd1f7a93526d2eec5bec5b76b880177e2610b69716b4f0577950308>
Monero Address: 4BKjy1uVRTPiz4pHyaXXawb82XpzLiowSDd8rEQJGqvN6AD6kWosLQ6VJXW9sghopxXgQSh1RTd54JdvvCRsXiF41xvfeW5