Skip to content

fix: add sender to execute message hash#3896

Merged
skosito merged 7 commits intodevelopfrom
add-sender-to-execute-msg-hash
May 28, 2025
Merged

fix: add sender to execute message hash#3896
skosito merged 7 commits intodevelopfrom
add-sender-to-execute-msg-hash

Conversation

@skosito
Copy link
Member

@skosito skosito commented May 21, 2025

Description

https://github.com/zeta-chain/protocol-private/issues/262

solana PR: zeta-chain/protocol-contracts-solana#111

also adds validation for sender before creation execute msg

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

  • Bug Fixes
    • Improved validation and formatting of sender addresses for Solana message execution, ensuring correct handling based on message type.
    • Enhanced error handling for invalid Solana public key strings to prevent unexpected failures.
  • Tests
    • Updated test cases to reflect new sender address validation and expected hash values.
  • Documentation
    • Added a new entry to the changelog describing the sender field addition to the Solana execute message hash.

@skosito skosito added the SOLANA_TESTS Run make start-solana-test label May 21, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 21, 2025

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

This update introduces conditional validation and formatting of sender addresses based on the execution type for Solana gateway messages. The sender is now handled as either an Ethereum or Solana address depending on context, with explicit validation and normalization. Hash calculation logic and corresponding tests are updated to reflect these changes, and error handling is improved to prevent panics during public key parsing.

Changes

File(s) Change Summary
changelog.md Added a new fix entry describing the inclusion of the sender field in the Solana execute message hash, referencing PR #3896.
pkg/contracts/solana/gateway_message.go Modified Hash() methods for MsgExecute and MsgExecuteSPL to conditionally append sender bytes as Ethereum or Solana addresses based on executeType. No changes to exported/public entity signatures.
pkg/contracts/solana/gateway_message_test.go Updated test cases for hash calculations with new expected values and sender formats. Changed sender in revert tests to Solana public key and adjusted string representation accordingly. No changes to exported/public entity signatures.
zetaclient/chains/solana/signer/execute.go Added validateSender function for sender address validation/formatting based on execution type. Integrated validation into createMsgExecute. One new internal function added.
zetaclient/chains/solana/signer/execute_spl.go Incorporated sender validation into createMsgExecuteSPL via the new validateSender function. Ensures sender is checked and normalized before use. No changes to exported/public entity signatures.
zetaclient/chains/solana/signer/withdraw_spl.go Changed decodeMintAccountDetails to use error-checked Solana public key parsing instead of panic-inducing method, improving robustness and error reporting. No changes to exported/public entity signatures.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Signer
    participant Validator

    Client->>Signer: Request to create MsgExecute/MsgExecuteSPL
    Signer->>Signer: validateSender(sender, executeType)
    alt executeType == Call
        Signer->>Signer: Validate as Ethereum address
    else executeType == Revert
        Signer->>Signer: Validate as Solana public key
    end
    Signer->>Signer: Construct message with validated sender
    Signer->>Validator: Send message for processing
    Validator-->>Signer: Validation/Execution result
    Signer-->>Client: Response
Loading
sequenceDiagram
    participant System
    participant decodeMintAccountDetails

    System->>decodeMintAccountDetails: Provide asset (public key string)
    decodeMintAccountDetails->>decodeMintAccountDetails: Parse asset with error handling
    alt Invalid public key
        decodeMintAccountDetails-->>System: Return error
    else Valid public key
        decodeMintAccountDetails->>decodeMintAccountDetails: Query account info
        decodeMintAccountDetails-->>System: Return account details
    end
Loading

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.

❤️ 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this 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.

@codecov
Copy link

codecov bot commented May 21, 2025

Codecov Report

Attention: Patch coverage is 0% with 28 lines in your changes missing coverage. Please review.

Project coverage is 64.94%. Comparing base (a2ffdb6) to head (0ca0df7).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
zetaclient/chains/solana/signer/execute.go 0.00% 18 Missing ⚠️
zetaclient/chains/solana/signer/execute_spl.go 0.00% 5 Missing ⚠️
zetaclient/chains/solana/signer/withdraw_spl.go 0.00% 5 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #3896      +/-   ##
===========================================
- Coverage    64.99%   64.94%   -0.05%     
===========================================
  Files          470      470              
  Lines        34354    34379      +25     
===========================================
  Hits         22329    22329              
- Misses       10993    11018      +25     
  Partials      1032     1032              
Files with missing lines Coverage Δ
zetaclient/chains/solana/signer/execute_spl.go 0.00% <0.00%> (ø)
zetaclient/chains/solana/signer/withdraw_spl.go 0.00% <0.00%> (ø)
zetaclient/chains/solana/signer/execute.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@skosito skosito marked this pull request as ready for review May 23, 2025 13:31
@skosito skosito requested a review from a team as a code owner May 23, 2025 13:31
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: 3

🧹 Nitpick comments (1)
zetaclient/chains/solana/signer/withdraw_spl.go (1)

160-165: Excellent defensive programming improvement.

The change from MustPublicKeyFromBase58 to PublicKeyFromBase58 with proper error handling prevents potential panics and aligns with robust error handling practices. This ensures the application can gracefully handle invalid public key strings rather than crashing.

Consider adding unit tests to cover the error path when PublicKeyFromBase58 fails:

func TestSigner_decodeMintAccountDetails_InvalidAsset(t *testing.T) {
    signer := &Signer{} // initialize appropriately
    _, err := signer.decodeMintAccountDetails(context.Background(), "invalid-base58")
    require.Error(t, err)
    require.Contains(t, err.Error(), "invalid character")
}
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 160-163: zetaclient/chains/solana/signer/withdraw_spl.go#L160-L163
Added lines #L160 - L163 were not covered by tests


[warning] 165-165: zetaclient/chains/solana/signer/withdraw_spl.go#L165
Added line #L165 was not covered by tests

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b06813 and 0b51192.

⛔ Files ignored due to path filters (1)
  • contrib/localnet/solana/gateway.so is excluded by !**/*.so
📒 Files selected for processing (6)
  • changelog.md (1 hunks)
  • pkg/contracts/solana/gateway_message.go (2 hunks)
  • pkg/contracts/solana/gateway_message_test.go (4 hunks)
  • zetaclient/chains/solana/signer/execute.go (4 hunks)
  • zetaclient/chains/solana/signer/execute_spl.go (2 hunks)
  • zetaclient/chains/solana/signer/withdraw_spl.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.go`: Review the Go code, point out issues relative to principles of clean code, expressiveness, and performance.

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

  • zetaclient/chains/solana/signer/withdraw_spl.go
  • zetaclient/chains/solana/signer/execute_spl.go
  • zetaclient/chains/solana/signer/execute.go
  • pkg/contracts/solana/gateway_message_test.go
  • pkg/contracts/solana/gateway_message.go
🪛 GitHub Check: codecov/patch
zetaclient/chains/solana/signer/withdraw_spl.go

[warning] 160-163: zetaclient/chains/solana/signer/withdraw_spl.go#L160-L163
Added lines #L160 - L163 were not covered by tests


[warning] 165-165: zetaclient/chains/solana/signer/withdraw_spl.go#L165
Added line #L165 was not covered by tests

zetaclient/chains/solana/signer/execute_spl.go

[warning] 98-101: zetaclient/chains/solana/signer/execute_spl.go#L98-L101
Added lines #L98 - L101 were not covered by tests


[warning] 142-142: zetaclient/chains/solana/signer/execute_spl.go#L142
Added line #L142 was not covered by tests

zetaclient/chains/solana/signer/execute.go

[warning] 93-96: zetaclient/chains/solana/signer/execute.go#L93-L96
Added lines #L93 - L96 were not covered by tests


[warning] 111-111: zetaclient/chains/solana/signer/execute.go#L111
Added line #L111 was not covered by tests


[warning] 184-191: zetaclient/chains/solana/signer/execute.go#L184-L191
Added lines #L184 - L191 were not covered by tests


[warning] 195-199: zetaclient/chains/solana/signer/execute.go#L195-L199
Added lines #L195 - L199 were not covered by tests

🔇 Additional comments (5)
changelog.md (1)

52-52: LGTM: Proper changelog documentation.

The changelog entry accurately documents the fix for adding sender to Solana execute message hash and follows the established format.

zetaclient/chains/solana/signer/execute_spl.go (1)

97-102:

Details

❓ Verification inconclusive

Critical sender validation enhancement.

The addition of sender validation before message creation is essential for ensuring address format consistency based on the execute type. This prevents potential issues with incompatible address formats in subsequent processing.

Please verify that the validateSender function properly handles all execute types and provide comprehensive test coverage:

Add unit tests to ensure sender validation works correctly for different execute types:

func TestCreateMsgExecuteSPL_ValidateSender(t *testing.T) {
    tests := []struct {
        name        string
        sender      string
        executeType contracts.ExecuteType
        expectError bool
    }{
        {
            name:        "valid ethereum address for call",
            sender:      "0x42bd6E2ce4CDb2F58Ed0A0E427F011A0645D5E33",
            executeType: contracts.ExecuteTypeCall,
            expectError: false,
        },
        {
            name:        "valid solana address for revert",
            sender:      "CVoPuE3EMu6QptGHLx7mDGb2ZgASJRQ5BcTvmhZNJd8A",
            executeType: contracts.ExecuteTypeRevert,
            expectError: false,
        },
        // Add more test cases
    }
    // Implementation here
}

🏁 Script executed:

#!/bin/bash
# Verify validateSender function implementation and usage
ast-grep --pattern 'func validateSender($_, $_) ($_,  error) {
  $$$
}'

# Check for similar validation in execute.go
rg -A 10 "validateSender.*executeType"

Length of output: 4195


🏁 Script executed:

#!/bin/bash
# Locate ExecuteType definition in the contracts package
rg "type ExecuteType" -R .

# List all ExecuteType constants and their values
rg "ExecuteType.*=" -R .

# Confirm the two known execute types
rg "ExecuteTypeCall" -R .
rg "ExecuteTypeRevert" -R .

Length of output: 1729


Ensure validateSender Covers All ExecuteType Variants

The current validateSender implementation only checks for ExecuteTypeCall (Ethereum) and otherwise treats every other case as a Solana address. If there are additional contracts.ExecuteType constants, they’ll be misrouted to the Solana branch, leading to subtle errors. Please manually verify the complete set of ExecuteType values and, if any beyond ExecuteTypeCall and ExecuteTypeRevert exist, refactor validateSender to use an explicit switch and return an error for unsupported cases.

• validateSender implementation:
zetaclient/chains/solana/signer/execute.go:184–200
• Invocation sites:

  • zetaclient/chains/solana/signer/execute.go
  • zetaclient/chains/solana/signer/execute_spl.go

Also add unit tests covering every ExecuteType (valid and invalid formats, plus unsupported enums), for example:

func TestValidateSender_AllExecuteTypes(t *testing.T) {
    cases := []struct {
        name        string
        sender      string
        executeType contracts.ExecuteType
        wantErr     bool
    }{
        {"ValidCall", "0x...", contracts.ExecuteTypeCall, false},
        {"ValidRevert", "So1anaAddr...", contracts.ExecuteTypeRevert, false},
        {"UnsupportedType", "any", contracts.ExecuteTypeMint, true},
        // …
    }
    // …
}
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 98-101: zetaclient/chains/solana/signer/execute_spl.go#L98-L101
Added lines #L98 - L101 were not covered by tests

pkg/contracts/solana/gateway_message_test.go (2)

158-158:

Details

❓ Verification inconclusive

Sender type consistency for revert operations.

The change from Ethereum addresses to Solana public keys for revert operations and the corresponding string representation method change (.Hex() to .String()) properly aligns with the conditional address handling based on execute type.

Ensure this change maintains compatibility with existing revert operations and that the gateway contract can properly handle both address formats:

Also applies to: 165-165, 183-183, 190-190


🌐 Web query:

What are the implications of changing sender address formats in Solana gateway execute revert operations? How does this affect backward compatibility?

💡 Result:

Based on the search results, there isn't specific information about changing sender address formats in Solana gateway execute revert operations. However, I can provide some insights about revert operations, backward compatibility concerns, and transaction handling in Solana that may be relevant to your query.

Revert Operations in Blockchain Environments

Execution reverts are critical mechanisms in blockchain environments that prevent incorrect transactions from completing. While the search results don't specifically address Solana gateway execute revert operations, they do provide information about EVM execution reverted errors, which might have similar principles.

When smart contracts encounter rule violations, execution reverts occur, functioning as safeguards against incorrect transactions[2]. Common causes include business logic violations, insufficient gas, invalid jumps, stack overflow/underflow, and invalid opcodes[2].

Backward Compatibility Considerations

Backward compatibility is a significant concern when implementing new features or changes in blockchain systems:

  1. Syscall Implementation: The search results indicate that "programs using the new syscall could not be used on Solana version which does not implement this feature. Existing programs that do not use this feature are not impacted at all."[6] This suggests that changes to core functionality like syscalls require feature gates to ensure backward compatibility.

  2. Transaction Version Changes: Solana has implemented versioned transactions to allow additional functionality in the runtime. While changes to onchain programs are not required for compatibility, developers must update client-side code to prevent errors due to different transaction versions[7].

  3. Feature Gating: For significant changes, Solana typically uses feature gates to enable new functionality only when the majority of the cluster runs the required version[6].

Transaction Handling and Error Management

If you're dealing with address format changes that might cause reverts, consider these aspects of Solana's transaction handling:

  1. Preflight Checks: By default, Solana performs preflight checks before submitting transactions, verifying signature validity, blockhash recency, and transaction simulation. Skipping these checks can lead to lost transactions[9].

  2. Retry Logic: Solana allows customizing rebroadcast logic for transactions through the maxRetries parameter, enabling developers to implement their own retry strategies for failed transactions[9].

  3. Re-signing Transactions: When a transaction fails, developers should ensure the initial transaction's blockhash has expired before re-signing to prevent duplicate transactions[9].

Best Practices for Implementation

When implementing changes that might affect address formats or cause reverts:

  1. Testing: Thoroughly test any changes to address formats with both old and new client code to ensure compatibility.

  2. Error Handling: Implement robust error handling that can gracefully manage reverts and provide clear error messages to users.

  3. Documentation: Clearly document any changes to address formats and their potential impact on existing applications.

While the search results don't directly address the implications of changing sender address formats in Solana gateway execute revert operations, these general principles from Solana's development ecosystem should help guide implementation decisions that maintain backward compatibility while enabling new functionality.

Citations:


Validate Sender Format Consistency for Revert Operations

The switch from Ethereum-style hex addresses (.Hex()) to Solana public keys (.String()) in revert tests correctly reflects our multi-chain handling. To ensure backward compatibility and prevent regressions:

• Add or update unit tests exercising both legacy Ethereum and new Solana address formats in revert flows.
• Verify the gateway contract’s revert logic accepts and logs .String()-based public keys without breaking existing clients.
• Confirm downstream consumers (logging, monitoring, client SDKs) handle the new format seamlessly.
• Update documentation to clearly state supported sender formats for revert operations.

Locations to review:

  • pkg/contracts/solana/gateway_message_test.go @ lines 158, 165, 183, 190

111-111:

Details

❓ Verification inconclusive

Hash values updated for execute type changes.

The updated expected hash values reflect the new hash calculation logic that conditionally includes sender information based on execute type.

Verify that the new hash values are computed correctly and align with the gateway contract expectations:

Also applies to: 137-137


🏁 Script executed:

#!/bin/bash
# Check the hash calculation logic in gateway_message.go
ast-grep --pattern 'func ($m *MsgExecute) Hash() [32]byte {
  $$$
}'

ast-grep --pattern 'func ($m *MsgExecuteSPL) Hash() [32]byte {
  $$$
}'

Length of output: 144


To locate the hash‐calculation logic so we can confirm the updated test vectors, let’s dump all Hash() methods and their surrounding types in gateway_message.go:


🏁 Script executed:

#!/bin/bash
# 1. List all Hash() methods returning [32]byte in gateway_message.go
rg -n 'Hash() \[32\]byte' --color=never pkg/contracts/solana/gateway_message.go

# 2. Show context around those method definitions
rg -n 'func.*Hash' --color=never pkg/contracts/solana/gateway_message.go -A5 -B2

# 3. Show MsgExecute type definition
rg -n 'type MsgExecute' --color=never pkg/contracts/solana/gateway_message.go -A5

# 4. Show MsgExecuteSPL type definition
rg -n 'type MsgExecuteSPL' --color=never pkg/contracts/solana/gateway_message.go -A5

Length of output: 2488


To confirm that sender-conditional logic is present, let’s dump the full Hash() implementations for both execute types:


🏁 Script executed:

#!/bin/bash
file="pkg/contracts/solana/gateway_message.go"

# MsgExecute.Hash
start=$(grep -n 'func (msg \*MsgExecute) Hash() \[32\]byte' "$file" | cut -d: -f1)
end_rel=$(tail -n +$start "$file" | grep -n '^}' | head -1 | cut -d: -f1)
end=$((start + end_rel - 1))
echo "=== MsgExecute.Hash() ==="
sed -n "${start},${end}p" "$file"

# MsgExecuteSPL.Hash
start2=$(grep -n 'func (msg \*MsgExecuteSPL) Hash() \[32\]byte' "$file" | cut -d: -f1)
end_rel2=$(tail -n +$start2 "$file" | grep -n '^}' | head -1 | cut -d: -f1)
end2=$((start2 + end_rel2 - 1))
echo "=== MsgExecuteSPL.Hash() ==="
sed -n "${start2},${end2}p" "$file"

Length of output: 2627


Please verify updated Hash() logic for execute messages

The Hash() implementations for both MsgExecute (lines 319–351) and MsgExecuteSPL (lines 632–666) now include conditional branches that choose between InstructionExecute/InstructionExecuteRevert (or their SPL counterparts) and encode the sender via either common.HexToAddress or solana.MustPublicKeyFromBase58 based on executeType. The test file at pkg/contracts/solana/gateway_message_test.go (lines 111 and 137) was updated with new expected hash strings.

• pkg/contracts/solana/gateway_message.go
– MsgExecute.Hash() (lines 319–351)
– MsgExecuteSPL.Hash() (lines 632–666)
• pkg/contracts/solana/gateway_message_test.go
– wantHash at line 111
– wantHash at line 137

Run the full test suite or independently compute the keccak256 of the constructed message bytes for both ExecuteTypeCall and revert flows to confirm those hex strings match the gateway contract’s spec.

zetaclient/chains/solana/signer/execute.go (1)

92-96: Sender validation implementation is correct.

The addition of sender validation based on execute type is a critical security improvement that ensures address format consistency before message creation.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 93-96: zetaclient/chains/solana/signer/execute.go#L93-L96
Added lines #L93 - L96 were not covered by tests

@swift1337 swift1337 self-requested a review May 27, 2025 11:35
@skosito skosito added this pull request to the merge queue May 28, 2025
Merged via the queue into develop with commit ef82b1c May 28, 2025
46 of 47 checks passed
@skosito skosito deleted the add-sender-to-execute-msg-hash branch May 28, 2025 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

SOLANA_TESTS Run make start-solana-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants