Hoje vamos ver duas das plataformas de contratos inteligentes mais promissoras do mundo – NEAR Protocol e Solana. Embora o Ethereum ainda domine esse mercado, o fato é que sua falta de escalabilidade e altas taxas forçaram a maioria dos desenvolvedores a procurar alternativas viáveis. Near e Solana emergiram como os dois primeiros colocados.
O que é Solana?
A solana foi fundada em 2017 por Anatoly Yakovenko, que já havia trabalhado na DropBox. Yakovenko, junto com Eric Williams e CTO Greg Fritzgerald, criou Solana para resolver os problemas existentes em Bitcoin e Ethereum. O projeto atraiu investimentos da Multicoin Capital, Foundation Capital, SLOW Capital, CMCC Global, Abstract Ventures e muito mais.
Características da blockchain Solana
- 50.000 transações por segundo e tempo de criação de bloco de 0,4 segundos
- O sistema pode fornecer 28,4 milhões de transações por segundo em uma rede de 40 gigabits.
- Solana usa o algoritmo de consenso Proof-of-History.
Como funciona a Prova de Histórico (PoH)?
Em uma rede descentralizada que se espalha por uma grande área, o consenso é essencial. O Bitcoin usa o consenso de prova de trabalho (PoW – Proof of Work) para cuidar do consenso. Embora o método seja altamente seguro, é difícil não ignorar seu problema mais significativo – a falta de escalabilidade. Não se esqueça que o Bitcoin só pode fazer 7 transações por segundo.
Solana usa prova de história (PoH – Proof of History), em que cria registros históricos para provar que um evento ocorre durante um momento específico no tempo. Aqui estão alguns pontos que você precisa ter em mente:
- O algoritmo usa uma função de atraso verificável de alta frequência que requer um certo número de etapas sequenciais para terminar.
- As transações ou eventos cronometrados na rede serão designados como uma contagem única de hash a, que pode ser verificada publicamente.
- A contagem permite que a rede saiba exatamente quando a transação ou o evento aconteceu.
- Cada nó possui um relógio criptográfico que ajuda a rastrear o tempo da rede e a ordem dos eventos.
Devido ao PoH, a rede Solana suporta 50.000 transações por segundo durante a execução com GPUs.
O que é um Cluster Solana?
Um cluster é um conjunto de computadores de propriedade independente trabalhando juntos e pode ser visto como um sistema singular. As principais características do Cluster são as seguintes:
- Eles ajudam a verificar a saída de programas não confiáveis enviados pelo usuário.
- Mantém um registro de qualquer transação ou evento que um usuário faz.
- Ele rastreia quais computadores fizeram um trabalho significativo para manter a rede funcionando.
- Ele rastreia a posse de ativos do mundo real.
Qual dos seguintes utiliza sharding?
Programação em Solana
Os contratos inteligentes em Solana são escritos em Rust ou C e compilados para bytecode Berkeley Packet Filter (BPF). Como existem mais ferramentas disponíveis, é recomendável que você codifique em Rust. Iniciantes devem codificar seus programas usando o framework Anchor, que simplifica a execução.
Solana tem um modelo de conta exclusivo que é semelhante aos arquivos do sistema operacional Linux. Eles podem conter quaisquer dados arbitrários e também conter metadados sobre como podem ser acessados. Tenha em mente, porém, que as contas têm um tamanho fixo e não podem ser redimensionadas.
O modelo de programação atual da Solana pode forçá-lo a mover a lógica do aplicativo para fora da cadeia ou modificar a funcionalidade para ser ineficiente e limitada pelo tamanho fixo da conta.
Qual das opções a seguir é parte integrante de Solana?
Exemplo de contrato
#![feature(proc_macro_hygiene)] use anchor_lang::prelude::*; use anchor_spl::token::{self, TokenAccount, Transfer}; #[program] pub mod plutocratic_hosting { use super::*; /// Initialize a new contract with initialized content. #[access_control(Initialize::validate(&ctx, nonce))] pub fn initialize( ctx: Context<Initialize>, price: u64, content: String, nonce: u8, ) -> ProgramResult { // Transfer funds to the contract vault. let cpi_accounts = Transfer { from: ctx.accounts.from.to_account_info().clone(), to: ctx.accounts.vault.to_account_info().clone(), authority: ctx.accounts.owner.clone(), }; let cpi_program = ctx.accounts.token_program.clone(); let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); token::transfer(cpi_ctx, price)?; // Initialize the content data. let content_record = &mut ctx.accounts.content; content_record.price = price; content_record.content = content; content_record.nonce = nonce; content_record.owner = *ctx.accounts.owner.to_account_info().key; content_record.vault = *ctx.accounts.vault.to_account_info().key; Ok(()) } /// Purchase content address for new price, if transferring more tokens. #[access_control(check_funds(&ctx.accounts.content, price))] pub fn purchase(ctx: Context<Purchase>, price: u64, content: String) -> ProgramResult { // Transfer funds from contract back to owner. let seeds = &[ ctx.accounts.content.to_account_info().key.as_ref(), &[ctx.accounts.content.nonce], ]; let signer = &[&seeds[..]]; let cpi_accounts = Transfer { from: ctx.accounts.vault.to_account_info().clone(), to: ctx.accounts.owner_token.to_account_info().clone(), authority: ctx.accounts.contract_signer.clone(), }; let cpi_program = ctx.accounts.token_program.clone(); let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer); token::transfer(cpi_ctx, ctx.accounts.content.price)?; // Transfer funds from new owner to contract. let cpi_accounts = Transfer { from: ctx.accounts.new_owner_token.to_account_info().clone(), to: ctx.accounts.vault.to_account_info().clone(), authority: ctx.accounts.new_owner.clone(), }; let cpi_program = ctx.accounts.token_program.clone(); let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); token::transfer(cpi_ctx, price)?; // Overwrite content let content_record = &mut ctx.accounts.content; content_record.price = price; content_record.content = content; content_record.owner = *ctx.accounts.new_owner.to_account_info().key; Ok(()) } } #[account] pub struct ContentRecord { /// Price at which the current content is owned. pub price: u64, /// Content Data. pub content: String, /// Public key of current owner of the content. pub owner: Pubkey, /// Address for token program of funds locked in contract. pub vault: Pubkey, /// Nonce for the content, to create valid program derived addresses. pub nonce: u8, } #[derive(Accounts)] pub struct Initialize<'info> { #[account(init)] content: ProgramAccount<'info, ContentRecord>, #[account(mut, "&vault.owner == contract_signer.key")] vault: CpiAccount<'info, TokenAccount>, /// Program derived address for the contract. contract_signer: AccountInfo<'info>, /// Token account the contract is made from. #[account(mut, has_one = owner)] from: CpiAccount<'info, TokenAccount>, /// Owner of the `from` token account. owner: AccountInfo<'info>, token_program: AccountInfo<'info>, rent: Sysvar<'info, Rent>, } impl<'info> Initialize<'info> { pub fn validate(ctx: &Context<Self>, nonce: u8) -> Result<()> { let signer = Pubkey::create_program_address( &[ ctx.accounts.content.to_account_info().key.as_ref(), &[nonce], ], ctx.program_id, ) .map_err(|_| ErrorCode::InvalidNonce)?; if &signer != ctx.accounts.contract_signer.to_account_info().key { return Err(ErrorCode::InvalidSigner.into()); } Ok(()) } } #[derive(Accounts)] pub struct Purchase<'info> { #[account(mut, has_one = vault)] content: ProgramAccount<'info, ContentRecord>, #[account(mut)] vault: CpiAccount<'info, TokenAccount>, #[account(seeds = [ content.to_account_info().key.as_ref(), &[content.nonce], ])] contract_signer: AccountInfo<'info>, #[account(mut, has_one = owner)] owner_token: CpiAccount<'info, TokenAccount>, #[account(mut)] new_owner_token: CpiAccount<'info, TokenAccount>, #[account(signer)] new_owner: AccountInfo<'info>, owner: AccountInfo<'info>, token_program: AccountInfo<'info>, } fn check_funds(check: &ContentRecord, new_price: u64) -> Result<()> { if check.price >= new_price { return Err(ErrorCode::InsufficientFunds.into()); } Ok(()) } #[error] pub enum ErrorCode { #[msg("The given nonce does not create a valid program derived address.")] InvalidNonce, #[msg("The derived signer does not match that which was given.")] InvalidSigner, #[msg("Insufficient funds provided to purchase route.")] InsufficientFunds, }
O que está acontecendo no contrato?
- Todas as contas a serem acessadas são anotadas na estrutura para cada chamada com #[derive(Accounts)].
- As funções ajudam a inicializar os dados da conta do proprietário inicial e da Compra. Isso permite que qualquer pessoa compre por mais tokens.
- Os dados temporários são passados para os parâmetros da função. Esses parâmetros estão dentro das funções de inicialização e compra. Isso também inclui o Contexto que mantém as contas necessárias para a transação.
- O estado do contrato está localizado na estrutura ContentRecord. Isso é anotado com #[account] para indicar que representa o layout de dados de uma conta.
O que é NEAR Protocol?
Entrando em vigor no verão de 2018, o protocolo foi projetado para criar o ambiente perfeito para aplicativos descentralizados, fornecendo velocidades mais altas, maior rendimento e melhor compatibilidade com outras blockchains. A NEAR possui uma técnica única de Sharding e apresenta um mecanismo de geração de blocos chamado “Doomslug” proposto em 2019. Doomslug permite finalidade prática ou “Doomslug”, garantindo que os blocos sejam finalizados em segundos.
O protocolo NEAR é desenvolvido pelo NEAR Collective, uma comunidade de desenvolvedores e pesquisadores que colaboram na construção do projeto. Alguns recursos importantes da NEAR são:
- NEAR é um sistema fragmentado que permite escalabilidade infinita.
- Um protocolo fácil de usar, a NEAR permite que os desenvolvedores criem aplicativos com facilidade e rapidez.
- NEAR não é uma rede secundária (side chain), mas um protocolo de camada 1.
- Os dApps criados usando a NEAR são executados no topo da camada NEAR subjacente.
O que é o coletivo NEAR (NEAR Collective)?
O Coletivo NEAR inclui organizações individuais e outros colaboradores que trabalham continuamente para melhorar o Protocolo NEAR. O Coletivo trabalha em projetos como escrever o código inicial e implementação para a Rede NEAR. A NEAR é totalmente descentralizada, operando de forma independente e não pode ser desligada ou manipulada, mesmo por quem a construiu.
É uma organização sem fins lucrativos focada na criação de um ecossistema vibrante em torno da blockchain NEAR. Auxilia na coordenação das atividades de governança e desenvolvimento. O NEAR Collective tem vários projetos, sendo a NEAR blockchain apenas um dos vários projetos sob o teto do Coletivo.
Mecanismo de Consenso NEAR
O mecanismo de consenso implementado no NEAR é chamado de Nightshade. Nightshade modela o sistema como uma única blockchain. A lista de todas as transações em cada bloco é dividida em blocos físicos, um bloco por fragmento. Todos os pedaços (chunks) se acumulam em um bloco. Observe que os chunks só podem ser validados por nós que mantêm o estado desse shard.
Falando em validação, um componente chave de NEAR são os validadores. Esses validadores são responsáveis por manter o consenso dentro do protocolo. Os validadores são nós especializados que precisam manter seus servidores online 100% do tempo, mantendo seus sistemas continuamente atualizados.
Aqui estão alguns pontos que você deve ter em mente sobre os validadores de rede.
- A NEAR determina seus validadores de rede a cada nova época, elegendo-os com base em sua participação.
- Os validadores já eleitos são reinscritos por meio de uma nova aposta automática de seus tokens mais as recompensas acumuladas.
- Os validadores potenciais devem ter sua participação acima de um nível determinado dinamicamente.
- Existem dois métodos que um validador pode usar para fortalecer seu staking – comprar os tokens por conta própria ou pedir emprestado por delegação de participação.
- A recompensa que você recebe é diretamente proporcional à sua aposta – quanto maior a quantidade de tokens em staking, mais recompensas.
O consenso é baseado no consenso da cadeia mais pesada. Ou seja, uma vez que um produtor de bloco publica um bloco, ele coleta as assinaturas dos nós validadores. O peso de um bloco é então a aposta cumulativa de todos os signatários cujas assinaturas estão incluídas no bloco. O peso de uma cadeia é a soma dos pesos dos blocos. Além disso, o consenso utiliza um dispositivo de finalidade que introduz condições de corte adicionais para maior segurança da cadeia.
Doomslug” é um mecanismo de geração de blocos de qual protocolo?
Aurora e NEAR Protocol
A Aurora também foi lançada no NEAR Protocol, fornecendo uma Experiência da camada 2 Ethereum. Algumas das maneiras pelas quais a Aurora melhora a NEAR são:
- Ele ajuda a aumentar a taxa de transferência para milhares de transações por segundo.
- Um tempo de finalização de bloco de 2 segundos.
- Crescimento do ecossistema à prova de futuro
- Baixas taxas de transação, que são 1000 vezes mais baixas que o Ethereum.
- Compatibilidade intransigente com Ethereum.
Exemplo de Contrato
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::collections::LookupMap; use near_sdk::{env, near_bindgen, AccountId, Balance, Promise}; #[global_allocator] static ALLOC: near_sdk::wee_alloc::WeeAlloc = near_sdk::wee_alloc::WeeAlloc::INIT; #[derive(BorshDeserialize, BorshSerialize)] pub struct ContentRecord { pub price: Balance, pub content: String, pub owner: AccountId, } #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct ContentTracker { values: LookupMap<String, ContentRecord>, contract_owner: AccountId, } impl Default for ContentTracker { fn default() -> Self { let contract_owner = env::predecessor_account_id(); Self { values: LookupMap::new(b"v".to_vec()), contract_owner, } } } #[near_bindgen] impl ContentTracker { /// Gets content at a given route. pub fn get_route(&self, route: String) -> Option<String> { self.values.get(&route).map(|v| v.content) } /// Purchases a route based on funds sent to the contract. #[payable] pub fn purchase(&mut self, route: String, content: String) { let deposit = env::attached_deposit(); assert!(deposit > 0); if let Some(entry) = self.values.get(&route) { assert!( deposit > entry.price, "Not enough deposit to purchase route, price: {} deposit: {}", entry.price, deposit ); // Refund purchase to existing owner Promise::new(entry.owner).transfer(entry.price); } // Update record for the contract state. self.values.insert( &route, &ContentRecord { price: deposit, content, owner: env::predecessor_account_id(), }, ); } /// Allows owner of the contract withdraw funds. pub fn withdraw(&mut self) { assert_eq!(env::predecessor_account_id(), self.contract_owner); // Send the contract funds to the contract owner Promise::new(self.contract_owner.clone()).transfer(env::account_balance()); } }
O que está acontecendo no contrato?
Então, o que está acontecendo aqui no contrato? Vamos olhar mais de perto.
- O contrato é definido por #[near_bindgen] no ContentTracker, é semelhante a um construtor no Solidity e é chamado quando o contrato é implantado.
- A função de compra é anotada com #[payable].
- O contrato inclui chamadas assíncronas na forma de Promise::new(…).transfer(…); lines.
- A estrutura de dados LookupMap<String, ContentRecord> lida com a pesquisa de valor-chave, que acessa o armazenamento. Isso é igual ao “mapping” do Solidity.
Conclusão
Tanto Solana quanto NEAR Protocol são contratos inteligente brilhantes, plataformas que construíram comunidades altamente ativas. Ambos trazem recursos especiais que ajudam a combater o maior problema que assola o mundo descentralizado – a velocidade. Ambas as plataformas ainda estão crescendo e são muito promissoras.