ESP32 WROOM-32D连接Web3触发core abort()异常求助
ESP32使用web3-arduino库触发abort异常的分析与解决
问题背景
使用web3-arduino库将ESP32 WROOM-32D连接Web3,在Arduino IDE和PlatformIO中测试eth_send示例,设备连接WiFi后触发abort异常,控制台输出:
[SETUP] WAIT 4... [SETUP] WAIT 3... [SETUP] WAIT 2... [SETUP] WAIT 1... .Connected abort() was called at PC 0x40162ff7 on core 1 Backtrace:0x40162ff7:0x3ffb23d00x4008cd21:0x3ffb23f0 0x40091ed1:0x3ffb2410 0x40162ff7:0x3ffb2490 0x4016303e:0x3ffb24b0 0x40154283:0x3ffb24d0 0x40153d92:0x3ffb24f0 0x40155275:0x3ffb2510 0x4015551d:0x3ffb2530 0x400dddef:0x3ffb2560 0x400de337:0x3ffb2580 0x400d293a:0x3ffb2610 0x400d2ada:0x3ffb27f0 0x400e0366:0x3ffb2820
经ESP exception Decoder解码后,关键调用栈片段:
0x400de337: Web3::EthGetTransactionCount(std::__cxx11::basic_string<char, std::allocator<char> > const*) (C:\Program Files (x86)\Arduino\libraries\web3-arduino\src\Web3.cpp line 137 0x400d293a: eth_send_example() at C:\Users\yanna\Documents\Arduino\basic_web3\eth_send/eth_send.ino line 53
异常原因分析
从解码后的栈信息可定位,异常触发在EthGetTransactionCount函数内的字符串拼接操作,根源是代码中多次错误地将C风格字符串/数组强制转换为std::string*类型,导致内存访问非法:
- 初始化
Web3对象时,直接把const char*类型的INFURA_HOST/INFURA_PATH强转为string*,传入的指针并非指向合法的std::string对象 - 调用
EthGetTransactionCount时,将宏定义的C字符串MY_ADDRESS强转为string*,属于非法类型转换 - 后续
Contract初始化、SendTransaction调用中,存在uint8_t[]强转string*的错误,进一步引发内存操作异常
解决方案
修正所有非法类型转换,正确构造std::string对象,修改后的完整代码如下:
#include <WiFi.h> #include <Web3.h> #include <Contract.h> #define USE_SERIAL Serial const char* ssid = "V1A7C"; const char* password = /*<password>*/; #define MY_ADDRESS "0x1b9aE0Be6d87e79b9Bd5A6FcDc67d92F76F6e0F6" #define CONTRACT_ADDRESS "0xDA832c3825A37d693d17D9360d5289B8B2b580f0" #define INFURA_HOST "eth-rinkeby.alchemyapi.io" #define INFURA_PATH "/v2/1yNgxbZKvL4JzOIjnNUywYue0ruh_Fjt" const char PRIVATE_KEY[] = {/*<32 bytes of private key>*/}; // 正确构造std::string对象,避免强制类型转换 Web3 web3(string(INFURA_HOST), string(INFURA_PATH)); void eth_send_example(); void setup() { USE_SERIAL.begin(115200); for(uint8_t t = 4; t > 0; t--) { USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); USE_SERIAL.flush(); delay(1000); } WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(1000); } USE_SERIAL.println("Connected"); eth_send_example(); } void loop() { } void eth_send_example() { // 正确构造Contract对象,传入合法的string Contract contract(&web3, string(CONTRACT_ADDRESS)); // 直接传入PRIVATE_KEY,const char*可隐式转换为uint8_t* contract.SetPrivateKey((uint8_t*)PRIVATE_KEY); // 传入std::string对象,而非强转C字符串 uint32_t nonceVal = (uint32_t)web3.EthGetTransactionCount(string(MY_ADDRESS)); uint32_t gasPriceVal = 141006540; uint32_t gasLimitVal = 3000000; // 用std::string替代uint8_t数组,消除类型不匹配问题 string toStr = CONTRACT_ADDRESS; string valueStr = "0x00"; string func = "mint(uint256)"; string p = contract.SetupContractData(&func, 123); // 传入合法的std::string对象 string result = contract.SendTransaction(nonceVal, gasPriceVal, gasLimitVal, toStr, valueStr, p); Serial.println(result.c_str()); }
关键修改点
- 初始化
Web3时,用string(INFURA_HOST)和string(INFURA_PATH)构造合法的std::string对象,不再强制转换指针 - 调用
EthGetTransactionCount时,传入string(MY_ADDRESS),避免C字符串转string*的非法操作 - 替换
uint8_t[]类型的toStr、valueStr为std::string,消除类型不匹配问题 SendTransaction调用时直接传入std::string对象(若库函数要求指针则传&toStr,优先直接传对象)- 打印
result时用c_str()转换为C风格字符串,适配Serial.println的参数要求
额外注意事项
- 确保PRIVATE_KEY是正确的32字节私钥(无
0x前缀),若带前缀需去掉后再传入 - 注意Rinkeby测试网已废弃,建议切换到Sepolia等活跃测试网,并同步修改节点地址
- ESP32内存有限,若后续仍有内存异常,可尝试增大堆内存或优化字符串操作
内容的提问来源于stack exchange,提问作者Yan Naing Win
相关产品推荐
相关产品推荐

