使用 Godot 引擎实现以太坊仪表盘 🛠️✨ 今天我打算分享一个如何使用 Godot 引擎实现以太坊仪表盘的项目。Godot 引擎是一款类 Python 语言开发工具,所见即所得的开发过程非常方便和高效。
本项目的数据获取采用了 Etherscan API 和 JSON-RPC 接口。以下是详细的实现过程和相关代码。
Etherscan 的数据获取 📊 原先我使用 Etherscan API 获取账户数据。Etherscan 提供的 API 非常简单,只需要提供地址和 API Token,就能返回所需的数据,数据以 JSON 格式展示:
request_url = """https://api.etherscan.io/api ?module=account &action=balance &address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae &tag=latest &apikey=YourApiKeyToken"""
返回的 JSON 数据如下所示,其中 result
字段为钱包中的 ETH 数量,单位为 wei:
{ "status" : "1" , "message" : "OK" , "result" : "40891626854930000000000" }
为什么需要更多选择? Etherscan API 对于免费用户每秒只能执行 5 次请求。由于我计划中的仪表盘需要查询的数据量较大,这样的限制使我们无法完全依赖 Etherscan API。为了确保数据的实时性和准确性,我们需要寻找其他数据获取方式。
使用 JSON-RPC 获取数据 🖥️ 好在区块链提供了公共 RPC 节点进行调用。我们可以通过这些节点与区块链交互。由于 Godot 中没有 web3.js
或 web3.py
等替代代码库,因此需要使用 JSON-RPC 请求获取数据。在此项目中,我们使用 Infura 提供的 RPC 节点和 INFURA_PROJECT_ID 进行数据请求。
以下是具体实现:
const INFURA_PROJECT_ID = "YOUR_INFURA_PROJECT_ID" const INFURA_JSONRPC = "https://mainnet.infura.io/v3/" + INFURA_PROJECT_ID var headers = ["Content-Type: application/json"] var payload = { "jsonrpc": 2.0, "method": "", "params": [], "id": 1 } func get_eth_balance(address: String): # 获取以太坊主币金额 var data = Utils.deep_copy(payload) data.method = "eth_getBalance" data.params = [address, "latest"] var payload = JSON.stringify(data) get_eth_balance_request.request_completed.connect(_on_get_eth_balance_request_done) get_eth_balance_request.request(INFURA_JSONRPC, headers, HTTPClient.METHOD_POST, payload)
返回的结果如下,其中 result
字段是余额,但格式为十六进制:
{ "jsonrpc" : "2.0" , "id" : 1 , "result" : "0x417dc47f925afc21b1c3" }
为什么需要自己写转换器? 由于 Godot 原生不支持超大数值计算(超出 2^64-1),我们需要将十六进制格式的余额转换成十进制。
实现十六进制转十进制 🔄 为了处理十六进制格式的余额,我们需要一个转换器,将十六进制字符串转换成十进制:
## 将十六进制字符串转换成十进制,会丢失第 17 位之后的精度 func hex_to_decimal(hex_str: String) -> float: # 移除字符串中的 0x 前缀 if hex_str.begins_with("0x"): hex_str = hex_str.substr(2) # 初始化结果 var result := 0.0 # 从十六进制字符串的最低位(最右边)开始遍历 for i in range(len(hex_str) - 1, -1, -1): # 获取当前十六进制字符对应的十进制值,并使用浮点数来避免整数溢出问题(牺牲精度) var decimal_value = float(hex_str[i].hex_to_int()) # 计算当前位的十进制值乘以16的相应幂次 var loc = len(hex_str) - i - 1 var value = decimal_value * pow(16, loc) # 将计算结果相加 result = result + value return result
通过这种方式,我们可以得到十进制格式的余额。虽然在精度上有些牺牲,但足以满足需求。
赠品 🎁 感谢您阅读到这里,下面附送两个额外的实用函数:
实现 round 函数,到 n 位小数 func round_to_decimals(x: float, digit: int) -> float: return round(x * pow(10.0, digit)) / pow(10.0, digit)
格式化输出可读性更高的数值 ## 将字符串进行格式化输出 ## 输入:8372914982598237298347 18, 6 ## 输出:8,372.91 func format_number(x: float, max_reserve_decimal: int = 6) -> String: # 计算小数点前面有多少位 var digits = len(str(int(x))) # 最少预留两个小数,最多预留 6 个小数。 var reserve_decimal = max(max_reserve_decimal - digits + 1, 2) x = round_to_decimals(x, reserve_decimal) # 格式化输出,加上逗号 var number_string = str(x) var parts = number_string.split(".") var num: String = parts[0] var dec: String = "." + parts[1] var reversed_str = num.reverse() var formatted_str = "" # 每三位插入逗号 for i in range(reversed_str.length()): if i > 0 and i % 3 == 0: formatted_str += "," formatted_str += reversed_str[i] # 再次反转字符串以得到正确顺序 formatted_str = formatted_str.reverse() # 拼接小数部分 formatted_str += dec return formatted_str
总结 🌟 通过本文,我们展示了如何使用 Godot 引擎和 Etherscan API 以及 JSON-RPC 接口来实现一个以太坊仪表盘。希望这些代码和方法对您有所帮助,并激发您在区块链开发中的更多灵感和创意。