Пример #1
0
def main(self):
    """
    to run:

    kosmos 'j.clients.tfchain.test(name="threebot_name_transfer")'
    """

    # create a tfchain client for devnet
    c = j.clients.tfchain.new("mydevclient", network_type="DEV")
    # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist

    # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network)
    explorer_client = TFChainExplorerGetClientStub()
    explorer_client.hash_add(
        "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a",
        '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"066c03b5cf6db18edd6013591ae6292e8a04f1cc18fc6f0a0f3946d40bb087b3","height":3628,"parent":"761af2728b6f07bbccf4ddaf330c0bb1465246f6fe25fbfb9989129b69fbd899","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","fulfillment":{"type":1,"data":{"publickey":"ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97","signature":"e5a47b166eb6724ca7a72b5ddaeff287ebdde09751ed10e8850d320744afc5f45e59aa66e2cc4dc45ff593a0eea696c4e780b81636a1ce748c7149a9ee0ba807"}}},{"parentid":"1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","fulfillment":{"type":1,"data":{"publickey":"ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa","signature":"5ce7a10373214d269837e9c176ec806469d2b80f200f9ee961c63553b6ee200f88958293a571889f26b2b52664f3c9ff2441eaf8ed61830b51d640003b06fb00"}}}],"coinoutputs":[{"value":"501000000000","condition":{"type":1,"data":{"unlockhash":"0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55"}}},{"value":"198000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}},"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"},{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}},"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}],"coinoutputids":["4b43906584620e8a13d98a917d424fb154dd1222a72b886a887c416b2a9120f5","19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376"],"coinoutputunlockhashes":["0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"0b5d7509e467b943af12db2d73ddb78a5ec8cfdf64c3c6ecacb2de4af68bdc4d","height":33,"parent":"40e281daee6f113b788d64b8247381c36fe4885233a7475c9be2cce852e1696e","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"a3c8f44d64c0636018a929d2caeec09fb9698bfdcbfa3a8225585a51e09ee563","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"e5b69be3b385f0a33f7978e0d6af30cf37c975bbb99d0f3d06f199cd579d3e6854f6cb398c88082e438c89d11d04de0e7d3b2876e250d4ba8ae457f88547f605"}}}],"coinoutputs":[{"value":"1000000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99998999000000000","condition":{"type":1,"data":{"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"100000000000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"coinoutputids":["75f297550acfa48490c21490f82c3c308326c16f950e17ef3a286486065a51b8","6d157a1eb23cadde122192869bc51e2a0fe44a2d8aba898cbdda8b7218a0f8cb"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"1b144b89c4b65cc67416e27286e802c50f78bc7326b4b0e5f6f967f99cc39419","height":200,"parent":"68e3886c9a4c59dea8c7a0eb138ede0e83716b995fd8ebfa5dfc766bfb349565","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"6d157a1eb23cadde122192869bc51e2a0fe44a2d8aba898cbdda8b7218a0f8cb","fulfillment":{"type":1,"data":{"publickey":"ed25519:00bde9571b30e1742c41fcca8c730183402d967df5b17b5f4ced22c677806614","signature":"05c72055d4cca6d8620fd7453c89ac8deaf92c38e366604dc6405cb097321b74e2e5f7ece15b440f4af5721b8aa6ea1f57f4fce44d2a2c6c0fb7a1e068a0480d"}}}],"coinoutputs":[{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99998498000000000","condition":{"type":1,"data":{"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99998999000000000","condition":{"type":1,"data":{"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}},"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}],"coinoutputids":["1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","e27ed8bbe45177fafdfd7d21394ff483b8bde24f551dd927a046a0b7c37ec228"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"5ab2604c7d54dd9ea39d829724e46deb8bbf2889d8627a3bb3b57907c6f4dff4","height":1433,"parent":"6b9fdad35096c5a84dcdb6e3e9ec2a8c7562f567e05b1207a7f9330ed51582bb","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"e27ed8bbe45177fafdfd7d21394ff483b8bde24f551dd927a046a0b7c37ec228","fulfillment":{"type":1,"data":{"publickey":"ed25519:41e84f3b0f6a06dd7e45ded4d0e227869725355b73906b82d9e3ffc0b6b01416","signature":"47a4d1a6aeb7403ea5c2cbcc26f84bb1964aadcb8765696db4a623694991f794663b860898db53401dd4324477c43f9fff177b74909201a03e131c2cd885cc0d"}}}],"coinoutputs":[{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99997997000000000","condition":{"type":1,"data":{"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99998498000000000","condition":{"type":1,"data":{"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}},"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}],"coinoutputids":["b90422bad2dffde79f0a46bd0a41055cf7974b080e115d76f69891ca31d31f11","f386312779f382f16fa836038b3d25536b928ba88ae1afa1f8c0e8dc25c0ba16"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"81d81b413fc8af3e528478e639d5a6e999e5e96611593cd2458b4d2d7abc3880","height":1433,"parent":"6b9fdad35096c5a84dcdb6e3e9ec2a8c7562f567e05b1207a7f9330ed51582bb","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"f386312779f382f16fa836038b3d25536b928ba88ae1afa1f8c0e8dc25c0ba16","fulfillment":{"type":1,"data":{"publickey":"ed25519:4e42a2fcfc0963d6fa7bb718fd088d9b6544331e8562d2743e730cdfbedeb55a","signature":"4abae694cf6a6408eca6f034ea2ec6930b9a73303c3e70d3444cf36a9966b0c4cc1b65168c23640affb5bdeae539ea583d42da52c58d21f59b71c288b3faef0e"}}}],"coinoutputs":[{"value":"2000000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99995996000000000","condition":{"type":1,"data":{"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}}}],"minerfees":["1000000000"],"arbitrarydata":"Zm9vYmFy"}},"coininputoutputs":[{"value":"99997997000000000","condition":{"type":1,"data":{"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}},"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}],"coinoutputids":["d1f74e90eba8095e78f08a6284c7b76d4cda86b06ac742062d6e0e02dc4607eb","1edccdb04100ffd05d97431b6798533fa57dc7ed1ea58c75f0f445fb64442d6e"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":["039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a"],"unconfirmed":false}',
    )
    explorer_client.hash_add(
        "018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd",
        '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"066c03b5cf6db18edd6013591ae6292e8a04f1cc18fc6f0a0f3946d40bb087b3","height":3628,"parent":"761af2728b6f07bbccf4ddaf330c0bb1465246f6fe25fbfb9989129b69fbd899","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","fulfillment":{"type":1,"data":{"publickey":"ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97","signature":"e5a47b166eb6724ca7a72b5ddaeff287ebdde09751ed10e8850d320744afc5f45e59aa66e2cc4dc45ff593a0eea696c4e780b81636a1ce748c7149a9ee0ba807"}}},{"parentid":"1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","fulfillment":{"type":1,"data":{"publickey":"ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa","signature":"5ce7a10373214d269837e9c176ec806469d2b80f200f9ee961c63553b6ee200f88958293a571889f26b2b52664f3c9ff2441eaf8ed61830b51d640003b06fb00"}}}],"coinoutputs":[{"value":"501000000000","condition":{"type":1,"data":{"unlockhash":"0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55"}}},{"value":"198000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}},"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"},{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}},"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}],"coinoutputids":["4b43906584620e8a13d98a917d424fb154dd1222a72b886a887c416b2a9120f5","19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376"],"coinoutputunlockhashes":["0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"d0d290dccddaf086708e4163eacd420bfbaa7acb77deea97c6a8792a139f6e7e","height":3583,"parent":"ca746d80740ff45f6e7f0d6c8b6278b35b1040b4e21baaf41bd03cd3a7a176be","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"1edccdb04100ffd05d97431b6798533fa57dc7ed1ea58c75f0f445fb64442d6e","fulfillment":{"type":1,"data":{"publickey":"ed25519:7469d51063cdb690cc8025db7d28faadc71ff69f7c372779bf3a1e801a923e02","signature":"6f38467bb4ca23900e424d5ac2066a09b61fe9d9ae84a4231755063f591d04711f0a5ab11b60b42c2c32a8e7f73fc1cc1cb0073b036bc417ed504a8ef5f25402"}}}],"coinoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}}},{"value":"99995795000000000","condition":{"type":1,"data":{"unlockhash":"01f706dcbb9f0cb1e97d891ada3a133f68612ebff948c5bbae7851108a65dab7782907eecd86be"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99995996000000000","condition":{"type":1,"data":{"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}},"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}],"coinoutputids":["670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","984555e190d58dc752aad81b0a6cf6194fa5bf89b8614efcd9604d138a8953bc"],"coinoutputunlockhashes":["018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd","01f706dcbb9f0cb1e97d891ada3a133f68612ebff948c5bbae7851108a65dab7782907eecd86be"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}',
    )
    explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}'
    explorer_client.hash_add(
        "552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e",
        '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}',
    )
    explorer_client.hash_add(
        "039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a",
        '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"4c70a0406f36cf354edf87642df3f34568fd0a89c052a81d11cc6e4f8fbf685e","height":45,"parent":"f7b78b17d581ff9e58ffbcce1701d4dcadb0781590ca68e839def0dc98b0360a","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"7d4a100fc3bc08b2bdd1284c17260dd2bd6b55fd6c1429dbbd683bf362d92b50","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"c34b8ca1ab08930bc68d61026af504d62d8a8bbda9b79ae01a387560fba22d39b12021e16566732b742ea686f997b3c19c807523797cdc0d74a4d25123691004"}}},{"parentid":"83503f9cea00d562e0460eace93159a4c4dd00df4703c96947e81885b46da04c","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f6eea681a259baf14433ac55b4293b22ca2056810ee8fed2129039224d14558f54ca58c6d96e9885cb20ecdf7e64ba81d1a83c6e9a42bf9464287fa6359d360c"}}},{"parentid":"578aa43de72b42b4f4547c5ddc7f61736b1cac206e1789bc89fcd9333cf3d1f3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"a0521d14dfe4a0c9b8b57ed361d738b48b6a8346097246effe0b4ee67b6fecbc3a90e4671ddc0b164f6c2839df249bb5998f10216a4a674ba8d24b8ad6bdf808"}}},{"parentid":"5a1454762e6895431e1b9e4e435e4d0ad60a3881843ac46b88e220771055ca87","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"900e7868780e67bcb68af3ec6976e84289850d0db59210d4689b1c0e2deb3164b9e93eb9ee5a38850f2319463b0845163e1eee443d7b645c59485c2aa0837707"}}},{"parentid":"c04ebebe17a1759457eecaf4d5d33f5ddbe8d154b0be1606f05bc8fd02ab9cd4","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"e992b1cd3347b5362e820166d5929de7c682130c7143fc4c9ff3156f5d44110753687697a0154a2043290b3f022e2537f3e3a6807caf9150f8c255d74e386d0a"}}}],"coinoutputs":[{"value":"42000000000","condition":{"type":4,"data":{"unlockhashes":["01ffd7c884aa869056bfb832d957bb71a0005fee13c19046cebec84b3a5047ee8829eab070374b","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"minimumsignaturecount":1}}},{"value":"7000000000","condition":{"type":1,"data":{"unlockhash":"01972837ee396f22f96846a0c700f9cf7c8fa83ab4110da91a1c7d02f94f28ff03e45f1470df82"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"coinoutputids":["29152fe03a2c8782fcbd670579686088c52be83fa3870f5f0788073d97fb5fb2","0fc9b16bb180cd8f8a7144d65e6c8fca66994a4ccaee42e324289d4039ab2841"],"coinoutputunlockhashes":["039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a","01972837ee396f22f96846a0c700f9cf7c8fa83ab4110da91a1c7d02f94f28ff03e45f1470df82"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}',
    )
    # add threebot records:
    explorer_client.threebot_record_add(
        ThreeBotRecord(
            identifier=3,
            names=[BotName(value=s) for s in ["foorbar", "chatbot.example"]],
            addresses=[NetworkAddress(address=s) for s in ["example.org", "127.0.0.1"]],
            public_key=PublicKey.from_json("ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa"),
            expiration=1552581420,
        )
    )
    explorer_client.threebot_record_add(
        ThreeBotRecord(
            identifier=5,
            names=[],
            addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]],
            public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"),
            expiration=1552585420,
        )
    )
    c._explorer_get = explorer_client.explorer_get
    c._explorer_post = explorer_client.explorer_post

    # the devnet genesis seed is the seed of the wallet,
    # which receives all block stakes and coins in the genesis block of the tfchain devnet
    DEVNET_GENESIS_SEED = "image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract"

    # create a new devnet wallet
    w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED)
    # we create a new wallet using an existing seed,
    # such that our seed is used and not a new randomly generated seed

    # a tfchain (JS) wallet uses the underlying tfchain client for all its
    # interaction with the tfchain network
    assert w.network_type == "DEV"

    # getting the balance of a wallet is as easy as getting the 'balance' property
    balance = w.balance

    # the available and locked tokens can be easily checked
    assert str(balance.available) == "3698"
    assert str(balance.locked) == "0"

    # assert the addresses are correct
    assert w.addresses == [
        "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a",
        "018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd",
    ]

    # transfering a name is easy as well:
    result = w.threebot.name_transfer(
        sender=3,  # identifier of sender 3Bot
        receiver=5,  # identifier of receiver 3Bot
        names=["foobar", "chatbot.example"],  # names to be transfered from sender to receiver 3Bot
    )
    assert result.submitted  # we expect the transaction to be submitted

    expected_transaction = {
        "version": 146,
        "data": {
            "sender": {
                "id": 3,
                "signature": "e1b1bb0f6f9493b17f8959d2ff67741eee0642737c277e46644e2902e805866036af2ebf8ece2c4eb02539f2f0de49679231959d677f86ff05c19bc1f6c2eb00",
            },
            "receiver": {
                "id": 5,
                "signature": "be7f8a47a1de99a5aaff1684c5973d50d3e1777c271309b08175b993802d4b19980a38c7d6d59362bff542cced12818d72745405f15ed9170319020a27aae30a",
            },
            "names": ["foobar", "chatbot.example"],
            "txfee": "1000000000",
            "coininputs": [
                {
                    "parentid": "19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376",
                    "fulfillment": {
                        "type": 1,
                        "data": {
                            "publickey": "ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa",
                            "signature": "47d76c8cc278c1077574d0de6aaca6c13414bbf1c13f4f97cecb7ac1a19763eb9e0cf7c2584a8ade4bc7a8f4e220aa3b5d021ffd092af6dc8a07760a21e2e101",
                        },
                    },
                }
            ],
            "refundcoinoutput": {
                "value": "97000000000",
                "condition": {
                    "type": 1,
                    "data": {
                        "unlockhash": "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"
                    },
                },
            },
        },
    }
    # ensure our transaction is as expected
    assert result.transaction.json() == expected_transaction

    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == expected_transaction

    # if no names to be transfered are defined, a ValueError is raised
    with pytest.raises(ValueError):
        w.threebot.name_transfer(sender=3, receiver=5, names=[])

    # if names are defined to be transfered but one of the two 3Bots do no exist,
    # an j.clients.tfchain.errors.ThreeBotNotFound will be raised
    with pytest.raises(j.clients.tfchain.errors.ThreeBotNotFound):
        w.threebot.name_transfer(sender=2, receiver=5, names=["foobar"])
    with pytest.raises(j.clients.tfchain.errors.ThreeBotNotFound):
        w.threebot.name_transfer(sender=3, receiver=4, names=["foobar"])

    # make our receiver 3Bot expired
    explorer_client.threebot_record_add(
        ThreeBotRecord(
            identifier=5,
            names=[],
            addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]],
            public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"),
            expiration=1549012664,
        ),
        force=True,
    )

    # if the receiver 3Bot is inactive, an error will be raised
    with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive):
        w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"])

    # make our sender 3Bot expired
    explorer_client.threebot_record_add(
        ThreeBotRecord(
            identifier=3,
            names=[BotName(value=s) for s in ["foorbar", "chatbot.example"]],
            addresses=[NetworkAddress(address=s) for s in ["example.org", "127.0.0.1"]],
            public_key=PublicKey.from_json("ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa"),
            expiration=1549012664,
        ),
        force=True,
    )

    # if the sender and receiver 3Bots are inactive, an error will be raised
    with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive):
        w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"])

    # make our receiver 3Bot active again
    explorer_client.threebot_record_add(
        ThreeBotRecord(
            identifier=5,
            names=[],
            addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]],
            public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"),
            expiration=1552585420,
        ),
        force=True,
    )

    # if the sender 3Bot is inactive, an error will be raised
    with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive):
        w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"])
def main(self):
    """
    to run:

    js_shell 'j.clients.tfchain.test(name="atomicswap_participate")'
    """

    # create a tfchain client for devnet
    c = j.clients.tfchain.new("mytestclient", network_type="TEST")
    # or simply `c = j.tfchain.clients.mytestclient`, should the client already exist

    # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network)
    explorer_client = TFChainExplorerGetClientStub()
    # add the blockchain info
    explorer_client.chain_info = '{"blockid":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","difficulty":"29305","estimatedactivebs":"2067","height":16922,"maturitytimestamp":1549649615,"target":[0,2,60,124,18,9,53,143,255,130,219,75,17,252,30,24,177,101,116,228,26,221,54,224,30,251,45,78,1,199,78,60],"totalcoins":"0","arbitrarydatatotalsize":4351,"minerpayoutcount":17006,"transactioncount":17547,"coininputcount":635,"coinoutputcount":1228,"blockstakeinputcount":16922,"blockstakeoutputcount":16923,"minerfeecount":624,"arbitrarydatacount":573}'
    explorer_client.hash_add(
        '583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc',
        '{"hashtype":"blockid","block":{"minerpayoutids":["eb538b38d8fcf7b0ef037eccf8cab1096c2b98031311453c150b2b150c483941"],"transactions":[{"id":"92132a65558684f154a56232acf9b7dd1e003d0f3ebdb2c4b44494d3c5e7f658","height":16922,"parent":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ca1da3d88904a532692ad2bb67122747eea4d91ead119043253ecb34410bbcc3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"120c7bdf823a45fde303a725a1d757b3ece975abcd326ec036c056c6499b6de6cd798f18f8dff8c7adebcf19901e358609e675871335a71678c17de3e1dadb04"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["615f6f9d28d97082b423de7a878830b739b8fc4737c7ed20d3923a0019dbaed6"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"35879735f395c25fa7c0366bec7002f960798517e5335b5f27348c3a1b1923d4","timestamp":1549649728,"pobsindexes":{"BlockHeight":16921,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ca1da3d88904a532692ad2bb67122747eea4d91ead119043253ecb34410bbcc3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"120c7bdf823a45fde303a725a1d757b3ece975abcd326ec036c056c6499b6de6cd798f18f8dff8c7adebcf19901e358609e675871335a71678c17de3e1dadb04"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","difficulty":"29305","estimatedactivebs":"2067","height":16922,"maturitytimestamp":1549649615,"target":[0,2,60,124,18,9,53,143,255,130,219,75,17,252,30,24,177,101,116,228,26,221,54,224,30,251,45,78,1,199,78,60],"totalcoins":"0","arbitrarydatatotalsize":4351,"minerpayoutcount":17006,"transactioncount":17547,"coininputcount":635,"coinoutputcount":1228,"blockstakeinputcount":16922,"blockstakeoutputcount":16923,"minerfeecount":624,"arbitrarydatacount":573},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}'
    )
    # add the wallet info
    explorer_client.hash_add(
        '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0',
        '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"bca044302e018e67600bd0bd3223ae8dbb702eb528e73d6cfa9d057d4f73b03a","height":16911,"parent":"b4882a0b8632396a9c5d83a5c8684ab76736f4bff6d971795ed7334fac8aa339","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"357451c3f3a15f6150aedede9d5228ec5dfc2d32c9b62c2a46128533a7845c72","fulfillment":{"type":1,"data":{"publickey":"ed25519:fdb2e1b898dda304f748c0ff812a24729b2aafd344512079ab778eb368b18645","signature":"bd9dd36e86c08a5990ad5282d1079705c3a4b1cf3896e96791aa7db97002d5eb002c50467f45bd3ac1086292932cd2ab53c91b2e8bb74b9d9c9c0d558082ef08"}}}],"coinoutputs":[{"value":"51000000000","condition":{"type":1,"data":{"unlockhash":"01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0"}}},{"value":"99994187000000000","condition":{"type":1,"data":{"unlockhash":"0183841ae8952a2ba72db0d6fce6208df70f2a936ee589ff852e06b20af48b40489572b1a69b2a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99994239000000000","condition":{"type":1,"data":{"unlockhash":"019bb005b78a47fd084f4f3a088d83da4fadfc8e494ce4dae0d6f70a048a0a745d88ace6ce6f1c"}},"unlockhash":"019bb005b78a47fd084f4f3a088d83da4fadfc8e494ce4dae0d6f70a048a0a745d88ace6ce6f1c"}],"coinoutputids":["753aaeaa0c9e6c9f1f8da1974c83d8ca067ad536f464a2e2fc038bbd0404d084","8c8dbd70c6eb2d5d181aa5ae430f2cc86e038b92e45dd6f6d5a28400efad4511"],"coinoutputunlockhashes":["01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0","0183841ae8952a2ba72db0d6fce6208df70f2a936ee589ff852e06b20af48b40489572b1a69b2a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}'
    )
    # override internal functionality, as to use our stub client
    c._explorer_get = explorer_client.explorer_get
    c._explorer_post = explorer_client.explorer_post

    # a wallet is required to initiate an atomic swap contract
    w = c.wallets.new(
        "mytestwallet",
        seed=
        'remain solar kangaroo welcome clean object friend later bounce strong ship lift hamster afraid you super dolphin warm emotion curve smooth kiss stem diet'
    )
    # money is required to be available in the wallet
    assert str(w.balance.available) == '51'

    # a participation atomic swap contract can be created and signed as follows:
    result = w.atomicswap.participate(
        initiator=
        '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c',
        amount=50,
        secret_hash=
        '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba',
        submit=False)  # submit=True is the default
    assert not result.submitted
    assert result.transaction.is_fulfilled()
    # the contract is returned as part of the result
    assert str(result.contract.amount) == '50'
    assert str(
        result.contract.sender
    ) == '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0'
    assert str(
        result.contract.receiver
    ) == '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c'
    assert result.contract.refund_timestamp > 1549649728
    assert result.contract.secret_hash == '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba'
    # one would than use `w.transaction_sign(result.transaction)` to submit it for real

    # however, usually an atomic swap contract is participated as follows:
    result = w.atomicswap.participate(
        initiator=
        '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c',
        amount=50,
        secret_hash=
        '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba')
    assert result.submitted
    # the contract is returned as part of the result
    assert str(result.contract.amount) == '50'
    assert str(
        result.contract.sender
    ) == '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0'
    assert str(
        result.contract.receiver
    ) == '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c'
    assert result.contract.refund_timestamp > 1549649728
    assert result.contract.secret_hash == '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba'

    # ensure our contract was submitted
    transaction = explorer_client.posted_transaction_get(result.transaction.id)
    contract = AtomicSwapContract(transaction.coin_outputs[0], unspent=True)
    assert contract == result.contract
    # and ensure the transaction is fully signed
    for ci in transaction.coin_inputs:
        assert len(ci.fulfillment.signature.value) == 64

    # FYI: a contract's amount has to be greater than the network's minimum miner fee,
    # while tfchain does allow it, this client will raise an exception when you
    # do try to give a value equal to or less than the networks' miner fee.
    # This because such a contract cannot be redeemed or refunded.
    with pytest.raises(tfchain.errors.AtomicSwapInsufficientAmountError):
        w.atomicswap.participate(
            initiator=
            '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c',
            amount=c.minimum_miner_fee - '0.000000001 TFT',
            secret_hash=
            '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba')
Пример #3
0
def main(self):
    """
    to run:

    js_shell 'j.clients.tfchain.test(name="atomicswap_initiate")'
    """
    
    # create a tfchain client for devnet
    c = j.clients.tfchain.new("mytestclient", network_type="TEST")
    # or simply `c = j.tfchain.clients.mytestclient`, should the client already exist

    # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network)
    explorer_client = TFChainExplorerGetClientStub()
    # add the blockchain info
    explorer_client.chain_info = '{"blockid":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","difficulty":"30203","estimatedactivebs":"2365","height":16639,"maturitytimestamp":1549646167,"target":[0,2,43,120,39,20,204,42,102,32,125,110,53,77,39,71,99,124,13,223,197,154,115,42,126,62,185,120,208,177,21,190],"totalcoins":"0","arbitrarydatatotalsize":4328,"minerpayoutcount":16721,"transactioncount":17262,"coininputcount":633,"coinoutputcount":1225,"blockstakeinputcount":16639,"blockstakeoutputcount":16640,"minerfeecount":622,"arbitrarydatacount":572}'
    explorer_client.hash_add('5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8', '{"hashtype":"blockid","block":{"minerpayoutids":["84b378d60cbdd78430b39c8eddf226119b6f28256388557dd15f0b046bf3c3ed"],"transactions":[{"id":"9aec9f849e35f0bdd14c5ea9daed20c8fbfa09f5a6771bb46ce787eb7e2b00a0","height":16639,"parent":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"144b2b7711fda335cdae5865ab3729d641266087bc4e088d9fba806345045903","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f09af1c62026aed18d1d8f80e5a7bd4947a6cb5b6b69097c5b10cb983f0d729662c511a4852fa63690884e2b5c600e3935e08b81aaa757d9f0eb740292ec8309"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["83aa29b3e77f703526e28fbc0d2bfcf2b66c06b665e11cb5535b9575fd0e8105"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"8485f94209bf3e01ed169244ab2072ebb0d1c5dc589c95b39a3fbab3641b7a7e","timestamp":1549646257,"pobsindexes":{"BlockHeight":16638,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"144b2b7711fda335cdae5865ab3729d641266087bc4e088d9fba806345045903","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f09af1c62026aed18d1d8f80e5a7bd4947a6cb5b6b69097c5b10cb983f0d729662c511a4852fa63690884e2b5c600e3935e08b81aaa757d9f0eb740292ec8309"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","difficulty":"30203","estimatedactivebs":"2365","height":16639,"maturitytimestamp":1549646167,"target":[0,2,43,120,39,20,204,42,102,32,125,110,53,77,39,71,99,124,13,223,197,154,115,42,126,62,185,120,208,177,21,190],"totalcoins":"0","arbitrarydatatotalsize":4328,"minerpayoutcount":16721,"transactioncount":17262,"coininputcount":633,"coinoutputcount":1225,"blockstakeinputcount":16639,"blockstakeoutputcount":16640,"minerfeecount":622,"arbitrarydatacount":572},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}')
    # add the wallet info
    explorer_client.hash_add('011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f', '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"4d64c4f184ef5c7267585df8bc6af8a3e9f5963903c30ff23cfdfb068cccded7","height":16623,"parent":"95caf23ce383e01bd8af5d9391123091426278716ec5eb01a986c833119511df","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"c61aebcc2555ea16ef25152966fbbdaf2e7ba6a33c75c1033249cacc6331b2e8","fulfillment":{"type":1,"data":{"publickey":"ed25519:89ba466d80af1b453a435175dbba6da7718e9cb19c64c0ed41fca3e6982e3636","signature":"3f7c30fe4bdfc37a3f483487ef7450ee63fb6d28a7e173d6b372d895f8442ce198bf3b171cfc6315d6f03a37f00675f336a91c25b179f153237330491845f00c"}}}],"coinoutputs":[{"value":"51000000000","condition":{"type":1,"data":{"unlockhash":"011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f"}}},{"value":"999627999999501","condition":{"type":1,"data":{"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"999679999999501","condition":{"type":1,"data":{"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}},"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}],"coinoutputids":["243c1bb1c7dcc18a612cf1cba4ec433f25aaedbd9916b203a66b95635f9e28b2","9516f1c1cafd58e475f424931c2f2ab9d2df62fdd263d0b075b260df80284b47"],"coinoutputunlockhashes":["011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f","0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}')
    # override internal functionality, as to use our stub client
    c._explorer_get = explorer_client.explorer_get
    c._explorer_post = explorer_client.explorer_post

    # a wallet is required to initiate an atomic swap contract
    w = c.wallets.new("mytestwallet", seed='survey exile lab cook license sock rose squirrel noodle point they lounge oval kit tape virus loop scare water gorilla baby educate program wish')
    # money is required to be available in the wallet
    assert str(w.balance.available) == '51'

    # an atomic swap contract can be created and signed without being submitted as follows:
    result = w.atomicswap.initiate(
        participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6',
        amount=50, submit=False) # submit=True is the default
    assert not result.submitted
    assert result.transaction.is_fulfilled()
    # the contract is returned as part of the result
    assert str(result.contract.amount) == '50'
    assert str(result.contract.sender) == '011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f'
    assert str(result.contract.receiver) == '0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6'
    assert result.contract.refund_timestamp > 1549646257
    assert result.contract.secret_hash == AtomicSwapSecretHash.from_secret(result.secret)
    # one would than use `w.transaction_sign(result.transaction)` to submit it for real

    # However, usually an atomic swap contract is initiated as follows:
    result = w.atomicswap.initiate(
        participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6',
        amount=50, data='the beginning of it all') # data is optional
    assert result.submitted
    # the contract is returned as part of the result
    assert str(result.contract.amount) == '50'
    assert str(result.contract.sender) == '011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f'
    assert str(result.contract.receiver) == '0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6'
    assert result.contract.refund_timestamp > 1549646257
    assert result.contract.secret_hash == AtomicSwapSecretHash.from_secret(result.secret)

    # ensure our contract was submitted
    transaction = explorer_client.posted_transaction_get(result.transaction.id)
    contract = AtomicSwapContract(transaction.coin_outputs[0], unspent=True)
    assert contract == result.contract
    # and ensure the transaction is fully signed
    for ci in transaction.coin_inputs:
        assert len(ci.fulfillment.signature.value) == 64

    # FYI: a contract's amount has to be greater than the network's minimum miner fee,
    # while tfchain does allow it, this client will raise an exception when you
    # do try to give a value equal to or less than the networks' miner fee.
    # This because such a contract cannot be redeemed or refunded.
    with pytest.raises(tfchain.errors.AtomicSwapInsufficientAmountError):
        w.atomicswap.initiate(
            participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6',
            amount=c.minimum_miner_fee-'0.000000001 TFT')
Пример #4
0
def main(self):
    """
    to run:

    js_shell 'j.clients.tfchain.test(name="wallet_coins_send")'
    """

    # create a tfchain client for devnet
    c = j.clients.tfchain.new("mydevclient", network_type="DEV")
    # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist

    # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network)
    explorer_client = TFChainExplorerGetClientStub()
    # set the current block chain info
    explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}'
    explorer_client.hash_add(
        '552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e',
        '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}'
    )
    # add initial condition
    explorer_client.mint_condition_add(
        condition=j.clients.tfchain.types.conditions.from_recipient(
            '01a006599af1155f43d687635e9680650003a6c506934996b90ae84d07648927414046f9f0e936'
        ),
        height=0,
    )
    # overwrite the explorer get/post logic
    c._explorer_get = explorer_client.explorer_get
    c._explorer_post = explorer_client.explorer_post

    # the devnet genesis seed is the seed of the wallet,
    # which receives all block stakes and coins in the genesis block of the tfchain devnet
    DEVNET_GENESIS_SEED = "image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract"

    # create a new devnet wallet
    w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED)
    # we create a new wallet using an existing seed,
    # such that our seed is used and not a new randomly generated seed

    # a tfchain (JS) wallet uses the underlying tfchain client for all its
    # interaction with the tfchain network
    assert w.network_type == "DEV"

    # balance will be fully 0 for wallet due to our stub state
    assert w.balance.available == 0
    assert w.balance.unconfirmed == 0
    assert w.balance.locked == 0

    # (1) if the wallet has no powers to mint coins,
    # the transaction will be not be submitted as the transaction won't be fulfilled
    result = w.minter.coins_new(
        recipient=
        '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a',
        amount=100,
    )
    assert not result.submitted
    assert not result.transaction.is_fulfilled()
    assert not result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentSingleSignature)

    # define the current mint condition to be ours
    explorer_client.mint_condition_add(
        condition=j.clients.tfchain.types.conditions.from_recipient(
            '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'
        ),
        height=3643,
    )

    # (2) creating coins and sending it to a personal wallet on the used tfchain network can be done as follows:
    result = w.minter.coins_new(
        recipient=
        "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a",
        amount="108.24"  # the amount of TFT to send
    )
    assert result.submitted  # it is expected the transaction is submitted

    # validate more for testing purposes
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentSingleSignature)
    assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # (3) creating coins and sending it to a personal wallet with a lock and data is possible as well
    result = w.minter.coins_new(
        recipient=
        "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f",
        amount=200,  # the amount of TFT to send
        lock=
        '07/12/2020 14:35',  # a lock can be a timestamp, data-time str, duration str, or block height
        data='maximum 83 bytes can be used as optional data')
    assert result.submitted  # it is expected the transaction is submitted

    # validate more for testing purposes
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentSingleSignature)
    assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # (4) one can also send to a full multi-sig wallet, when creating coins
    result = w.minter.coins_new(
        recipient=[
            "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f",
            "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"
        ],
        amount="50 TFT",  # the amount of TFT to send
        lock=
        1550665225,  # a lock can be a timestamp, data-time str, duration str, or block height
        data=b'binary data can be added as well')
    assert result.submitted  # it is expected the transaction is submitted

    # validate more for testing purposes
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentSingleSignature)
    assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # (5) one can also send to a x-out-of-n multisig wallet, when creating coins
    result = w.minter.coins_new(
        recipient=(1, [
            "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f",
            "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"
        ]),
        amount='300.0',  # the amount of TFT to send
        lock=
        35000,  # a lock can be a timestamp, data-time str, duration str, or block height
        data=bytearray(b'binary data can be added as well'))
    assert result.submitted  # it is expected the transaction is submitted

    # validate more for testing purposes
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentSingleSignature)
    assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # define the minter condition as multi-sig
    explorer_client.mint_condition_add(
        condition=j.clients.tfchain.types.conditions.from_recipient((1, [
            '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a',
            '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f',
        ])),
        height=3643,
        force=True)

    # (6) creating coins and sending works the same if the condition is multi-sig,
    #     the only difference is that it might be possible that the transaction is not submitted yet,
    #     should more signatures be required in order to fulfill the mint fulfillment
    result = w.minter.coins_new(
        recipient=
        "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f",
        amount="108.24"  # the amount of TFT to send
    )
    assert result.submitted  # it is expected the transaction is submitted

    # validate more for testing purposes
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(
        parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment,
                      FulfillmentMultiSignature)
    assert result.transaction.parent_mint_condition.unlockhash == '039481e77f55a2a4aee707c07d69a11b1d9dc4100ccc50b9f82d56b411826014e5ea1f477be065'
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()
Пример #5
0
def main(self):
    """
    to run:

    js_shell 'j.clients.tfchain.test(name="minter_condition_set")'
    """
    
    # create a tfchain client for devnet
    c = j.clients.tfchain.new("mydevclient", network_type="DEV")
    # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist

    # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network)
    explorer_client = TFChainExplorerGetClientStub()
    # define current block height
    explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}'
    explorer_client.hash_add('552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e', '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}')
    # add initial condition
    explorer_client.mint_condition_add(
        condition=conditions.from_recipient('01a006599af1155f43d687635e9680650003a6c506934996b90ae84d07648927414046f9f0e936'),
        height=0,
    )
    # overwrite get/post logic
    c._explorer_get = explorer_client.explorer_get
    c._explorer_post = explorer_client.explorer_post

    # the devnet genesis seed is the seed of the wallet,
    # which receives all block stakes and coins in the genesis block of the tfchain devnet
    DEVNET_GENESIS_SEED="image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract"

    # create a new devnet wallet
    w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED)
    # we create a new wallet using an existing seed,
    # such that our seed is used and not a new randomly generated seed

    # only if you have the correct minting powers,
    # you can set a new minter definition, otherwise an error will be raised

    # set another mint condition manually
    explorer_client.mint_condition_add(
        condition=conditions.from_recipient('014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'),
        height=3643,
    )

    condition = c.minter.condition_get()
    assert condition.unlockhash == w.address

    # (1) once you have the correct powers, you can can overwrite it as follows:
    result = w.minter.definition_set(minter=(1, [
        '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a',
        '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f',
    ]))
    # check if the current transaction is submitted
    assert result.submitted # it is expected

    # check if all is fulfilled
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature)
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # set another mint condition manually
    explorer_client.mint_condition_add(
        condition=conditions.from_recipient((1, [
        '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a',
        '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f',
        ])),
        height=3644,
    )

    # (2) when defining a new minter definition you can also attach data if desired
    result = w.minter.definition_set(
        minter='011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f', # new minter power
        data='redefine minter conditions', # optional data, can also be as binary data
    )
    assert result.submitted # it is expected the transaction is submitted
    assert result.transaction.is_fulfilled()
    assert result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment, FulfillmentMultiSignature)
    # ensure the transaction is posted and as expected there as well
    txn = explorer_client.posted_transaction_get(result.transaction.id)
    assert txn.json() == result.transaction.json()

    # set another mint condition manually
    explorer_client.mint_condition_add(
        condition=conditions.from_recipient('011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f'),
        height=3645,
    )

    # if an invalid recipient is given it, a ValueError or TypeError is raised
    with pytest.raises(ValueError):
        w.minter.definition_set(minter=None)
    with pytest.raises(ValueError):
        w.minter.definition_set(minter='0123bla')
    with pytest.raises(TypeError):
        w.minter.definition_set(minter=1)

    # (3) if the wallet has no powers to redefine the powers,
    # the transaction will be not be submitted as the transaction won't be fulfilled
    result = w.minter.definition_set(minter='014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a')
    assert not result.submitted
    assert not result.transaction.is_fulfilled()
    assert not result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get())
    assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature)