NEAR Protocol và Solana

12 min read
Near Protocol and Solana
To Share and +4 nLEARNs

Hôm nay, chúng ta cùng xem qua hai trong số các nền tảng hợp đồng thông minh hot nhất hiện tại, đó chính là NEAR Protocol và Solana. Trong khi Ethereum vẫn đang thống trị thị trường này, thực tế là việc thiếu khả năng mở rộng và phí cao đã buộc hầu hết các nhà phát triển phải tìm kiếm các giải pháp thay thế khả thi. NEAR và Solana là hai cái tên đã nổi lên trong thời gian gần đây.

Solana là gì?

Solana được thành lập vào năm 2017 bởi Anatoly Yakovenko, trước đó đã làm việc tại DropBox. Yakovenko, cùng với Eric Williams và CTO Greg Fritzgerald, đã tạo ra Solana để giải quyết các vấn đề hiện có trong Bitcoin và Ethereum. Dự án đã thu hút các quỹ đầu tư hàng đầu như Multicoin Capital, Foundation Capital, SLOW Capital, CMCC Global, Abstract Ventures, v.v.

NEAR Solana

Các tính năng của Solana Blockchain

  • 50,000 giao dịch mỗi giây và thời gian 0,4 giây mỗi block
  • Hệ thống có thể cung cấp 28,4 triệu giao dịch mỗi giây trên mạng lưới 40 gigabit
  • Solana sử dụng thuật toán đồng thuận Proof of History (PoH)

Proof of History (PoH) làm việc như thế nào?

Trong mạng lưới phi tập trung trải rộng trên một khu vực rộng lớn, sự đồng thuận là điều cần thiết. Bitcoin sử dụng cơ chế Proof of Work (PoW) để đạt được sự đồng thuận. Mặc dù phương pháp này có tính bảo mật cao, nhưng khó có thể bỏ qua vấn đề quan trọng nhất của nó, đó là thiếu khả năng mở rộng. Đừng quên rằng Bitcoin chỉ có thể thực hiện 7 giao dịch mỗi giây.

Solana sử dụng Proof of History, trong đó nó tạo ra các bản ghi lịch sử để chứng minh rằng một sự kiện đã xảy ra vào một thời điểm cụ thể. Dưới đây là một số điểm bạn cần lưu ý:

  • Thuật toán sử dụng hàm tần số cao có thể xác minh được độ trễ (Verifiable Delay Function), yêu cầu một số bước tuần tự nhất định để kết thúc.
  • Các giao dịch hoặc sự kiện được thực hiện trong mạng lưới sẽ được chỉ định một số hash (băm) duy nhất, có thể được xác minh công khai.
  • Tính toán cho phép mạng lưới biết chính xác thời điểm giao dịch hoặc sự kiện đã xảy ra.
  • Mỗi node đều có một đồng hồ mật mã giúp theo dõi thời gian trên mạng lưới và thứ tự của các sự kiện.

Nhờ vào PoH, mạng lưới Solana cho phép thực hiện 50,000 giao dịch mỗi giây khi chạy với GPU. 

Solana Cluster là gì?

Là một tập hợp các máy tính sở hữu độc lập làm việc cùng nhau và có thể được xem như một hệ thống đơn lẻ. Các tính năng chính của Cluster như sau:

  • Chúng giúp xác minh đầu ra của các chương trình không đáng tin cậy, do người dùng gửi. 
  • Ghi và lưu lại bất kỳ giao dịch hoặc sự kiện nào mà người dùng thực hiện.
  • Theo dõi những máy tính nào đã làm công việc có ý nghĩa để duy trì cho mạng lưới hoạt động.
  • Theo dõi việc sở hữu các tài sản trong thế giới thực.

Lập trình trong Solana

Các hợp đồng thông minh trong Solana được viết bằng Rust hoặc C và được biên dịch sang bytecode Berkeley Packet Filter (BPF). Vì có nhiều công cụ hơn, bạn nên viết mã bằng Rust. Người mới bắt đầu nên viết chương trình của họ bằng Anchor framework, giúp đơn giản hóa việc thực thi.

Solana có một mô hình tài khoản duy nhất tương tự như các tệp trong hệ điều hành Linux. Chúng có thể chứa bất kỳ dữ liệu tùy ý nào và cũng chứa siêu dữ liệu về cách chúng có thể được truy cập. Tuy nhiên, hãy nhớ rằng các tài khoản có kích thước cố định và không thể thay đổi kích thước. 

Mô hình lập trình hiện tại của Solana có thể buộc bạn phải di chuyển logic ứng dụng ra khỏi chuỗi hoặc sửa đổi chức năng không hiệu quả và bị giới hạn bởi kích thước tài khoản cố định. 

Mẫu hợp đồng thông minh

#![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,
}

Điều gì đang xảy ra trong hợp đồng?

  • Tất cả các tài khoản được truy cập đều được chú thích trong cấu trúc cho mỗi lệnh gọi với #[derive(Accounts)]. 
  • Các chức năng giúp khởi tạo dữ liệu tài khoản cho chủ sở hữu ban đầu và mua hàng. Điều này cho phép bất kỳ ai mua nó sẽ có thêm token.
  • Dữ liệu tạm thời được chuyển vào các tham số của hàm. Các tham số này nằm bên trong các chức năng khởi tạo và mua hàng. Điều này cũng bao gồm bối cảnh nắm giữ các tài khoản yêu cầu cho giao dịch.
  • Trạng thái của hợp đồng nằm trong cấu trúc ContentRecord. Điều này được chú thích thêm với #[account] để biết rằng nó đại diện cho bố cục dữ liệu cho một tài khoản.

NEAR Protocol là gì?

Ra đời vào mùa hè năm 2018, giao thức được thiết kế để tạo ra môi trường hoàn hảo cho các ứng dụng phi tập trung bằng cách cung cấp tốc độ cao hơn, thông lượng cao hơn và khả năng tương thích tốt hơn với các chuỗi khác. NEAR có một kỹ thuật Sharding độc đáo và giới thiệu một cơ chế tạo khối được gọi là “Doomslug” được đề xuất vào năm 2019. Doomslug cho phép tính cuối cùng thực tế (“Doomslug” finality), đảm bảo rằng các khối nhận được tính chính thức trong vài giây.

NEAR Protocol được phát triển bởi NEAR Collective, một cộng đồng các nhà phát triển và nhà nghiên cứu hợp tác xây dựng dự án. Một số đặc điểm nổi bật của NEAR là:

  • NEAR là một hệ thống phân mảnh (sharded), cho phép khả năng mở rộng vô hạn. 
  • Một giao thức dễ sử dụng, NEAR cho phép các nhà phát triển xây dựng ứng dụng một cách dễ dàng và nhanh chóng. 
  • NEAR không phải là một side chain mà là một giao thức Layer 1. 
  • dApps được tạo bằng cách sử dụng NEAR chạy trên nền là lớp NEAR bên dưới.

NEAR Collective là gì? 

NEAR Collective bao gồm các tổ chức cá nhân và những người đóng góp khác đang liên tục làm việc để phát triển và cải thiện NEAR Protocol. Collective làm việc trên các dự án như viết code ban đầu và triển khai cho mạng lưới NEAR. NEAR hoàn toàn phi tập trung, hoạt động độc lập và không thể bị tắt hoặc thao túng, ngay cả bởi những người đã xây dựng nó.

Đây là một tổ chức phi lợi nhuận tập trung vào việc tạo ra một hệ sinh thái sôi động xung quanh NEAR Blockchain. Nó giúp điều phối các hoạt động quản trị và phát triển. NEAR Collective có một số dự án, với NEAR Blockchain chỉ là một trong số các dự án dưới sự bảo trợ của tập thể.

Cơ chế đồng thuận trên NEAR

Cơ chế đồng thuận được thực hiện trên NEAR được gọi là Nightshade. Nightshade mô hình hóa hệ thống như một chuỗi khối duy nhất. Danh sách tất cả các giao dịch trong mỗi khối được chia thành các phần vật lý, một phần cho mỗi phân đoạn. Tất cả các khối tích lũy thành một khối. Lưu ý rằng các phân đoạn chỉ có thể được xác thực bởi các node duy trì trạng thái của phân đoạn đó.

Nói về xác thực (validator), một thành phần quan trọng của NEAR là các validator. Các validator này chịu trách nhiệm duy trì sự đồng thuận trong giao thức. Validator là các node chuyên biệt cần giữ máy chủ của họ trực tuyến 100% thời gian trong khi giữ cho hệ thống của họ được cập nhật liên tục. 

Dưới đây là một số điểm cần lưu ý về các validator mạng lưới:

  • NEAR xác định các validator của mình ở mỗi epoch mới, lựa chọn dựa trên số tiền mà họ stake.
  • Các validator đã được chọn sẽ được đăng ký lại bằng cách tự động re-staking token của họ cộng với phần thưởng đã tích lũy.
  • Các validator tiềm năng phải được stake trên một mức được xác định cụ thể.
  • Có hai phương pháp mà validator có thể sử dụng để củng cố việc stake của họ là mua token của chính họ hoặc vay thông qua stake ủy quyền.
  • Phần thưởng bạn nhận được tỷ lệ thuận với tiền đã stake của bạn — stake càng nhiều, phần thưởng của bạn càng nhiều.

Đồng thuận dựa trên sự đồng thuận dây chuyền trên chuỗi. Có nghĩa là, khi một nhà sản xuất khối tạo ra một khối, họ sẽ thu thập chữ ký của các validator node. Trọng lượng của một khối sau đó là số tiền tích lũy của tất cả những người ký có chữ ký được bao gồm trong khối. Trọng lượng của một chuỗi là tổng trọng lượng của khối. Ngoài ra, sự đồng thuận sử dụng một tiện ích cuối cùng đưa ra các điều kiện cắt giảm bổ sung để bảo mật chuỗi cao hơn.

Aurora và NEAR Protocol

Aurora cũng đã ra mắt trên NEAR Protocol, cung cấp trải nghiệm Ethereum Layer 2. Một số điểm mà Aurora giúp cải thiện NEAR là:

  • Giúp tăng thông lượng lên hàng nghìn giao dịch mỗi giây.
  • Thời gian hoàn thành khối là 2 giây.
  • Tăng trưởng hệ sinh thái trong tương lai.
  • Phí giao dịch thấp, thấp hơn 1,000 lần so với Ethereum.
  • Khả năng tương thích hoàn hảo với Ethereum.

Mẫu hợp đồng thông minh

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());
    }
}

Điều gì đang xảy ra trong hợp đồng?

Những gì đang xảy ra ở đây trong hợp đồng trên? Chúng ta hãy xem xét kỹ hơn.

  • Hợp đồng được xác định bởi #[near_bindgen] trong ContentTracker, nó tương tự như một phương thức khởi tạo trong Solidity và được gọi khi hợp đồng được triển khai.
  • Chức năng mua hàng được chú thích bằng #[payable].
  • Hợp đồng bao gồm các lệnh gọi không đồng bộ dưới dạng Promise::new(…).transfer(…); lines.
  • Cấu trúc dữ liệu LookupMap<String, ContentRecord> xử lý tra cứu key-value, truy cập bộ nhớ. Điều này tương đương với Solidity “mapping.”

Kết luận

Cả Solana và NEAR Protocol đều là những nền tảng hợp đồng thông minh tuyệt vời, được xây dựng bởi những cộng đồng tích cực. Cả hai đều mang lại những tính năng đặc biệt giúp giải quyết các vấn đề lớn nhất đang gây ra cho thế giới phi tập trung đó chính là tốc độ. Cả hai nền tảng vẫn đang phát triển và hứa hẹn sẽ mở rộng trong tương lai.

186
Scroll to Top