Skip to content

Commit 2c0bb9e

Browse files
authored
Merge pull request #1956 from mintlayer/feature/wasm-tx-decode
Add tx decode to js value to wasm lib
2 parents f901f33 + f589573 commit 2c0bb9e

10 files changed

Lines changed: 341 additions & 60 deletions

File tree

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/src/address/dehexify.rs

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16+
use crypto::vrf::VRFPublicKey;
1617
use serialization::json_encoded::JsonEncoded;
1718

18-
use crate::chain::{tokens::TokenId, ChainConfig, DelegationId, Destination, PoolId};
19+
use crate::chain::{tokens::TokenId, ChainConfig, DelegationId, Destination, OrderId, PoolId};
1920

2021
use super::hexified::HexifiedAddress;
2122

@@ -25,6 +26,8 @@ pub fn dehexify_all_addresses(conf: &ChainConfig, input: &str) -> String {
2526
let result = HexifiedAddress::<PoolId>::replace_with_address(conf, &result).to_string();
2627
let result = HexifiedAddress::<DelegationId>::replace_with_address(conf, &result).to_string();
2728
let result = HexifiedAddress::<TokenId>::replace_with_address(conf, &result).to_string();
29+
let result = HexifiedAddress::<OrderId>::replace_with_address(conf, &result).to_string();
30+
let result = HexifiedAddress::<VRFPublicKey>::replace_with_address(conf, &result).to_string();
2831

2932
result
3033
}
@@ -39,3 +42,131 @@ pub fn to_dehexified_json<T: serde::Serialize>(
3942
}
4043

4144
// TODO: add tests that create blocks, and ensure the replacement in json works properly.
45+
#[cfg(test)]
46+
mod tests {
47+
use rstest::rstest;
48+
use strum::{EnumCount, EnumDiscriminants, EnumIter, IntoEnumIterator};
49+
50+
use crypto::{
51+
key::{KeyKind, PrivateKey},
52+
vrf::{VRFKeyKind, VRFPrivateKey, VRFPublicKey},
53+
};
54+
use test_utils::random::{gen_random_alnum_string, make_seedable_rng, Seed};
55+
56+
use crate::{
57+
address::{hexified::HexifiedAddress, pubkeyhash::PublicKeyHash, Address},
58+
chain::{
59+
config::create_regtest, tokens::TokenId, DelegationId, Destination, DestinationTag,
60+
OrderId, PoolId,
61+
},
62+
primitives::H256,
63+
};
64+
65+
#[derive(PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumDiscriminants)]
66+
#[strum_discriminants(name(HexifiableTag), derive(EnumIter))]
67+
enum Hexifiable {
68+
Destination(Destination),
69+
PoolId(PoolId),
70+
DelegationId(DelegationId),
71+
TokenId(TokenId),
72+
OrderId(OrderId),
73+
VRFPublicKey(VRFPublicKey),
74+
}
75+
76+
#[rstest]
77+
#[trace]
78+
#[case(Seed::from_entropy())]
79+
fn many_random_instances(#[case] seed: Seed) {
80+
use crate::address::dehexify::dehexify_all_addresses;
81+
use randomness::seq::IteratorRandom;
82+
83+
let mut rng = make_seedable_rng(seed);
84+
let chain_config = create_regtest();
85+
86+
let strings = (0..100)
87+
.map(|_| gen_random_alnum_string(&mut rng, 0, 50))
88+
.collect::<Vec<String>>();
89+
90+
let keys = (0..strings.len())
91+
.map(|_| match HexifiableTag::iter().choose(&mut rng).unwrap() {
92+
HexifiableTag::Destination => {
93+
let dest = match DestinationTag::iter().choose(&mut rng).unwrap() {
94+
DestinationTag::AnyoneCanSpend => Destination::AnyoneCanSpend,
95+
DestinationTag::PublicKey => {
96+
let (_private_key, public_key) =
97+
PrivateKey::new_from_rng(&mut rng, KeyKind::Secp256k1Schnorr);
98+
Destination::PublicKey(public_key)
99+
}
100+
DestinationTag::PublicKeyHash => {
101+
let (_private_key, public_key) =
102+
PrivateKey::new_from_rng(&mut rng, KeyKind::Secp256k1Schnorr);
103+
Destination::PublicKeyHash(PublicKeyHash::from(&public_key))
104+
}
105+
DestinationTag::ScriptHash => Destination::ScriptHash(
106+
crate::primitives::Id::new(H256::random_using(&mut rng)),
107+
),
108+
DestinationTag::ClassicMultisig => {
109+
let (_private_key, public_key) =
110+
PrivateKey::new_from_rng(&mut rng, KeyKind::Secp256k1Schnorr);
111+
Destination::ClassicMultisig(PublicKeyHash::from(&public_key))
112+
}
113+
};
114+
Hexifiable::Destination(dest)
115+
}
116+
HexifiableTag::PoolId => Hexifiable::PoolId(PoolId::random_using(&mut rng)),
117+
HexifiableTag::DelegationId => {
118+
Hexifiable::DelegationId(DelegationId::random_using(&mut rng))
119+
}
120+
HexifiableTag::TokenId => Hexifiable::TokenId(TokenId::random_using(&mut rng)),
121+
HexifiableTag::OrderId => Hexifiable::OrderId(OrderId::random_using(&mut rng)),
122+
HexifiableTag::VRFPublicKey => Hexifiable::VRFPublicKey(
123+
VRFPrivateKey::new_from_rng(&mut rng, VRFKeyKind::Schnorrkel).1,
124+
),
125+
})
126+
.collect::<Vec<_>>();
127+
128+
let final_str = strings
129+
.iter()
130+
.zip(keys.iter())
131+
.map(|(s, k)| {
132+
let hexified = match k {
133+
Hexifiable::Destination(d) => HexifiedAddress::new(d).to_string(),
134+
Hexifiable::PoolId(d) => HexifiedAddress::new(d).to_string(),
135+
Hexifiable::DelegationId(d) => HexifiedAddress::new(d).to_string(),
136+
Hexifiable::TokenId(d) => HexifiedAddress::new(d).to_string(),
137+
Hexifiable::OrderId(d) => HexifiedAddress::new(d).to_string(),
138+
Hexifiable::VRFPublicKey(d) => HexifiedAddress::new(d).to_string(),
139+
};
140+
s.clone() + &hexified
141+
})
142+
.collect::<Vec<_>>()
143+
.join("");
144+
145+
let to_test = dehexify_all_addresses(&chain_config, &final_str);
146+
147+
let expected = strings
148+
.iter()
149+
.zip(keys.into_iter())
150+
.map(|(s, k)| {
151+
let address_str = match k {
152+
Hexifiable::Destination(d) => {
153+
Address::new(&chain_config, d).unwrap().to_string()
154+
}
155+
Hexifiable::PoolId(d) => Address::new(&chain_config, d).unwrap().to_string(),
156+
Hexifiable::DelegationId(d) => {
157+
Address::new(&chain_config, d).unwrap().to_string()
158+
}
159+
Hexifiable::TokenId(d) => Address::new(&chain_config, d).unwrap().to_string(),
160+
Hexifiable::OrderId(d) => Address::new(&chain_config, d).unwrap().to_string(),
161+
Hexifiable::VRFPublicKey(d) => {
162+
Address::new(&chain_config, d).unwrap().to_string()
163+
}
164+
};
165+
s.clone() + &address_str
166+
})
167+
.collect::<Vec<_>>()
168+
.join("");
169+
170+
assert_eq!(to_test, expected);
171+
}
172+
}

common/src/chain/transaction/signature/inputsig/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,18 @@ use standard_signature::StandardInputSignature;
2828

2929
use super::{DestinationSigError, Signable};
3030

31-
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd, EnumDiscriminants)]
31+
#[derive(
32+
Debug,
33+
Encode,
34+
Decode,
35+
Clone,
36+
Eq,
37+
PartialEq,
38+
Ord,
39+
PartialOrd,
40+
EnumDiscriminants,
41+
serde::Serialize,
42+
)]
3243
#[strum_discriminants(name(InputWitnessTag))]
3344
pub enum InputWitness {
3445
#[codec(index = 0)]

common/src/chain/transaction/signature/inputsig/standard_signature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use super::{
4747
},
4848
};
4949

50-
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
50+
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, serde::Serialize)]
5151
pub struct StandardInputSignature {
5252
sighash_type: SigHashType,
5353
raw_signature: Vec<u8>,

common/src/chain/transaction/signed_transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
use serialization::{Decode, Encode};
2525
use utils::ensure;
2626

27-
#[derive(Debug, Clone, PartialEq, Eq, Encode)]
27+
#[derive(Debug, Clone, PartialEq, Eq, Encode, serde::Serialize)]
2828
pub struct SignedTransaction {
2929
transaction: Transaction,
3030
signatures: Vec<InputWitness>,

wasm-wrappers/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ serialization = { path = "../serialization" }
1919
tx-verifier = { path = "../chainstate/tx-verifier" }
2020
utils = { path = "../utils" }
2121

22-
bip39 = { workspace = true, default-features = false, features = ["std", "zeroize"] }
22+
bip39 = { workspace = true, default-features = false, features = [
23+
"std",
24+
"zeroize",
25+
] }
2326
fixed-hash.workspace = true
2427
itertools.workspace = true
2528
serde.workspace = true
@@ -33,6 +36,7 @@ tsify = "0.5"
3336
wasm-bindgen = "0.2"
3437
# web-sys provides `console::log` and is useful during debugging.
3538
web-sys = { version = "0.3", features = ["console"] }
39+
serde-wasm-bindgen = "0.6"
3640

3741
[dev-dependencies]
3842
hex.workspace = true

wasm-wrappers/WASM-API.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ ScriptHash and ClassicMultisig destinations are not supported.
211211
Given inputs as bytes, outputs as bytes, and flags settings, this function returns
212212
the transaction that contains them all, as bytes.
213213

214+
### Function: `decode_signed_transaction_to_js`
215+
216+
Decodes a signed transaction from its binary encoding into a JavaScript object.
217+
214218
### Function: `encode_witness_no_signature`
215219

216220
Encode an input witness of the variant that contains no signature.

0 commit comments

Comments
 (0)