解码BSC交易Input Data触发OverflowError问题求助
解决BSC交易Input Data解码时的OverflowError问题
调用BSCScan API获取指定BSC交易的Input Data后,使用eth_abi的decode方法解码address[]和uint256[]类型数据时,触发OverflowError: Python int too large to convert to C ssize_t错误。
原代码
import requests from web3 import Web3 from eth_abi import decode def get_transaction_input_data(tx_hash): apikey = "xxx" url = f"https://api.bscscan.com/api?module=proxy&action=eth_getTransactionByHash&txhash={txhash}&apikey={apikey}" response = requests.get(url) transaction = response.json().get('result', {}) return transaction.get('input', '') input_data = get_transaction_input_data("0xcbf70aa81c21cff3ae91fc95e0ec5b473fbb4d046e898b02cf93830e98fdeb7e") print(f"Input Data: {input_data}") w3 = Web3(Web3.HTTPProvider('https://bsc-dataseed1.binance.org/')) types = ['address[]', 'uint256[]'] decoded_data = decode(types, bytes.fromhex(input_data[2:])) recipients = decoded_data[0] amounts = decoded_data[1] print("Recipients: ", recipients) print("Amounts: ", amounts)
报错信息
File "D:\python\bsc\query.py", line 23, in <module> decoded_data = decode(types, bytes.fromhex(input_data[2:])) File "D:\python\bsc\venv\lib\site-packages\eth_abi\codec.py", line 161, in decode return decoder(stream) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 129, in __call__ return self.decode(stream) File "D:\python\bsc\venv\lib\site-packages\eth_utils\functional.py", line 47, in inner return callback(fn(*args, **kwargs)) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 175, in decode yield decoder(stream) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 129, in __call__ return self.decode(stream) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 146, in decode stream.push_frame(start_pos) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 95, in push_frame self.seek_in_frame(0) File "D:\python\bsc\venv\lib\site-packages\eth_abi\decoding.py", line 84, in seek_in_frame self.seek(self._total_offset + pos, *args, **kwargs) OverflowError: Python int too large to convert to C ssize_t
问题原因
EVM交易的Input Data前4字节是函数签名哈希,用于标识调用的合约函数。原代码仅去掉了0x前缀(input_data[2:]),但保留了函数签名,导致eth_abi将前4字节错误解析为数组长度,得到一个极大的数值,后续计算偏移量时超出了C类型ssize_t的范围,触发溢出错误。
解决方案
方案一:修正解码数据范围
去掉0x前缀和前4字节的函数签名(共10个字符:2个0x字符 + 8个函数签名十六进制字符),仅解码实际参数部分:
import requests from eth_abi import decode def get_transaction_input_data(tx_hash): apikey = "xxx" url = f"https://api.bscscan.com/api?module=proxy&action=eth_getTransactionByHash&txhash={tx_hash}&apikey={apikey}" response = requests.get(url) transaction = response.json().get('result', {}) return transaction.get('input', '') input_data = get_transaction_input_data("0xcbf70aa81c21cff3ae91fc95e0ec5b473fbb4d046e898b02cf93830e98fdeb7e") print(f"Input Data: {input_data}") # 去掉0x前缀和前4字节函数签名,提取实际参数数据 pure_param_data = bytes.fromhex(input_data[10:]) types = ['address[]', 'uint256[]'] decoded_data = decode(types, pure_param_data) recipients = decoded_data[0] amounts = decoded_data[1] print("Recipients: ", recipients) print("Amounts: ", amounts)
方案二:使用Web3的函数解码(推荐)
利用Web3的decode_function_input方法,自动处理函数签名和参数解码,更健壮且不易出错。需要提前获取对应合约的ABI(可从BSCScan的合约页面获取):
import requests from web3 import Web3 def get_transaction_input_data(tx_hash): apikey = "xxx" url = f"https://api.bscscan.com/api?module=proxy&action=eth_getTransactionByHash&txhash={tx_hash}&apikey={apikey}" response = requests.get(url) transaction = response.json().get('result', {}) return transaction.get('input', '') input_data = get_transaction_input_data("0xcbf70aa81c21cff3ae91fc95e0ec5b473fbb4d046e898b02cf93830e98fdeb7e") print(f"Input Data: {input_data}") w3 = Web3(Web3.HTTPProvider('https://bsc-dataseed1.binance.org/')) # 替换为目标合约的实际ABI(这里以multisend函数为例) contract_abi = [ { "inputs": [ {"internalType": "address[]", "name": "_recipients", "type": "address[]"}, {"internalType": "uint256[]", "name": "_amounts", "type": "uint256[]"} ], "name": "multisend", "outputs": [], "stateMutability": "payable", "type": "function" } ] contract = w3.eth.contract(abi=contract_abi) # 自动解码函数签名和参数 function, decoded_params = contract.decode_function_input(input_data) print("Recipients: ", decoded_params['_recipients']) print("Amounts: ", decoded_params['_amounts'])
内容的提问来源于stack exchange,提问作者jdoe
相关产品推荐
相关产品推荐

