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

feat: add initial integration (POC) of the axelar-encoding crate #22

Merged
merged 17 commits into from
Jul 2, 2024

Conversation

eloylp
Copy link
Member

@eloylp eloylp commented Jun 10, 2024

Description

Closes https://github.com/eigerco/solana-axelar-internal/issues/317

This implements the axelar-encoding crate in the multisig-prover wasm contract. The current PR is just a POC to share with the team and solve all the possible doubts. Actually it compiles, but there could be some misinterpretations regarding data, specially when we deal with raw bytes.

Some comments were left in order to get early feedback and start discussion.

Note : CI is failing because we are trying to reach the axelar-encoding crate from a private repo. Whenever we are comfortable with the integration/crate public API, we should update the solana-axelar repo with the latest changes from solana-axelar-internal (which is the private fork we are working on because of privacy reasons) that includes the axelar encoding crate. Then change the cargo import to point to the public repo.

Todos

  • Unit tests
  • Documentation
  • Connect epics/issues

Steps to Test

$ cargo test

@eloylp eloylp force-pushed the multisig-prover-new-encode branch from f9cdf08 to 3d98fad Compare June 10, 2024 08:45
@eloylp eloylp force-pushed the multisig-prover-new-encode branch from 3d98fad to 0c3c7cf Compare June 10, 2024 08:45
enc_cc_id,
msg.source_address.to_string(),
msg.destination_chain.to_string(),
msg.destination_address.to_string(),
Copy link
Member Author

Choose a reason for hiding this comment

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

I think we would need to deeper check if this strings representations are really the expected ones in the other end.

Copy link
Member Author

Choose a reason for hiding this comment

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

So all this fields, and it's related types, can be built again from a String representation. So obviously we are doing good here, as we are being agnostic. The decoding part would need know beforehand how to represent the decoded String on respective types. Where is that decoding part ? I am missing something.

Copy link
Member

@roberts-pumpurs roberts-pumpurs Jun 13, 2024

Choose a reason for hiding this comment

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

The decoding part would need know beforehand how to represent the decoded String on respective types. Where is that decoding part ?

Maybe this is a fait point in that the axelar-rkyv-encoding crate should operate on the original router_api::Message types rather than Strings?

I am looking at how the flow goes:

  1. The relayer gets the raw bytes from amplifier API and tries to decode it using a hardcoded decoder [link to code] - in the linked example we're using bcs decoding (will be replaced with rkyv soon).
  2. The messages get bcs decoded (this is our code btw). Looking at the implementation, most of the parameters are just left as bytes and we don't really interact with them. The only parameter that gets interpreted in any way is the destination_address.

When I was working on the "e2e" tests between evm and solana, I was relying on the Pubkey::to_string() implementation when being invoked on the source chain (here's the decoding). iirc Pukey::to_string() is a base58 encoded string.

Where is the issue: We force the origin chain to produce strings of "destination_address" that must be properly parsed by the destination chain / destination relayer.

Solution: nothing we can really do here? Because theoretically its up to the caller on the source chain to properly encode destination_address so that we can parse it. Anyone can call a source gateway and pass destination addresses as hex encoded, binary encoded strings, base58 encoded strings, etc. And we cannot realistically handle this.

And if we want this encoding be generic, then we cannot force it to use base58 encoded strings for ed25519 addresses either. This means that the parsing of the string gets propagated to the relayer.

Unless we step back from this encoding being Solana-agnostic: this encoding is now Solana-specific and all incoming destination_address params must be (base58|hex|something else) encoded strings. Then we can add this enforcement in the encoding library and make this restriction explicit.

Copy link

@tilacog tilacog Jun 13, 2024

Choose a reason for hiding this comment

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

I think we would need to deeper check if this strings representations are really the expected ones in the other end.
[...] The decoding part would need know beforehand how to represent the decoded String on respective types. Where is that decoding part ? I am missing something.

What you are doing here is just transforming the outer types, but the actual work will be performed by rkyv, so we don't need to worry about any manual serialization or deserialization. It's just like serde, where the type system will do all the heavy lifting for us.

Maybe this is a fait point in that the axelar-rkyv-encoding crate should operate on the original router_api::Message types rather than Strings?

The original Axelar/CosmWasm types are all Strings in the end, so I'm not worried about data loss — as long as we don't forget any data point when transforming the types into the ones in axelar-rkyv-encoding.

This means that the parsing of the string gets propagated to the relayer.

True.

Unless we step back from this encoding being Solana-agnostic: this encoding is now Solana-specific and all incoming destination_address params must be (base58|hex|something else) encoded strings.

Well, since we are in control of the final types, we can force the destination_address to be [u8; 32], just like solana_program::pubkey::Pubkey. The fit will be even tighter.

Copy link
Member Author

@eloylp eloylp Jun 13, 2024

Choose a reason for hiding this comment

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

Are the different parts of a same flow (chain scoped, so integration scoped) able to know (by agreement) how to properly handle the data at each stage right ? If yes, i would probably leave the encoding crate chain agnostic.

Copy link

@tilacog tilacog Jun 13, 2024

Choose a reason for hiding this comment

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

So far, the axelar-rkyv-encoding is independent of Solana, and I'll try my best to ensure it stays that way. Importing any Solana dependencies would mean bringing in the whole circus of Solana crates as Amplifier dependencies, and I want to avoid that.

Copy link
Member

Choose a reason for hiding this comment

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

Well, since we are in control of the final types, we can force the destination_address to be [u8; 32], just like solana_program::pubkey::Pubkey. The fit will be even tighter.

The benefits of this:

  • we can directly map the bytes into a public key (this only affects the relayer)
  • there's no evm or cosmos chain compatibility that we'd have to worry about (they use 20 bytes for addresses)

On the other hand the interface for the EVM Gateway expects that the address is already provided as a string rather than raw bytes.

iirc I tried doing exactly this (trying to send raw bytes, then converting them to a String inside Solidity, then sending it to the EVM gateway). But I had major issues with paring the events - the data didn't make sense. I think this is because ethers library generates the interfaces and types for events, and it expects the string parameter to be a valid UTF-8 string - but Solidity does not enforce strings to be utf8 hence the issue in parsing.

I think that we should rather leave the parameter as a String and keep the parsing logic on the relayer - with the assumption that the origin chain always sends base58 encoded to parse string as base58 for Solana. I think its easy to reason with this assumptoin. Even now, every gmp packet is expected to uphold some arbitrary encoding enforced by the destination relayer.

@eloylp eloylp self-assigned this Jun 10, 2024
@eloylp eloylp added the enhancement New feature or request label Jun 10, 2024
@eloylp eloylp changed the title Add initial integration (POC) of the axelar-encoding crate feat: add initial integration (POC) of the axelar-encoding crate Jun 10, 2024
Cargo.toml Outdated Show resolved Hide resolved
// Following 2: We are just moving the bytes around, hoping this conversions match. Not sure if `HexBinary`
// representation will match here with the decoding part.
multisig::key::Signature::EcdsaRecoverable(r) => {
Signature::EcdsaRecoverable(r.as_ref().try_into().unwrap())
Copy link
Member Author

Choose a reason for hiding this comment

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

I need to get rid of unwraps on this code

Copy link
Member Author

Choose a reason for hiding this comment

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

this was fixed at 12c37e1 , although i still think the error handling should ideally provide more details. Propagating errors up in the call stack without references can be confusing when their are shown on an log line.

Copy link
Member

@roberts-pumpurs roberts-pumpurs left a comment

Choose a reason for hiding this comment

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

Great work, I added a few comments, mostly questions rather than suggestions.

Could you also add some encoding unittests to ensure that everything works?

contracts/multisig-prover/src/encoding/mod.rs Outdated Show resolved Hide resolved
contracts/multisig-prover/src/encoding/sol/mod.rs Outdated Show resolved Hide resolved
contracts/multisig-prover/src/encoding/sol/mod.rs Outdated Show resolved Hide resolved
contracts/multisig-prover/src/payload.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
contracts/multisig-prover/src/encoding/sol/mod.rs Outdated Show resolved Hide resolved
contracts/multisig-prover/src/payload.rs Outdated Show resolved Hide resolved
@eloylp
Copy link
Member Author

eloylp commented Jun 11, 2024

Great work, I added a few comments, mostly questions rather than suggestions.

Could you also add some encoding unittests to ensure that everything works?

Thank you @roberts-pumpurs ! Of course, let's add that unit tests 👍

@eloylp eloylp force-pushed the multisig-prover-new-encode branch from 6532d85 to 6ec5af1 Compare June 13, 2024 16:57
@eloylp eloylp changed the base branch from main to solana June 21, 2024 11:00
@eloylp eloylp requested review from tilacog and roberts-pumpurs July 2, 2024 15:14
let enc_weight =
axelar_rkyv_encoding::types::U256::from_le(to_u256_le(signer.weight.u128()));

signers.insert(enc_pubkey, enc_weight);
Copy link
Member Author

Choose a reason for hiding this comment

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

@roberts-pumpurs , @tilacog , please let's ensure this is correct. I am directly using signer.pub_key here, and avoiding a conversion from a String (the keys of the map), assuming they are the same.

@eloylp eloylp marked this pull request as ready for review July 2, 2024 15:17
@roberts-pumpurs roberts-pumpurs merged commit aa9e3ab into solana Jul 2, 2024
1 of 5 checks passed
@eloylp eloylp deleted the multisig-prover-new-encode branch September 4, 2024 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants