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

Move Polkadot implementation to Rust #3857

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft

Move Polkadot implementation to Rust #3857

wants to merge 18 commits into from

Conversation

doom
Copy link
Contributor

@doom doom commented May 27, 2024

Description

How to test

Types of changes

Checklist

  • Create pull request as draft initially, unless its complete.
  • Add tests to cover changes as needed.
  • Update documentation as needed.
  • If there is a related Issue, mention it in the description.

If you're adding a new blockchain

  • I have read the guidelines for adding a new blockchain.

Copy link
Collaborator

@satoshiotomakan satoshiotomakan left a comment

Choose a reason for hiding this comment

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

Review№1: ss58 address review

rust/tw_ss58_address/Cargo.toml Outdated Show resolved Hide resolved
rust/tw_ss58_address/src/lib.rs Outdated Show resolved Hide resolved
vec![network as u8]
},
_ => {
let first = ((network & 0b0000_0000_1111_1100) as u8) >> 2;
Copy link
Collaborator

Choose a reason for hiding this comment

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

These magic values can be declared as const globally

rust/tw_ss58_address/src/lib.rs Outdated Show resolved Hide resolved

let bytes = match key {
PublicKey::Ed25519(k) => k.as_slice(),
_ => return Err(AddressError::InvalidInput),
Copy link
Collaborator

Choose a reason for hiding this comment

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

AddressError::PublicKeyTypeMismatch suits here too.
Also, personally I prefer to take a strict public key type in the address implementation, so tw_keypair::ed25519::sha512::PublicKey, and do the tw::PublicKey -> tw_keypair::ed25519::sha512::PublicKey conversion in entry.rs implementation.
For example,

let public_key = public_key
.to_secp256k1()
.ok_or(AddressError::PublicKeyTypeMismatch)?;
Ok(GreenfieldAddress::with_secp256k1_pubkey(public_key))

address: &str,
_prefix: Option<Self::AddressPrefix>,
) -> AddressResult<Self::Address> {
PolkadotAddress::from_str(address)?.with_network_check()
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should allow to verify Kusama, Acala and other addresses via the Polkadot implementation. To achieve this, it's worth to check the address prefix if it's provided and SS58

}

lazy_static! {
static ref CALL_INDICES_BY_NETWORK: HashMap<NetworkId, CallIndicesTable> = call_indices! {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it's worth to move the "standard" call indices to a dedicated module like src/extrinsic/standard_extrinsic.rs as well as encode_transfer, encode_asset_transfer etc, so to make src/extrinsic/mod.rs more general and re-usable.

Comment on lines +137 to +138
// `Extrinsic` is (for now) just a lightweight wrapper over the actual protobuf object.
// In the future, we will refine the latter to let the caller specify arbitrary extrinsics.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I personally prefer to separate business logic (low-level blockchain implementation) and TrustWallet Protobuf interface. Please consider adding a src/extrinsic_builder.rs or src/extrinsic_protobuf.rs that will try to convert Protobuf messages to Extrinsics.

Comment on lines +201 to +202
let address =
SS58Address::from_str(&t.to_address).map_err(|_| EncodeError::InvalidAddress)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Recently, we added error contexts to add some useful info to the SigningOutput.error_message string: #3806
To be able to add an error context, please consider changing the EncodeResult type to Result<T, TWError<EncodeError>>.

Comment on lines +306 to +308
// TODO: check address network ?
let address =
SS58Address::from_str(&b.controller).map_err(|_| EncodeError::InvalidAddress)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

That would be great but not required. In Cosmos we also ignored the address networks because of the complexity. It's also a responsibility for the API user to validate input addresses

}
}

// TODO: implement U128 support (we don't have it yet in tw_number)
Copy link
Collaborator

Choose a reason for hiding this comment

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

u128 and i128 are standard Rust types, but it would be useful to implement some functions that we have for U256, I256

};
}

tuple_impl!(T0, T1, T2, T3, T4, T5, T6, T7);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we really need to implement that trait for tuple of 7 items? :D
Tbh I like the macro, but I find it difficult to maintain. Do you think we can just implement the Scale coding for a simple tuple? Do we even need it?

}

#[cfg(test)]
mod tests {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good test coverage 👍

Comment on lines +50 to +60
message_oneof: Proto::mod_SigningInput::OneOfmessage_oneof::polymesh_call(
Proto::PolymeshCall {
message_oneof: Proto::mod_PolymeshCall::OneOfmessage_oneof::identity_call(
Proto::Identity {
message_oneof: Proto::mod_Identity::OneOfmessage_oneof::add_authorization(
Proto::mod_Identity::AddAuthorization {
call_indices: Some(Proto::CallIndices {
variant: Proto::mod_CallIndices::OneOfvariant::custom(
Proto::CustomCallIndices {
module_index: 0x07,
method_index: 0x0d,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Highly nested code. Could you please move some parts to functions?
For example,

fn custom_call_indices(module: u8, method: u8) -> Option<Proto::CallIndices> {
Some(Proto::CallIndices {
                                    variant: Proto::mod_CallIndices::OneOfvariant::custom(
                                        Proto::CustomCallIndices {
                                            module_index: module as u32,
                                            method_index: method as u32,
// ...
}

Comment on lines +148 to +149
pub fn leading_zeros(&self) -> u32 {
self.0.leading_zeros()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just curious what the value is 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants