Проверка целостности при извлечении данных из Ethereum с помощью тестов Go
В этом руководстве мы рассмотрим, как использовать тесты для обеспечения целостности извлечения данных Ethereum в приложении на Go. Мы будем использовать клиент Go-Ethereum для получения данных о блоках и транзакциях и пакет testify для наших тестов.
Предварительные требования
- Базовое понимание языка программирования Go
- Go, установленный в вашей системе
- Установленный клиент geth (Go-Ethereum)
- Установленный пакет testify (перейдите по ссылке github.com/stretchr/testify)
Настройка проекта
Создайте проект Go:
mkdir ethereum-data-extraction
cd ethereum-data-extraction
go mod init ethereum-data-extraction
Установите зависимости:
go get github.com/ethereum/go-ethereum
go get github.com/stretchr/testify
Код для извлечения данных
Извлечение данных о блоках
Начнем с функции извлечения данных блока:
package blockchain
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
)
type BlockData struct {
Number *big.Int
Hash string
ParentHash string
Nonce uint64
Sha3Uncles string
Miner string
Difficulty *big.Int
ExtraData string
Size uint64
GasLimit uint64
GasUsed uint64
Timestamp uint64
Transactions []string
}
func getClient() (*ethclient.Client, error) {
client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID")
if err != nil {
return nil, err
}
return client, nil
}
func GetBlockData(blockNumber *big.Int) (*BlockData, error) {
client, err := getClient()
if err != nil {
log.Fatal("Failed to get client:", err)
}
block, err := client.BlockByNumber(context.Background(), blockNumber)
if err != nil {
log.Fatalf("Failed to retrieve the block: %v", err)
return nil, err
}
transactionHashes := make([]string, len(block.Body().Transactions))
for i, tx := range block.Body().Transactions {
transactionHashes[i] = tx.Hash().Hex()
}
blockData := &BlockData{
Number: block.Number(),
Hash: block.Hash().Hex(),
ParentHash: block.ParentHash().Hex(),
Nonce: block.Nonce(),
Sha3Uncles: block.UncleHash().Hex(),
Miner: block.Coinbase().Hex(),
Difficulty: block.Difficulty(),
ExtraData: string(block.Extra()),
Size: block.Size(),
GasLimit: block.GasLimit(),
GasUsed: block.GasUsed(),
Timestamp: block.Time(),
Transactions: transactionHashes,
}
return blockData, nil
}
Извлечение данных о транзакциях
Далее мы определим функцию для извлечения данных о транзакциях:
package blockchain
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
type TransactionData struct {
Hash string
Nonce uint64
From string
To string
Value *big.Int
Gas uint64
GasPrice *big.Int
Data string
}
func GetTxData(txHash string) (*TransactionData, error) {
client, err := getClient()
if err != nil {
log.Fatal("Failed to get client:", err)
return nil, err
}
tx, _, err := client.TransactionByHash(context.Background(), common.HexToHash(txHash))
if err != nil {
log.Fatal("Failed to retrieve transaction:", err)
return nil, err
}
sender, err := getTxSender(tx)
if err != nil {
log.Fatalf("Failed to get sender: %v", err)
return nil, err
}
decodedData := decodeTxData(tx.Data())
return &TransactionData{
Hash: tx.Hash().Hex(),
Nonce: tx.Nonce(),
From: sender,
To: tx.To().Hex(),
Value: tx.Value(),
Gas: tx.Gas(),
GasPrice: tx.GasPrice(),
Data: decodedData,
}, nil
}
func getChainId() (*big.Int, error) {
client, err := getClient()
if err != nil {
log.Fatal("Failed to get client:", err)
return big.NewInt(0), err
}
chainId, err := client.NetworkID(context.Background())
if err != nil {
log.Fatal("Failed to get chainId:", err)
return big.NewInt(0), err
}
return chainId, nil
}
func getTxSender(tx *types.Transaction) (string, error) {
chainId, err := getChainId()
if err != nil {
log.Fatal("Failed to get chainId:", err)
return "", err
}
sender, err := types.Sender(types.NewLondonSigner(chainId), tx)
if err != nil {
log.Fatal("Not able to retrieve sender:", err)
return "", err
}
return sender.Hex(), nil
}
func decodeTxData(data []byte) string {
dataHex := common.Bytes2Hex(data)
return dataHex
}
Написание тестов
Теперь давайте напишем тесты для проверки целостности функций извлечения данных:
package blockchain
import (
"fmt"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetBlockData(t *testing.T) {
blockNumber := big.NewInt(20076728)
blockData, err := GetBlockData(blockNumber)
// Use fmt.Sprintf to format the log message
t.Log(fmt.Sprintf("Block Data: \n%+v\nError: \n%v", blockData, err))
assert.Nil(t, err)
assert.NotNil(t, blockData)
}
func TestGetTransactionData(t *testing.T) {
blockNumber := big.NewInt(20076728)
blockData, err := GetBlockData(blockNumber)
assert.Nil(t, err)
assert.NotNil(t, blockData)
if len(blockData.Transactions) > 0 {
tx := blockData.Transactions[0]
txData, err := GetTxData(tx)
// Use fmt.Sprintf to format the log message
t.Log(fmt.Sprintf("Transaction Data: \n%+v\nError: \n%v", txData, err))
assert.Nil(t, err)
assert.NotNil(t, txData)
} else {
t.Skip("No transactions found in the block")
}
}
Запустите тесты, используя следующую команду:
go test -v
Выходные данные:
--- PASS: TestGetBlockData (0.95s)
=== RUN TestGetTransactionData
Current working directory: /mnt/c/github/dfbeat-v2/pkg/blockchain
Current working directory: /mnt/c/github/dfbeat-v2/pkg/blockchain
Current working directory: /mnt/c/github/dfbeat-v2/pkg/blockchain
blockchain_test.go:33: Transaction Data:
&{Hash:0x47e80ad8fa5f3bc94160f7eb1a3357f87b2756190007ab815b1a1890ddb65949 Nonce:249 BlockHash: BlockNumber:0 TransactionIndex:0 From:0x71B8CF59230bb295ade15506efd258eb458056A1 To:0x80a64c6D7f12C47B7c66c5B4E20E72bc1FCd5d9e Value:+50000000000000000 Gas:297438 GasPrice:+81175867687 Data:088890dc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000071b8cf59230bb295ade15506efd258eb458056a1000000000000000000000000000000000000000000000000000000006669c2ac0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f3fd27ffb4712278e6d51d7d526a0ce431d454c5}
Error:
<nil>
--- PASS: TestGetTransactionData (0.56s)
Заключение
В этом руководстве мы показали, как извлекать данные о блоках и транзакциях из блокчейна Ethereum с помощью Go и клиента Go-Ethereum. Мы также рассказали о том, как писать и запускать тесты для обеспечения целостности процесса извлечения данных. Выполнив эти шаги, вы сможете надежно извлекать и проверять данные блокчейна в своих Go-приложениях.