コード例 #1
0
def get_all_used_addresses(threshold=1, account=0, verbose=False, index=0):
    addresses = []
    missing = 0
    while missing <= threshold:
        keypath = energi.serialize_pathd(
            energi.create_pathd(account=account, index=index))
        public_key = ledger.get_public_key(keypath)
        address = energi.encode_address(energi.compress_public_key(public_key))
        uncompressed_address = energi.encode_address(public_key)

        find_change = False

        if not is_unused(address) or not is_unused(uncompressed_address):
            ae = address_entry(address,
                               uncompressed_address,
                               public_key,
                               index=index,
                               account=account)
            if verbose:
                print('found used: %s' % ae['path'])
            addresses.append(ae)
            missing = 0
            find_change = True

        if find_change:
            addresses += get_all_used_change(index, threshold, account,
                                             verbose)

        missing += 1
        index += 1

    return addresses
コード例 #2
0
def search_address_path(address_in, account=0):
    if isinstance(address_in, str):
        address_in = bytes([ord(c) for c in address_in])

    index = 0
    change = 0
    state = 0
    while True:
        keypath = energi.serialize_pathd(
            energi.create_pathd(index=index, change=change, account=account))
        public_key = ledger.get_public_key(keypath)
        address = energi.encode_address(energi.compress_public_key(public_key))
        uncompressed_address = energi.encode_address(public_key)

        if address_in == address or address_in == uncompressed_address:
            return energi.create_pathd(index=index,
                                       change=change,
                                       account=account)

        unused = is_unused(address) and is_unused(uncompressed_address)

        if state == 0:
            if unused:
                return None
            state = 1
            change = 1
        elif state == 1:
            if unused:
                index += 1
                change = 0
                state = 0
            else:
                change += 1
コード例 #3
0
def get_all_used_change(for_index, threshold=1, account=0, verbose=False):
    addresses = []
    missing = 0
    change = 1
    while missing <= threshold:
        keypath = energi.serialize_pathd(
            energi.create_pathd(index=for_index,
                                change=change,
                                account=account))
        public_key = ledger.get_public_key(keypath)
        address = energi.encode_address(energi.compress_public_key(public_key))
        uncompressed_address = energi.encode_address(public_key)

        if not is_unused(address) or not is_unused(uncompressed_address):
            ae = address_entry(address,
                               uncompressed_address,
                               public_key,
                               change=change,
                               index=for_index,
                               account=account)
            if verbose:
                print('found used: %s' % ae['path'])
            addresses.append(ae)
            missing = 0

        missing += 1
        change += 1

    return addresses
コード例 #4
0
def create_mnb(mne):
    collat_outpoint = Transaction.COutPoint(serialize.hs2b(mne['txid']), mne['nout'])

    mnp = Masternode.CMasternodePing(collat_outpoint)
    mn_privkey = energi.decode_address(mne['mn_privkey'])
    block_hash = Masternode.get_block_hash(13)
    mnp.sign(block_hash, mn_privkey)

    mnb = Masternode.CMasternodeBroadcast()
    mnb.outpoint = collat_outpoint
    mnb.addr = parse_ipport(mne['ip'])

    mn_private_key = secp256k1.PrivateKey(mn_privkey, raw = True)
    mn_public_key = mn_private_key.pubkey.serialize(compressed = False)

    co_ae = walletdb.get_addr_txid(mne['txid'], mne['nout'])
    if co_ae is None:
        raise RuntimeError('cannot find address for txid: %s' % mne['txid'])
    co_public_key = co_ae['pubkey']

    mnb.pubkey_collateral = energi.compress_public_key(co_public_key)
    mnb.pubkey_masternode = mn_public_key

    mnb.last_ping = mnp

    print('Signing on ledger:')
    mnb.hw_sign(energi.serialize_pathd(co_ae))

    print('MasternodeBroadcast:\n%s' % mnb)
    return mnb
コード例 #5
0
def get_address(ae, display=False):
    keypath = energi.serialize_pathd(ae)
    public_key = ledger.get_public_key(keypath, display)
    address = energi.encode_address(energi.compress_public_key(public_key))
    uncompressed_address = energi.encode_address(public_key)
    return address_entry(address, uncompressed_address, public_key,
                         ae['purpose'], ae['coin'], ae['account'],
                         ae['change'], ae['index'])
コード例 #6
0
def get_next_change(for_index, account=0):
    i = 1
    while True:
        keypath = energi.serialize_pathd(
            energi.create_pathd(index=for_index, change=i, account=account))
        public_key = ledger.get_public_key(keypath)
        address = energi.encode_address(energi.compress_public_key(public_key))
        uncompressed_address = energi.encode_address(public_key)

        if is_unused(address) and is_unused(uncompressed_address):
            return address_entry(address,
                                 uncompressed_address,
                                 public_key,
                                 index=for_index,
                                 change=i,
                                 account=account)

        i += 1
コード例 #7
0
def get_next_unused(index=0, n=1, account=0):
    count = 0
    i = index
    rl = []
    while count < n:
        keypath = energi.serialize_pathd(
            energi.create_pathd(index=i, account=0))
        public_key = ledger.get_public_key(keypath)
        address = energi.encode_address(energi.compress_public_key(public_key))
        uncompressed_address = energi.encode_address(public_key)

        if is_unused(address) and is_unused(uncompressed_address):
            rl.append(
                address_entry(address,
                              uncompressed_address,
                              public_key,
                              index=i,
                              account=account))
            count += 1

        i += 1

    return rl
コード例 #8
0
def create_tx(address_to, value_sats, addr_d, fee_minimum = 0, used_inputs = []):
    # fee_minimum is in Sats
    _NRGSAT = 10**8

    # extract utxos from addr_d (not from the change address though)
    utxol = []
    for a in addr_d:
        if 'change' != a and 'utxos' in addr_d[a]:
            for u in addr_d[a]['utxos']:
                utxol.append(u)

    # calculate transfer amounts
    fee_est = eel.get_fee_estimate() * _NRGSAT
    if fee_est < fee_minimum:
        fee_est = fee_minimum
    fee_amt = int(fee_est)
    balance = sum([u['satoshis'] for u in utxol])
    send_amt = value_sats if value_sats is not None else balance - fee_amt

    # Use as many unspent txs as we need
    amt = 0
    ul = []
    for u in utxol:
        ul.append(u)
        used_inputs.append(u)
        amt += u['satoshis']
        if amt >= send_amt + fee_amt: # assuming 1kB tx
            break

    if amt < send_amt + fee_amt:
        raise RuntimeError('error: wallet balance insufficient: %d' % amt)

    # build transaction
    tx = CTransaction()
    tx.vin = []
    for u in ul:
        h = serialize.hs2b(u['txid'])
        op = COutPoint(h, u['nout'])
        tx.vin.append(CTxIn(outpoint = op, nSequence = 2**32 - 1))

    # randomize input order (somewhat)
    random.shuffle(tx.vin)

    txout = CTxOut(send_amt, script.standard_p2pkh_pkh(energi.decode_address(address_to)))
    tx.vout = [txout]

    change_path = None
    if send_amt + fee_amt < amt:
        change_pubkey = energi.compress_public_key(addr_d['change']['public_key'])
        change_out = CTxOut(amt - (send_amt + fee_amt), script.standard_p2pkh(change_pubkey))
        tx.vout.append(change_out)
        change_path = energi.serialize_pathd(addr_d['change'])

    # randomize output order (somewhat)
    random.shuffle(tx.vout)

    txs = sign_tx(tx, address_d = addr_d, change_path = change_path)

    print('Transaction signed.  Verifying.')

    if not verify_tx(txs):
        raise RuntimeError('transaction did not verify')

    print('Verified.')

    return txs.serialize()
コード例 #9
0
def sign_tx(tx_in, address_d, change_path = None, txid_d = None):
    tx = CTransaction(tx_in)

    # First, we need a trusted input blob for each vin[i].
    sys.stdout.write('Loading input transactions (%d)...  ' % len(tx.vin)); sys.stdout.flush()
    til = []
    for i in range(len(tx.vin)):
        d = {}

        # get the txid for the output this input refers to
        txid = tx.vin[i].prevout.hash
        txid_hs = serialize.b2hs(txid[::-1])

        # and the index into vout
        n = tx.vin[i].prevout.n

        # get the transaction from energid
        tx_i_hex = eel.get_hex_transaction(txid_hs) if txid_d is None else txid_d[txid_hs]['hex']
        tx_i = CTransaction().deserialize(BytesIO(serialize.hs2b(tx_i_hex)))

        # save scriptPubKey for later
        d['scriptPubKey'] = tx_i.vout[n].scriptPubKey

        # we'll send this in chunks; the first includes up to vin len
        buf = struct.pack('<i', tx_i.nVersion) + serialize.ser_compact_size(len(tx_i.vin))
        r = ledger.call_get_trusted_input_first(n, buf)
        if r != b'':
            raise RuntimeError('get_trusted_input_first: %s' % r)

        # now send vin
        for j in range(len(tx_i.vin)):
            buf = tx_i.vin[j].serialize()
            r = ledger.call_get_trusted_input_next(buf)
            if r != b'':
                raise RuntimeError('get_trusted_input_next: %s' % r)

        # send len of vout and vout[0]
        buf = serialize.ser_compact_size(len(tx_i.vout)) + tx_i.vout[0].serialize()
        r = ledger.call_get_trusted_input_next(buf)
        if r != b'':
            raise RuntimeError('get_trusted_input_next (0): %s' % (r))

        # send the rest of vout
        for j in range(1, len(tx_i.vout)):
            buf = tx_i.vout[j].serialize()
            r = ledger.call_get_trusted_input_next(buf)
            if r != b'':
                raise RuntimeError('get_trusted_input_next (%d): %s' % (j, r))

        # send locktime
        buf = struct.pack('<I', tx_i.nLockTime)
        r = ledger.call_get_trusted_input_next(buf)
        if r == b'':
            raise RuntimeError('bad trusted input response')

        d['tib'] = r
        til.append(d)

    # Second, we need a signature to put in each vin[i].scriptSig.
    sigs = []
    for i in range(len(tx.vin)):

        tx_i = CTransaction(tx)
        for v in tx_i.vin:
            v.scriptSig = b''
        tx_i.vin[i].scriptSig = til[i]['scriptPubKey']

        # get (hash160) public key we need to sign with
        if not script.is_standard(til[i]['scriptPubKey']):
            raise RuntimeError('we can only include P2PKH transactions')

        sd = script.disass(til[i]['scriptPubKey'])

        # save for later
        hpubkey = sd[2]['data']

        # again, we'll send the transaction in chunks
        buf = struct.pack('<i', tx_i.nVersion) + serialize.ser_compact_size(len(tx_i.vin)) + bytes([1, len(til[0]['tib'])]) + til[0]['tib'] + serialize.ser_string(tx_i.vin[0].scriptSig) + struct.pack('<I', tx_i.vin[0].nSequence)
        r = ledger.call_hash_input_start_first(buf)
        if b'' != r:
            raise RuntimeError('hash_input_start_first: %s' % r)

        for j in range(1, len(tx_i.vin)):
            buf = bytes([1, len(til[j]['tib'])]) + til[j]['tib'] + serialize.ser_string(tx_i.vin[j].scriptSig) + struct.pack('<I', tx_i.vin[j].nSequence)
            r = ledger.call_hash_input_start_next(buf)
            if b'' != r:
                raise RuntimeError('hash_input_start_next: %s' % r)

        # okay, all the inputs have been given; now the outputs
        buf = serialize.ser_vector(tx_i.vout)
        bufl = [buf[x:x + 200] for x in range(0, len(buf), 200)] # can be broken up arbitrarily

        # everything but the very last one
        for b in bufl[:-1]:
            r = ledger.call_hash_input_finalize_full(b)
            if b'' != r:
                raise RuntimeError('hash_input_finalize_full: %s' % r)

        # register the change path if we have it
        if change_path is not None:
            r = ledger.call_hash_input_finalize_full_change(change_path)
            if b'' != r:
                raise RuntimeError('hash_input_finalize_full_change: %s' % r)

        sys.stdout.write('\nSign input %d: ' % (i + 1)); sys.stdout.flush()

        # now the last part of the outputs
        r = ledger.call_hash_input_finalize_full_last(bufl[-1])
        if r != bytearray(b'\x00\x00'):
            raise RuntimeError('hash_input_finalize_full: %s' % r)

        sys.stdout.write('signed'); sys.stdout.flush()

        # get the address path for the given hashed pubkey
        addr = energi.address_repr(hpubkey)
        keypath = energi.serialize_pathd(address_d[addr])

        # now sign
        buf = serialize.hs2b(keypath) + b'\x00' + struct.pack('>I', tx_i.nLockTime) + bytes([_hashtype_d['SIGHASH_ALL']])
        r = ledger.call_hash_sign(buf) # last byte is hashtype

        # save for scriptSig
        pubkey = address_d[addr]['pubkey'] if 'pubkey' in address_d[addr] else address_d[addr]['public_key']
        if energi.hash160(pubkey) != hpubkey:
            pubkey = energi.compress_public_key(pubkey)
            if energi.hash160(pubkey) != hpubkey:
                raise RuntimeError('address confusion')
        sigs.append({'signature': r, 'pubkey': pubkey})

    sys.stdout.write('\n'); sys.stdout.flush()

    # Finally, everything should be signed.  Construct scriptSig for each vin
    for i in range(len(tx.vin)):
        tx.vin[i].scriptSig = script.standard_scriptsig(sigs[i]['signature'], sigs[i]['pubkey'])

    return tx