Skip to content

Commit

Permalink
Replace Vec::from_hex with hex!
Browse files Browse the repository at this point in the history
This makes the code less noisy and is a preparation for changing it to
`const`-based literal. Because of the preparation, places that used
variables to store the hex string were changed to constants.

There are still some instances of `Vec::from_hex` left - where they
won't be changeable to `const` and where `hex!` is unavailable
(integration tests). These may be dealt with later.

See also #1189
  • Loading branch information
Kixunil committed Dec 3, 2022
1 parent 55b93e9 commit 103f434
Show file tree
Hide file tree
Showing 18 changed files with 198 additions and 196 deletions.
2 changes: 1 addition & 1 deletion bitcoin/src/address.rs
Expand Up @@ -884,7 +884,7 @@ mod tests {

use super::*;
use crate::crypto::key::PublicKey;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::ToHex;
use crate::internal_macros::{hex, hex_into, hex_script};
use crate::network::constants::Network::{Bitcoin, Testnet};

Expand Down
6 changes: 3 additions & 3 deletions bitcoin/src/base58.rs
Expand Up @@ -273,7 +273,7 @@ impl std::error::Error for Error {
#[cfg(test)]
mod tests {
use super::*;
use crate::hashes::hex::FromHex;
use crate::internal_macros::hex;

#[test]
fn test_base58_encode() {
Expand All @@ -300,7 +300,7 @@ mod tests {
assert_eq!(&res, exp);

// Addresses
let addr = Vec::from_hex("00f8917303bfa8ef24f292e8fa1419b20460ba064d").unwrap();
let addr = hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d");
assert_eq!(&encode_check(&addr[..]), "1PfJpZsjreyVrqeoAfabrRwwjQyoSQMmHH");
}

Expand All @@ -319,7 +319,7 @@ mod tests {
// Addresses
assert_eq!(
decode_check("1PfJpZsjreyVrqeoAfabrRwwjQyoSQMmHH").ok(),
Some(Vec::from_hex("00f8917303bfa8ef24f292e8fa1419b20460ba064d").unwrap())
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
);
// Non Base58 char.
assert_eq!(decode("¢").unwrap_err(), Error::BadByte(194));
Expand Down
45 changes: 23 additions & 22 deletions bitcoin/src/bip158.rs
Expand Up @@ -560,6 +560,7 @@ mod test {
use crate::consensus::encode::deserialize;
use crate::hash_types::BlockHash;
use crate::hashes::hex::FromHex;
use crate::internal_macros::hex;

#[test]
fn test_blockfilters() {
Expand All @@ -570,12 +571,12 @@ mod test {
for t in testdata.iter().skip(1) {
let block_hash = BlockHash::from_hex(t.get(1).unwrap().as_str().unwrap()).unwrap();
let block: Block =
deserialize(&Vec::from_hex(t.get(2).unwrap().as_str().unwrap()).unwrap()).unwrap();
deserialize(&hex!(t.get(2).unwrap().as_str().unwrap())).unwrap();
assert_eq!(block.block_hash(), block_hash);
let scripts = t.get(3).unwrap().as_array().unwrap();
let previous_filter_header =
FilterHeader::from_hex(t.get(4).unwrap().as_str().unwrap()).unwrap();
let filter_content = Vec::from_hex(t.get(5).unwrap().as_str().unwrap()).unwrap();
let filter_content = hex!(t.get(5).unwrap().as_str().unwrap());
let filter_header =
FilterHeader::from_hex(t.get(6).unwrap().as_str().unwrap()).unwrap();

Expand All @@ -585,7 +586,7 @@ mod test {
for input in tx.input.iter() {
txmap.insert(
input.previous_output,
Script::from(Vec::from_hex(si.next().unwrap().as_str().unwrap()).unwrap()),
Script::from(hex!(si.next().unwrap().as_str().unwrap())),
);
}
}
Expand Down Expand Up @@ -632,22 +633,22 @@ mod test {
fn test_filter() {
let mut patterns = HashSet::new();

patterns.insert(Vec::from_hex("000000").unwrap());
patterns.insert(Vec::from_hex("111111").unwrap());
patterns.insert(Vec::from_hex("222222").unwrap());
patterns.insert(Vec::from_hex("333333").unwrap());
patterns.insert(Vec::from_hex("444444").unwrap());
patterns.insert(Vec::from_hex("555555").unwrap());
patterns.insert(Vec::from_hex("666666").unwrap());
patterns.insert(Vec::from_hex("777777").unwrap());
patterns.insert(Vec::from_hex("888888").unwrap());
patterns.insert(Vec::from_hex("999999").unwrap());
patterns.insert(Vec::from_hex("aaaaaa").unwrap());
patterns.insert(Vec::from_hex("bbbbbb").unwrap());
patterns.insert(Vec::from_hex("cccccc").unwrap());
patterns.insert(Vec::from_hex("dddddd").unwrap());
patterns.insert(Vec::from_hex("eeeeee").unwrap());
patterns.insert(Vec::from_hex("ffffff").unwrap());
patterns.insert(hex!("000000"));
patterns.insert(hex!("111111"));
patterns.insert(hex!("222222"));
patterns.insert(hex!("333333"));
patterns.insert(hex!("444444"));
patterns.insert(hex!("555555"));
patterns.insert(hex!("666666"));
patterns.insert(hex!("777777"));
patterns.insert(hex!("888888"));
patterns.insert(hex!("999999"));
patterns.insert(hex!("aaaaaa"));
patterns.insert(hex!("bbbbbb"));
patterns.insert(hex!("cccccc"));
patterns.insert(hex!("dddddd"));
patterns.insert(hex!("eeeeee"));
patterns.insert(hex!("ffffff"));

let mut out = Vec::new();
{
Expand All @@ -661,14 +662,14 @@ mod test {
let bytes = out;

{
let query = vec![Vec::from_hex("abcdef").unwrap(), Vec::from_hex("eeeeee").unwrap()];
let query = vec![hex!("abcdef"), hex!("eeeeee")];
let reader = GcsFilterReader::new(0, 0, M, P);
assert!(reader
.match_any(&mut bytes.as_slice(), &mut query.iter().map(|v| v.as_slice()))
.unwrap());
}
{
let query = vec![Vec::from_hex("abcdef").unwrap(), Vec::from_hex("123456").unwrap()];
let query = vec![hex!("abcdef"), hex!("123456")];
let reader = GcsFilterReader::new(0, 0, M, P);
assert!(!reader
.match_any(&mut bytes.as_slice(), &mut query.iter().map(|v| v.as_slice()))
Expand All @@ -690,7 +691,7 @@ mod test {
for p in &patterns {
query.push(p.clone());
}
query.push(Vec::from_hex("abcdef").unwrap());
query.push(hex!("abcdef"));
assert!(!reader
.match_all(&mut bytes.as_slice(), &mut query.iter().map(|v| v.as_slice()))
.unwrap());
Expand Down
8 changes: 4 additions & 4 deletions bitcoin/src/bip32.rs
Expand Up @@ -834,7 +834,7 @@ mod tests {

use super::ChildNumber::{Hardened, Normal};
use super::*;
use crate::hashes::hex::FromHex;
use crate::internal_macros::hex;
use crate::network::constants::Network::{self, Bitcoin};

#[test]
Expand Down Expand Up @@ -1008,7 +1008,7 @@ mod tests {
#[test]
fn test_vector_1() {
let secp = Secp256k1::new();
let seed = Vec::from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
let seed = hex!("000102030405060708090a0b0c0d0e0f");

// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
Expand Down Expand Up @@ -1044,7 +1044,7 @@ mod tests {
#[test]
fn test_vector_2() {
let secp = Secp256k1::new();
let seed = Vec::from_hex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542").unwrap();
let seed = hex!("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");

// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
Expand Down Expand Up @@ -1080,7 +1080,7 @@ mod tests {
#[test]
fn test_vector_3() {
let secp = Secp256k1::new();
let seed = Vec::from_hex("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be").unwrap();
let seed = hex!("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be");

// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
Expand Down
29 changes: 15 additions & 14 deletions bitcoin/src/blockdata/block.rs
Expand Up @@ -418,12 +418,13 @@ mod tests {

use crate::hashes::hex::FromHex;
use crate::consensus::encode::{deserialize, serialize};
use crate::internal_macros::hex;

#[test]
fn test_coinbase_and_bip34() {
// testnet block 100,000
let block_hex = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3703a08601000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
let block: Block = deserialize(&Vec::<u8>::from_hex(block_hex).unwrap()).unwrap();
const BLOCK_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3703a08601000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
let block: Block = deserialize(&hex!(BLOCK_HEX)).unwrap();

let cb_txid = "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38";
assert_eq!(block.coinbase().unwrap().txid().to_string(), cb_txid);
Expand All @@ -432,8 +433,8 @@ mod tests {


// block with 9-byte bip34 push
let bad_hex = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
let bad: Block = deserialize(&Vec::<u8>::from_hex(bad_hex).unwrap()).unwrap();
const BAD_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
let bad: Block = deserialize(&hex!(BAD_HEX)).unwrap();

let push = Vec::<u8>::from_hex("a08601112233445566").unwrap();
assert_eq!(bad.bip34_block_height(), Err(super::Bip34Error::UnexpectedPush(push)));
Expand All @@ -442,11 +443,11 @@ mod tests {
#[test]
fn block_test() {
// Mainnet block 00000000b0c5a240b2a61d2e75692224efd4cbecdf6eaf4cc2cf477ca7c270e7
let some_block = Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000").unwrap();
let cutoff_block = Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap();
let some_block = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000");
let cutoff_block = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac");

let prevhash = Vec::from_hex("4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000").unwrap();
let merkle = Vec::from_hex("bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c").unwrap();
let prevhash = hex!("4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000");
let merkle = hex!("bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c");
let work = Work::from(0x100010001_u128);

let decode: Result<Block, _> = deserialize(&some_block);
Expand Down Expand Up @@ -484,8 +485,8 @@ mod tests {

let decode: Result<Block, _> = deserialize(&segwit_block);

let prevhash = Vec::from_hex("2aa2f2ca794ccbd40c16e2f3333f6b8b683f9e7179b2c4d74906000000000000").unwrap();
let merkle = Vec::from_hex("10bc26e70a2f672ad420a6153dd0c28b40a6002c55531bfc99bf8994a8e8f67e").unwrap();
let prevhash = hex!("2aa2f2ca794ccbd40c16e2f3333f6b8b683f9e7179b2c4d74906000000000000");
let merkle = hex!("10bc26e70a2f672ad420a6153dd0c28b40a6002c55531bfc99bf8994a8e8f67e");
let work = Work::from(0x257c3becdacc64_u64);

assert!(decode.is_ok());
Expand Down Expand Up @@ -513,13 +514,13 @@ mod tests {

#[test]
fn block_version_test() {
let block = Vec::from_hex("ffffff7f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let block = hex!("ffffff7f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
let decode: Result<Block, _> = deserialize(&block);
assert!(decode.is_ok());
let real_decode = decode.unwrap();
assert_eq!(real_decode.header.version, Version(2147483647));

let block2 = Vec::from_hex("000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let block2 = hex!("000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
let decode2: Result<Block, _> = deserialize(&block2);
assert!(decode2.is_ok());
let real_decode2 = decode2.unwrap();
Expand All @@ -528,7 +529,7 @@ mod tests {

#[test]
fn validate_pow_test() {
let some_header = Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap();
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
let some_header: Header = deserialize(&some_header).expect("Can't deserialize correct block header");
assert_eq!(some_header.validate_pow(some_header.target()).unwrap(), some_header.block_hash());

Expand All @@ -549,7 +550,7 @@ mod tests {

#[test]
fn compact_roundrtip_test() {
let some_header = Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap();
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");

let header: Header = deserialize(&some_header).expect("Can't deserialize correct block header");

Expand Down

0 comments on commit 103f434

Please sign in to comment.