1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-13 19:18:56 +00:00

Segwit: Fixed Unittests and new tests.

- Wrong BIP-32 path in change address leads to ButtonRequest.
- Add tests for change address with segwit and correct bip32 path.
This commit is contained in:
Jochen Hoenicke 2017-03-30 20:02:05 +02:00 committed by Pavol Rusnak
parent 1bee5f4de7
commit f9cd5da505
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
2 changed files with 195 additions and 6 deletions

View File

@ -97,6 +97,7 @@ class TestMsgSigntx(common.TrezorTest):
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -142,6 +143,7 @@ class TestMsgSigntx(common.TrezorTest):
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_FeeOverThreshold),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -187,6 +189,7 @@ class TestMsgSigntx(common.TrezorTest):
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -238,6 +241,7 @@ class TestMsgSigntx(common.TrezorTest):
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -298,6 +302,7 @@ class TestMsgSigntx(common.TrezorTest):
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),

View File

@ -41,8 +41,6 @@ class TestMsgSigntxSegwit(common.TrezorTest):
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
#address_n=self.client.expand_path("49'/1'/0'/1/0"),
#script_type=proto_types.PAYTOP2SHWITNESS,
address='2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX',
script_type=proto_types.PAYTOADDRESS,
amount=123456789 - 11000 - 12300000,
@ -65,6 +63,42 @@ class TestMsgSigntxSegwit(common.TrezorTest):
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100bd3d8b8ad35c094e01f6282277300e575f1021678fc63ec3f9945d6e35670da3022052e26ef0dd5f3741c9d5939d1dec5464c15ab5f2c85245e70a622df250d4eb7c012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
def test_send_p2sh_change(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/1/0"),
# 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
amount=123456789,
prev_hash=binascii.unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'),
prev_index=0,
script_type=proto_types.SPENDP2SHWITNESS,
)
out1 = proto_types.TxOutputType(address='QWywnqNMsMNavbCgMYiQLa91ApvsVRoaqt1i',
amount=12300000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
address_n=self.client.expand_path("49'/1'/0'/1/0"),
script_type=proto_types.PAYTOP2SHWITNESS,
amount=123456789 - 11000 - 12300000,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100bd3d8b8ad35c094e01f6282277300e575f1021678fc63ec3f9945d6e35670da3022052e26ef0dd5f3741c9d5939d1dec5464c15ab5f2c85245e70a622df250d4eb7c012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
def test_send_native(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
@ -80,8 +114,6 @@ class TestMsgSigntxSegwit(common.TrezorTest):
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
#address_n=self.client.expand_path("49'/1'/0'/1/0"),
#script_type=proto_types.PAYTOWITNESS,
address='QWzGpyMkAEvmkSVprBzRRVQMP6UPp17q4kQn',
script_type=proto_types.PAYTOADDRESS,
amount=12300000 - 11000 - 5000000,
@ -104,6 +136,42 @@ class TestMsgSigntxSegwit(common.TrezorTest):
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014d16b8c0680c61fc6ed2e407455715055e41052f502483045022100a7ca8f097525f9044e64376dc0a0f5d4aeb8d15d66808ba97979a0475b06b66502200597c8ebcef63e047f9aeef1a8001d3560470cf896c12f6990eec4faec599b950121033add1f0e8e3c3136f7428dd4a4de1057380bd311f5b0856e2269170b4ffa65bf00000000')
def test_send_native_change(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/0/0"),
# QWywnqNMsMNavbCgMYiQLa91ApvsVRoaqt1i
amount=12300000,
prev_hash=binascii.unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'),
prev_index=0,
script_type=proto_types.SPENDWITNESS,
)
out1 = proto_types.TxOutputType(address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp',
amount=5000000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
address_n=self.client.expand_path("49'/1'/0'/1/0"),
script_type=proto_types.PAYTOWITNESS,
amount=12300000 - 11000 - 5000000,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1, out2 ])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014d16b8c0680c61fc6ed2e407455715055e41052f502483045022100a7ca8f097525f9044e64376dc0a0f5d4aeb8d15d66808ba97979a0475b06b66502200597c8ebcef63e047f9aeef1a8001d3560470cf896c12f6990eec4faec599b950121033add1f0e8e3c3136f7428dd4a4de1057380bd311f5b0856e2269170b4ffa65bf00000000')
def test_send_both(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
@ -198,7 +266,7 @@ class TestMsgSigntxSegwit(common.TrezorTest):
# store signature
inp1.multisig.signatures[0] = signatures1[0]
# sign with third key
inp1.address_n[2] = 0x80000003;
inp1.address_n[2] = 0x80000003
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -251,7 +319,7 @@ class TestMsgSigntxSegwit(common.TrezorTest):
# store signature
inp1.multisig.signatures[1] = signatures1[0]
# sign with first key
inp1.address_n[2] = 0x80000001;
inp1.address_n[2] = 0x80000001
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
@ -267,5 +335,121 @@ class TestMsgSigntxSegwit(common.TrezorTest):
# c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001012812fe3916f228cda6c7b57d5464541265a63ad118f430a805eeec8bddbe1cf40000000000ffffffff01a0791800000000002200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a10400483045022100cc97f21a7cabc543a9b4ac52424e8f7e420622903f2417a1c08a6af68058ec4a02200baca0b222fc825078d94e8e1b55f174c4828bed16697e4281cda2a0c799eecf01473044022009b8058dc30fa7a13310dd8f1a99c4341c4cd95f771c5a41c4381f956e2344c102205e829c560c0184fd4b4db8971f99711e2a87409afa4df0840b4f12a87b2c8afc0169522102740ec30d0af8591a0dd4a3e3b274e57f3f73bdc0638a9603f9ee6ade0475ba57210311aada919974e882abf0c67b5c0fba00000b26997312ca00345027d22359443021029382591271a79d4b12365fa27c67fad3753150d8eaa987e5a12dc5ba1bb2fa1653ae00000000')
def test_send_multisig_3_change(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[2,0]), nodes),
signatures=[b'', b'', b''],
m=2,
)
multisig2 = proto_types.MultisigRedeemScriptType(
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,1]), nodes),
signatures=[b'', b'', b''],
m=2,
)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/2/0"),
prev_hash=binascii.unhexlify('c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc'),
prev_index=0,
script_type=proto_types.SPENDWITNESS,
multisig=multisig,
amount=1604000
)
out1 = proto_types.TxOutputType(address_n=self.client.expand_path("999'/1'/1'/1/1"),
amount=1603000,
multisig=multisig2,
script_type=proto_types.PAYTOP2SHWITNESS)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
# store signature
inp1.multisig.signatures[0] = signatures1[0]
# sign with third key
inp1.address_n[2] = 0x80000003
out1.address_n[2] = 0x80000003
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
# 31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101fc7901dd033f8c02da14f3ac916b6498036b80b4a0b4dc124e02c2bb408034c90000000000ffffffff01b87518000000000017a914a8655acf68f785125561158b0f4db9b5d0044047870400473044022057b571986c07f8ccb231811334ad06ee6f87b722495def2e9511c1da46f3433202207b6e95bdd99e7fc7d319486437cb930d40a4af3cd753c4cb960b330badbf7f35014730440220517ecc6d0a2544276921d8fc2077aec4285ab83b1b21f5eb73cdb6187a0583e4022043fb5ab942f8981c04a54c66a57c4d291fad8514d4a8afea09f01f2db7a8f32901695221038e81669c085a5846e68e03875113ddb339ecbb7cb11376d4163bca5dc2e2a0c1210348c5c3be9f0e6cf1954ded1c0475beccc4d26aaa9d0cce2dd902538ff1018a112103931140ebe0fbbb7df0be04ed032a54e9589e30339ba7bbb8b0b71b15df1294da53ae00000000')
def test_send_multisig_4_change(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,1]), nodes),
signatures=[b'', b'', b''],
m=2,
)
multisig2 = proto_types.MultisigRedeemScriptType(
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,2]), nodes),
signatures=[b'', b'', b''],
m=2,
)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/1/1"),
prev_hash=binascii.unhexlify('31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5'),
prev_index=0,
script_type=proto_types.SPENDP2SHWITNESS,
multisig=multisig,
amount=1603000
)
out1 = proto_types.TxOutputType(address_n=self.client.expand_path("999'/1'/1'/1/2"),
amount=1602000,
multisig=multisig2,
script_type=proto_types.PAYTOWITNESS)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
# store signature
inp1.multisig.signatures[0] = signatures1[0]
# sign with third key
inp1.address_n[2] = 0x80000003
out1.address_n[2] = 0x80000003
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
# c0bf56060a109624b4635222696d94a7d533cacea1b3f8245417a4348c045829
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101e5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc3100000000232200205b9824093eaf5cdcf8247c00dc0b557a7720957828fcde8384ac11f80a91f403ffffffff01d071180000000000220020e77caf5fbef07b1e461475c02afd4aed877693263d69c81e14617304349b629a040047304402204832553b0da1009da496881e58e8e2e41010cfe5c0161623048093f1b1a817b7022020dad8bf887acf574af80bfe4b39cd24e95019fd5e6b8ae967471e21ddc67354014830450221009e5d60847e7275edcf4619ed8ee462c56a042eef75d17da2d44e6b13d78e50e50220665195492900ef87a5eb8a924fa0ac9afc4fc75ca704ff356dc3a213979970c80169522103f4040006e3561b3e76c6d4113225c84748ab9d55ffd23f9578ab4c18fb0c3b9721020975f2e6922897ff6b80da6412a8d6ebd67e33c9611d081656a53ef967964e5021026b0546f23a6ce6b756c2c30b4176ce6f1c3268744f7aca82668d5116c4f764e453ae00000000')
if __name__ == '__main__':
unittest.main()