def sign(self,tx_num_str,keys): if self.marked_signed(): die(1,'Transaction is already signed!') self.die_if_incorrect_chain() if (self.has_segwit_inputs() or self.has_segwit_outputs()) and not g.proto.cap('segwit'): die(2,yellow("TX has Segwit inputs or outputs, but {} doesn't support Segwit!".format(g.coin))) qmsg('Passing {} key{} to {}'.format(len(keys),suf(keys,'s'),g.proto.daemon_name)) if self.has_segwit_inputs(): from mmgen.addr import KeyGenerator,AddrGenerator kg = KeyGenerator('std') ag = AddrGenerator('segwit') keydict = MMGenDict([(d.addr,d.sec) for d in keys]) sig_data = [] for d in self.inputs: e = dict([(k,getattr(d,k)) for k in ('txid','vout','scriptPubKey','amt')]) e['amount'] = e['amt'] del e['amt'] if d.mmid and d.mmid.mmtype == 'S': e['redeemScript'] = ag.to_segwit_redeem_script(kg.to_pubhex(keydict[d.addr])) sig_data.append(e) msg_r('Signing transaction{}...'.format(tx_num_str)) wifs = [d.sec.wif for d in keys] ret = g.rpch.signrawtransaction(self.hex,sig_data,wifs,g.proto.sighash_type,on_fail='return') from mmgen.rpc import rpc_error,rpc_errmsg if rpc_error(ret): errmsg = rpc_errmsg(ret) if 'Invalid sighash param' in errmsg: m = 'This is not the BCH chain.' m += "\nRe-run the script without the --coin=bch option." else: m = errmsg msg(yellow(m)) return False else: if ret['complete']: # Msg(pretty_hexdump(unhexlify(self.hex),cols=16)) # DEBUG # pmsg(make_chksum_6(unhexlify(self.hex)).upper()) self.hex = ret['hex'] self.compare_size_and_estimated_size() dt = DeserializedTX(self.hex) self.check_hex_tx_matches_mmgen_tx(dt) self.coin_txid = CoinTxID(dt['txid'],on_fail='return') self.check_sigs(dt) assert self.coin_txid == g.rpch.decoderawtransaction(self.hex)['txid'],( 'txid mismatch (after signing)') msg('OK') return True else: msg('failed\n{} returned the following errors:'.format(g.proto.daemon_name.capitalize())) msg(repr(ret['errors'])) return False
def parse_arg1(arg, arg_id): m1 = 'First argument must be a numeric generator ID or two colon-separated generator IDs' m2 = 'Second part of first argument must be a numeric generator ID or one of {}' def check_gen_num(n): if not (1 <= int(n) <= len(g.key_generators)): die(1, '{}: invalid generator ID'.format(n)) return int(n) if arg_id == 'a': if is_int(arg): a_num = check_gen_num(arg) return (KeyGenerator(proto, addr_type, a_num), a_num) else: die(1, m1) elif arg_id == 'b': if is_int(arg): return KeyGenerator(proto, addr_type, check_gen_num(arg)) elif arg in ext_progs + ['ext']: return init_tool(get_tool(arg)) else: die(1, m2.format(ext_progs))
def _create_fake_unspent_data(self, adata, tx_data, non_mmgen_input='', non_mmgen_input_compressed=True): out = [] for d in tx_data.values(): al = adata.addrlist(al_id=d['al_id']) for n, (idx, coinaddr) in enumerate(al.addrpairs()): lbl = get_label(do_shuffle=True) out.append( self._create_fake_unspent_entry(coinaddr, d['al_id'], idx, lbl, segwit=d['segwit'])) if n == 0: # create a duplicate address. This means addrs_per_wallet += 1 out.append( self._create_fake_unspent_entry(coinaddr, d['al_id'], idx, lbl, segwit=d['segwit'])) if non_mmgen_input: from mmgen.obj import PrivKey privkey = PrivKey(self.proto, os.urandom(32), compressed=non_mmgen_input_compressed, pubkey_type='std') from mmgen.addr import AddrGenerator, KeyGenerator rand_coinaddr = AddrGenerator(self.proto, 'compressed').to_addr( KeyGenerator(self.proto, 'std').to_pubhex(privkey)) of = joinpath(self.cfgs[non_mmgen_input]['tmpdir'], non_mmgen_fn) write_data_to_file(outfile=of, data=privkey.wif + '\n', desc=f'compressed {self.proto.name} key', quiet=True, ignore_opt_outdir=True) out.append( self._create_fake_unspent_entry(rand_coinaddr, non_mmgen=True, segwit=False)) return out
def _make_txcreate_cmdline(self, tx_data): from mmgen.obj import PrivKey privkey = PrivKey(self.proto, os.urandom(32), compressed=True, pubkey_type='std') t = ('compressed', 'segwit')['S' in self.proto.mmtypes] from mmgen.addr import AddrGenerator, KeyGenerator rand_coinaddr = AddrGenerator(self.proto, t).to_addr( KeyGenerator(self.proto, 'std').to_pubhex(privkey)) # total of two outputs must be < 10 BTC (<1000 LTC) mods = { 'btc': (6, 4), 'bch': (6, 4), 'ltc': (600, 400) }[self.proto.coin.lower()] for k in self.cfgs: self.cfgs[k]['amts'] = [None, None] for idx, mod in enumerate(mods): self.cfgs[k]['amts'][idx] = '{}.{}'.format( getrandnum(4) % mod, str(getrandnum(4))[:5]) cmd_args = ['--outdir=' + self.tmpdir] for num in tx_data: s = tx_data[num] cmd_args += [ '{}:{},{}'.format(s['al_id'], s['addr_idxs'][0], self.cfgs[num]['amts'][0]), ] # + one change address and one BTC address if num is list(tx_data.keys())[-1]: cmd_args += ['{}:{}'.format(s['al_id'], s['addr_idxs'][1])] cmd_args += [ '{},{}'.format(rand_coinaddr, self.cfgs[num]['amts'][1]) ] return cmd_args + [tx_data[num]['addrfile'] for num in tx_data]
if not b and type(arg2) == int: speed_test(a, ag, arg2) elif not b and hasattr(arg2, 'read'): dump_test(a, ag, arg2) elif a and b and type(arg2) == int: if opt.all: from mmgen.protocol import CoinProtocol, init_genonly_altcoins init_genonly_altcoins(testnet=proto.testnet) for coin in ci.external_tests[proto.network][b.desc]: if coin.lower() not in CoinProtocol.coins: # ymsg('Coin {} not configured'.format(coin)) continue proto = init_proto(coin) if addr_type not in proto.mmtypes: continue # proto has changed, so reinit kg and ag a = KeyGenerator(proto, addr_type, a_num) ag = AddrGenerator(proto, addr_type) b_chk = ci.get_test_support(proto.coin, addr_type.name, proto.network, tool=b.desc, verbose=not opt.quiet) if b_chk == b.desc: gentool_test(a, b, ag, arg2) else: gentool_test(a, b, ag, arg2) else: opts.usage()
assert 1 <= a <= len( g.key_generators), '{}: invalid key generator'.format(a) if b in ('ext', 'pyethereum', 'pycoin', 'keyconv', 'zcash_mini'): init_external_prog() else: b = int(b) assert 1 <= b <= len( g.key_generators), '{}: invalid key generator'.format(b) assert a != b, 'Key generators are the same!' except Exception as e: die(1, '{}\n{}: invalid generator argument'.format(e[0], cmd_args[0])) from mmgen.addr import KeyGenerator, AddrGenerator from mmgen.obj import PrivKey kg_a = KeyGenerator(addr_type, a) ag = AddrGenerator(addr_type) if a and b: if opt.all: from mmgen.protocol import init_coin, init_genonly_altcoins, CoinProtocol init_genonly_altcoins('btc', trust_level=0) mmgen_supported = CoinProtocol.get_valid_coins(upcase=True) for coin in ci.external_tests[('mainnet', 'testnet')[g.testnet]][ext_lib]: if coin not in mmgen_supported: continue init_coin(coin) tmp_addr_type = addr_type if addr_type in g.proto.mmtypes else MMGenAddrType( g.proto.dfl_mmtype) kg_a = KeyGenerator(tmp_addr_type, a) ag = AddrGenerator(tmp_addr_type)
def sign(self, c, tx_num_str, keys): self.die_if_incorrect_chain() if g.coin == 'BCH' and (self.has_segwit_inputs() or self.has_segwit_outputs()): die( 2, yellow( "Segwit inputs cannot be spent or spent to on the BCH chain!" )) qmsg('Passing {} key{} to bitcoind'.format(len(keys), suf(keys, 's'))) if self.has_segwit_inputs(): from mmgen.addr import KeyGenerator, AddrGenerator kg = KeyGenerator() ag = AddrGenerator('segwit') keydict = MMGenDict([(d.addr, d.sec) for d in keys]) sig_data = [] for d in self.inputs: e = dict([(k, getattr(d, k)) for k in ('txid', 'vout', 'scriptPubKey', 'amt')]) e['amount'] = e['amt'] del e['amt'] if d.mmid and d.mmid.mmtype == 'S': e['redeemScript'] = ag.to_segwit_redeem_script( kg.to_pubhex(keydict[d.addr])) sig_data.append(e) msg_r('Signing transaction{}...'.format(tx_num_str)) ht = ('ALL', 'ALL|FORKID')[g.coin == 'BCH'] # sighashtype defaults to 'ALL' wifs = [d.sec.wif for d in keys] # keys.pmsg() # pmsg(wifs) ret = c.signrawtransaction(self.hex, sig_data, wifs, ht, on_fail='return') from mmgen.rpc import rpc_error, rpc_errmsg if rpc_error(ret): errmsg = rpc_errmsg(ret) if 'Invalid sighash param' in errmsg: m = 'This is not the BCH chain.' m += "\nRe-run the script without the --aug1hf or --coin=bch option." else: m = errmsg msg(yellow(m)) return False else: if ret['complete']: self.hex = ret['hex'] vmsg('Signed transaction size: {}'.format(len(self.hex) / 2)) dt = DeserializedTX(self.hex) txid = dt['txid'] self.check_sigs(dt) assert txid == c.decoderawtransaction( self.hex)['txid'], 'txid mismatch (after signing)' self.btc_txid = BitcoinTxID(txid, on_fail='return') msg('OK') return True else: msg('failed\nBitcoind returned the following errors:') msg(repr(ret['errors'])) return False
""".format(sec, wif, a_addr, b_addr, pnm=g.proj_name, a=m[a], b=m[b]).rstrip()) # Begin execution compressed = True from mmgen.addr import KeyGenerator, AddrGenerator from mmgen.obj import PrivKey ag = AddrGenerator(('p2pkh', 'segwit')[bool(opt.segwit)]) if a and b: m = "Comparing address generators '{}' and '{}'" qmsg(green(m.format(g.key_generators[a - 1], g.key_generators[b - 1]))) last_t = time.time() kg_a = KeyGenerator(a) kg_b = KeyGenerator(b) for i in range(rounds): if time.time() - last_t >= 0.1: qmsg_r('\rRound %s/%s ' % (i + 1, rounds)) last_t = time.time() sec = PrivKey(os.urandom(32), compressed) a_addr = ag.to_addr(kg_a.to_pubhex(sec)) b_addr = ag.to_addr(kg_b.to_pubhex(sec)) vmsg('\nkey: %s\naddr: %s\n' % (sec.wif, a_addr)) if a_addr != b_addr: match_error(sec, sec.wif, a_addr, b_addr, a, b) if not opt.segwit: compressed = not compressed qmsg_r('\rRound %s/%s ' % (i + 1, rounds))
arg2 = parse_arg2() ag = AddrGenerator(addr_type) if not b and type(arg2) == int: speed_test(a,ag,arg2) elif not b and hasattr(arg2,'read'): dump_test(a,ag,arg2) elif a and b and type(arg2) == int: if opt.all: from mmgen.protocol import CoinProtocol,init_genonly_altcoins init_genonly_altcoins(testnet=g.proto.testnet) for coin in ci.external_tests[g.proto.network][b.desc]: if coin.lower() not in CoinProtocol.coins: # ymsg('Coin {} not configured'.format(coin)) continue g.proto = init_proto(coin) if addr_type not in g.proto.mmtypes: continue # g.proto has changed, so reinit kg and ag just to be on the safe side: a = KeyGenerator(addr_type,a_num) ag = AddrGenerator(addr_type) b_chk = ci.get_test_support(g.coin,addr_type.name,g.proto.network,tool=b.desc,verbose=not opt.quiet) if b_chk == b.desc: gentool_test(a,b,ag,arg2) else: gentool_test(a,b,ag,arg2) else: opts.usage()