M-I02: normalize input hex addresses#663
Conversation
📝 WalkthroughWalkthroughThis pull request replaces go-ethereum/common hex address validation with a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
pkg/app/app_v1.go (1)
35-37: Wrap normalization error with%wto preserve error chain.Current formatting drops typed error semantics for upstream handling.
♻️ Suggested patch
- return nil, fmt.Errorf("invalid owner wallet address: %v", err) + return nil, fmt.Errorf("invalid owner wallet address: %w", err)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/app/app_v1.go` around lines 35 - 37, The error returned from core.NormalizeHexAddress when assigning app.OwnerWallet should be wrapped using %w to preserve the error chain; update the error return in the block that calls core.NormalizeHexAddress (the assignment to app.OwnerWallet) so the fmt.Errorf uses "%w" and returns the original error (err) instead of "%v", ensuring callers can use errors.Is / errors.As on the wrapped error.clearnode/api/channel_v1/handler.go (1)
92-93: Preserve underlying DB error details in both receiver-state reads.Both branches now lose
err, which makes incident debugging harder.♻️ Suggested patch
- return nil, rpc.Errorf("failed to get last %s user state for transfer receiver with address %s", senderState.Asset, receiverWallet) + return nil, rpc.Errorf("failed to get last %s user state for transfer receiver with address %s: %v", senderState.Asset, receiverWallet, err) ... - return nil, rpc.Errorf("failed to get last %s user state for transfer receiver with address %s", senderState.Asset, receiverWallet) + return nil, rpc.Errorf("failed to get last %s user state for transfer receiver with address %s: %v", senderState.Asset, receiverWallet, err)Also applies to: 109-110
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clearnode/api/channel_v1/handler.go` around lines 92 - 93, The two error-return branches that currently call rpc.Errorf("failed to get last %s user state for transfer receiver with address %s", senderState.Asset, receiverWallet) are dropping the underlying err; update both failing branches (the receiver-state read branches that call rpc.Errorf) to include the original err details in the message (e.g., pass err as an argument or format it into the string) so rpc.Errorf includes the underlying DB error, referencing the existing variables err, senderState.Asset, and receiverWallet in each updated call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clearnode/api/channel_v1/submit_session_key_state.go`:
- Around line 35-45: Normalization of user/session keys via
core.NormalizeHexAddress (used on coreState.UserAddress and
coreState.SessionKey) can cause misses in GetLastChannelSessionKeyVersion(...)
because historical rows may use legacy (non-canonical) keys; add a migration
plan or implement a temporary dual-read reconciliation: when reading last
session version (the code path invoking GetLastChannelSessionKeyVersion),
attempt lookup by the normalized key first and if not found perform a fallback
lookup using the legacy/raw key and reconcile results (or mark for migration),
and when writing persist both canonical and legacy keys or schedule a DB
backfill to update existing rows before switching to normalized-only keys.
Ensure changes are applied around the functions NormalizeHexAddress, the submit
handler (where coreState is normalized), and the GetLastChannelSessionKeyVersion
lookup to avoid forking during rollout.
In `@pkg/core/utils_test.go`:
- Around line 42-45: The "missing_0x_prefix" test currently expects an error for
a non-0x-prefixed address; update the test to accept normalization instead: set
wantErr to false for the "missing_0x_prefix" case and assert that the function
under test returns the normalized form (i.e., the input prefixed with "0x" —
"0x1234567890abcdef1234567890abcdef12345678") or otherwise matches the canonical
normalized value produced by your NormalizeAddress/NormalizeHexAddress helper;
keep the original input and only change the expectation and add the
normalization assertion.
In `@pkg/core/utils.go`:
- Around line 28-43: NormalizeHexAddress currently rejects 40-char hex addresses
without the "0x" prefix; update it to accept and canonicalize those by
lowercasing input, allowing either a 42-char string with "0x" prefix or a
40-char hex string, validating hex characters in either case and returning the
lowercased address with a "0x" prefix; adjust the validation logic in
NormalizeHexAddress to check for len==40 (no prefix) or len==42 with prefix,
validate characters starting at the appropriate index, and return the canonical
"0x"+lowercasedHex string on success.
---
Nitpick comments:
In `@clearnode/api/channel_v1/handler.go`:
- Around line 92-93: The two error-return branches that currently call
rpc.Errorf("failed to get last %s user state for transfer receiver with address
%s", senderState.Asset, receiverWallet) are dropping the underlying err; update
both failing branches (the receiver-state read branches that call rpc.Errorf) to
include the original err details in the message (e.g., pass err as an argument
or format it into the string) so rpc.Errorf includes the underlying DB error,
referencing the existing variables err, senderState.Asset, and receiverWallet in
each updated call.
In `@pkg/app/app_v1.go`:
- Around line 35-37: The error returned from core.NormalizeHexAddress when
assigning app.OwnerWallet should be wrapped using %w to preserve the error
chain; update the error return in the block that calls core.NormalizeHexAddress
(the assignment to app.OwnerWallet) so the fmt.Errorf uses "%w" and returns the
original error (err) instead of "%v", ensuring callers can use errors.Is /
errors.As on the wrapped error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 570d4409-d395-40ff-b255-656f68d044d4
📒 Files selected for processing (7)
clearnode/api/app_session_v1/submit_session_key_state.goclearnode/api/channel_v1/handler.goclearnode/api/channel_v1/request_creation.goclearnode/api/channel_v1/submit_session_key_state.gopkg/app/app_v1.gopkg/core/utils.gopkg/core/utils_test.go
H-H01: fix(contracts): disallow challenge with CLOSE or FIN_MIG intents (#631) H-M01: fix(contracts/ChannelHub): remove transferred amount check (#636) fix(contracts/ChannelHub): allow unblocking escrow ops after migration (#637) M-C01: feat(contracts): add token check between states (#639) H-L03: fix(contracts/ChannelHub): skip disputed escrow during purge (#640) M-H04: feat(contracts/ChannelHub): purge during escrow challenge finalization, count both skip and purge (#641) M-M02: fix(contracts): require zero allocs on close (#643) M-C02: fix(rpc/core): apply finalize escrow deposit correctly (#644) H-L02: fix(contracts/ChannelHub): revert on withdrawFromVault failure (#651) M-H03: fix(clearnode): log correct fields on failure (#647) M-C03: fix(pkg/core): disallow negative amount transitions (#645) H-L01: fix(contracts/ChannelHub): add CH address to prevent val addition replay (#650) M-H06(clearnode): restrict max channel challenge duration (#654) M-M03(clearnode): revert EscrowLock on insufficient home user balance (#655) M-M04(clearnode): support default signer even if it is not approved (#656) M-M05(clearnode): require correct intent on FinalizeEscrowWithdrawal (#657) M-M09: reject asset decimals exceeding its token's decimals (#659) M-L01: return correct errors during state advancement validation (#660) M-L03: limit number of related ids per session key state (#662) M-I02: normalize input hex addresses (#663) M-H01: feat(contracts/ChannelHub): restrict to one node (#649) M-H07: fix(contracts/ChannelHub): emit stored, not arbitrary candidate state (#664) M-I01: feat(contracts/ChannelHub): remove updateLastState flag (#665) H-L06: fix(contracts/ChannelHub): remove payable from methods, clarify in create (#666) H-L09: feat(contracts/ChannelEngine): add non-home migration version check (#669) YNU-839: fix blockchain listener lifecycle (#658) M-H09: use channel signer for all channel state node sigs (#667) H-L07: fix(contracts/ChannelHub): restrict createChannel to non-existing channels (#668) H-I02: docs(contracts): add a note that rebasing tokens are not supported (#670) H-I03: fix(contracts/ChannelHub): use CIE pattern in depositToHub (#671) M-H11: revert empty signatures on quorum verification (#672) M-H11: reject issuance of receiver state during escrow ops (#674) H-I01: docs(contracts): note that fee-on-transfer tokens are not supported (#675) M-L04: docs: mention liquidity monitoring (#677) fix(contracts/ChannelHub): fix initialize escrow deposit dos (#679) M-H08: enforce strict transition ordering after MutualLock and EscrowLock (#680) fix: run forge fmt (#681) M-L05: docs(contracts): document native token deposits (#685) fix(clearnode): resolve a set of audit findings (#686) M-H13: feat(contract): add validateChallengeSignature, revert in SK validator (#688)
Description
The clearnode API accepts wallet addresses without the
0xprefix.common.IsHexAddressvalidates format but accepts both"0xabc123..."(42 chars) and"abc123..."(40 chars) as valid. Both representations decode to the same 20-byte address viacommon.HexToAddress, producing identical channel IDs, signatures, and on-chain behavior — but they are treated as different strings in the database.The signature verification in
ChannelSigValidator.Verify(pkg/core/channel_signer.go:213) compares the recovered address (always"0x..."-prefixed viaEthereumAddress.String()) against the wallet usingstrings.EqualFold. A no-prefix wallet will always fail this comparison, causing the entire database transaction to roll back.However, this is an accidental guard — the rejection happens at signature validation (line 150), not at input sanitization (line 27). The code between those lines (channel ID computation, existing channel lookup, state advancement validation) all execute with a wallet string that doesn't match the database's expected format before the transaction is rolled back.
Summary by CodeRabbit
Bug Fixes
Tests