def broadcast_transaction(self, transaction): """ Broadcasts a transaction to the Bitcoin network Args: transaction (bytes or str): serialized, signed transaction Returns: str: The transaction ID """ if isinstance(transaction, bytes): signed_hex = bytes_to_str(transaction) elif isinstance(transaction, Transaction): signed_hex = bytes_to_str(bytes(transaction)) elif isinstance(transaction, str): signed_hex = transaction else: raise TypeError( "transaction must be one of: bytes, str, Transaction.") data = {"rawtx": signed_hex} r = self._request("POST", "tx/send", json=data) if r.status_code == 200: j = r.json() return j["txid"] elif r.status_code == 400: j = r.json() # TODO: Change this to some more meaningful exception type raise exceptions.TransactionBroadcastError(j['message']) else: # Some other status code... should never happen. raise exceptions.TransactionBroadcastError( "Unexpected response: %r" % r.status_code)
def broadcast_transaction(self, transaction): """ Broadcasts a transaction to the Bitcoin network Args: transaction (bytes or str): serialized, signed transaction Returns: str: The transaction ID """ if isinstance(transaction, bytes): signed_hex = bytes_to_str(transaction) elif isinstance(transaction, Transaction): signed_hex = bytes_to_str(bytes(transaction)) elif isinstance(transaction, str): signed_hex = transaction else: raise TypeError( "transaction must be one of: bytes, str, Transaction.") data = {"signed_hex": signed_hex} r = self._request("POST", "transactions/send", json=data) if r.status_code == 200: j = r.json() return j["transaction_hash"] elif r.status_code == 400: j = r.json() # TODO: Change this to some more meaningful exception type raise exceptions.TransactionBroadcastError(j['message']) else: # Some other status code... should never happen. raise exceptions.TransactionBroadcastError( "Unexpected response: %r" % r.status_code)
def test_serialization(): scr = 'OP_ADD OP_IF OP_DUP OP_HASH160 0x68bf827a2fa3b31e53215e5dd19260d21fdf053e OP_EQUALVERIFY OP_CHECKSIG OP_ELSE OP_IF OP_DUP OP_ELSE OP_2ROT OP_ENDIF OP_HASH160 0x68bf827a2fa3b31e53215e5dd19260d21fdf053e OP_EQUAL OP_ENDIF 0x010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101' # nopep8 s = Script(scr) assert s._tokens == ['OP_ADD', 'OP_IF', 'OP_DUP', 'OP_HASH160', b'h\xbf\x82z/\xa3\xb3\x1eS!^]\xd1\x92`\xd2\x1f\xdf\x05>', 'OP_EQUALVERIFY', 'OP_CHECKSIG', 'OP_ELSE', 'OP_IF', 'OP_DUP', 'OP_ELSE', 'OP_2ROT', 'OP_ENDIF', 'OP_HASH160', b'h\xbf\x82z/\xa3\xb3\x1eS!^]\xd1\x92`\xd2\x1f\xdf\x05>', 'OP_EQUAL', 'OP_ENDIF', b'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01'] # nopep8 s_bytes = bytes(s) s_hex_str = bytes_to_str(s_bytes) s1 = Script.from_bytes(pack_var_str(s_bytes))[0] assert bytes(s1) == s_bytes raw_scr = "483045022100d60baf72dbaed8d15c3150e3309c9f7725fbdf91b0560330f3e2a0ccb606dfba02206422b1c73ce390766f0dc4e9143d0fbb400cc207e4a9fd9130e7f79e52bf81220121034ccd52d8f72cfdd680077a1a171458a1f7574ebaa196095390ae45e68adb3688" # nopep8 s = Script(bytes.fromhex(raw_scr)) s._check_tokenized() assert s._tokens assert s._ast s_hex_str = bytes_to_str(bytes(s)) assert s_hex_str == raw_scr s = Script('OP_0 OP_IF 0x1337c0de OP_ENDIF OP_1') b = bytes.fromhex("0063041337c0de6851") s1 = Script.from_bytes(pack_var_str(b))[0] assert bytes(s) == b assert bytes(s) == bytes(s1)
def __str__(self): """ Gives the hex-encoded serialization of the header. Returns: str: hex-encoded string. """ return bytes_to_str(bytes(self))
def to_hex(self): """ Generates a hex encoding of the serialized script. Returns: str: Hex-encoded serialization. """ return bytes_to_str(bytes(self))
def to_hex(self): """ Generates a hex encoding of the serialized transaction. Returns: str: Hex-encoded serialization. """ return bytes_to_str(bytes(self))
def to_hex(self): """ 序列化字节流的十六进制表示。 返回值: h (str): 十六进制字符串. """ return bytes_to_str(bytes(self))
def to_hex(self): """ 生成序列化密钥的十六进制编码。 返回值: str: 表示密钥的十六进制编码字符串。 """ return bytes_to_str(bytes(self))
def write_ew_message(msg): """Write a message to the blockchain.""" print("write_ew_message({})" % msg) # Create a bitcoin script object with our message if len(msg) > 72: raise Exception('Message is too long and may not be accepted.') msg = "EW " + msg message_script = Script('OP_RETURN 0x{}'.format(utils.bytes_to_str(msg.encode()))) # Define the fee we're willing to pay for the tx tx_fee = 11000 # Get the first UTXO from our set that can cover the fee utxo = None for utxo_addr, utxos in wallet.get_utxos().items(): for u in utxos: if u.value > tx_fee: utxo = u break if utxo: break if not utxo: raise Exception('No UTXOs available to pay for the transaction.') # Build the transaction inputs (there is only one, but Transaction expects a list) inputs = [TransactionInput(outpoint=utxo.transaction_hash, outpoint_index=utxo.outpoint_index, script=utxo.script, sequence_num=0xffffffff)] outputs = [] # Build one output with our custom message script outputs.append(TransactionOutput(value=0, script=message_script)) # Build another output to pay the UTXO money back to one of our addresses _, change_key_hash = utils.address_to_key_hash(wallet._accounts[0].get_next_address(True)) outputs.append(TransactionOutput(value=utxo.value - tx_fee, script=Script.build_p2pkh(change_key_hash))) # Build an unsigned transaction object txn = Transaction(version=Transaction.DEFAULT_TRANSACTION_VERSION, inputs=inputs, outputs=outputs, lock_time=0 ) # Sign the transaction with the correct private key private_key = wallet.get_private_key(utxo_addr) txn.sign_input(input_index=0, hash_type=Transaction.SIG_HASH_ALL, private_key=private_key, sub_script=utxo.script ) # Broadcast the transaction tx = wallet.broadcast_transaction(txn.to_hex()) return tx
def test_is_p2pkh_sig(): t = Transaction.from_hex("0100000001205607fb482a03600b736fb0c257dfd4faa49e45db3990e2c4994796031eae6e000000008b483045022100ed84be709227397fb1bc13b749f235e1f98f07ef8216f15da79e926b99d2bdeb02206ff39819d91bc81fecd74e59a721a38b00725389abb9cbecb42ad1c939fd8262014104e674caf81eb3bb4a97f2acf81b54dc930d9db6a6805fd46ca74ac3ab212c0bbf62164a11e7edaf31fbf24a878087d925303079f2556664f3b32d125f2138cbefffffffff0128230000000000001976a914f1fd1dc65af03c30fe743ac63cef3a120ffab57d88ac00000000") # nopep8 assert t.inputs[0].script.is_p2pkh_sig() sig_info = t.inputs[0].script.extract_sig_info() assert bytes_to_str(sig_info['public_key']) == '04e674caf81eb3bb4a97f2acf81b54dc930d9db6a6805fd46ca74ac3ab212c0bbf62164a11e7edaf31fbf24a878087d925303079f2556664f3b32d125f2138cbef' # nopep8 input_addresses = t.inputs[0].script.get_addresses() assert len(input_addresses) == 1 assert input_addresses[0] == '1NKxQnbtKDdL6BY1UaKdrzCxQHfn3TQnqZ'
def _send_transaction_eoa(address, params, value=0, data=""): gas = params['estimate'] gas_price = DEFAULT_GAS_PRICE nonce = _get_nonce() tx = Transaction(nonce, gas_price, gas, address, value, parse_as_bin(data)).sign(signing_key) response = rpc_call("eth_sendRawTransaction", ["0x" + bytes_to_str(rlp.encode(tx))]) result = response.get("result") if not result: raise RpcException(response.get("error")) return result
def __str__(self): """ Returns a human readable formatting of this input. Returns: s (str): A string containing the human readable input. """ return ( "CoinbaseInput(" + "Outpoint: %s " % (self.outpoint) + "Outpoint Index: 0x%08x " % (self.outpoint_index) + "Script: %s " % (bytes_to_str(self.script)) + "Sequence: 0x%08x)" % (self.sequence_num))
def broadcast_transaction(self, transaction): """ Broadcasts a transaction to the Bitcoin network Args: transaction (bytes or str): serialized, signed transaction Returns: str: The transaction ID """ if isinstance(transaction, bytes): signed_hex = bytes_to_str(transaction) elif isinstance(transaction, Transaction): signed_hex = bytes_to_str(bytes(transaction)) elif isinstance(transaction, str): signed_hex = transaction else: raise TypeError( "transaction must be one of: bytes, str, Transaction.") data = {"signed_hex": signed_hex} response_body = self._request("POST", "transactions/send", data=data).json() return response_body["transaction_hash"]
def __str__(self): """ Creates a human-readable string representation of the script. Returns: s (str): String representation of the script """ script = "" self._check_tokenized() for t in self._tokens: if isinstance(t, bytes): script += "0x%s " % bytes_to_str(t) else: script += t + " " return script.rstrip()
def test_multisig(): # This test-case taken from: # https://gist.github.com/gavinandresen/3966071 pubkeys = [ "0491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f86", # nopep8 "04865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec6874", # nopep8 "048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d46213"] # nopep8 serialized_pubkeys = [bytes.fromhex(p) for p in pubkeys] redeem_script = Script.build_multisig_redeem(2, serialized_pubkeys) assert bytes_to_str(bytes(redeem_script)) == "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae" # nopep8 assert redeem_script.is_multisig_redeem() # Get the address of the redeem script assert redeem_script.address(True).startswith("2") address = redeem_script.address() assert address == "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC"
def test_txn_serialization(txns_json): ''' txn_json: a JSON dict from api.chain.com that also contains the raw hex of the transaction in the 'hex' key ''' for txn_json in txns_json: txn = txn_from_json(txn_json) txn_bytes = bytes(txn) txn_hash = txn.hash try: assert txn.num_inputs == len(txn_json['inputs']) assert txn.num_outputs == len(txn_json['outputs']) assert str(txn_hash) == txn_json['hash'], \ "Hash does not match for txn: %s\nCorrect bytes:\n%s\nConstructed bytes:\n%s\nJSON:\n%s" % ( txn_json['hash'], txn_json['hex'], bytes_to_str(txn_bytes), txn_json) except AssertionError as e: print(e) raise
def test_multisig_sign(): # This test case taken from: # https://github.com/libbitcoin/libbitcoin-explorer/wiki/How-to-Spend-From-a-Multisig-Address unsigned_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f70100000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 tx = txn.Transaction.from_hex(unsigned_hex) pub_keys_hex = [ "02b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b", "025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c", "021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f010" ] pub_keys = [bytes.fromhex(p) for p in pub_keys_hex] redeem_script = script.Script.build_multisig_redeem(2, pub_keys) script.Script.build_p2sh( bytes.fromhex("5c406de4915e37a7e71c7ef9bff42fbf1404daa0")) priv_keys_hex = [ "0x9d695afea1c3ab99e11248e4b74e698332b11f5c5c051e6e80da61aa19ae7c89", "0x68ebab45a918444d7e088c49bda76d7df89b9ea6ba5ddeb1aab5945391828b83" ] priv_keys = [crypto.PrivateKey.from_int(int(p, 0)) for p in priv_keys_hex] # Now sign the input with the first private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) # Check the sig script assert utils.bytes_to_str( tx.inputs[0].script.ast[1] ) == "30440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901" # nopep8 # Now sign with the second private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) assert utils.bytes_to_str( tx.inputs[0].script.ast[2] ) == "3045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b01" # nopep8 # Now make sure the entire serialized txn is correct assert tx.to_hex( ) == "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd00004730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 script_pub_key = script.Script.build_p2sh(redeem_script.hash160()) assert tx.verify_input_signature(0, script_pub_key) assert not tx.verify_input_signature(0, redeem_script) wrong_script_pub_key = script.Script( "OP_HASH160 0x5c406de4915e37a7e71c7ef9bff42fbf1404daa1 OP_EQUAL") assert not tx.verify_input_signature(0, wrong_script_pub_key) # Test not enough signatures tx = txn.Transaction.from_hex(unsigned_hex) # Sign the input with only the first private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) assert not tx.verify_input_signature(0, script_pub_key) # Try doing it with the 2nd private key but not the first tx = txn.Transaction.from_hex(unsigned_hex) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) assert not tx.verify_input_signature(0, script_pub_key) # Now try doing the sigs in reverse order tx = txn.Transaction.from_hex(unsigned_hex) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) # This should still work assert tx.verify_input_signature(0, script_pub_key) # The partial should also work assert tx.verify_partial_multisig(0, script_pub_key) # Now hack the txn bytes to have the sigs in reverse order. # This should fail. txn_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd0000483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b9014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 tx = txn.Transaction.from_hex(txn_hex) assert not tx.verify_input_signature(0, script_pub_key) # Test a partially signed txn txn_hex = "0100000001124f2e9522043794a438bfa44dd161b8976af246e4850948f85a2b50c113611a000000009200483045022100ec2e3fd3e116eb25644f055ba7945d940f828b39060d4a93c7d2b6d3cbd9d41802203c9f1ad2208122e1ffcbeba09d37a596ae5ce445be465b9417481f66ab804b070147522102395a983fd92e55200fbde624f62cda10f8d0adf8261506e5c983cfe92326c5aa2102bb70b001d807721e74d96bda71d225dc6c09fe8d541d260258145b42afac93e152ae0000000001a0860100000000001976a914e205124b0e25dc77e2b29b2e57c2f56ed10771eb88ac095635ac" # nopep8 tx = txn.Transaction.from_hex(txn_hex) sig_info = tx.inputs[0].script.extract_multisig_sig_info() script_pub_key = script.Script.build_p2sh( sig_info['redeem_script'].hash160()) assert not tx.verify_input_signature(0, script_pub_key) assert tx.verify_partial_multisig(0, script_pub_key)
def to_hex(self, compressed=True): if compressed: return bytes_to_str(self.compressed_bytes) else: return bytes_to_str(bytes(self))
else: for arg in sys.argv: if arg == 'USD': rate = Price(wallet.balance())._get_usd_rate() print(rate) elif ':' in arg: address = arg.split(':')[1].strip() btc_amount = float(arg.split(':')[2].strip()) sat_amount = convert_to_satoshis(btc_amount) txs = wallet.send_to(address, sat_amount) tx = txs[0] obj = {} obj['txid'] = tx['txid'] obj['hex'] = tx['txn'].to_hex() print(json.dumps({'tx': obj})) elif '>' in arg: commands = arg.split('>') result = None for command in commands: toCallOn = result or wallet methodToCall = getattr(toCallOn, command) result = methodToCall() if isinstance(result, bytes): print(json.dumps({'data': bytes_to_str(result)})) else: print(json.dumps({'data': result})) else: execute(arg)
from pywallet.utils import HDPrivateKey, HDKey from two1.bitcoin.utils import bytes_to_str from service.api.ethereum.utils import normalize_key, ecsign from service.settings import RELAY_ACCOUNT_PHRASE master_key = HDPrivateKey.master_key_from_mnemonic(RELAY_ACCOUNT_PHRASE) root_key = HDKey.from_path(master_key, "m/44'/60'/0'/0/0") sender = root_key[-1].public_key.address() signing_key = bytes_to_str(bytes(root_key[-1])[-32:]) normalized_key = normalize_key(signing_key) def sign(hash): return ecsign(hash, normalized_key)
def __str__(self): """ Returns a hex string in RPC order """ return bytes_to_str(self._bytes[::-1])
def test_rest(): m = mock_provider m.hd_master_key = master m.reset_mocks() m.set_num_used_accounts(1) m.set_num_used_addresses(account_index=0, n=1, change=0) m.set_num_used_addresses(account_index=0, n=2, change=1) m.set_txn_side_effect_for_hd_discovery() wallet = Two1Wallet(params_or_file=config, data_provider=m, passphrase=passphrase) # First 5 internal addresses of account 0 # These can be gotten from https://dcpos.github.io/bip39/ ext_addrs = ["1Kv1QLXekeE42rKhvZ41kHS1auE7R3t21o", "1CYhVFaBwmTQRQwdyLc4rq9HwaxdqtQ68G", "18KCKKB5MGs4Rqu4t8jL9Bkt9SAp7NpUvm", "1FqUrpUpqWfHoPVga4uMKYCPHHoApvNiPa", "12zb1hJP5WEHCSKz5LyoPM9iaCwXtTthRc"] int_addrs = ["1Hiv6LroFmqcaVV9rhY6eNUjnFQh4y6kL7", "1GTUuNbgk4sv7LPQd2WqSP9PiinzeuBmay", "14fpkEZZ6QP3QEcQnfSjH7adkC2RsMuiZw", "1LPNyqqX6RU5b4oPumePR72tFfwiNUho4s", "1FqvNKJb8au82PhtGP8D1odXWVC1Ae4jN9"] bad_addrs = ["1CEDwjjtYjCQUoRZQW9RUXHH5Ao7PWYKf", "1CbHFUNsyCzZSDu7hYae7HHqgzMjBfqoP9"] paths = wallet.find_addresses(int_addrs + ext_addrs + bad_addrs) assert len(paths.keys()) == 10 for i in range(5): # Hardened account key derivation, thus 0x80000000 assert paths[ext_addrs[i]] == (0x80000000, 0, i) assert paths[int_addrs[i]] == (0x80000000, 1, i) # Check address belongs assert wallet.address_belongs(ext_addrs[i]) == "m/44'/0'/0'/0/%d" % i assert wallet.address_belongs(int_addrs[i]) == "m/44'/0'/0'/1/%d" % i for b in bad_addrs: assert b not in paths assert wallet.address_belongs(b) is None # Check that there's an account name assert wallet.get_account_name(0) == "default" # Check the balance assert wallet.balances == {'confirmed': 10000, 'total': 20000} # Check that we can get a new payout address ext_addr = wallet.get_payout_address("default") assert ext_addr == ext_addrs[1] assert wallet.accounts[0].last_indices[0] == 0 # Check the balance again - should be the same m.set_num_used_addresses(0, 1, 0) assert wallet.balances == {'confirmed': 10000, 'total': 20000} # Try sending below the dust limit with pytest.raises(ValueError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=544) # Try sending a non-integer amount (mistaken user tries to send in btc # instead of satoshi) with pytest.raises(exceptions.SatoshiUnitsError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=0.0001) # Try sending more than we have and make sure it raises an exception with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=1000000) # Should still fail when using unconfirmed if amount is greater # than unconfirmed balance with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=True, amount=1000000) # Should fail when not using unconfirmed txns and # confirmed < amount < unconfirmed. with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=False, amount=15000) # Should get past checking balance but raise a NotImplementedError with pytest.raises(NotImplementedError): wallet.send_to( address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=False, amount=7700) # Should get past checking balance but raise a signing error with pytest.raises(NotImplementedError): wallet.send_to( address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=True, amount=12581) # test number of addresses in spread_utxos with pytest.raises(ValueError): wallet.spread_utxos( threshold=500000, num_addresses=0, accounts=[]) with pytest.raises(ValueError): wallet.spread_utxos( threshold=500000, num_addresses=101, accounts=[]) # test units for spread_utxos with pytest.raises(exceptions.SatoshiUnitsError): wallet.spread_utxos( threshold=0.0001, num_addresses=1, accounts=[]) # Finally check storing to a file params = {} with tempfile.NamedTemporaryFile(delete=True) as tf: wallet.to_file(tf) # Read it back tf.seek(0, 0) params = json.loads(tf.read().decode('utf-8')) # Check that the params match expected assert params['master_key'] == config['master_key'] assert params['master_seed'] == config['master_seed'] assert params['locked'] assert params['key_salt'] == bytes_to_str(enc_key_salt) assert params['passphrase_hash'] == passphrase_hash assert params['account_type'] == "BIP44BitcoinMainnet" assert params['account_map']['default'] == 0 assert len(params['accounts']) == 1 assert params['accounts'][0]['last_payout_index'] == 0 assert params['accounts'][0]['last_change_index'] == 1 assert params['accounts'][0]['public_key'] == config['accounts'][0]['public_key'] # Now create the wallet from the file with pytest.raises(exceptions.PassphraseError): w2 = Two1Wallet(params_or_file=tf.name, data_provider=m, passphrase='wrong_pass') # Now do with the correct passphrase m.set_txn_side_effect_for_hd_discovery() w2 = Two1Wallet(params_or_file=tf.name, data_provider=m, passphrase=passphrase) assert len(w2.accounts) == 1 assert not w2._testnet acct = w2.accounts[0] assert acct.last_indices[0] == 0 assert acct.last_indices[1] == 1
def test_rest(): m = mock_provider m.hd_master_key = master m.reset_mocks() m.set_num_used_accounts(1) m.set_num_used_addresses(account_index=0, n=1, change=0) m.set_num_used_addresses(account_index=0, n=2, change=1) m.set_txn_side_effect_for_hd_discovery() wallet = Two1Wallet(params_or_file=config, data_provider=m, passphrase=passphrase) # First 5 internal addresses of account 0 # These can be gotten from https://dcpos.github.io/bip39/ ext_addrs = [ "1Kv1QLXekeE42rKhvZ41kHS1auE7R3t21o", "1CYhVFaBwmTQRQwdyLc4rq9HwaxdqtQ68G", "18KCKKB5MGs4Rqu4t8jL9Bkt9SAp7NpUvm", "1FqUrpUpqWfHoPVga4uMKYCPHHoApvNiPa", "12zb1hJP5WEHCSKz5LyoPM9iaCwXtTthRc" ] int_addrs = [ "1Hiv6LroFmqcaVV9rhY6eNUjnFQh4y6kL7", "1GTUuNbgk4sv7LPQd2WqSP9PiinzeuBmay", "14fpkEZZ6QP3QEcQnfSjH7adkC2RsMuiZw", "1LPNyqqX6RU5b4oPumePR72tFfwiNUho4s", "1FqvNKJb8au82PhtGP8D1odXWVC1Ae4jN9" ] bad_addrs = [ "1CEDwjjtYjCQUoRZQW9RUXHH5Ao7PWYKf", "1CbHFUNsyCzZSDu7hYae7HHqgzMjBfqoP9" ] paths = wallet.find_addresses(int_addrs + ext_addrs + bad_addrs) assert len(paths.keys()) == 10 for i in range(5): # Hardened account key derivation, thus 0x80000000 assert paths[ext_addrs[i]] == (0x80000000, 0, i) assert paths[int_addrs[i]] == (0x80000000, 1, i) # Check address belongs assert wallet.address_belongs(ext_addrs[i]) == "m/44'/0'/0'/0/%d" % i assert wallet.address_belongs(int_addrs[i]) == "m/44'/0'/0'/1/%d" % i for b in bad_addrs: assert b not in paths assert wallet.address_belongs(b) is None # Check that there's an account name assert wallet.get_account_name(0) == "default" # Check the balance assert wallet.balances == {'confirmed': 100000, 'total': 200000} # Check that we can get a new payout address ext_addr = wallet.get_payout_address("default") assert ext_addr == ext_addrs[1] assert wallet.accounts[0].last_indices[0] == 0 # Check the balance again - should be the same m.set_num_used_addresses(0, 1, 0) assert wallet.balances == {'confirmed': 100000, 'total': 200000} # Try sending below the dust limit with pytest.raises(ValueError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=544) # Try sending a non-integer amount (mistaken user tries to send in btc # instead of satoshi) with pytest.raises(exceptions.SatoshiUnitsError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=0.0001) # Try sending more than we have and make sure it raises an exception with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", amount=10000000) # Should still fail when using unconfirmed if amount is greater # than unconfirmed balance with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=True, amount=10000000) # Should fail when not using unconfirmed txns and # confirmed < amount < unconfirmed. with pytest.raises(exceptions.WalletBalanceError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=False, amount=150000) # Should get past checking balance but raise a NotImplementedError with pytest.raises(NotImplementedError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=False, amount=7700) # Should get past checking balance but raise a signing error with pytest.raises(NotImplementedError): wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM", use_unconfirmed=True, amount=12581) # test number of addresses in spread_utxos with pytest.raises(ValueError): wallet.spread_utxos(threshold=500000, num_addresses=0, accounts=[]) with pytest.raises(ValueError): wallet.spread_utxos(threshold=500000, num_addresses=101, accounts=[]) # test units for spread_utxos with pytest.raises(exceptions.SatoshiUnitsError): wallet.spread_utxos(threshold=0.0001, num_addresses=1, accounts=[]) # Finally check storing to a file params = {} with tempfile.NamedTemporaryFile(delete=True) as tf: wallet.to_file(tf) # Read it back tf.seek(0, 0) params = json.loads(tf.read().decode('utf-8')) # Check that the params match expected assert params['master_key'] == config['master_key'] assert params['master_seed'] == config['master_seed'] assert params['locked'] assert params['key_salt'] == bytes_to_str(enc_key_salt) assert params['passphrase_hash'] == passphrase_hash assert params['account_type'] == "BIP44BitcoinMainnet" assert params['account_map']['default'] == 0 assert len(params['accounts']) == 1 assert params['accounts'][0]['last_payout_index'] == 0 assert params['accounts'][0]['last_change_index'] == 1 assert params['accounts'][0]['public_key'] == config['accounts'][0][ 'public_key'] # Now create the wallet from the file with pytest.raises(exceptions.PassphraseError): w2 = Two1Wallet(params_or_file=tf.name, data_provider=m, passphrase='wrong_pass') # Now do with the correct passphrase m.set_txn_side_effect_for_hd_discovery() w2 = Two1Wallet(params_or_file=tf.name, data_provider=m, passphrase=passphrase) assert len(w2.accounts) == 1 assert not w2._testnet acct = w2.accounts[0] assert acct.last_indices[0] == 0 assert acct.last_indices[1] == 1
import requests import json import time from two1.bitcoin.utils import bytes_to_str from pywallet.utils import HDPrivateKey, HDKey from web3 import Web3 mnemonic = os.environ['MNEMONIC'] infura_key = os.environ['INFURA_KEY'] w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/' + infura_key)) master_key = HDPrivateKey.master_key_from_mnemonic(mnemonic) root_key = HDKey.from_path(master_key, "m/44'/60'/0'/0/0") sender_address = w3.toChecksumAddress(root_key[-1].public_key.address()) private_key = bytes_to_str(bytes(root_key[-1])[-32:]) DAI_BASE_VALUE = 1000000000000000000 class Call: def __init__(self, method, params): self.method = method self.params = params class State: def __init__(self): self.safes = {} self.last_module_block = "0x4ca0b0" self.last_top_up_block = "0x4ca0b0"
passphrase = "test_wallet" passphrase_hash = PBKDF2.crypt(passphrase) master_key = "xprv9s21ZrQH143K2dUcTctuNw8oV8e7gi4ZbHFGAnyGJtWwmKbKTbLGtx48DQGzioGDdhVn8zFhJe8hbDdfDnK19ykxjwXLzd6EpxnTqi4zQGN" # nopep8 master_seed = "tuna object element cancel hard nose faculty noble swear net subway offer" mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key, master_seed=master_seed, passphrase=passphrase, key_salt=enc_key_salt) config = {'master_key': mkey_enc, 'master_seed': mseed_enc, 'locked': True, 'passphrase_hash': passphrase_hash, 'key_salt': bytes_to_str(enc_key_salt), 'account_type': "BIP44BitcoinMainnet", 'accounts': [{'public_key': "xpub6CNX3TRAXGpoV1a3ai3Hs9R85t63V3k6BGsTaxZZMJJ4DL6kRY8riYA1r6hxyeuxgeb33FfBgrJrV6wxv6VXEVHAfPGJNw8ZzbEJHgsbmpz", # nopep8 'last_payout_index': 2, 'last_change_index': 1}], 'account_map': {'default': 0}} master = HDPrivateKey.master_key_from_mnemonic(master_seed, passphrase) mock_provider = MockProvider("BIP44BitcoinMainnet", master) def test_encrypt_decrypt(): mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=config['master_key'], master_seed=config['master_seed'], passphrase=passphrase, key_salt=enc_key_salt)
def to_hex(self): return bytes_to_str(bytes(self))
mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key, master_seed=master_seed, passphrase=passphrase, key_salt=enc_key_salt) config = { 'master_key': mkey_enc, 'master_seed': mseed_enc, 'locked': True, 'passphrase_hash': passphrase_hash, 'key_salt': bytes_to_str(enc_key_salt), 'account_type': "BIP44BitcoinMainnet", 'accounts': [{ 'public_key': "xpub6CNX3TRAXGpoV1a3ai3Hs9R85t63V3k6BGsTaxZZMJJ4DL6kRY8riYA1r6hxyeuxgeb33FfBgrJrV6wxv6VXEVHAfPGJNw8ZzbEJHgsbmpz", # nopep8 'last_payout_index': 2, 'last_change_index': 1 }], 'account_map': { 'default': 0 } } master = HDPrivateKey.master_key_from_mnemonic(master_seed, passphrase) mock_provider = MockProvider("BIP44BitcoinMainnet", master)
def test_multisig_sign(): # This test case taken from: # https://github.com/libbitcoin/libbitcoin-explorer/wiki/How-to-Spend-From-a-Multisig-Address unsigned_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f70100000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 tx = txn.Transaction.from_hex(unsigned_hex) pub_keys_hex = ["02b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b", "025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c", "021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f010"] pub_keys = [bytes.fromhex(p) for p in pub_keys_hex] redeem_script = script.Script.build_multisig_redeem(2, pub_keys) script.Script.build_p2sh( bytes.fromhex("5c406de4915e37a7e71c7ef9bff42fbf1404daa0")) priv_keys_hex = ["0x9d695afea1c3ab99e11248e4b74e698332b11f5c5c051e6e80da61aa19ae7c89", "0x68ebab45a918444d7e088c49bda76d7df89b9ea6ba5ddeb1aab5945391828b83"] priv_keys = [crypto.PrivateKey.from_int(int(p, 0)) for p in priv_keys_hex] # Now sign the input with the first private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) # Check the sig script assert utils.bytes_to_str(tx.inputs[0].script.ast[1]) == "30440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901" # nopep8 # Now sign with the second private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) assert utils.bytes_to_str(tx.inputs[0].script.ast[2]) == "3045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b01" # nopep8 # Now make sure the entire serialized txn is correct assert tx.to_hex() == "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd00004730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 script_pub_key = script.Script.build_p2sh(redeem_script.hash160()) assert tx.verify_input_signature(0, script_pub_key) assert not tx.verify_input_signature(0, redeem_script) wrong_script_pub_key = script.Script( "OP_HASH160 0x5c406de4915e37a7e71c7ef9bff42fbf1404daa1 OP_EQUAL") assert not tx.verify_input_signature(0, wrong_script_pub_key) # Test not enough signatures tx = txn.Transaction.from_hex(unsigned_hex) # Sign the input with only the first private key tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) assert not tx.verify_input_signature(0, script_pub_key) # Try doing it with the 2nd private key but not the first tx = txn.Transaction.from_hex(unsigned_hex) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) assert not tx.verify_input_signature(0, script_pub_key) # Now try doing the sigs in reverse order tx = txn.Transaction.from_hex(unsigned_hex) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[1], sub_script=redeem_script) tx.sign_input(input_index=0, hash_type=txn.Transaction.SIG_HASH_ALL, private_key=priv_keys[0], sub_script=redeem_script) # This should still work assert tx.verify_input_signature(0, script_pub_key) # The partial should also work assert tx.verify_partial_multisig(0, script_pub_key) # Now hack the txn bytes to have the sigs in reverse order. # This should fail. txn_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd0000483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b9014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000" # nopep8 tx = txn.Transaction.from_hex(txn_hex) assert not tx.verify_input_signature(0, script_pub_key) # Test a partially signed txn txn_hex = "0100000001124f2e9522043794a438bfa44dd161b8976af246e4850948f85a2b50c113611a000000009200483045022100ec2e3fd3e116eb25644f055ba7945d940f828b39060d4a93c7d2b6d3cbd9d41802203c9f1ad2208122e1ffcbeba09d37a596ae5ce445be465b9417481f66ab804b070147522102395a983fd92e55200fbde624f62cda10f8d0adf8261506e5c983cfe92326c5aa2102bb70b001d807721e74d96bda71d225dc6c09fe8d541d260258145b42afac93e152ae0000000001a0860100000000001976a914e205124b0e25dc77e2b29b2e57c2f56ed10771eb88ac095635ac" # nopep8 tx = txn.Transaction.from_hex(txn_hex) sig_info = tx.inputs[0].script.extract_multisig_sig_info() script_pub_key = script.Script.build_p2sh(sig_info['redeem_script'].hash160()) assert not tx.verify_input_signature(0, script_pub_key) assert tx.verify_partial_multisig(0, script_pub_key)