Cùng Khám Phá Các Tính Năng Hay Của Dfuse



Các Trạng Thái Của Một Transaction Ethereum Và Cách Điều Hướng Chúng Bằng Dfuse


Như bài trước thì mình đã làm rõ được các trạng thái trong lifecycle của một transaction và giới thiệu về Dfuse. Hiện dfuse đang hỗ trợ cho 2 nền tảng là Ethereum và EOSIO thì trong bài viết này mình sẽ đi vào cách sử dụng của thằng dfuse trên nền tảng Ethereum.

Tạo tài khoản free

1. đăng ký

Mọi người truy cập đến https://app.dfuse.io để tạo tại khoản

Tại thời điểm viết bài này thì mình không đăng ký (Sign Up) bằng email được có thể là do lỗi tạm thời của nhà phát triển. Ngoài cách đăng ký bình thường thì vẫn có 2 cách Oauth là bằng Google và Github, mình lựa chọn bằng google

Điền các thông tin cần thiết và chọn "Create Account"

Sau khi tạo xong sẽ có giao diện như sau

2. tạo API key

Truy cập https://app.dfuse.io/keys --> chọn "CREATE NEW KEY"

kết quả sẽ như sau

3. Các cách Authentication

Có 2 loại key trong cách sử dụng dfuse:

  • Loại có thể tồn tại lâu API key - sẽ có dạng server_abcdef123123123000000000000000000, từ loại này thì có thể tạo ra được loại key tồn tại thời gian ngắn JWT.
  • Loại tồn tại trong thời gian ngắn JWT - sẽ có dạng như sau:
    eyJhbGciOiJLTVNFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTYxMzI4MjAsImp0aSI6IjQwNWVmOTUxLTAwZTYtNGJmNC1hZWMxLTU0NTU1ZWMzMTUwMiIsImlhdCI6MTU1NjA0NjQyMCwiaXNzIjoiZGZ1c2UuaW8iLCJzdWIiOiJ1aWQ6MHdlbnU2NmUwNzU4OWRhODY4MWNlIiwiYWtpIjoiM2NhYWEzYzA3M2FlZjVkMmYxOGUwNjJmZDkzYzg3YzMzYWIxYzA1YzEzNjI3NjU2OTgzN2Y5NDc5NzZlMjM0YSIsInRpZXIiOiJmcmVlLXYxIiwic3RibGsiOi0zNjAwLCJ2IjoxfQ.000HeTujIuS_LRvvPN6ZRCmtoZqZyV6P1enNBviwK8v7Tf7BLHJIrEpQoEREKSIMdZWPrMQl_OE55yJP0MxUDA
    

Thì từ API key chúng ta có thể lấy được JWT bằng cách tạo request lên https://auth.dfuse.io/v1/auth/issue

    
curl -XPOST \
  -H "Content-Type: application/json" \
  --data '{"api_key":"<API-KEY>"}' \
  "https://auth.dfuse.io/v1/auth/issue"

Response trả về

    
{
  "token":"eyJhbGciOiJLTVNFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTYxMzI4MjAsImp0aSI6IjQwNWVmOTUxLTAwZTYtNGJmNC1hZWMxLTU0NTU1ZWMzMTUwMiIsImlhdCI6MTU1NjA0NjQyMCwiaXNzIjoiZGZ1c2UuaW8iLCJzdWIiOiJ1aWQ6MHdlbnU2NmUwNzU4OWRhODY4MWNlIiwiYWtpIjoiM2NhYWEzYzA3M2FlZjVkMmYxOGUwNjJmZDkzYzg3YzMzYWIxYzA1YzEzNjI3NjU2OTgzN2Y5NDc5NzZlMjM0YSIsInRpZXIiOiJmcmVlLXYxIiwic3RibGsiOi0zNjAwLCJ2IjoxfQ.000HeTujIuS_LRvvPN6ZRCmtoZqZyV6P1enNBviwK8v7Tf7BLHJIrEpQoEREKSIMdZWPrMQl_OE55yJP0MxUDA",
  "expires_at":1556132820
}

Hãy nhớ rằng loại JWT này sẽ có thời gian hết hạn, trường response expires_at ở trên chính là thời gian mà token này hết hạn. Vì vậy trước khi sử dụng chúng ta cần xem lại trường này xem ngày hiện tại đã hết hoặc gần hết chưa để tạo một token mới. Cách đơn giản để xem thời gian hết hạn là sử dụng các trang convert timestamp online here


REST Authentication

Đối với REST API chúng ta có thể set token vào header của request như sau

curl -H "Authorization: Bearer <YOURTOKENHERE>" -u https://mainnet.eos.dfuse.io/v0/state/... [ ... ]

WebSocket Authentication

Con trong websocket thì ta sử dụng như sau

ws wss://mainnet.eos.dfuse.io/v1/stream?token=<YOURTOKENHERE>

Explore ETH thông qua dfuse

Cách tốt nhất để biết dfuse có thể làm được những gì đó chính là hãy dùng thử các tính năng của nó. GraphiQL là một công cụ cho phép bạn có thể viết và thực thi query GraphQL từ browser. Nó thì đã được tích hợp sẵn xác thực JWT ẩn danh nên vấn đề xác thực chúng ta không cần quan tâm, công việc bây giờ là cần tìm hiểu về documented GraphQL schema để có thể viết được các câu query như mong muốn. Cái này thì có hỗ trợ Ctrl+<Space> nha, để truy cập GraphiQL thì bấm vào link ảnh bên dưới.

Dưới đây sẽ là một vài ví dụ

Fetch

  • Get thông tin của transaction bằng mã hash

    {
      transaction(hash: "0x1f73b43dc9c48cc131a931fac7095de9e5eba0c5184ec0c5c5f1f32efa2a6bab") {
        from
        to
        gasPrice(encoding: ETHER)
      }
    }
    

Try it on GraphiQL

  • Get block
      {
        blockByNumber(number: 7280000) {
          hash
          header { parentHash difficulty }
        }
      }
    

Try it on GraphiQL

Stream

  • Stream blocks (sau mỗi 12s sẽ get về một lần)
      subscription{
        blocks(lowBlockNum:-1){
          node{
            number hash
            transactionTraces { edges { node { hash } } }
            uncles { hash }
          }
        }
      }
    

Try it on GraphiQL

  • Stream transactions bằng câu lệnh query

     subscription {
         searchTransactions(indexName: CALLS, query: "-value:0", lowBlockNum: -1) {
            undo cursor
            node {
              block { number }
              matchingCalls { from to value(encoding: ETHER) }
            }
          }
     }
    

Search

Các truy vấn tìm kiếm (hoặc stream data thông qua subscription GraphQL hay paginated phân trang thông qua GraphQL query) thì được xây dựng bằng dfuse Search Query Language. Hãy xem tài liệu tại Ethereum Search Terms Reference để biết danh sách đầy đủ các thuật ngữ sẽ được chấp nhận.

Mọi người có thể truyền các truy vấn tìm kiếm nào vào trực tiếp https://ethq.app hoặc truyền vào các phần tham số của phương thức searchTransaction trong GraphiQL.

Dfuse thì có 2 kiểu indexe riêng biệt là: CALLSLOGS

  • Tìm kiếm các transactions có transfer ETHER( tức là amount khác 0) từ một địa chỉa hoặc đến một địa chỉ nào đó.

    # with indexName = CALLS
    -value:0 (to:0x32be343b94f860124dc4fee278fdcbd38c102d88 OR
              from:0x32be343b94f860124dc4fee278fdcbd38c102d88)
    

Try it on GraphiQL

Try it on ETHQ

  • Tìm kiếm các giao dịch có chứa method transfer(address, uint256) trên token contract ERC-20 đã biết

    # with indexName = CALLS
    method:'transfer(address,uint256)' to:0xdac17f958d2ee523a2206206994597c13d831ec7
    

    Try it on GraphiQL

    Try it on ETHQ

Method cũng có thể được chỉ định với tiền tố 8 bit of hàm băm keccak, ví dụ: method:a9059cbb

  • Tìm kiếm các transaction được ký bởi một địa chỉ nhất định :

    # with indexName = CALLS
    signer:0x59a5208B32e627891C389EbafC644145224006E8
    

    Try it on GraphiQL

    Try it on ETHQ

  • Tìm kiếm các transaction cung cấp đầu vào cho một contract nhất định:

    # with indexName = CALLS
    input.0:0x84ae8708798c74ef8d00f540c4012963955106ff to:0x06012c8cf97bead5deae237070f9587f8e7a266d
    

    Try it on GraphiQL

    Try it on ETHQ

  • Tìm kiếm các giao dịch khớp với một topic cụ thể trong logs của các cuộc gọi đến EVM:

    # with indexName = LOGS
    topic.0:0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
    

    Try it on GraphiQL

  • Tìm kiếm các giao dịch khớp với một đoạn dữ liệu cụ thể (32 byte) trong logs của EVM:

    # with indexName = LOGS
    data.0:0x0000000000000000000000004a220e6096b25eadb88358cb44068a3248254675
    

    Try it on GraphiQL

Bắt đầu nhanh với JavaScript

Bài demo này mình sẽ hướng dẫn trong môi trường node về cách để theo dõi khi có bất kỳ một transaction mới được gửi lên mạng. Dfuse hiện hỗ trợ cho Ethereum là mạng mainnetropsten. Chúng ta có thể test thử 2 mạng này

1. create project

mkdir -p example-dfuse-javascript
cd example-dfuse-javascript
npm init -y

2. get API key Dfuse

Như hướng dẫn get key ở trên mình xin phép không nhắc lại phần này nữa mọi người có thể kéo lên trên và thực hiện tương tự

3. add các thư viện cần thiết

Install package dfuse

npm install @dfuse/client

Trong môi trường nodejs bạn sẽ cần thêm 2 thư viện nữa dó là node-fetch package phục vụ cho request HTTP và ws phục vụ cho connect WebSocket.

npm install node-fetch ws

4. Create the client

Đầu tiên cần tạo một file main để cho ứng dụng có thể chạy. mình sẽ tạo file có tên app.js, sau khi tạo xong sẽ là các import và thiết lập API cho client

// app.js

const { createDfuseClient } = require("@dfuse/client")

const client = createDfuseClient({
  apiKey: process.env.DFUSE_API_KEY,
  network: "mainnet.eth.dfuse.io", // ở đây có thể để là ropsten nếu trong môi trường test
})

Để sử dụng đươc biện môi tường DFUSE_API_KEY như trên chúng ta cần tạo file biến môi trường .env và cài đặt thêm package dotenv

# file .env

# nhớ thay API-KEY của bạn vào đây nha
DFUSE_API_KEY=server_abcdef12345678900000000000 

5. Định nghĩa GraphQL operation

Đầu tiên hãy chúng ta cần định nghĩa GraphQL operation dưới dạng string mà chúng ta sẽ sử dụng để thực hiện subscription GraphQL. Ở đây chúng ta sẽ định nghĩa những thành phần nào mà ta muốn nhận về sau khi đã subscription.

// app.js

...

const operation = `subscription($cursor: String!) {
  searchTransactions(indexName:CALLS, query:"-value:0 type:call", lowBlockNum: -1, cursor: $cursor) {
    undo cursor
    node { hash matchingCalls { from to value(encoding:ETHER) } }
  }
}`

...

Tiếp đến là chúng ta cần subscription GraphQL để stream transfers. Sẽ cần sử dụng đến thao tác searchTransactions với query "-value:0 type:call". Query này có thể hiểu là sẽ nhận về tất cả các transaction gửi lên mạng mà trường value có gá trị khác 0

// app.js

...

async function main() {
  const stream = await client.graphql(operation, (message) => {
    if (message.type === "data") {
      const { undo, cursor, node: { hash, value, matchingCalls }} = message.data.searchTransactions
      matchingCalls.forEach(({ from, to, value }) => {
        console.log(`Transfer ${from} -> ${to} [${value} Ether]${undo ? " REVERTED" : ""}`)
      })

      stream.mark({ cursor })
    }

    if (message.type === "error") {
      console.log("An error occurred", message.errors, message.terminal)
    }

    if (message.type === "complete") {
      console.log("Completed")
    }
  })

  // Nó sẽ đợi đến khi nào srteam hoàn tất hoặc mãi mãi
  await stream.join()
  await client.release()
  
  main().catch((error) => console.log("Unexpected error", error))
}

...

File app.js đầy đủ

global.fetch = require('node-fetch');
global.WebSocket = require('ws');
const dotenv = require('dotenv');
dotenv.config();

const { createDfuseClient } = require('@dfuse/client');

const client = createDfuseClient({
  apiKey: process.env.DFUSE_API_KEY,
  // network: 'ropsten.eth.dfuse.io'
  network: 'mainnet.eth.dfuse.io'
});

const operation = `subscription($cursor: String!) {
    searchTransactions(indexName:CALLS, query:"-value:0 type:call", lowBlockNum: -1, cursor: $cursor) {
      undo cursor
      node { hash matchingCalls { from to value(encoding:ETHER) } }
    }
  }`;

async function main() {
  const stream = await client.graphql(operation, (message) => {
    if (message.type === 'data') {
      const {
        undo,
        cursor,
        node: { hash, value, matchingCalls }
      } = message.data.searchTransactions;
      matchingCalls.forEach(({ from, to, value }) => {
        console.log(`Transfer ${from} -> ${to} [${value} Ether]${undo ? ' REVERTED' : ''}`);
      });

      stream.mark({ cursor });
    }

    if (message.type === 'error') {
      console.log('An error occurred', message.errors, message.terminal);
    }

    if (message.type === 'complete') {
      console.log('Completed');
    }
  });

  await stream.join();
  await client.release();
}

main().catch((error) => console.log('Unexpected error', error));

kết qủa chạy ứng dụng sẽ như sau

Track transaction lifecycle real-time

trong docs của dfuse thì có một mẫu và bài hướng dẫn chi tiết về cách tracking lifecycle của một transaction các bạn có thể đón đọc tại https://docs.dfuse.io/guides/ethereum/tutorials/lifecycle/

Và có thể xem chi tiết code bằng cách clone docs và vào thư mục như đường dẫn bên dưới đây

git clone https://github.com/dfuse-io/docs.git
cd docs/tutorials/eth/lifecycle

Kết luận

Bài viết là những suy nghĩ và những tính năng hay mình chọn lọc được từ docs của dfuse rất mong có thể cho bạn cái nhìn tổng quát và biết cách sử dụng thằng này. Rất vui và hiện gặp lại các bạn trong những bài viết tiếp theo



Nguồn : https://docs.dfuse.io/

All Rights Reserved