From 4ffe5c48d2663911fe00975ad631d1e029da8cab Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 12 Oct 2024 09:14:45 +0000 Subject: [PATCH] tx.file: new transaction file format - the new format is plain JSON, readable with tools such as `jq`. Filenames and extensions for raw, signed and sent transactions remain unchanged - reading/writing the legacy format continues to be supported, but new transactions cannot be written to it. This means users who upgrade MMGen Wallet to this commit on their online computer(s) must upgrade it on their offline signing device(s) as well: upgraded offline installations can interoperate with non-upgraded online installations, but not vice-versa - no additional action is required: this change is transparent to the user Testing: $ test/unit_tests.py tx.txfile $ test/cmdtest.py -n main $ test/test-release.sh -A autosign --- mmgen/data/version | 2 +- mmgen/tx/base.py | 1 + mmgen/tx/file.py | 70 ++++++++++++++++++- .../altcoins/etc/tracking-wallet.json | 1 + test/ref/tx/0A869F[1.23456,32].regtest.asubtx | 1 + test/ref/tx/7A8157[6.65227,34].rawtx | 1 + .../ref/tx/91060A-BCH[1.23456].regtest.arawtx | 1 + test/ref/tx/BB3FD2[7.57134314,123].sigtx | 1 + .../C09D73-LTC[981.73747,2000].testnet.rawtx | 1 + test/ref/tx/D850C6-MM1[43.21,50000].subtx | 1 + test/unit_tests_d/ut_tx.py | 41 +++++++++-- 11 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 test/ref/data_dir/altcoins/etc/tracking-wallet.json create mode 100644 test/ref/tx/0A869F[1.23456,32].regtest.asubtx create mode 100644 test/ref/tx/7A8157[6.65227,34].rawtx create mode 100644 test/ref/tx/91060A-BCH[1.23456].regtest.arawtx create mode 100644 test/ref/tx/BB3FD2[7.57134314,123].sigtx create mode 100644 test/ref/tx/C09D73-LTC[981.73747,2000].testnet.rawtx create mode 100644 test/ref/tx/D850C6-MM1[43.21,50000].subtx diff --git a/mmgen/data/version b/mmgen/data/version index 0fbe2a7c..4e053177 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -15.1.dev4 +15.1.dev5 diff --git a/mmgen/tx/base.py b/mmgen/tx/base.py index 2a15d3f8..47a62fd8 100755 --- a/mmgen/tx/base.py +++ b/mmgen/tx/base.py @@ -92,6 +92,7 @@ class Base(MMGenObject): Non-{gc.proj_name} addresses found in inputs: {{}} """ + file_format = 'json' class Input(MMGenTxIO): scriptPubKey = ListItemAttr(HexStr) diff --git a/mmgen/tx/file.py b/mmgen/tx/file.py index 53bc0ca0..f8e64fa6 100755 --- a/mmgen/tx/file.py +++ b/mmgen/tx/file.py @@ -19,10 +19,15 @@ """ tx.file: Transaction file operations for the MMGen suite """ -import os + +import os, json from ..util import ymsg,make_chksum_6,die from ..obj import MMGenObject,HexStr,MMGenTxID,CoinTxID,MMGenTxComment +from ..rpc import json_encoder + +def json_dumps(data): + return json.dumps(data, separators = (',', ':'), cls=json_encoder) def get_proto_from_coin_id(tx, coin_id, chain): coin, tokensym = coin_id.split(':') if ':' in coin_id else (coin_id, None) @@ -49,6 +54,21 @@ def eval_io_data(tx, data, desc): return io_list(parent=tx, data=[io(tx.proto,**d) for d in data]) class MMGenTxFile(MMGenObject): + data_label = 'MMGenTransaction' + attrs = { + 'chain': None, + 'txid': MMGenTxID, + 'send_amt': 'skip', + 'timestamp': None, + 'blockcount': None, + 'serialized': None, + } + extra_attrs = { + 'locktime': None, + 'comment': MMGenTxComment, + 'coin_txid': CoinTxID, + 'sent_timestamp': None, + } def __init__(self,tx): self.tx = tx @@ -62,7 +82,38 @@ class MMGenTxFile(MMGenObject): if len(data) > tx.cfg.max_tx_file_size: die('MaxFileSizeExceeded', f'Transaction file size exceeds limit ({tx.cfg.max_tx_file_size} bytes)') - return self.parse_data_legacy(data, metadata_only) + return (self.parse_data_json if data[0] == '{' else self.parse_data_legacy)(data, metadata_only) + + def parse_data_json(self, data, metadata_only): + tx = self.tx + tx.file_format = 'json' + outer_data = json.loads(data) + data = outer_data[self.data_label] + if outer_data['chksum'] != make_chksum_6(json_dumps(data)): + chk = make_chksum_6(json_dumps(data)) + die(3, f'{self.data_label}: invalid checksum for TxID {data["txid"]} ({chk} != {outer_data["chksum"]})') + + tx.proto = get_proto_from_coin_id(tx, data['coin_id'], data['chain']) + + for k, v in self.attrs.items(): + if v != 'skip': + setattr(tx, k, v(data[k]) if v else data[k]) + + if metadata_only: + return + + for k, v in self.extra_attrs.items(): + if k in data: + setattr(tx, k, v(data[k]) if v else data[k]) + + for k in ('inputs', 'outputs'): + setattr(tx, k, eval_io_data(tx, data[k], k)) + + tx.check_txfile_hex_data() + + tx.parse_txfile_serialized_data() # Ethereum RLP or JSON data + + assert tx.proto.coin_amt(data['send_amt']) == tx.send_amt, f'{data["send_amt"]} != {tx.send_amt}' def parse_data_legacy(self, data, metadata_only): tx = self.tx @@ -209,7 +260,20 @@ class MMGenTxFile(MMGenObject): return '\n'.join([make_chksum_6(' '.join(lines))] + lines) + '\n' - fmt_data = format_data_legacy() + def format_data_json(): + data = json_dumps({ + 'coin_id': coin_id + } | { + k: getattr(tx, k) for k in self.attrs + } | { + 'inputs': [e._asdict() for e in tx.inputs], + 'outputs': [e._asdict() for e in tx.outputs] + } | { + k: getattr(tx, k) for k in self.extra_attrs if getattr(tx, k) + }) + return '{{"{}":{},"chksum":"{}"}}'.format(self.data_label, data, make_chksum_6(data)) + + fmt_data = {'json': format_data_json, 'legacy': format_data_legacy}[tx.file_format]() if len(fmt_data) > tx.cfg.max_tx_file_size: die( 'MaxFileSizeExceeded', f'Transaction file size exceeds limit ({tx.cfg.max_tx_file_size} bytes)' ) diff --git a/test/ref/data_dir/altcoins/etc/tracking-wallet.json b/test/ref/data_dir/altcoins/etc/tracking-wallet.json new file mode 100644 index 00000000..37fc7074 --- /dev/null +++ b/test/ref/data_dir/altcoins/etc/tracking-wallet.json @@ -0,0 +1 @@ +{"coin":"ETC","network":"MAINNET","accounts":{"65f56389a1c702ab62a32c13d43d87a734b5e11f":{"mmid":"98831F3A:E:12","comment":"","balance":"99.997088092"},"d4ab1fecf420cbdc3d551c1935acdeaa1fb5b181":{"mmid":"98831F3A:E:13","comment":"","balance":"0"}},"tokens":{"492934308e98b590a626666b703a6ddf2120e85e":{"params":{"symbol":"MM1","decimals":18},"65f56389a1c702ab62a32c13d43d87a734b5e11f":{"mmid":"98831F3A:E:12","comment":"","balance":"43.21"},"d4ab1fecf420cbdc3d551c1935acdeaa1fb5b181":{"mmid":"98831F3A:E:13","comment":"","balance":"1.23456"}}}} diff --git a/test/ref/tx/0A869F[1.23456,32].regtest.asubtx b/test/ref/tx/0A869F[1.23456,32].regtest.asubtx new file mode 100644 index 00000000..ffbced50 --- /dev/null +++ b/test/ref/tx/0A869F[1.23456,32].regtest.asubtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"BTC","chain":"regtest","txid":"0A869F","send_amt":"1.23456","timestamp":"20241011_142209","blockcount":395,"serialized":"0200000000010116ee956bfc0e1e902f2fdf9c92e4cfeb129856efb30bb94563792fdac83258eb0000000017160014e665d2746915d246d8ee50fcbd092778107657a6fdffffff0200ca5b07000000001976a914000000000000000000000000000000000000000088ace094df9c0b0000001976a9142d1fd5841f0c217662f01a97a1fdf34de1d233f888ac024730440220278901a54dd4834ead1b3896a97eedb546a61f1df239a0e807f11e4aa00ee2ac022033a50b5e5e76835aa2eaa14df2ff5f8985d617dffc66d0f9841b5a2943077599012103fba670aa3ae2be0a8b65b3eca71760aff9026a81d61046c0e1c2fb237140381700000000","inputs":[{"txid":"eb5832c8da2f796345b90bb3ef569812ebcfe4929cdf2f2f901e0efc6b95ee16","vout":0,"scriptPubKey":"a91487d16a346909c7aeb90ca2ac8cfeb24784f4193887","comment":"","amt":"500","addr":"2N5dN5ady9UzR3qYdRSmTPUWpHhAmVbHoRD","confs":2,"mmid":"DE05F9A1:S:1","sequence":4294967293}],"outputs":[{"addr":"mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8","amt":"1.23456","is_chg":false},{"addr":"mjdYqZ8VzXawMSu2hFPYn18EC8Y6WEs3BC","amt":"498.76538592","is_chg":true,"mmid":"DE05F9A1:C:5"}],"comment":"This one\u2019s worth a comment","coin_txid":"a7b9b1a3607334e8ff5dc0bc9902bbfb7493b8070aa020748ecb237a9aca9785","sent_timestamp":"20241011_142211"},"chksum":"e22da6"} \ No newline at end of file diff --git a/test/ref/tx/7A8157[6.65227,34].rawtx b/test/ref/tx/7A8157[6.65227,34].rawtx new file mode 100644 index 00000000..3598e575 --- /dev/null +++ b/test/ref/tx/7A8157[6.65227,34].rawtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"BTC","chain":"mainnet","txid":"7A8157","send_amt":"6.65227","timestamp":"20241010_154753","blockcount":1000000,"serialized":"02000000011a7537162621fc98a191fdb96e1dbcfa290935ff7661a3d9e60525f3d1b703a30000000000fdffffff0388e1b913000000001976a91471402298f14e70277ab549ccb6a5a34eb862faa888ac70adec130000000017a914a7c818791e3c19d62459901e7a94c566d1f397e08738eb94af000000001976a9147819b0332bb615808965de645d488d242c82194f88ac00000000","inputs":[{"vout":0,"txid":"a303b7d1f32505e6d9a36176ff350929fabc1d6eb9fd91a198fc21261637751a","scriptPubKey":"76a91429d8b6a52a93730cb125db5984debd38528b0d7c88ac","comment":"House purchase","amt":"36.11009344","addr":"14pGKP3YbVg1XHLh523QxR2xHuA3iy9p1U","confs":316150,"mmid":"10175B2D:L:5","sequence":4294967293}],"outputs":[{"addr":"1BKpBsAb4fF8NkhWni17aEGTNJsCQJ3yCZ","amt":"3.30949","is_chg":false,"mmid":"10175B2D:L:12"},{"addr":"3GzAUTwc8j8MuKsVs6qfCbNKVeuLgXmt6Q","amt":"3.34278","is_chg":false},{"addr":"1Bx2rscjX7w8PwFuY3Nn2GyJUZXcXam1mE","amt":"29.45772344","is_chg":true,"mmid":"10175B2D:L:99"}]},"chksum":"95d646"} \ No newline at end of file diff --git a/test/ref/tx/91060A-BCH[1.23456].regtest.arawtx b/test/ref/tx/91060A-BCH[1.23456].regtest.arawtx new file mode 100644 index 00000000..e0330c0a --- /dev/null +++ b/test/ref/tx/91060A-BCH[1.23456].regtest.arawtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"BCH","chain":"regtest","txid":"91060A","send_amt":"1.23456","timestamp":"20241011_143137","blockcount":395,"serialized":"0200000001f5615164c22c221122649c7076b30a815a25ed125fb89b8c15902e56c939b64f0100000000ffffffff0200ca5b07000000001976a914000000000000000000000000000000000000000088ac008adf9c0b0000001976a914e9bd3f5df1e2621e8d69fa5a7fb4d48f12a1f5ac88ac00000000","inputs":[{"txid":"4fb639c9562e90158c9bb85f12ed255a810ab376709c642211222cc2645161f5","vout":1,"scriptPubKey":"76a914c330f16a6618930f9de900813855135da8f5f89788ac","comment":"","amt":"500","addr":"bchreg:qrpnput2vcvfxruaayqgzwz4zdw63a0cjujruft7h6","confs":2,"mmid":"D1432478:L:1","sequence":4294967295}],"outputs":[{"addr":"bchreg:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqha9s37tt","amt":"1.23456","is_chg":false},{"addr":"bchreg:qr5m606a783xy85dd8a95la56j839g044s7gcgjq60","amt":"498.76535808","is_chg":true,"mmid":"D1432478:C:5"}]},"chksum":"41eb4f"} \ No newline at end of file diff --git a/test/ref/tx/BB3FD2[7.57134314,123].sigtx b/test/ref/tx/BB3FD2[7.57134314,123].sigtx new file mode 100644 index 00000000..2214ac17 --- /dev/null +++ b/test/ref/tx/BB3FD2[7.57134314,123].sigtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"BTC","chain":"mainnet","txid":"BB3FD2","send_amt":"7.57134314","timestamp":"20241011_142633","blockcount":1000000,"serialized":"02000000060284369838bc1c49bbd7f049b44dca984c321e0d388ee8d98f6b9540b5f84f1c070000008a473044022019420c68234f0e9cfab7e3dacfc788394079bc7336edfe413bdcf83e0ebec23b02204a768ae3a4ee6f18a0d2b9bac74b48066f877997df6132fcc8ec970d4f4c4f0a014104db76a322761544a242906b7eeb511652fd39fd5ba62513f1b7cf6f118ccb60ba659223c7020f2c2720c386c07af85a389b58744aba61f91de38963159634bbaefdffffffa7ff3445e91216438ba3b657d8d6b340968568dbc9dee6fb89710e30a0aa1b24050000008a473044022075b41b8e07a20b72cb47ace38d0f267a3d9fa26bdf6d42d63d114a02d909d69402207fd6a009cc929360b0ab54f3ef1ed25c21f24ed7c7533b8681cdb7406b7cf39e01410431cc2c45e20e8b61246de7c116ef85dd0f24baa4839b087d300c18013c6f10cc8716dbcecbb524a3e7a86aab4140fd08dadce7b141e215365657df35736e3bf0fdffffffdfb57b74e14fc12f503394bcdb6078b64bda5ba101ef91c48c415b045b3f4b88060000008a473044022056965340804c6bdcc91643ff62719de9c67a98d6c303effe5f92bb3504acb034022012b715ec5309390557ea6b9916dfac0a878cb92f38465573c824bd37e75f3c4c01410420759fdc7c3498fa763143968e1afdb5ce94d5a3ab1f2bf371bf9ffd6f98c0bd945b8232191cdc591b79efa790ae1b2b374281365bc0a594a2b9042383cf54fbfdffffff202742dce48557639ce9c771f38cf99e87dd5b456d325084318323a70b884bb8030000008a4730440220274f3b05172271d9b03b1f65418a4736018625528cca31d34e48c199a76e882d02206c773e0f4700fec6d421765eb7aa32ff2faf84dd460d865bf0a0855437b1ad58014104da56bfe43e91810923c1bc1133192c29bcb87e9143561e95f37e64ea6a3a0727e07d268dde51550e921941bd8bea62b57a7877682d0efc745b6e3637bfb1f598fdffffffda5f08da6c87aa63944a085e2b83b78da46a8ed2a4edab378d67dab4a45489dc0200000069463043022006a357b539ee1132f8e7acf639f1f1e2d1d6b0780651adc3e518959ded44ce30021f19dbddd3205131cbcdcd76a7ad1c971de28e892b4f784f97a187adaeb2811b01210202bd4eabda7cad013e86b4c9aa585f2b30112465e59c8cfe3b9f2f0e23d004ccfdffffffc500a26fcb500bf8b0a42c12afe0896cf13f2a22cb6d0492ba0e3bcc94f5c1f4060000008a473044022020d519e9857adb97f1309d615df27e842d836124d978b1eed152728e9640371702202fb8b912716c8d2ab440ed857b9ef612f55582be657f1ccbd1ce52d420a7e00d0141040cb4952cebfcd1997e0ee138f36d497c93a0e32d33bad64f9b3dad68f667b0fdb94a6acd8dd982aaae11c5383fcdd0566e11541ccc145afcf4fc6d6089acd9b4fdffffff0782735c02000000001976a914946fa0685d68a5529b72984b001a4a92488c234f88aca0157002000000001976a914d911377da08f36180b548863ae4f6b6ce7fa3c9c88acd8212103000000001976a914e6924141f80038d1f58614bac7663d20f5cef0ba88ac909d9d07000000001976a914e963216a0f78fb90581c9c7b0d7f3cd51f1a996088ac30d59c0d000000001976a9145dcbe5ccb0f4aec2c2595709d19da37ef42c010688ac30d6f80f0000000017a91460319c2bbfb021e286fb3ccdd56f72c71eae4ba9873d33eef5010000001976a914129ab98ff1b91a9b315791caf5fea8763bc25c2388ac00000000","inputs":[{"vout":7,"txid":"1c4ff8b540956b8fd9e88e380d1e324c98ca4db449f0d7bb491cbc3898368402","scriptPubKey":"76a9146b8e632a42712c29e4218acf38662fa8c314ce3988ac","comment":"Carl\u2019s capital","amt":"13.60436583","addr":"1AohsmrSN5EEq3hKRmJst5Cd499frvBtTV","confs":777965,"mmid":"2A884160:L:3","sequence":4294967293},{"vout":5,"txid":"241baaa0300e7189fbe6dec9db68859640b3d6d857b6a38b431612e94534ffa7","scriptPubKey":"76a914df7b68e82f072645b9ff5e9337f595cb18f1129a88ac","comment":"Job 2","amt":"21.9421892","addr":"1MNfXSaEedSTpVscvwLgzmHmnH8Fufmwse","confs":795387,"mmid":"5095427A:L:7","sequence":4294967293},{"vout":6,"txid":"884b3f5b045b418cc491ef01a15bda4bb67860dbbc9433502fc14fe1747bb5df","scriptPubKey":"76a9144a11fd9fb532d492fe62c9edbad58348078eb05288ac","comment":"Alice\u2019s allowance","amt":"10.31186404","addr":"17keZDKjcGYiXdrw5AVPxHzdWWEKXkVMfR","confs":702557,"mmid":"EF0FF91E:L:2","sequence":4294967293},{"vout":3,"txid":"b84b880ba72383318450326d455bdd879ef98cf371c7e99c635785e4dc422720","scriptPubKey":"76a914683e6075fd3dc0588d3b8158cb4ff8c527b9e05188ac","comment":"Automotive","amt":"20.84025332","addr":"1AWBzy45rq2nq6ysUMc1P8hHJGknFmjEkr","confs":412021,"mmid":"2492C61F:L:5","sequence":4294967293},{"vout":2,"txid":"dc8954a4b4da678d37abeda4d28e6aa48db7832b5e084a9463aa876cda085fda","scriptPubKey":"76a91402e58613eaf1170c1eda856e657e8b16f4a8edff88ac","comment":"","amt":"12.78721971","addr":"1GKJyRUw2Wnn9EHs7EuxvYSr347JGXUNv","confs":94772,"sequence":4294967293},{"vout":6,"txid":"f4c1f594cc3b0eba92046dcb222a3ff16c89e0af122ca4b0f80b50cb6fa200c5","scriptPubKey":"76a914bbf2b4247778ccc866c953aa536849e6c1ef3f4c88ac","comment":"Travel expenses","amt":"12.29698691","addr":"1J8n7Dk6t1aXhghrcNE6HBjhjgxqEo5tYj","confs":837387,"mmid":"D14A9A58:L:7","sequence":4294967293}],"outputs":[{"addr":"1EXrjLsEWU967RRytVYCQAL12DEyKs92HB","amt":"0.39613314","is_chg":false,"mmid":"5095427A:L:544"},{"addr":"1LnkFsPKYbeBpZG7d82a2VbC4fg62Tu5mh","amt":"0.409","is_chg":false,"mmid":"D14A9A58:L:504"},{"addr":"1N29d6FRF35PXki6e3pRwr7L6A9QFwrzU7","amt":"0.52503","is_chg":false,"mmid":"2492C61F:L:12"},{"addr":"1NH3CQZ5RvpPgBc4md7npedYo8CXVQgSto","amt":"1.2777","is_chg":false,"mmid":"EF0FF91E:L:1022"},{"addr":"19Yx6u4ePk6px6fWUeW3jy8vHURgh6CvsW","amt":"2.28382","is_chg":false,"mmid":"2A884160:L:37"},{"addr":"3ATeDveB3iibDJpEMoEw3cguD7KYsGJv3s","amt":"2.67966","is_chg":false},{"addr":"12hNWvbwSFa71iN9SgQXT32qapFpDHWEvi","amt":"84.20995901","is_chg":true,"mmid":"D14A9A58:L:998"}],"comment":"\u00c0\u00c5\u00ca\u00cf\u00d4\u00d9\u00de\u00e3\u00e8\u00ed\u00f2\u00f7\u00fc\u0101\u0106\u010b\u0110\u0115\u011a\u011f\u0124\u0129\u012e\u0133\u0138\u013d\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e","coin_txid":"bf67775188e674788eaa110608f028cda1ba13b93bfcf188081c7232bd06caa9","sent_timestamp":"20241011_142633"},"chksum":"f7dd42"} \ No newline at end of file diff --git a/test/ref/tx/C09D73-LTC[981.73747,2000].testnet.rawtx b/test/ref/tx/C09D73-LTC[981.73747,2000].testnet.rawtx new file mode 100644 index 00000000..58221ac7 --- /dev/null +++ b/test/ref/tx/C09D73-LTC[981.73747,2000].testnet.rawtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"LTC","chain":"testnet","txid":"C09D73","send_amt":"981.73747","timestamp":"20241011_142938","blockcount":1000000,"serialized":"02000000023088a0bfd661b1102f25d4963cb44027855166bed946f4286c509969c8b298130300000000fdffffff395fc6e667bc2c84d199b618f6b309facd975837c983ad44f2425ed94bc26a7c0100000000fdffffff04e0d5e949020000001976a914cfceadbbbcc160a35e0cff9e90039451495cb57588ace0eeb56e0700000017a914714a56e6b30326420f358d5bf130caaee27609358778bafc220d0000001976a914bed52df4b7fdfedae9470239c1a80e17c8b400b488ac5f150922660000001976a914bc5d121e221457b98343fe69fa7e2e855b740fb488ac00000000","inputs":[{"vout":3,"txid":"1398b2c86999506c28f446d9be6651852740b43c96d4252f10b161d6bfa08830","scriptPubKey":"76a91497c85adaaf5bd12acde85b79311c1f5712bff23b88ac","comment":"","amt":"1484.89524648","addr":"muMWLvUo85eFpgkprNUFiZCfoWGKo2duj9","confs":821544,"mmid":"D59AC957:L:2","sequence":4294967293},{"vout":1,"txid":"7c6ac24bd95e42f244ad83c9375897cdfa09b3f618b699d1842cbc67e6c65f39","scriptPubKey":"76a91479db077835922a8c8da6cea87a6e4ea5f527fdc588ac","comment":"\u6240\u4ee5\uff0c\u6211\u5011\u975e\u5e38\u9700\u8981\u9019\u6a23\u4e00\u7a2e\u96fb\u5b50\u652f\u4ed8\u7cfb\u7d71\uff0c\u5b83\u57fa\u65bc\u5bc6\u78bc\u5b78\u539f\u7406\u800c\u4e0d\u57fa\u65bc\u4fe1\u7528\uff0c\u4f7f\u5f97\u4efb\u4f55\u9054","amt":"3883.42907183","addr":"mrdGSgNP1NVCJxPHCzYHDGQz9LcSezrNHJ","confs":775261,"mmid":"5E75A2D0:L:5","sequence":4294967293}],"outputs":[{"addr":"mzTjm3gKT44wAWHo1bJzqrQ6A7BoHs8L3P","amt":"98.29996","is_chg":false,"mmid":"5E75A2D0:L:12"},{"addr":"QWw1XAvBMcnUUvUUgYHQFx9KLWUnjrTnPq","amt":"319.22188","is_chg":false},{"addr":"mxuz4UTTehBrH6GYUNJYJYoy31UaaXAD8W","amt":"564.21563","is_chg":false,"mmid":"D59AC957:L:1022"},{"addr":"mxgvpnhfdZQEMNEdCkvYoT7WiLfKARa8Qa","amt":"4386.57684831","is_chg":true,"mmid":"D59AC957:L:1023"}]},"chksum":"bad2aa"} \ No newline at end of file diff --git a/test/ref/tx/D850C6-MM1[43.21,50000].subtx b/test/ref/tx/D850C6-MM1[43.21,50000].subtx new file mode 100644 index 00000000..19e83ec9 --- /dev/null +++ b/test/ref/tx/D850C6-MM1[43.21,50000].subtx @@ -0,0 +1 @@ +{"MMGenTransaction":{"coin_id":"ETC:MM1","chain":"classic","txid":"D850C6","send_amt":"43.21","timestamp":"20241011_144051","blockcount":20,"serialized":"f8a902850ba43b740082ea6094492934308e98b590a626666b703a6ddf2120e85e80b844a9059cbb00000000000000000000000065f56389a1c702ab62a32c13d43d87a734b5e11f00000000000000000000000000000000000000000000000257a8c21048a1000046a064093d1ddd4ee3bbb3f88e27388272bf62d744ef77d03a307a68ed674d671eeba07d7332481c857c9f030386c68e95b4d8e688abe77b938d93d62d83c8c61b2269","inputs":[{"comment":"","amt":"110.654317776666555545","addr":"1f5c9ee4a60d4a3c8b89eec978438bb6b53abf4a","confs":0,"mmid":"98831F3A:E:11"}],"outputs":[{"addr":"65f56389a1c702ab62a32c13d43d87a734b5e11f","amt":"43.21","is_chg":false,"mmid":"98831F3A:E:12"}],"comment":"\u5fc5\u8981\u306a\u306e\u306f\u3001\u4fe1\u7528\u3067\u306f\u306a\u304f\u6697\u53f7\u5316\u3055\u308c\u305f\u8a3c\u660e\u306b\u57fa\u3065\u304f\u96fb\u5b50\u53d6\u5f15\u30b7\u30b9\u30c6\u30e0\u3067\u3042\u308a\u3001\u3053\u308c\u306b\u3088\u308a\u5e0c\u671b\u3059\u308b\u4e8c\u8005\u304c\u4fe1\u7528\u3067\u304d\u308b\u7b2c\u4e09\u8005\u6a5f\u95a2\u3092\u4ecb\u3055\u305a\u306b\u76f4\u63a5\u53d6\u5f15\u3067\u304d\u308b\u3088\u3046","coin_txid":"61f624d8a279e566055294e6a3d17f4c7438e80f50a509e145df150b0447b53c","sent_timestamp":"20241011_144051"},"chksum":"974b90"} \ No newline at end of file diff --git a/test/unit_tests_d/ut_tx.py b/test/unit_tests_d/ut_tx.py index 0ab811a7..7dce3e8f 100755 --- a/test/unit_tests_d/ut_tx.py +++ b/test/unit_tests_d/ut_tx.py @@ -11,10 +11,11 @@ from mmgen.tx import NewTX,CompletedTX,UnsignedTX from mmgen.tx.file import MMGenTxFile from mmgen.daemon import CoinDaemon from mmgen.protocol import init_proto +from mmgen.cfg import Config from ..include.common import cfg, qmsg, vmsg -async def do_txfile_test(desc,fns): +async def do_txfile_test(desc, fns, cfg=cfg, check=False): qmsg(f' Testing CompletedTX initializer ({desc})') for fn in fns: qmsg(f' parsing: {os.path.basename(fn)}') @@ -31,14 +32,18 @@ async def do_txfile_test(desc,fns): assert fn_gen == os.path.basename(fn), f'{fn_gen} != {fn}' - text = f.format() + if check: + text = f.format() + with open(fpath) as fh: + text_chk = fh.read() + assert text == text_chk, f'\nformatted text:\n{text}\n !=\noriginal file:\n{text_chk}' qmsg(' OK') return True class unit_tests: - altcoin_deps = ('txfile_alt',) + altcoin_deps = ('txfile_alt', 'txfile_alt_legacy') async def tx(self,name,ut): qmsg(' Testing NewTX initializer') @@ -53,9 +58,33 @@ class unit_tests: qmsg(' OK') return True - async def txfile(self,name,ut): + async def txfile(self, name, ut): return await do_txfile_test( 'Bitcoin', + ( + 'tx/7A8157[6.65227,34].rawtx', + 'tx/BB3FD2[7.57134314,123].sigtx', + 'tx/0A869F[1.23456,32].regtest.asubtx', + ), + check = True + ) + + async def txfile_alt(self, name, ut): + return await do_txfile_test( + 'altcoins', + ( + 'tx/C09D73-LTC[981.73747,2000].testnet.rawtx', + 'tx/91060A-BCH[1.23456].regtest.arawtx', + 'tx/D850C6-MM1[43.21,50000].subtx', # token tx + ), + # token resolved by tracking wallet under data_dir: + cfg = Config({'data_dir': 'test/ref/data_dir'}), + check = True + ) + + async def txfile_legacy(self, name, ut): + return await do_txfile_test( + 'Bitcoin - legacy file format', ( '0B8D5A[15.31789,14,tl=1320969600].rawtx', '542169[5.68152,34].sigtx', @@ -64,9 +93,9 @@ class unit_tests: ) ) - async def txfile_alt(self,name,ut): + async def txfile_alt_legacy(self, name, ut): return await do_txfile_test( - 'altcoins', + 'altcoins - legacy file format', ( '460D4D-BCH[10.19764,tl=1320969600].rawtx', 'ethereum/5881D2-MM1[1.23456,50000].rawtx',