Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
fix: Modify to decode cosmos tx at runtime (#22)
Browse files Browse the repository at this point in the history
* fix: Modify to decode cosmos tx in runtime

* fix: Fix wallet balance error

* refactor: Refactor codebase for overall improvements

* fix: Fix tx hash issue

---------

Co-authored-by: Jungyong Um <[email protected]>
  • Loading branch information
code0xff and Jungyong Um authored Jun 16, 2024
1 parent 79660b1 commit 03b7fa2
Show file tree
Hide file tree
Showing 21 changed files with 173 additions and 127 deletions.
9 changes: 5 additions & 4 deletions client/rpc/src/cosm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use jsonrpsee::{
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::{Bytes, H256};
use sp_core::{sha2_256, Bytes, H256};
use sp_runtime::{traits::Block as BlockT, transaction_validity::TransactionSource};
use std::{marker::PhantomData, sync::Arc};

Expand Down Expand Up @@ -67,18 +67,19 @@ where
use hp_rpc::ConvertTxRuntimeApi;

let chain_id = self.chain_spec.id();
let tx = hp_cosmos::Tx::decode(&tx_bytes, chain_id).map_err(|e| {
hp_cosmos::Tx::decode(&tx_bytes, chain_id.as_bytes()).map_err(|e| {
request_err(format!("invalid transaction error; code: {}, message: {}", e as u8, e))
})?;
let block_hash = self.client.info().best_hash;
let extrinsic = self
.client
.runtime_api()
.convert_tx(block_hash, tx.clone())
.convert_tx(block_hash, tx_bytes.to_vec(), chain_id.as_bytes().to_vec())
.map_err(|_| internal_err("cannot access runtime api"))?;
let tx_hash = sha2_256(&tx_bytes);
self.pool
.submit_one(block_hash, TransactionSource::Local, extrinsic)
.map_ok(move |_| tx.hash.into())
.map_ok(move |_| H256(tx_hash))
.map_err(|e| internal_err(e.to_string()))
.await
}
Expand Down
4 changes: 2 additions & 2 deletions frame/cosmos-accounts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::connect())]
pub fn connect(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
let _ = Self::connect_account(&who)?;
Self::connect_account(&who)?;
Ok(())
}
}
Expand All @@ -104,7 +104,7 @@ pub mod pallet {
{
pub fn connect_account(who: &T::AccountId) -> Result<(), DispatchError> {
let address = who.to_cosm_address().ok_or(Error::<T>::DeriveFailed)?;
Connections::<T>::insert(&address, &who);
Connections::<T>::insert(address, who);
Self::deposit_event(Event::<T>::Connected { address, who: who.clone() });
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion frame/cosmos-accounts/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ pub struct HorizonWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for HorizonWeight<T> {
fn connect() -> Weight {
Weight::from_parts(50_000_000, 0)
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes(1u64))
}
}
66 changes: 42 additions & 24 deletions frame/cosmos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ where
}

pub fn check_self_contained(&self) -> Option<Result<H160, TransactionValidityError>> {
if let Call::transact { tx } = self {
if let Call::transact { tx_bytes, chain_id } = self {
let tx = hp_io::decode_tx::decode(tx_bytes, chain_id)?;
let check = || {
if let Some(hp_cosmos::SignerPublicKey::Single(hp_cosmos::PublicKey::Secp256k1(
pk,
Expand Down Expand Up @@ -111,12 +112,12 @@ where
dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
len: usize,
) -> Option<Result<(), TransactionValidityError>> {
if let Call::transact { tx } = self {
if let Call::transact { tx_bytes, chain_id } = self {
if let Err(e) = CheckWeight::<T>::do_pre_dispatch(dispatch_info, len) {
return Some(Err(e))
return Some(Err(e));
}

Some(Pallet::<T>::validate_transaction_in_block(*origin, tx))
Some(Pallet::<T>::validate_transaction_in_block(*origin, tx_bytes, chain_id))
} else {
None
}
Expand All @@ -128,12 +129,12 @@ where
dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
len: usize,
) -> Option<TransactionValidity> {
if let Call::transact { tx } = self {
if let Call::transact { tx_bytes, chain_id } = self {
if let Err(e) = CheckWeight::<T>::do_validate(dispatch_info, len) {
return Some(Err(e))
return Some(Err(e));
}

Some(Pallet::<T>::validate_transaction_in_pool(*origin, tx))
Some(Pallet::<T>::validate_transaction_in_pool(*origin, tx_bytes, chain_id))
} else {
None
}
Expand Down Expand Up @@ -223,14 +224,19 @@ pub mod pallet {
{
/// Transact an Cosmos transaction.
#[pallet::call_index(0)]
#[pallet::weight(tx.auth_info.fee.gas_limit)]
pub fn transact(origin: OriginFor<T>, tx: hp_cosmos::Tx) -> DispatchResultWithPostInfo {
#[pallet::weight({ 0 })]
pub fn transact(
origin: OriginFor<T>,
tx_bytes: Vec<u8>,
chain_id: Vec<u8>,
) -> DispatchResultWithPostInfo {
let source = ensure_cosmos_transaction(origin)?;
let tx = hp_io::decode_tx::decode(&tx_bytes, &chain_id).unwrap();
if !tx.is_valid() {
return Err(DispatchErrorWithPostInfo {
post_info: Default::default(),
error: Error::<T>::InvalidTx.into(),
})
});
}
Self::apply_validated_transaction(source, tx)
}
Expand All @@ -244,13 +250,17 @@ impl<T: Config> Pallet<T> {
/// (just before applying the extrinsic).
pub fn validate_transaction_in_block(
origin: H160,
tx: &hp_cosmos::Tx,
tx_bytes: &[u8],
chain_id: &[u8],
) -> Result<(), TransactionValidityError> {
let (who, _) = Self::account(&origin);
let tx = hp_io::decode_tx::decode(tx_bytes, chain_id)
.ok_or(TransactionValidityError::Invalid(InvalidTransaction::Call))?;

if tx.auth_info.signer_infos[0].sequence < who.sequence {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Stale));
} else if tx.auth_info.signer_infos[0].sequence > who.sequence {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Future))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Future));
}

let mut total_payment = 0u128;
Expand All @@ -261,21 +271,28 @@ impl<T: Config> Pallet<T> {
},
}
if total_payment > who.amount {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Payment))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Payment));
}

Ok(())
}

// Controls that must be performed by the pool.
fn validate_transaction_in_pool(origin: H160, tx: &hp_cosmos::Tx) -> TransactionValidity {
fn validate_transaction_in_pool(
origin: H160,
tx_bytes: &[u8],
chain_id: &[u8],
) -> TransactionValidity {
let (who, _) = Self::account(&origin);
let tx = hp_io::decode_tx::decode(tx_bytes, chain_id)
.ok_or(TransactionValidityError::Invalid(InvalidTransaction::Call))?;

let transaction_nonce = tx.auth_info.signer_infos[0].sequence;

if transaction_nonce < who.sequence {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Stale));
} else if transaction_nonce > who.sequence {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Future))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Future));
}
let mut total_payment = 0u128;
total_payment = total_payment.saturating_add(tx.auth_info.fee.amount[0].amount);
Expand All @@ -285,7 +302,7 @@ impl<T: Config> Pallet<T> {
},
}
if total_payment > who.amount {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Payment))
return Err(TransactionValidityError::Invalid(InvalidTransaction::Payment));
}

let mut builder =
Expand Down Expand Up @@ -323,12 +340,14 @@ impl<T: Config> Pallet<T> {
});
let origin = T::AddressMapping::into_account_id(source);
let fee = Self::compute_fee(tx.len, e.weight);
if let Ok(_) = T::Currency::withdraw(
if T::Currency::withdraw(
&origin,
fee,
WithdrawReasons::FEE,
ExistenceRequirement::AllowDeath,
) {
)
.is_ok()
{
Ok(PostDispatchInfo { actual_weight: Some(e.weight), pays_fee: Pays::No })
} else {
Err(DispatchErrorWithPostInfo {
Expand All @@ -353,7 +372,7 @@ impl<T: Config> Pallet<T> {
return Err(CosmosError {
weight: total_weight,
error: CosmosErrorCode::ErrUnauthorized,
})
});
}
let weight = T::MsgHandler::msg_send(from_address, to_address, amount[0].amount)
.map_err(|e| CosmosError {
Expand All @@ -374,7 +393,7 @@ impl<T: Config> Pallet<T> {
return Err(CosmosError {
weight: total_weight,
error: CosmosErrorCode::ErrInsufficientFee,
})
});
}
let origin = T::AddressMapping::into_account_id(*source);
let _ = T::Currency::withdraw(
Expand Down Expand Up @@ -414,8 +433,7 @@ impl<T: Config> Pallet<T> {
// Base fee is already included.
let adjusted_weight_fee = T::WeightPrice::convert(weight);
let length_fee = Self::length_to_fee(len);
let inclusion_fee = length_fee + adjusted_weight_fee;
inclusion_fee
length_fee + adjusted_weight_fee
}

/// Compute the length portion of a fee by invoking the configured `LengthToFee` impl.
Expand Down
4 changes: 2 additions & 2 deletions primitives/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl Serialize for CosmosSignature {
where
S: Serializer,
{
serializer.serialize_str(&array_bytes::bytes2hex("", &self.0))
serializer.serialize_str(&array_bytes::bytes2hex("", self.0))
}
}

Expand All @@ -115,7 +115,7 @@ impl<'de> Deserialize<'de> for CosmosSignature {
where
D: Deserializer<'de>,
{
let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?)
let signature_hex = array_bytes::hex2bytes(String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
CosmosSignature::try_from(signature_hex.as_ref())
.map_err(|e| de::Error::custom(format!("{:?}", e)))
Expand Down
36 changes: 18 additions & 18 deletions primitives/cosmos/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,24 @@ pub enum DecodeTxError {
impl Display for DecodeTxError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
DecodeTxError::EmptyFeeAmount => write!(f, "{}", "empty fee amount"),
DecodeTxError::EmptyMessages => write!(f, "{}", "empty messages"),
DecodeTxError::EmptyMsgSendAmount => write!(f, "{}", "empty message send amount"),
DecodeTxError::EmptySignatures => write!(f, "{}", "empty signatures"),
DecodeTxError::EmptySigners => write!(f, "{}", "empty signers"),
DecodeTxError::EmptyTxBytes => write!(f, "{}", "empty tx bytes"),
DecodeTxError::InvalidMsgData => write!(f, "{}", "invalid message data"),
DecodeTxError::InvalidSignDoc => write!(f, "{}", "invalid sign doc"),
DecodeTxError::InvalidTxData => write!(f, "{}", "invalid tx data"),
DecodeTxError::TooLongTxBytes => write!(f, "{}", "too long tx bytes"),
DecodeTxError::TooManyFeeAmount => write!(f, "{}", "too many fee amount"),
DecodeTxError::TooManyMessages => write!(f, "{}", "too many messages"),
DecodeTxError::TooManyMsgSendAmount => write!(f, "{}", "too many message send amount"),
DecodeTxError::TooManySignatures => write!(f, "{}", "too many signatures"),
DecodeTxError::TooManySigners => write!(f, "{}", "too many signers"),
DecodeTxError::UnsupportedMsgType => write!(f, "{}", "unsupported message type"),
DecodeTxError::UnsupportedSignerType => write!(f, "{}", "unsupported signer type"),
DecodeTxError::UnsupportedSignMode => write!(f, "{}", "unsupported sign mode"),
DecodeTxError::EmptyFeeAmount => write!(f, "empty fee amount"),
DecodeTxError::EmptyMessages => write!(f, "empty messages"),
DecodeTxError::EmptyMsgSendAmount => write!(f, "empty message send amount"),
DecodeTxError::EmptySignatures => write!(f, "empty signatures"),
DecodeTxError::EmptySigners => write!(f, "empty signers"),
DecodeTxError::EmptyTxBytes => write!(f, "empty tx bytes"),
DecodeTxError::InvalidMsgData => write!(f, "invalid message data"),
DecodeTxError::InvalidSignDoc => write!(f, "invalid sign doc"),
DecodeTxError::InvalidTxData => write!(f, "invalid tx data"),
DecodeTxError::TooLongTxBytes => write!(f, "too long tx bytes"),
DecodeTxError::TooManyFeeAmount => write!(f, "too many fee amount"),
DecodeTxError::TooManyMessages => write!(f, "too many messages"),
DecodeTxError::TooManyMsgSendAmount => write!(f, "too many message send amount"),
DecodeTxError::TooManySignatures => write!(f, "too many signatures"),
DecodeTxError::TooManySigners => write!(f, "too many signers"),
DecodeTxError::UnsupportedMsgType => write!(f, "unsupported message type"),
DecodeTxError::UnsupportedSignerType => write!(f, "unsupported signer type"),
DecodeTxError::UnsupportedSignMode => write!(f, "unsupported sign mode"),
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions primitives/cosmos/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ impl TryFrom<&cosmrs::Any> for Msg {
r#type: "cosmos-sdk/MsgSend".to_string(),
value: TypedMsg::MsgSend {
amount,
from_address: msg_send.from_address.into(),
to_address: msg_send.to_address.into(),
from_address: msg_send.from_address,
to_address: msg_send.to_address,
},
})
} else {
Expand Down Expand Up @@ -116,7 +116,7 @@ impl SignAminoDoc {
for msg in &tx.body.messages {
msgs.push(msg.try_into()?);
}
return Ok(Self {
Ok(Self {
account_number: "0".to_string(),
chain_id: chain_id.to_string(),
fee: tx.auth_info.fee.clone().into(),
Expand All @@ -125,7 +125,7 @@ impl SignAminoDoc {
sequence: tx.auth_info.signer_infos[0].sequence.to_string(),
})
} else {
return Err(DecodeTxError::UnsupportedSignMode)
Err(DecodeTxError::UnsupportedSignMode)
}
}
}
Loading

0 comments on commit 03b7fa2

Please sign in to comment.