Desenvolvimento Local

Inicializando um Validador Local

Testar o código do seu programa localmente pode ser muito mais confiável do que testar na devnet e pode ajudá-lo a testar antes de experimentar na devnet.

Você pode configurar seu validador de teste local instalando o conjunto de ferramentas da Solana e executando:

solana-test-validator

Benefícios de usar local-test-validator incluem:

  • Sem limites de taxa de RPC
  • Sem limites de airdrop
  • Implantação direta de programas na cadeia (--bpf-program ...)
  • Clonagem de contas de um cluster público, incluindo programas (--clone ...)
  • Retenção configurável de histórico de transações (--limit-ledger-size ...)
  • Comprimento de época configurável (--slots-per-epoch ...)
  • Pular para um slot arbitrário (--warp-slot ...)

Conectando a Ambientes

Ao trabalhar com desenvolvimento Solana, você precisará se conectar a um ponto de extremidade de API RPC específico. Solana tem 3 ambientes públicos de desenvolvimento:

  • mainnet-beta https://api.mainnet-beta.solana.com
  • devnet https://api.devnet.solana.com
  • testnet https://api.testnet.solana.com
Press </> button to view full source
import { clusterApiUrl, Connection } from "@solana/web3.js";

(async () => {
  const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
})();
from solana.rpc.api import Client

client = Client("https://api.mainnet-beta.solana.com")
#include "solana.hpp"

using namespace many::solana;

int main() {
    Connection connection("https://api.mainnet-beta.solana.com");
    return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;

fn main() {
    let rpc_url = String::from("https://api.mainnet-beta.solana.com");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
}
solana config set --url https://api.mainnet-beta.solana.com

Finalmente, você também pode se conectar a um cluster privado, local ou executado remotamente com o seguinte:

Press </> button to view full source
import { Connection } from "@solana/web3.js";

(async () => {
  // This will connect you to your local validator
  const connection = new Connection("http://127.0.0.1:8899", "confirmed");
})();
from solana.rpc.api import Client

client = Client("http://127.0.0.1:8899")
#include "solana.hpp"

using namespace many::solana;

int main() {
    Connection connection("http://127.0.0.1:8899");
    return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;

fn main() {
    let rpc_url = String::from("http://127.0.0.1:8899");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
}
solana config set --url http://privaterpc.com

Subscrevendo a Eventos

Os websockets fornecem uma interface pub/sub onde você pode ouvir determinados eventos. Em vez de executar um ping em um ponto de extremidade HTTP típico em um intervalo para obter atualizações frequentes, você pode receber essas atualizações apenas quando elas ocorrem.

Connectionopen in new window, uma classe web3 da Solana, gera internamente um ponto de extremidade de websocket e registra um cliente websocket quando você cria uma nova instância Connection (consulte o código-fonte aquiopen in new window).

A classe Connection expõe métodos pub/sub - todos eles começam com on, como emissores de eventos. Quando você chama esses métodos ouvintes, é registrada uma nova assinatura no cliente websocket daquela instância Connection. O exemplo do método pub/sub que usamos abaixo é onAccountChangeopen in new window. O retorno de chamada fornecerá os dados de estado atualizados por meio de argumentos (consulte AccountChangeCallbackopen in new window como exemplo).

Press </> button to view full source
import { clusterApiUrl, Connection, Keypair } from "@solana/web3.js";

(async () => {
  // Establish new connect to devnet - websocket client connected to devnet will also be registered here
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

  // Create a test wallet to listen to
  const wallet = Keypair.generate();

  // Register a callback to listen to the wallet (ws subscription)
  connection.onAccountChange(
    wallet.publicKey(),
    (updatedAccountInfo, context) =>
      console.log("Updated account info: ", updatedAccountInfo),
    "confirmed"
  );
})();
import asyncio
from solders.keypair import Keypair
from solana.rpc.websocket_api import connect

async def main():
    async with connect("wss://api.devnet.solana.com") as websocket:
        # Create a Test Wallet
        wallet = Keypair()
        # Subscribe to the Test wallet to listen for events
        await websocket.account_subscribe(wallet.pubkey())
        # Capture response from account subscription 
        first_resp = await websocket.recv()
        print("Subscription successful with id {}, listening for events \n".format(first_resp.result))
        updated_account_info = await websocket.recv()
        print(updated_account_info)
        
asyncio.run(main())
// clang++ on_account_change.cpp -o on_account_change -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  Connection connection("https://api.devnet.solana.com");

  auto key_pair = Keypair::generate();

  int subscriptionId = connection.on_account_change(key_pair.public_key, [&](Result<Account> result) {
    Account account = result.unwrap();
    std::cout << "owner = " << account.owner.to_base58() << std::endl;
    std::cout << "lamports = " << account.lamports << std::endl;
    std::cout << "data = " << account.data << std::endl;
    std::cout << "executable = " << (account.executable ? "true" : "false") << std::endl;
  });

  sleep(1);

  std::string tx_hash = connection.request_airdrop(key_pair.public_key).unwrap();
  std::cout << "tx hash = " << tx_hash << std::endl;

  for (int i = 0; i < 10; i++) {
    connection.poll();
    sleep(1);
  }

  connection.remove_account_listener(subscriptionId);

  return 0;
}
use solana_client::pubsub_client::PubsubClient;
use solana_client::rpc_config::RpcAccountInfoConfig;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let wallet = Keypair::new();
    let pubkey = Signer::pubkey(&wallet);
    let ws_url = String::from("wss://api.devnet.solana.com/");
    println!("{}", ws_url);
    if let Ok(subscription) = PubsubClient::account_subscribe(
        &ws_url,
        &pubkey,
        Some(RpcAccountInfoConfig {
            encoding: None,
            data_slice: None,
            commitment: Some(CommitmentConfig::confirmed()),
        }),
    ) {
        let (mut ws_client, receiver) = subscription;
        println!("Subscription successful, listening for events");
        let handle = std::thread::spawn(move || loop {
            println!("Waiting for a message");
            match receiver.recv() {
                Ok(message) => println!("{:?}", message),
                Err(err) => {
                    println!("Connection broke with {:}", err);
                    break;
                }
            }
        });
        handle.join().unwrap();
        ws_client.shutdown().unwrap()
    } else {
        println!("Errooooor");
    }
}

Obtendo SOL de Teste

Ao trabalhar localmente, você vai precisar de algum SOL para enviar transações. Em ambientes fora da mainnet, você pode receber SOL por meio de airdrop em seu endereço.

Press </> button to view full source
import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";

(async () => {
  const keypair = Keypair.generate();

  const connection = new Connection("http://127.0.0.1:8899", "confirmed");

  const signature = await connection.requestAirdrop(
    keypair.publicKey,
    LAMPORTS_PER_SOL
  );
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
  await connection.confirmTransaction({
      blockhash,
      lastValidBlockHeight,
      signature
    });
})();
from solders.keypair import Keypair
from solana.rpc.api import Client

wallet = Keypair()

client = Client("https://api.devnet.solana.com")

#Input Airdrop amount in LAMPORTS
client.request_airdrop(wallet.pubkey(), 1000000000)

#Airdrops 1 SOL
// clang++ request_airdrop.cpp -o request_airdrop -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  Connection connection("https://api.devnet.solana.com");

  auto key_pair = Keypair::generate();

  std::string tx_hash = connection.request_airdrop(key_pair.public_key).unwrap();

  std::cout << "tx hash = " << tx_hash << std::endl;

  return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::native_token::LAMPORTS_PER_SOL;
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let wallet = Keypair::new();
    let pubkey = Signer::pubkey(&wallet);
    let rpc_url = String::from("https://api.devnet.solana.com");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
    match client.request_airdrop(&pubkey, LAMPORTS_PER_SOL) {
        Ok(sig) => loop {
            if let Ok(confirmed) = client.confirm_transaction(&sig) {
                if confirmed {
                    println!("Transaction: {} Status: {}", sig, confirmed);
                    break;
                }
            }
        },
        Err(_) => println!("Error requesting airdrop"),
    };
}
solana airdrop 1

# Return
# "1 SOL"

Usando Contas e Programas Da Mainnet

Muitas vezes, os testes locais dependem de programas e contas disponíveis apenas na mainnet. A CLI da Solana permite:

  • Baixar programas e contas
  • Carregar programas e contas em um validador local

Como carregar contas da mainnet

É possível baixar a conta de emissão de token SRM para um arquivo:

Press </> button to view full source
# solana account -u <source cluster> --output <output format> --output-file <destination file name/path> <address of account to fetch>
solana account -u m --output json-compact --output-file SRM_token.json SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt

O carregamento para a sua rede local é feito passando o arquivo da conta e o endereço de destino (no cluster local) ao iniciar o validador:

Press </> button to view full source
# solana-test-validator --account <address to load the account to> <path to account file> --reset
solana-test-validator --account SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt SRM_token.json --reset

Como carregar programas da mainnet

Da mesma forma, é possível baixar o programa Serum Dex v3:

Press </> button to view full source
# solana program dump -u <source cluster> <address of account to fetch> <destination file name/path>
solana program dump -u m 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so

O carregamento para a sua rede local é feito passando o arquivo do programa e o endereço de destino (no cluster local) ao iniciar o validador:

Press </> button to view full source
# solana-test-validator --bpf-program <address to load the program to> <path to program file> --reset
solana-test-validator --bpf-program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so --reset
Last Updated:
Contributors: Daniel Cukier