函數式程式設計技術解析:使用 Rust 和 Elixir 讀寫乙太坊智慧合約!

Rust 和 Elixir 如何讀取以太坊和其他 EVM 智能合約:函數式編程和區塊鏈

本系列將重點介紹兩種函數式編程語言:Rust&Elixir。本篇分享函數式編程的思想和實踐。

在這篇文章中將展示Elixir&Rust讀取以太坊智能合約的功能。重要的是,該程序不僅在以太坊上工作,而且還在任何支持EVM的區塊鏈上工作,例如,Polkadot上的Moonbeam !

Ethereumex & ExABI

我更喜歡 Elixir 的兩個存儲庫是 Ethereumex:用于以太坊區塊鏈的 Elixir JSON-RPC 客戶端。

ExABI:Solidity的應用程序二進制接口(ABI)描述了如何將二進制數據轉換為Solidity編程語言能夠理解的類型。

ABI 小貼士:

ABI(應用程序二進制接口)是計算機科學中兩個程序模塊之間的接口。

它與API(應用程序接口)非常相似,API是代碼接口的可讀表示形式。ABI定義了用于與二進制合約交互的方法和結構,就像API那樣,只是在更低的層次上。

.abi文件包含了json格式的函數接口和事件的描述。

這是 HelloWorld.sol 的示例 ABI:

[{

"constant": true,

"inputs": [],

"name": "get",

"outputs": [{

"name": "",

"type": "string"

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

}]

Ethereumex 的配置

首先,讓我們將 Ethereumex 添加到 mix.exs 中的 depsand 應用領域!

# mix.exs:

def application do

[

mod: ,

extra_applications: [:logger, :runtime_tools, :ethereumex]

]

end

……

defp deps do

[

{:ethereumex, "~> 0.7.0"}

]

end

然后,在config/config.exs中。將以太坊協議主機參數添加到配置文件中:

# config.exs

config :ethereumex,

url: "http://localhost:8545" # node url

Tx結構

在 Elixir 中顯示

通過代碼很容易理解Elixir中的Struct。

以太坊的tx在Elixir中顯示:

Transaction{

nonce: nonce, # counter to ensure the sequence of txs

gas_price: @gas.price, # gas fee

gas_limit: @gas.limit, # gas gas limit

to: bin_to, # addr in binary

value: 0, # the eth u are going to send

init: <<>>, # bytecode

data: data # the data u are going to send

}

我們剛剛讀取了以太坊中的數據,因此隨機數是沒有用的。只有在我們把數據寫進合約的時候才需要更改隨機數。

eth_call

立即執行一個新的消息調用,而不需要在區塊鏈上創建交易。

參數

Object -交易調用對象

from: DATA, 20 Bytes -(可選)交易發送的地址

to: DATA, 20 Bytes -交易被指向到的地址

gas: QUANTITY -(可選)為交易執行提供的gas整數。eth_call消耗零gas,但某些執行可能需要這個參數

gasPrice: QUANTITY -(可選)每一種付費gas使用的gasPrice的整數

value: QUANTITY -(可選)與該交易一起發送的值的整數

data: DATA -(可選)方法簽名和編碼參數的哈希值

QUANTITY|TAG -整數區塊號,或字符串”latest”, “earliest”或”pending”,參見默認區塊參數

返回

DATA -已執行合約的返回值。

例子

// Request

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[],"id":1}'

// Result

{

"id":1,

"jsonrpc": "2.0",

"result": "0x"

}

gas的機制對新人不友好,所以我們現在可以設置gas_price和gas_limit為一個特定的數字:

@gas %

在 Rust 中顯示

它是 Rust 中的一個類似結構:

/// from: https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/sending-ethereum-transactions-with-rust/

let tx = TransactionRequest {

from: accounts[0],

to: Some(accounts[1]),

gas: None, // gaslimit

gas_price: None,

value: Some(U256::from(10000)),

data: None,

nonce: None,

condition: None

};

現在我們應該處理tx的兩個參數:

to & data。

地址的字符串到二進制

區塊鏈中使用的地址(如0x769699506f972A992fc8950C766F0C7256Df601f)可以在Elixir程序中轉換為二進制:

@spec addr_to_bin(String.t()) :: Binary.t()

def addr_to_bin(addr_str) do

addr_str

|> String.replace("0x", "")

|> Base.decode16!(case: :mixed)

end

智能合約功能到數據

我們希望通過以太坊函數和參數列表的字符串樣式生成數據:

@spec get_data(String.t(), List.t()) :: String.t()

def get_data(func_str, params) do

payload =

func_str

|> ABI.encode(params)

|> Base.encode16(case: :lower)

"0x" <> payload

“以太坊函數的字符串樣式”示例:

@func %{

balance_of: "balanceOf(address)",

token_of_owner_by_index: "tokenOfOwnerByIndex(address, uint256)",

token_uri: "tokenURI(uint256)",

get_evidence_by_key: "getEvidenceByKey(string)",

new_evidence_by_key: "newEvidenceByKey(string, string)",

mint_nft: "mintNft(address, string)",

owner_of: "ownerOf(uint256)"

}

eth函數的字符串樣式抽象為”function_name(param_type1, param_type2,…)”

深入了解encode函數的實現是很好的!

def encode(function_signature, data, data_type \\ :input)

# string type of function to function_selector

# then call encode function again with function_selector

def encode(function_signature, data, data_type) when is_binary(function_signature) do

function_signature

|> Parser.parse!()

|> encode(data, data_type)

end

def encode(%FunctionSelector{} = function_selector, data, data_type) do

TypeEncoder.encode(data, function_selector, data_type)

end

FunctionSelector的結構:

iex(5)> ABI.Parser.parse!("baz(uint8)")

%ABI.FunctionSelector{

function: "baz",

input_names: [],

inputs_indexed: nil,

method_id: nil,

returns: [],

type: nil,

types: [uint: 8]

}

TypeEncoder.encode 的工作是編譯數據,function_selector 和 data_type 轉換為數據。

智能合約響應的翻譯器

在 Elixir 中編寫一個 TypeTransalator 將十六進制數據更改為普通數據用于智能合約的響應是好的:

defmodule Utils.TypeTranslator do

……

def data_to_int(raw) do

raw

|> hex_to_bin()

|> ABI.TypeDecoder.decode_raw([{:uint, 256}])

|> List.first()

end

def data_to_str(raw) do

raw

|> hex_to_bin()

|> ABI.TypeDecoder.decode_raw([:string])

|> List.first()

end

def data_to_addr(raw) do

addr_bin =

raw

|> hex_to_bin()

|> ABI.TypeDecoder.decode_raw([:address])

|> List.first()

"0x" <> Base.encode16(addr_bin, case: :lower)

end

……

end

我們要選擇的函數是基于響應的類型,我們可以在ABI中獲取它:

{

"constant": true,

"inputs": [],

"name": "get",

"outputs": [{

"name": "",

"type": "string" # The response is string!

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

}

Elixir中的調用者

這是最后一步!只要把上面的功能混合在一起,智能合約的數據讀取就可以工作了!

例如:讀取ERC20代幣的余額:

@spec balance_of(String.t(), String.t()) :: Integer.t()

def balance_of(contract_addr, addr_str) do

{:ok, addr_bytes} = TypeTranslator.hex_to_bytes(addr_str)

data = get_data("balanceOf(address)", [addr_bytes])

{:ok, balance_hex} =

Ethereumex.HttpClient.eth_call(%{ # the tx is encapsulated by ethereumex.

data: data,

to: contract_addr

})

TypeTranslator.data_to_int(balance_hex)

end

Rust 中的調用者

最后一個是調用以太坊的例子

extern crate hex;

use hex_literal::hex;

use web3::{

contract::,

types::,

};

#[tokio::main]

async fn main() -> web3::contract::Result<()> {

let _ = env_logger::try_init();

let http = web3::transports::Http::new("https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161")?;

let web3 = web3::Web3::new(http);

let addr_u8 = hex::decode("7Ad11de6d4C3DA366BC929377EE2CaFEcC412A10").expect("Decoding failed");

let addr_h160 = H160::from_slice(&addr_u8);

let contra = Contract::from_json(

web3.eth(),

addr_h160,

include_bytes!("../contracts/hello_world.json"),

)?;

// let acct:[u8; 20] = hex!("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac").into();



let result = contra.query::("get", (), None, Options::default(), None).await?;

println!("{}", result);

Ok(())

}

發文者:鏈站長,轉載請註明出處:https://www.jmb-bio.com/4172.html

讚! (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Previous 2023 年 2 月 28 日 下午 10:12
Next 2023 年 2 月 28 日 下午 10:20

相關文章

  • 未來 Web 應用程式構建展望:探索新的技術方向!

    在未來,我們會怎樣構建 Web 應用程序呢? 如果行業正常發展下去的話,那麼今天我們認為很難、做起來很有價值的事情在明天都會變得很輕松普遍。我想我們會發現很多新的抽象,讓 Google Docs 寫起來也能像今天的普通 Web 應用一樣簡單。 這就引出來一個問題——這些抽象會是什麼樣子?我們今天能發現它們嗎?想要找出答案,一種方法是審視我們在構建 Web 應…

    區塊鏈技術 2023 年 2 月 28 日
  • Solana 技術解析:深入瞭解 Solana 網路的運行原理和特點!

    每個區塊鏈網絡,都有網絡層、共識層、應用層的區分。每個區塊鏈網絡的特性不同,也有事因為在不同的分層里的設計思路不一樣。本文中,我們將整理Solana網絡的運行邏輯,可以通過這些資料了解到為什麼Solana會在以太坊2.0還沒上線的時候,會比以太坊好用。 以太坊的總帳本在1.0鏈上,是由礦工維護的,在2.0里,礦工變成驗證者,驗證者用計算設備建立驗證器代替了原…

    區塊鏈技術 2023 年 2 月 28 日
  • 乙太坊的設計理念詳解:探索乙太坊的發展歷程和設計理念!

    叔塊(uncle blocks)獎勵 GHOST 協議是一項不起的創新,由 Yonatan Sompolinsky 和 Aviv Zohar 在 2013 年 10 月首次提出的。它是解決快速出塊伴生問題的第一個認真嘗試。 GHOST 的用意是解決這樣一個難題:更短的出塊時間(因此確認速度會更快)會導致有更多區塊 “過時” 因而安全性會下降 —— 因為區塊在…

    2023 年 2 月 28 日
  • 不斷進擊的乙太坊:EIP-1559 之後的 EIP-3074

     Ropsten 測試網已于 6 月 24 日上線,區塊高度為 10,499,401。 ▪️ 自部署以來,約有 88,500 個測試網以太坊被燒毀,價值 1.776 億美元。 ▪️ 大約在 Eth3 啟動的同時,價值 2 億美元的 10 萬以太坊已經被存入 Eth3 的質押合約。 備受期待的以太坊改進提案 EIP-1559 最終…

    2023 年 2 月 28 日
  • 區塊鏈數據爬蟲實戰:使用 Python 爬取交易清單資料!

    前言 今天主要分享如何利用爬蟲爬取區塊鏈瀏覽器上的交易列表數據。 原因 dune上沒有bsc鏈上的轉賬明細數據表。Footprint Analytics上現有的bsc_transactions表transfer_type粒度不夠。 環境 python 3.7 數據存儲:mysql 5.7 緩存:redis 6.2.6 開發工具:pycharm 思路 (1)所…

    2023 年 2 月 28 日
每日鏈頭條給你最新幣圈相關資訊!