Introduction
In this tutorial, we'll walk through how to use tests to ensure the integrity of Ethereum data extraction in a Go application. We'll be using the Go-Ethereum client to retrieve block and transaction data and using the testify package for our tests.
Prerequisites
Project Setup
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
Code for Data Extraction
Block Data Extraction
Let's start with the function to extract block data.
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 }
Transaction Data Extraction
Next, we define the function to extract transaction data.
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 }
Writing Tests
Now, let's write tests to assert the integrity of the data extraction functions.
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") } }
Run the tests using the following command:
go test -v
The output:
--- 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)
Conclusion
In this tutorial, we have demonstrated how to extract block and transaction data from the Ethereum blockchain using Go and the Go-Ethereum client. We also covered how to write and run tests to ensure the integrity of the data extraction process. By following these steps, you can reliably retrieve and verify blockchain data in your Go applications.
The above is the detailed content of Asserting Integrity in Ethereum Data Extraction with Go through tests. For more information, please follow other related articles on the PHP Chinese website!