1from pycoin.block import Block 2from pycoin.coins.bitcoin.ScriptTools import BitcoinScriptTools 3from pycoin.coins.bitcoin.Tx import Tx 4from pycoin.coins.exceptions import ValidationFailureError 5from pycoin.coins.tx_utils import create_tx, split_with_remainder, distribute_from_split_pool, sign_tx, create_signed_tx 6from pycoin.coins.SolutionChecker import ScriptError 7from pycoin.contrib.msg_signing import MessageSigner 8from pycoin.contrib.who_signed import WhoSigned 9from pycoin.ecdsa.secp256k1 import secp256k1_generator 10from pycoin.encoding.b58 import b2a_hashed_base58 11from pycoin.key.HDSeed import HDSeed 12from pycoin.key.Keychain import Keychain 13from pycoin.key.Key import Key, InvalidSecretExponentError, InvalidPublicPairError 14from pycoin.key.BIP32Node import BIP32Node 15from pycoin.key.BIP49Node import BIP49Node 16from pycoin.key.BIP84Node import BIP84Node 17from pycoin.key.electrum import ElectrumWallet 18from pycoin.message.make_parser_and_packer import ( 19 make_parser_and_packer, standard_messages, 20 standard_message_post_unpacks, standard_streamer, standard_parsing_functions 21) 22from pycoin.encoding.hexbytes import b2h, h2b 23from pycoin.satoshi import errno, flags 24from pycoin.solve.utils import build_hash160_lookup, build_p2sh_lookup, build_sec_lookup 25from pycoin.vm.annotate import Annotate 26 27from .AddressAPI import make_address_api 28from .ParseAPI import ParseAPI 29from .ContractAPI import ContractAPI 30from .parseable_str import parseable_str 31 32 33class API(object): 34 pass 35 36 37class Network(object): 38 def __init__(self, symbol, network_name, subnet_name): 39 self.symbol = symbol 40 self.network_name = network_name 41 self.subnet_name = subnet_name 42 43 def full_name(self): 44 return "%s %s" % (self.network_name, self.subnet_name) 45 46 def __repr__(self): 47 return "<Network %s>" % self.full_name() 48 49 50def make_output_for_secret_exponent(Key): 51 def f(secret_exponent): 52 yield ("secret_exponent", '%d' % secret_exponent, None) 53 yield ("secret_exponent_hex", '%x' % secret_exponent, " hex") 54 key = Key(secret_exponent) 55 yield ("wif", key.wif(is_compressed=True), None) 56 yield ("wif_uncompressed", key.wif(is_compressed=False), " uncompressed") 57 return f 58 59 60def make_output_for_public_pair(Key, network): 61 def f(public_pair): 62 yield ("public_pair_x", '%d' % public_pair[0], None) 63 yield ("public_pair_y", '%d' % public_pair[1], None) 64 yield ("public_pair_x_hex", '%x' % public_pair[0], " x as hex") 65 yield ("public_pair_y_hex", '%x' % public_pair[1], " y as hex") 66 yield ("y_parity", "odd" if (public_pair[1] & 1) else "even", None) 67 68 key = Key(public_pair=public_pair) 69 yield ("key_pair_as_sec", b2h(key.sec(is_compressed=True)), None) 70 yield ("key_pair_as_sec_uncompressed", b2h(key.sec(is_compressed=False)), " uncompressed") 71 72 network_name = network.network_name 73 hash160_u = key.hash160(is_compressed=False) 74 hash160_c = key.hash160(is_compressed=True) 75 76 yield ("hash160", b2h(hash160_c), None) 77 78 if hash160_c and hash160_u: 79 yield ("hash160_uncompressed", b2h(hash160_u), " uncompressed") 80 81 address = network.address.for_p2pkh(hash160_c) 82 yield ("address", address, "%s address" % network_name) 83 yield ("%s_address" % network.symbol, address, "legacy") 84 85 address = key.address(is_compressed=False) 86 yield ("address_uncompressed", address, "%s address uncompressed" % network_name) 87 yield ("%s_address_uncompressed" % network.symbol, address, "legacy") 88 89 # don't print segwit addresses unless we're sure we have a compressed key 90 if hash160_c and hasattr(network.address, "for_p2pkh_wit"): 91 address_segwit = network.address.for_p2pkh_wit(hash160_c) 92 if address_segwit: 93 # this network seems to support segwit 94 yield ("address_segwit", address_segwit, "%s segwit address" % network_name) 95 yield ("%s_address_segwit" % network.symbol, address_segwit, "legacy") 96 97 p2sh_script = network.contract.for_p2pkh_wit(hash160_c) 98 p2s_address = network.address.for_p2s(p2sh_script) 99 if p2s_address: 100 yield ("p2sh_segwit", p2s_address, None) 101 102 p2sh_script_hex = b2h(p2sh_script) 103 yield ("p2sh_segwit_script", p2sh_script_hex, " corresponding p2sh script") 104 105 return f 106 107 108def create_bitcoinish_network(symbol, network_name, subnet_name, **kwargs): 109 # potential kwargs: 110 # tx, block, magic_header_hex, default_port, dns_bootstrap, 111 # wif_prefix_hex, address_prefix_hex, pay_to_script_prefix_hex 112 # bip32_prv_prefix_hex, bip32_pub_prefix_hex, sec_prefix, script_tools 113 # bip49_prv_prefix, bip49_pub_prefix, bip84_prv_prefix, bip84_pub_prefix 114 115 network = Network(symbol, network_name, subnet_name) 116 117 generator = kwargs.get("generator", secp256k1_generator) 118 kwargs.setdefault("sec_prefix", "%sSEC" % symbol.upper()) 119 KEYS_TO_H2B = ("bip32_prv_prefix bip32_pub_prefix bip49_prv_prefix bip49_pub_prefix " 120 "bip84_prv_prefix bip84_pub_prefix wif_prefix address_prefix " 121 "pay_to_script_prefix sec_prefix magic_header").split() 122 for k in KEYS_TO_H2B: 123 k_hex = "%s_hex" % k 124 if k_hex in kwargs: 125 kwargs[k] = h2b(kwargs[k_hex]) 126 127 script_tools = kwargs.get("script_tools", BitcoinScriptTools) 128 129 UI_KEYS = ("bip32_prv_prefix bip32_pub_prefix bip49_prv_prefix bip49_pub_prefix " 130 "bip84_prv_prefix bip84_pub_prefix wif_prefix sec_prefix " 131 "address_prefix pay_to_script_prefix bech32_hrp").split() 132 ui_kwargs = {k: kwargs[k] for k in UI_KEYS if k in kwargs} 133 134 _bip32_prv_prefix = ui_kwargs.get("bip32_prv_prefix") 135 _bip32_pub_prefix = ui_kwargs.get("bip32_pub_prefix") 136 _wif_prefix = ui_kwargs.get("wif_prefix") 137 _sec_prefix = ui_kwargs.get("sec_prefix") 138 139 def bip32_as_string(blob, as_private): 140 prefix = ui_kwargs.get("bip32_%s_prefix" % ("prv" if as_private else "pub")) 141 return b2a_hashed_base58(prefix + blob) 142 143 def bip49_as_string(blob, as_private): 144 prefix = ui_kwargs.get("bip49_%s_prefix" % ("prv" if as_private else "pub")) 145 return b2a_hashed_base58(prefix + blob) 146 147 def bip84_as_string(blob, as_private): 148 prefix = ui_kwargs.get("bip84_%s_prefix" % ("prv" if as_private else "pub")) 149 return b2a_hashed_base58(prefix + blob) 150 151 def wif_for_blob(blob): 152 return b2a_hashed_base58(_wif_prefix + blob) 153 154 def sec_text_for_blob(blob): 155 return _sec_prefix + b2h(blob) 156 157 NetworkKey = Key.make_subclass(symbol, network=network, generator=generator) 158 NetworkElectrumKey = ElectrumWallet.make_subclass(symbol, network=network, generator=generator) 159 NetworkBIP32Node = BIP32Node.make_subclass(symbol, network=network, generator=generator) 160 NetworkBIP49Node = BIP49Node.make_subclass(symbol, network=network, generator=generator) 161 NetworkBIP84Node = BIP84Node.make_subclass(symbol, network=network, generator=generator) 162 163 NETWORK_KEYS = "network_name subnet_name dns_bootstrap default_port magic_header".split() 164 for k in NETWORK_KEYS: 165 if k in kwargs: 166 setattr(network, k, kwargs[k]) 167 168 network.Tx = network.tx = kwargs.get("tx") or Tx 169 network.Block = network.block = kwargs.get("block") or Block.make_subclass(symbol, network.tx) 170 171 streamer = standard_streamer(standard_parsing_functions(network.block, network.tx)) 172 173 network.message = API() 174 network.message.parse, network.message.pack = make_parser_and_packer( 175 streamer, standard_messages(), standard_message_post_unpacks(streamer)) 176 177 network.output_for_secret_exponent = make_output_for_secret_exponent(NetworkKey) 178 network.output_for_public_pair = make_output_for_public_pair(NetworkKey, network) 179 180 network.keychain = Keychain 181 182 parse_api_class = kwargs.get("parse_api_class", ParseAPI) 183 network.parse = parse_api_class(network, **ui_kwargs) 184 185 network.contract = ContractAPI(network, script_tools) 186 187 network.address = make_address_api(network.contract, **ui_kwargs) 188 189 def keys_private(secret_exponent, is_compressed=True): 190 return NetworkKey(secret_exponent=secret_exponent, is_compressed=is_compressed) 191 192 def keys_public(item, is_compressed=None): 193 if isinstance(item, tuple): 194 if is_compressed is None: 195 is_compressed = True 196 # it's a public pair 197 return NetworkKey(public_pair=item, is_compressed=is_compressed) 198 if is_compressed is not None: 199 raise ValueError("can't set is_compressed from sec") 200 return NetworkKey.from_sec(item) 201 202 network.keys = API() 203 network.keys.private = keys_private 204 network.keys.public = keys_public 205 206 def electrum_seed(seed): 207 return NetworkElectrumKey(initial_key=seed) 208 209 def electrum_private(master_private_key): 210 return NetworkElectrumKey(master_private_key=master_private_key) 211 212 def electrum_public(master_public_key): 213 return NetworkElectrumKey(master_public_key=master_public_key) 214 215 network.keys.bip32_seed = NetworkBIP32Node.from_master_secret 216 network.keys.bip32_deserialize = NetworkBIP32Node.deserialize 217 network.keys.bip49_deserialize = NetworkBIP49Node.deserialize 218 network.keys.bip84_deserialize = NetworkBIP84Node.deserialize 219 220 network.keys.electrum_seed = electrum_seed 221 network.keys.electrum_private = electrum_private 222 network.keys.electrum_public = electrum_public 223 network.keys.InvalidSecretExponentError = InvalidSecretExponentError 224 network.keys.InvalidPublicPairError = InvalidPublicPairError 225 226 network.msg = API() 227 message_signer = MessageSigner(network, generator) 228 network.msg.sign = message_signer.sign_message 229 network.msg.verify = message_signer.verify_message 230 network.msg.parse_signed = message_signer.parse_signed_message 231 network.msg.hash_for_signing = message_signer.hash_for_signing 232 network.msg.signature_for_message_hash = message_signer.signature_for_message_hash 233 network.msg.pair_for_message_hash = message_signer.pair_for_message_hash 234 network.script = script_tools 235 236 network.bip32_as_string = bip32_as_string 237 network.bip49_as_string = bip49_as_string 238 network.sec_text_for_blob = sec_text_for_blob 239 network.wif_for_blob = wif_for_blob 240 241 def network_build_hash160_lookup(iter): 242 return build_hash160_lookup(iter, [generator]) 243 244 network.tx.solve = API() 245 network.tx.solve.build_hash160_lookup = network_build_hash160_lookup 246 network.tx.solve.build_p2sh_lookup = build_p2sh_lookup 247 network.tx.solve.build_sec_lookup = build_sec_lookup 248 249 network.validator = API() 250 network.validator.ScriptError = ScriptError 251 network.validator.ValidationFailureError = ValidationFailureError 252 network.validator.errno = errno 253 network.validator.flags = flags 254 255 def my_create_tx(*args, **kwargs): 256 return create_tx(network, *args, **kwargs) 257 258 def my_sign_tx(*args, **kwargs): 259 return sign_tx(network, *args, **kwargs) 260 261 def my_create_signed_tx(*args, **kwargs): 262 return create_signed_tx(network, *args, **kwargs) 263 264 def my_split_with_remainder(*args, **kwargs): 265 return split_with_remainder(network, *args, **kwargs) 266 267 network.tx_utils = API() 268 network.tx_utils.create_tx = my_create_tx 269 network.tx_utils.sign_tx = my_sign_tx 270 network.tx_utils.create_signed_tx = my_create_signed_tx 271 network.tx_utils.split_with_remainder = my_split_with_remainder 272 network.tx_utils.distribute_from_split_pool = distribute_from_split_pool 273 274 network.annotate = Annotate(script_tools, network.address) 275 276 network.who_signed = WhoSigned(script_tools, network.address, generator) 277 278 network.str = parseable_str 279 280 network.generator = generator 281 282 return network 283