Skip to content

Commit

Permalink
Support calculating the TX hash of a Substrate transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
10gic committed Jan 21, 2025
1 parent 23ae952 commit f510b1d
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 6 deletions.
1 change: 1 addition & 0 deletions rust/frameworks/tw_substrate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
tw_coin_entry = { path = "../../tw_coin_entry" }
tw_encoding = { path = "../../tw_encoding" }
tw_hash = { path = "../../tw_hash" }
tw_keypair = { path = "../../tw_keypair" }
tw_memory = { path = "../../tw_memory" }
Expand Down
9 changes: 7 additions & 2 deletions rust/frameworks/tw_substrate/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Copyright © 2017 Trust Wallet.

use crate::address::{SubstrateAddress, SubstratePrefix};
use crate::modules::transaction_util::SubstrateTransactionUtil;
use crate::substrate_coin_entry::SubstrateCoinEntry;
use std::str::FromStr;
use tw_coin_entry::coin_context::CoinContext;
Expand All @@ -14,7 +15,6 @@ use tw_coin_entry::modules::json_signer::NoJsonSigner;
use tw_coin_entry::modules::message_signer::NoMessageSigner;
use tw_coin_entry::modules::plan_builder::NoPlanBuilder;
use tw_coin_entry::modules::transaction_decoder::NoTransactionDecoder;
use tw_coin_entry::modules::transaction_util::NoTransactionUtil;
use tw_coin_entry::modules::wallet_connector::NoWalletConnector;
use tw_keypair::{ed25519, traits::KeyPairTrait, tw::PublicKey};
use tw_scale::RawOwned;
Expand Down Expand Up @@ -83,7 +83,7 @@ impl<T: SubstrateCoinEntry> CoinEntry for SubstrateEntry<T> {
type MessageSigner = NoMessageSigner;
type WalletConnector = NoWalletConnector;
type TransactionDecoder = NoTransactionDecoder;
type TransactionUtil = NoTransactionUtil;
type TransactionUtil = SubstrateTransactionUtil;

#[inline]
fn parse_address(
Expand Down Expand Up @@ -150,4 +150,9 @@ impl<T: SubstrateCoinEntry> CoinEntry for SubstrateEntry<T> {
let res = self.compile_impl(coin, input, signatures, public_keys);
self.0.signing_output(coin, res)
}

#[inline]
fn transaction_util(&self) -> Option<Self::TransactionUtil> {
Some(SubstrateTransactionUtil)
}
}
2 changes: 2 additions & 0 deletions rust/frameworks/tw_substrate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub use extrinsic::*;
pub mod extensions;
pub use extensions::*;

pub mod modules;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum EncodeError {
InvalidNetworkId,
Expand Down
5 changes: 5 additions & 0 deletions rust/frameworks/tw_substrate/src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

pub mod transaction_util;
27 changes: 27 additions & 0 deletions rust/frameworks/tw_substrate/src/modules/transaction_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

use tw_coin_entry::coin_context::CoinContext;
use tw_coin_entry::error::prelude::*;
use tw_coin_entry::modules::transaction_util::TransactionUtil;
use tw_encoding::hex;
use tw_hash::blake2::blake2_b;

pub struct SubstrateTransactionUtil;

impl TransactionUtil for SubstrateTransactionUtil {
fn calc_tx_hash(&self, coin: &dyn CoinContext, encoded_tx: &str) -> SigningResult<String> {
Self::calc_tx_hash_impl(coin, encoded_tx)
}
}

impl SubstrateTransactionUtil {
fn calc_tx_hash_impl(_coin: &dyn CoinContext, encoded_tx: &str) -> SigningResult<String> {
let tx_bytes = hex::decode(encoded_tx).map_err(|_| SigningErrorType::Error_input_parse)?;

let tx_hash = blake2_b(&tx_bytes, 32).map_err(|_| SigningErrorType::Error_internal)?;

Ok(hex::encode(&tx_hash, true))
}
}
File renamed without changes.
8 changes: 4 additions & 4 deletions tests/chains/Acala/TWAnySignerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
namespace TW::Polkadot::tests {

TEST(TWAnySignerAcala, Sign) {
// Successfully broadcasted: https://acala.subscan.io/extrinsic/3893620-3
// Successfully broadcasted: https://acala.subscan.io/extrinsic/0xb2450990defef55f075f41969c8ae7965ddf8446a0aae9510b8bbdbacb4ff344
const auto coin = TWCoinTypePolkadot;
auto secret = parse_hex("9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0");

Expand All @@ -28,7 +28,7 @@ TEST(TWAnySignerAcala, Sign) {
input.set_block_hash(blockHash.data(), blockHash.size());

input.set_nonce(0);
input.set_spec_version(2270);
input.set_spec_version(2170); // New transactions should use a newer specification version, such as 2270.
input.set_private_key(secret.data(), secret.size());
input.set_network(10); // Acala
input.set_transaction_version(2);
Expand Down Expand Up @@ -59,12 +59,12 @@ TEST(TWAnySignerAcala, Sign) {

const auto preImageHashData = data(preSigningOutput.data_hash());

EXPECT_EQ(hex(preImageHashData), "0a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8d502000000de08000002000000fc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc753700");
EXPECT_EQ(hex(preImageHashData), "0a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8d50200007a08000002000000fc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc7537");

Proto::SigningOutput output;
ANY_SIGN(input, TWCoinTypePolkadot);

EXPECT_EQ(hex(output.encoded()), "45028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900a9c3111fb98507f929e4da9aea30f996c69d2790e5a1e789f91634dc5d4f6afb155e0f1ea623498c04778f06dbc698109c3490c3e6b4c33d8e58ebab82a0f40bd5020000000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8");
EXPECT_EQ(hex(output.encoded()), "41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8");
}

} // namespace TW::Polkadot::tests
16 changes: 16 additions & 0 deletions tests/interface/TWTransactionUtilTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,19 @@ TEST(TWTransactionUtil, CalcTxHashSui) {

assertStringsEqual(txHashResult, "HkPo6rYPyDY53x1MBszvSZVZyixVN7CHvCJGX381czAh");
}

TEST(TWTransactionUtil, CalcTxHashPolkadot) {
constexpr auto coin = TWCoinTypePolkadot;
const auto encodedTxPtr = WRAPS(TWStringCreateWithUTF8Bytes("3d02849dca538b7a925b8ea979cc546464a3c5f81d2398a3a272f6f93bdf4803f2f783009025843bc49c1c4fbc99dbbd290c92f9879665d55b02f110abfb4800f0e7630877d2cffd853deae7466c22fbc8616a609e1b92615bb365ea8adccba5ef7624050503000007009dca538b7a925b8ea979cc546464a3c5f81d2398a3a272f6f93bdf4803f2f7830700aea68f0201"));
const auto txHashResult = WRAPS(TWTransactionUtilCalcTxHash(coin, encodedTxPtr.get()));

assertStringsEqual(txHashResult, "0x8da66d3fe0f592cff714ec107289370365117a1abdb72a19ac91181fdcf62bba");
}

TEST(TWTransactionUtil, CalcTxHashAcala) {
constexpr auto coin = TWCoinTypeAcala;
const auto encodedTxPtr = WRAPS(TWStringCreateWithUTF8Bytes("41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8"));
const auto txHashResult = WRAPS(TWTransactionUtilCalcTxHash(coin, encodedTxPtr.get()));

assertStringsEqual(txHashResult, "0xb2450990defef55f075f41969c8ae7965ddf8446a0aae9510b8bbdbacb4ff344");
}

0 comments on commit f510b1d

Please sign in to comment.