|
cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
|
Ethereum JSON-RPC client implementation (HTTPS). Network bring-up (Wi-Fi, SNTP) lives in net.cpp. More...
#include "eth_rpc.h"#include "eth_json.h"#include "https_post.h"#include <string.h>#include <strings.h>#include <stdlib.h>#include <stdio.h>#include <inttypes.h>#include "CW_Utils.h"#include "esp_log.h"Go to the source code of this file.
Macros | |
| #define | RESP_BUF_SIZE 1024U |
| #define | HEX_PER_BYTE 2U |
| #define | RESP_LOG_MAX 80 |
| #define | NONCE_MAX 0xFFFFFFFFULL |
| #define | RESULT_STR_MAX 80U |
Functions | |
| static bool | do_post (const char *body, char *resp_buf, size_t resp_buf_size) |
| POST a JSON-RPC body to the configured endpoint over HTTPS. | |
| static char | hex_nibble (uint8_t n) |
| Convert a nibble value to its lowercase ASCII hex digit. | |
| static void | bytes_to_hex (const uint8_t *data, size_t len, char *out) |
| Hex-encode a byte buffer (lowercase, no prefix, no NUL). | |
| void | eth_rpc_init (const char *rpc_url, const char *from_addr) |
| Set the RPC URL and the from-address used for nonce queries and ecrecover comparison. | |
| bool | eth_rpc_set_from (const char *addr) |
| Replace the from-address — the account a sale spends from. | |
| void | eth_rpc_set_auth (const char *project_id, const char *api_secret) |
| Optional: set Infura-style HTTP Basic Auth credentials. | |
| void | eth_rpc_set_ca_cert (const char *ca_pem) |
| Optional: pin the RPC endpoint's TLS certificate. | |
| bool | eth_rpc_get_nonce (uint64_t *nonce_out) |
| Fetch the confirmed transaction count (nonce) for from_addr. | |
| static const char * | from_no_prefix (void) |
| The configured from-address with any "0x" prefix removed. | |
| bool | eth_rpc_get_balance (uint64_t *wei_out) |
| Fetch the native balance of from_addr, in wei. | |
| bool | eth_rpc_get_token_balance (const char *token_addr, uint64_t *units_out) |
Fetch from_addr's balance of an ERC-20, via balanceOf over eth_call. | |
| bool | eth_rpc_send_raw_tx (const uint8_t *tx, size_t tx_len, char *tx_hash_out, size_t tx_hash_max, char *err_out, size_t err_max) |
| Broadcast a raw signed transaction (type-prefixed RLP bytes). | |
| bool | eth_rpc_get_token_decimals (const char *token_addr, uint64_t *dec_out) |
Read an ERC-20 contract's decimals(). | |
| bool | eth_rpc_err_already_known (const char *node_err) |
| true if a broadcast error message means the node already HAS this transaction ("already known", "known transaction") — i.e. an earlier attempt whose answer was lost got through. | |
| eth_rpc_receipt_result_t | eth_rpc_get_tx_receipt (const eth_receipt_expect_t *want) |
| Poll the receipt of a broadcast transaction (one shot). | |
Variables | |
| static const char *const | TAG = "eth_rpc" |
| static const char * | s_rpc_url = NULL |
| static const char * | s_from_addr = NULL |
| static const char * | s_project_id = NULL |
| static const char * | s_api_secret = NULL |
| static const char * | s_ca_cert = NULL |
| static char | s_from_buf [43] |
Ethereum JSON-RPC client implementation (HTTPS). Network bring-up (Wi-Fi, SNTP) lives in net.cpp.
Definition in file eth_rpc.cpp.
| #define HEX_PER_BYTE 2U |
Definition at line 39 of file eth_rpc.cpp.
Referenced by bytes_to_hex(), and eth_rpc_send_raw_tx().
| #define NONCE_MAX 0xFFFFFFFFULL |
Definition at line 47 of file eth_rpc.cpp.
Referenced by eth_rpc_get_nonce().
| #define RESP_BUF_SIZE 1024U |
Definition at line 36 of file eth_rpc.cpp.
Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_send_raw_tx(), tron_rpc_broadcast(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), tron_rpc_get_balance(), tron_rpc_get_energy(), tron_rpc_get_receipt(), tron_rpc_get_trc20_balance(), and tron_rpc_get_trc20_decimals().
| #define RESP_LOG_MAX 80 |
Definition at line 43 of file eth_rpc.cpp.
Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_get_tx_receipt(), eth_rpc_send_raw_tx(), https_post_json(), tron_rpc_broadcast(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), tron_rpc_get_balance(), tron_rpc_get_energy(), tron_rpc_get_trc20_balance(), and tron_rpc_get_trc20_decimals().
| #define RESULT_STR_MAX 80U |
Definition at line 50 of file eth_rpc.cpp.
Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), and eth_rpc_send_raw_tx().
|
static |
Hex-encode a byte buffer (lowercase, no prefix, no NUL).
| [in] | data | Input bytes. |
| [in] | len | Number of input bytes. |
| [out] | out | Output buffer of at least 2*len chars; not NUL-terminated. |
Definition at line 106 of file eth_rpc.cpp.
References hex_nibble(), and HEX_PER_BYTE.
Referenced by eth_rpc_send_raw_tx().
|
static |
POST a JSON-RPC body to the configured endpoint over HTTPS.
Thin wrapper over https_post_json that supplies this module's endpoint, optional Infura credentials and optional pinned certificate.
| [in] | body | JSON request body (NUL-terminated). |
| [out] | resp_buf | Response buffer, NUL-terminated on return. |
| [in] | resp_buf_size | Capacity of resp_buf. |
Definition at line 77 of file eth_rpc.cpp.
References https_post_json(), s_api_secret, s_ca_cert, s_project_id, and s_rpc_url.
Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_get_tx_receipt(), and eth_rpc_send_raw_tx().
| bool eth_rpc_err_already_known | ( | const char * | node_err | ) |
true if a broadcast error message means the node already HAS this transaction ("already known", "known transaction") — i.e. an earlier attempt whose answer was lost got through.
Definition at line 377 of file eth_rpc.cpp.
Referenced by sign_and_broadcast().
| bool eth_rpc_get_balance | ( | uint64_t * | wei_out | ) |
Fetch the native balance of from_addr, in wei.
For the pre-flight check that refuses a sale the payer cannot fund before the customer is asked for anything — see evm_balance_ok in main.cpp. Without it the first news of an empty account is the node's refusal after the PIN, the tap and the signature.
Saturating at UINT64_MAX (see eth_json_hex_quantity): 20 ETH does not fit a uint64 of wei, and over-reporting can only fail to refuse.
| [out] | wei_out | Balance on success; untouched on failure. |
Definition at line 212 of file eth_rpc.cpp.
References do_post(), eth_json_hex_quantity(), eth_json_result_string(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.
Referenced by evm_balance_ok().
| bool eth_rpc_get_nonce | ( | uint64_t * | nonce_out | ) |
Fetch the confirmed transaction count (nonce) for from_addr.
"latest", not "pending": a sale whose broadcast answer was lost may still be in the mempool, and a retry must REPLACE it (same nonce, only one can land) rather than queue behind it as a second payment.
Responses with an HTTP status other than 200, malformed JSON, or a nonce above 2^32-1 are rejected.
| [out] | nonce_out | Nonce on success; untouched on failure. |
Definition at line 157 of file eth_rpc.cpp.
References do_post(), eth_json_result_string(), NONCE_MAX, RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.
Referenced by pos_boot(), and sign_and_broadcast().
| bool eth_rpc_get_token_balance | ( | const char * | token_addr, |
| uint64_t * | units_out ) |
Fetch from_addr's balance of an ERC-20, via balanceOf over eth_call.
The token half of the same check, and the one that saves more: a transfer of more tokens than the account holds is not refused by the node at all. It is broadcast, mined, reverted, and charged for — so the customer waits through the whole confirmation only to be declined, and pays the gas for the privilege.
Saturating, like eth_rpc_get_balance.
| [in] | token_addr | "0x..."-prefixed contract address to call. |
| [out] | units_out | Balance in the token's base units on success; untouched on failure. |
Definition at line 239 of file eth_rpc.cpp.
References do_post(), eth_json_hex_quantity(), eth_json_result_string(), from_no_prefix(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.
Referenced by evm_balance_ok().
| bool eth_rpc_get_token_decimals | ( | const char * | token_addr, |
| uint64_t * | dec_out ) |
Read an ERC-20 contract's decimals().
Every amount this terminal signs is in 6-decimal base units, so a contract with any other precision would be charged the wrong sum — 10^12 too little for an 18-decimal token. Checked before such a contract can be accepted.
| [in] | token_addr | "0x"-prefixed contract address. |
| [out] | dec_out | decimals() on success; untouched on failure. |
Definition at line 354 of file eth_rpc.cpp.
References do_post(), eth_json_hex_quantity(), eth_json_result_string(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, and TAG.
Referenced by token_decimals_ok().
| eth_rpc_receipt_result_t eth_rpc_get_tx_receipt | ( | const eth_receipt_expect_t * | want | ) |
Poll the receipt of a broadcast transaction (one shot).
Calls eth_getTransactionReceipt. A broadcast acceptance only means the tx entered the mempool — a POS must wait for the mined receipt (status 0x1) before declaring the payment approved.
| [in] | want | What the receipt must show (see eth_json.h); its tx_hash is the hash computed on the device, not the node's answer to the broadcast. |
| ETH_RPC_RECEIPT_PENDING | Not mined yet — poll again later. |
| ETH_RPC_RECEIPT_SUCCESS | Mined, execution succeeded, and it is our transfer. |
| ETH_RPC_RECEIPT_REVERTED | Mined but reverted — funds NOT moved. |
| ETH_RPC_RECEIPT_RPC_ERROR | Transport/parse error (may be transient). |
| ETH_RPC_RECEIPT_MISMATCH | A receipt that is not our payment. |
Definition at line 385 of file eth_rpc.cpp.
References do_post(), eth_json_receipt_check(), ETH_JSON_RECEIPT_ERROR, ETH_JSON_RECEIPT_MISMATCH, ETH_JSON_RECEIPT_PENDING, ETH_JSON_RECEIPT_REVERTED, ETH_JSON_RECEIPT_SUCCESS, ETH_RPC_RECEIPT_MISMATCH, ETH_RPC_RECEIPT_PENDING, ETH_RPC_RECEIPT_REVERTED, ETH_RPC_RECEIPT_RPC_ERROR, ETH_RPC_RECEIPT_SUCCESS, RESP_LOG_MAX, TAG, and eth_receipt_expect_t::tx_hash.
Referenced by settle_inflight().
| void eth_rpc_init | ( | const char * | rpc_url, |
| const char * | from_addr ) |
Set the RPC URL and the from-address used for nonce queries and ecrecover comparison.
Must be called before any other eth_rpc_* function.
Lifetime: the module stores the pointers as-is (no copy). Both strings must outlive every eth_rpc_* call — pass string literals or static storage, never stack buffers.
| [in] | rpc_url | HTTPS JSON-RPC endpoint URL. |
| [in] | from_addr | "0x..."-prefixed 40-hex-char sender address. |
Definition at line 122 of file eth_rpc.cpp.
References s_from_addr, and s_rpc_url.
Referenced by eth_rpc_select_for().
| bool eth_rpc_send_raw_tx | ( | const uint8_t * | tx, |
| size_t | tx_len, | ||
| char * | tx_hash_out, | ||
| size_t | tx_hash_max, | ||
| char * | err_out, | ||
| size_t | err_max ) |
Broadcast a raw signed transaction (type-prefixed RLP bytes).
| [in] | tx | Signed transaction bytes. |
| [in] | tx_len | Length of tx in bytes. |
| [out] | tx_hash_out | "0x..."-prefixed tx hash on success; must be at least 68 bytes (2 + 64 + NUL). |
| [in] | tx_hash_max | Capacity of tx_hash_out. |
| [out] | err_out | On failure, the node's own error.message when it sent one ("insufficient funds for gas * price +
value", "nonce too low", …), truncated to fit; set to "" when the failure was a transport or parse error with no message to report. May be NULL. |
| [in] | err_max | Capacity of err_out. |
tx_hash_out. Definition at line 286 of file eth_rpc.cpp.
References bytes_to_hex(), do_post(), eth_json_error_message(), eth_json_result_string(), HEX_PER_BYTE, ok(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, and TAG.
Referenced by sign_and_broadcast().
| void eth_rpc_set_auth | ( | const char * | project_id, |
| const char * | api_secret ) |
Optional: set Infura-style HTTP Basic Auth credentials.
Same lifetime contract as eth_rpc_init: pointers are stored, not copied.
| [in] | project_id | Username (Infura project ID); NULL/empty disables auth. |
| [in] | api_secret | Password (Infura API secret); NULL/empty disables auth. |
Definition at line 146 of file eth_rpc.cpp.
References s_api_secret, and s_project_id.
Referenced by eth_rpc_select_for().
| void eth_rpc_set_ca_cert | ( | const char * | ca_pem | ) |
Optional: pin the RPC endpoint's TLS certificate.
When set, the HTTPS connection is validated only against this PEM (leaf or its issuing CA) instead of the full Mozilla CA bundle, so no unrelated CA can MITM the RPC traffic. Pointer stored as-is (must outlive every call — pass a static/embedded literal). NULL keeps the CA bundle.
| [in] | ca_pem | NUL-terminated PEM certificate, or NULL for the bundle. |
Definition at line 152 of file eth_rpc.cpp.
References s_ca_cert.
Referenced by eth_rpc_select_for().
| bool eth_rpc_set_from | ( | const char * | addr | ) |
Replace the from-address — the account a sale spends from.
The payer is the card on the reader, so it is not known until somebody taps. eth_rpc_init's from_addr is only the boot-time default (the config.h literal, used for the startup reachability probe); this is the per-tap override, and everything that reads the sender — the nonce, the balance, the ecrecover comparison — follows it.
Unlike every other setter in this header the string is copied, because its caller derives it into a stack buffer inside one sale.
| [in] | addr | "0x"-prefixed, 40 hex characters. A malformed one is refused rather than silently leaving the previous payer in force — the next nonce would otherwise be somebody else's. |
Definition at line 133 of file eth_rpc.cpp.
References s_from_addr, and s_from_buf.
Referenced by sign_and_broadcast().
|
static |
The configured from-address with any "0x" prefix removed.
Both callers below want the bare 40 characters — one to compare against what ecrecover returned, the other to pad into an ABI argument.
Definition at line 203 of file eth_rpc.cpp.
References s_from_addr.
Referenced by eth_rpc_get_token_balance().
|
static |
Convert a nibble value to its lowercase ASCII hex digit.
| [in] | n | Nibble value; only the range 0–15 is meaningful. |
Definition at line 93 of file eth_rpc.cpp.
Referenced by bytes_to_hex().
|
static |
Definition at line 59 of file eth_rpc.cpp.
Referenced by do_post(), and eth_rpc_set_auth().
|
static |
Definition at line 60 of file eth_rpc.cpp.
Referenced by do_post(), eth_rpc_set_ca_cert(), tron_post(), and tron_rpc_set_ca_cert().
|
static |
Definition at line 57 of file eth_rpc.cpp.
Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_init(), eth_rpc_set_from(), and from_no_prefix().
|
static |
Definition at line 131 of file eth_rpc.cpp.
Referenced by eth_rpc_set_from().
|
static |
Definition at line 58 of file eth_rpc.cpp.
Referenced by do_post(), and eth_rpc_set_auth().
|
static |
Definition at line 56 of file eth_rpc.cpp.
Referenced by do_post(), and eth_rpc_init().
|
static |
Definition at line 33 of file eth_rpc.cpp.
Referenced by app_main(), auth_post(), boot_fault(), build_time_floor(), card_fault(), card_post(), card_read_payouts(), clock_corroborated(), clock_post(), dns_task(), dual_get(), dual_set(), eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_get_tx_receipt(), eth_rpc_send_raw_tx(), evm_balance_ok(), fees_post(), https_post_json(), indev_read(), net_ap_start(), net_ap_stop(), net_time_background(), net_time_sync(), net_wifi_connect(), net_wifi_disconnect(), network_post(), nvs_load_ctr(), nvs_store_ctr(), nvs_u32_set(), nvs_u8_set(), on_time_sync(), ota_abort(), ota_begin(), ota_commit(), ota_end(), ota_mark_valid(), ota_post(), ota_write(), pin_fail_text(), pos_boot(), pos_handle_anomaly(), prov_auth_resolve(), prov_propose(), prov_start(), prov_stop(), refuse(), rejoin_cb(), rejoin_schedule(), resolve_evm_payout(), run_wizard(), settings_check_admin_code(), settings_factory_reset(), settings_inflight_save(), settings_set_admin_code(), settings_set_mainnet(), settings_set_touch_cal(), settings_set_wifi(), settings_wipe_if_new_build(), settle_inflight(), sign_and_broadcast(), sign_and_broadcast_tron(), sntp_start(), sync_time(), token_decimals_ok(), token_load(), tron_balance_ok(), tron_post(), tron_rpc_broadcast(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), tron_rpc_get_balance(), tron_rpc_get_energy(), tron_rpc_get_receipt(), tron_rpc_get_trc20_balance(), tron_rpc_get_trc20_decimals(), tx_ctx_from_json(), ui_task(), wifi_event_handler(), wifi_keep_or_drop(), wifi_post(), and wifi_try_saved().