Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: look into Solana program log message to determine SPL token withdrawal failure #3231

Closed
wants to merge 8 commits into from

Conversation

ws4charlie
Copy link
Contributor

@ws4charlie ws4charlie commented Nov 28, 2024

Description

This PR is a part of the whole fix to issue: zeta-chain/protocol-contracts-solana#63

  1. Define a constant message MsgWithdrawSPLTokenNonExistentAta which will be emitted from withdraw_spl_token. It is up to @skosito to use whatever message text reasonable for this purpose.
  2. zetaclient looks into log message to determine if the SPL token withdrawal should be failed or not and then post corresponding outbound status to the zetacore to finalize or abort (on failure) the CCTX.

In the gateway program, there are only TWO cases when a withdraw_spl_token tx succeed:

  1. all checks passed, the SPL token gets transferred to recipient ata account successfully.
  2. all checks passed but the SPL token transfer cannot be done due to non-existent recipient ata account.

The gateway program should fail the withdraw_spl_token tx on any other errors: nonce mismatch, wrong signature, message hash mismatch, ata and mint address mismatch, etc.

How Has This Been Tested?

  • Tested CCTX in localnet
  • Tested in development environment
  • Go unit tests
  • Go integration tests
  • Tested via GitHub Actions

Summary by CodeRabbit

Release Notes

  • New Features

    • Added functionality to whitelist SPL tokens on Solana.
    • Enhanced error handling for SPL token withdrawals, including improved logging.
    • Introduced a pprof server for performance profiling.
  • Bug Fixes

    • Resolved issues with unsupported transaction versions for Solana.
    • Fixed retries on failed inbound vote message validation.
  • Refactor

    • Streamlined code structure and maintainability across various components.
  • Tests

    • Expanded test coverage for withdrawal instruction parameters, focusing on error handling.

Copy link
Contributor

coderabbitai bot commented Nov 28, 2024

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces significant updates across multiple components, focusing on enhancing functionalities related to Solana transactions, particularly for SPL token handling. Key changes include the refactoring of the TSS package, improvements in error handling for transaction validations, and the introduction of new methods and constants for better logging and withdrawal instruction management. Additionally, the changelog reflects modifications in tests, structural code improvements, and the removal of outdated features, all aimed at increasing maintainability and operational clarity.

Changes

File Path Change Summary
changelog.md Updated to reflect modifications in tests, refactoring, and fixes, including moving a Bitcoin test, revamping the TSS package, and enhancing error handling for Solana transactions.
src/zetaclient.go Added look_into_solana_program_logs method; updated method signatures for skip_sol_unsupported_tx_version and retry_inbound_vote_validation to do_not_retry_inbound_vote_validation.
pkg/contracts/solana/instruction.go Introduced constants for SPL token withdrawal messages; added Failed method in various structs; modified ParseInstructionWithdraw and added ParseInstructionWithdrawSPL for better instruction handling.
pkg/contracts/solana/instruction_test.go Added Test_WithdrawSPLInstructionParams_Failed to validate the Failed method in WithdrawSPLInstructionParams, enhancing test coverage for withdrawal scenarios.
zetaclient/chains/solana/observer/outbound.go Updated logic in VoteOutboundIfConfirmed to evaluate transaction status based on log messages; streamlined nonce verification in CheckFinalizedTx; modified ParseGatewayInstruction to handle additional instruction types.
zetaclient/chains/solana/observer/outbound_test.go Updated error message assertion in Test_ParseInstructionWithdrawSPL for clarity regarding instruction types, maintaining overall test structure and logic.

Possibly related PRs

Suggested reviewers

  • fbac
  • skosito
  • kingpinXD
  • brewmaster012
  • lumtis
  • swift1337

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

!!!WARNING!!!
nosec detected in the following files: pkg/contracts/solana/instruction.go

Be very careful about using #nosec in code. It can be a quick way to suppress security warnings and move forward with development, it should be employed with caution. Suppressing warnings with #nosec can hide potentially serious vulnerabilities. Only use #nosec when you're absolutely certain that the security issue is either a false positive or has been mitigated in another way.

Only suppress a single rule (or a specific set of rules) within a section of code, while continuing to scan for other problems. To do this, you can list the rule(s) to be suppressed within the #nosec annotation, e.g: /* #nosec G401 */ or //#nosec G201 G202 G203
Broad #nosec annotations should be avoided, as they can hide other vulnerabilities. The CI will block you from merging this PR until you remove #nosec annotations that do not target specific rules.

Pay extra attention to the way #nosec is being used in the files listed above.

@github-actions github-actions bot added the nosec label Nov 28, 2024
@ws4charlie ws4charlie added SOLANA_TESTS Run make start-solana-test chain:solana zetaclient Issues related to ZetaClient audit Fixes for issues found in audit and removed nosec audit Fixes for issues found in audit labels Nov 28, 2024
@ws4charlie ws4charlie changed the title fix: look into Solana program log message to determine SPL token failure fix: look into Solana program log message to determine SPL token withdrawal failure Nov 28, 2024
@ws4charlie ws4charlie marked this pull request as ready for review November 28, 2024 03:37
@github-actions github-actions bot added the nosec label Nov 28, 2024
Copy link

codecov bot commented Nov 28, 2024

Codecov Report

Attention: Patch coverage is 62.96296% with 10 lines in your changes missing coverage. Please review.

Project coverage is 61.82%. Comparing base (c7deef5) to head (7b48d66).
Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
pkg/contracts/solana/instruction.go 64.70% 6 Missing ⚠️
zetaclient/chains/solana/observer/outbound.go 33.33% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #3231   +/-   ##
========================================
  Coverage    61.81%   61.82%           
========================================
  Files          431      431           
  Lines        30759    30766    +7     
========================================
+ Hits         19015    19021    +6     
- Misses       10886    10888    +2     
+ Partials       858      857    -1     
Files with missing lines Coverage Δ
zetaclient/chains/solana/signer/signer.go 23.14% <100.00%> (-0.35%) ⬇️
zetaclient/chains/solana/signer/withdraw_spl.go 0.00% <ø> (ø)
zetaclient/chains/solana/observer/outbound.go 25.81% <33.33%> (-1.01%) ⬇️
pkg/contracts/solana/instruction.go 28.23% <64.70%> (+9.66%) ⬆️

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
pkg/contracts/solana/instruction_test.go (1)

83-123: LGTM: Well-structured test with room for enhancement.

The test function follows good practices with table-driven tests and clear scenarios. Consider extracting repeated strings into constants for better maintainability:

 const (
    testSigner = "0xaD32427bA235a8350b7805C1b85147c8ea03F437"
+   testInstructionLog = "Program log: Instruction: WithdrawSPLToken"
 )
zetaclient/chains/solana/observer/outbound.go (2)

Line range hint 338-342: Consider using a constant for instruction count validation

For better maintainability and clarity, consider extracting the expected instruction count to a named constant.

+const expectedInstructionCount = 1
+
 // there should be only one single instruction ('withdraw' or 'withdraw_spl_token' or 'whitelist_spl_mint')
-if len(tx.Message.Instructions) != 1 {
-    return nil, fmt.Errorf("want 1 instruction, got %d", len(tx.Message.Instructions))
+if len(tx.Message.Instructions) != expectedInstructionCount {
+    return nil, fmt.Errorf("want %d instruction(s), got %d", expectedInstructionCount, len(tx.Message.Instructions))
 }

Line range hint 355-365: Consider adding exhaustive coin type validation

While the switch statement handles known coin types, it would be beneficial to validate that all possible coin types are explicitly handled during development.

Consider creating a test that verifies all CoinType enum values are handled:

func TestParseGatewayInstructionHandlesAllCoinTypes(t *testing.T) {
    // Get all CoinType values using reflection
    coinTypeType := reflect.TypeOf((*coin.CoinType)(nil)).Elem()
    for i := 0; i < coinTypeType.NumField(); i++ {
        field := coinTypeType.Field(i)
        if !field.IsExported() {
            continue
        }
        coinType := coin.CoinType(field.Tag.Get("protobuf_val"))
        
        // Verify each coin type is handled in the switch
        switch coinType {
        case coin.CoinType_Gas, coin.CoinType_Cmd, coin.CoinType_ERC20:
            // handled
        default:
            t.Errorf("CoinType %s is not handled in ParseGatewayInstruction", coinType)
        }
    }
}
zetaclient/chains/solana/observer/outbound_test.go (2)

510-510: LGTM! Consider adding more test cases.

The error message update improves clarity by specifically mentioning "withdraw_spl_token instruction". While the current test coverage is good, consider adding these test cases:

  1. Test with invalid decimals
  2. Test with maximum token amount
  3. Test with zero token amount

Line range hint 1-511: Document test data management.

The test file loads data from TestDataDir but its path and format aren't documented. Consider:

  1. Adding a package-level comment describing the test data structure
  2. Documenting the expected format of archived transaction results
  3. Including instructions for generating new test data
pkg/contracts/solana/instruction.go (2)

123-126: Implement unit tests for 'WithdrawInstructionParams.Failed' method

The Failed method for WithdrawInstructionParams currently always returns false. To ensure future robustness, consider adding unit tests to validate this behavior.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 124-125: pkg/contracts/solana/instruction.go#L124-L125
Added lines #L124 - L125 were not covered by tests


Line range hint 200-216: Add unit tests for 'ParseInstructionWithdrawSPL' function

To increase code reliability, implement unit tests that cover successful parsing and error handling of the ParseInstructionWithdrawSPL function.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 203-203: pkg/contracts/solana/instruction.go#L203
Added line #L203 was not covered by tests


[warning] 212-212: pkg/contracts/solana/instruction.go#L212
Added line #L212 was not covered by tests

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 08ff881 and 632ee11.

📒 Files selected for processing (5)
  • changelog.md (1 hunks)
  • pkg/contracts/solana/instruction.go (7 hunks)
  • pkg/contracts/solana/instruction_test.go (2 hunks)
  • zetaclient/chains/solana/observer/outbound.go (4 hunks)
  • zetaclient/chains/solana/observer/outbound_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
pkg/contracts/solana/instruction.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

pkg/contracts/solana/instruction_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/solana/observer/outbound.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

zetaclient/chains/solana/observer/outbound_test.go (1)

Pattern **/*.go: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

🪛 GitHub Check: codecov/patch
pkg/contracts/solana/instruction.go

[warning] 124-125: pkg/contracts/solana/instruction.go#L124-L125
Added lines #L124 - L125 were not covered by tests


[warning] 203-203: pkg/contracts/solana/instruction.go#L203
Added line #L203 was not covered by tests


[warning] 212-212: pkg/contracts/solana/instruction.go#L212
Added line #L212 was not covered by tests


[warning] 269-270: pkg/contracts/solana/instruction.go#L269-L270
Added lines #L269 - L270 were not covered by tests

zetaclient/chains/solana/observer/outbound.go

[warning] 161-161: zetaclient/chains/solana/observer/outbound.go#L161
Added line #L161 was not covered by tests


[warning] 163-165: zetaclient/chains/solana/observer/outbound.go#L163-L165
Added lines #L163 - L165 were not covered by tests

🔇 Additional comments (9)
pkg/contracts/solana/instruction_test.go (1)

4-4: LGTM: Import addition is appropriate.

The fmt package import is correctly added and utilized for string formatting in the test cases.

zetaclient/chains/solana/observer/outbound.go (2)

318-319: LGTM: Simplified nonce verification

The direct comparison improves code readability while maintaining the same functionality.


161-165: ⚠️ Potential issue

Add test coverage for outbound status determination logic

The new logic for determining outbound status based on log messages lacks test coverage. This is a critical path that affects transaction finality.

Let's verify the error handling implementation:

Would you like me to help create comprehensive test cases for this new functionality?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 161-161: zetaclient/chains/solana/observer/outbound.go#L161
Added line #L161 was not covered by tests


[warning] 163-165: zetaclient/chains/solana/observer/outbound.go#L163-L165
Added lines #L163 - L165 were not covered by tests

changelog.md (1)

17-17: LGTM! The changelog entry is well-formatted and accurately describes the change.

The entry follows the established format and clearly describes the purpose of PR #3231, which aligns with the PR objectives.

pkg/contracts/solana/instruction.go (5)

5-6: Verify compatibility of the 'slices' package with the project's Go version

The slices package was introduced in Go 1.21 as part of the standard library. Please ensure that the project's Go version is 1.21 or higher to support this package.


15-22: Log message constants are well-defined and enhance clarity

Defining MsgWithdrawSPLTokenSuccess and MsgWithdrawSPLTokenNonExistentAta as constants improves maintainability and consistency in log message handling.


76-78: Addition of 'Failed' method to 'OutboundInstruction' interface ensures uniform error handling

Including the Failed(logMessages []string) bool method in the OutboundInstruction interface provides a standardized way to determine instruction failure based on log messages.


291-296: Usage of 'containsLogMessage' function enhances log message processing

The containsLogMessage function efficiently checks for substrings within log messages using slices.IndexFunc, improving readability and performance.


188-199: ⚠️ Potential issue

Review the logic in 'WithdrawSPLInstructionParams.Failed' method for correctness and security

The Failed method uses log messages to determine the failure state of a withdraw_spl_token instruction. Ensure that:

  • The logic correctly interprets the presence or absence of success and failure messages.
  • The assumptions about log messages are validated to prevent malicious exploitation.

Consider adding comprehensive unit tests to cover different log scenarios, including cases where both messages are present.

pkg/contracts/solana/instruction_test.go Show resolved Hide resolved
pkg/contracts/solana/instruction.go Outdated Show resolved Hide resolved
Copy link
Contributor

@skosito skosito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me apart from one small comment

also, for completness and clarity, can we please add details in PR description or issue, why is this needed for this type of failure, but not for type of failure for example if wrong nonce or signature is provided, in that case it is just ignored on zetaclient or?

pkg/contracts/solana/instruction.go Outdated Show resolved Hide resolved
@ws4charlie
Copy link
Contributor Author

looks good to me apart from one small comment

also, for completness and clarity, can we please add details in PR description or issue, why is this needed for this type of failure, but not for type of failure for example if wrong nonce or signature is provided, in that case it is just ignored on zetaclient or?

Added more details according to our conversation in the Slack.

@ws4charlie ws4charlie requested a review from skosito November 29, 2024 17:03
e2e/e2etests/e2etests.go Outdated Show resolved Hide resolved
e2e/e2etests/e2etests.go Outdated Show resolved Hide resolved
e2e/e2etests/e2etests.go Outdated Show resolved Hide resolved
e2e/e2etests/test_spl_withdraw_fails_if_no_receiver_ata.go Outdated Show resolved Hide resolved
@ws4charlie ws4charlie requested a review from lumtis December 2, 2024 20:51
@skosito
Copy link
Contributor

skosito commented Dec 3, 2024

fixed here: #3238

@skosito skosito closed this Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
audit Fixes for issues found in audit breaking:cli chain:solana nosec SOLANA_TESTS Run make start-solana-test zetaclient Issues related to ZetaClient
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants