def add_address(self, target, value, height):
        assert len(target) == KEYLENGTH

        word = target
        key = ''
        path = [ '' ]
        i = self.db_utxo.iterator()

        while key != target:

            items = self.get_node(key)

            if word[0] in items.keys():
  
                i.seek(key + word[0])
                new_key, _ = i.next()

                if target.startswith(new_key):
                    # add value to the child node
                    key = new_key
                    word = target[len(key):]
                    if key == target:
                        break
                    else:
                        assert key not in path
                        path.append(key)
                else:
                    # prune current node and add new node
                    prefix = self.common_prefix(new_key, target)
                    index = len(prefix)

                    ## get hash and value of new_key from parent (if it's a leaf)
                    if len(new_key) == KEYLENGTH:
                        parent_key = self.get_parent(new_key)
                        parent = self.get_node(parent_key)
                        z = parent[ new_key[len(parent_key)] ]
                        self.put_node(prefix, { target[index]:(None,0), new_key[index]:z } )
                    else:
                        # if it is not a leaf, update the hash of new_key because skip_string changed
                        h, v = self.get_node_hash(new_key, self.get_node(new_key), prefix)
                        self.put_node(prefix, { target[index]:(None,0), new_key[index]:(h,v) } )

                    path.append(prefix)
                    self.parents[new_key] = prefix
                    break

            else:
                assert key in path
                items[ word[0] ] = (None,0)
                self.put_node(key,items)
                break

        # write 
        s = (int_to_hex(value, 8) + int_to_hex(height,4)).decode('hex')
        self.db_utxo.put(target, s)
        # the hash of a node is the txid
        _hash = target[20:52]
        self.update_node_hash(target, path, _hash, value)
Example #2
0
 def color_selected(self, color_button):
     color = color_button.get_color()
     value = utils.hex_to_rgb(color.to_string())
     raw_r, raw_g, raw_b = value
     val_str = "#" + utils.int_to_hex(int((float(raw_r) * 255.0) / 65535.0)) + \
                     utils.int_to_hex(int((float(raw_g) * 255.0) / 65535.0)) + \
                     utils.int_to_hex(int((float(raw_b) * 255.0) / 65535.0))
                     
     self.write_value(val_str)
    def add_key(self, target, value, height):
        assert len(target) == KEYLENGTH
        path = self.get_path(target, new=True)
        if path is True:
            return
        #print "add key: target", target.encode('hex'), "path", map(lambda x: x.encode('hex'), path)
        parent = path[-1]
        parent_node = self.get_node(parent)
        n = len(parent)
        c = target[n]
        if parent_node.has(c):
            h, v = parent_node.get(c)
            skip = self.get_skip(parent + c)
            child = parent + c + skip
            assert not target.startswith(child)
            prefix = self.common_prefix(child, target)
            index = len(prefix)

            if len(child) == KEYLENGTH:
                # if it's a leaf, get hash and value of new_key from parent
                d = Node.from_dict({
                    target[index]: (None, 0),
                    child[index]: (h, v)
                    })
            else:
                # if it is not a leaf, update its hash because skip_string changed
                child_node = self.get_node(child)
                h, v = child_node.get_hash(child, prefix)
                d = Node.from_dict({
                    target[index]: (None, 0),
                    child[index]: (h, v)
                    })
            self.set_skip(prefix + target[index], target[index+1:])
            self.set_skip(prefix + child[index], child[index+1:])
            self.put_node(prefix, d)
            path.append(prefix)
            self.parents[child] = prefix

            # update parent skip
            new_skip = prefix[n+1:]
            self.set_skip(parent+c, new_skip)
            parent_node.set(c, None, 0)
            self.put_node(parent, parent_node)
        else:
            # add new letter to parent
            skip = target[n+1:]
            self.set_skip(parent+c, skip)
            parent_node.set(c, None, 0)
            self.put_node(parent, parent_node)

        # write the new leaf
        s = (int_to_hex(value, 8) + int_to_hex(height,4)).decode('hex')
        self.db_utxo.put(target, s)
        # the hash of a leaf is the txid
        _hash = target[20:52]
        self.update_node_hash(target, path, _hash, value)
Example #4
0
 def set_spent(self, addr, txi, txid, index, height, undo):
     key = self.address_to_key(addr)
     leaf = key + txi
     s = self.delete_key(leaf)
     value = hex_to_int(s[0:8])
     in_height = hex_to_int(s[8:12])
     undo[leaf] = value, in_height
     # delete backlink txi-> addr
     self.db_addr.delete(txi)
     # add to history
     txo = (txid + int_to_hex(index,4) + int_to_hex(height,4)).decode('hex')
     self.db_hist_add(addr, txi + int_to_hex(in_height,4).decode('hex') + txo)
 def add_to_history(self, addr, tx_hash, tx_pos, value, tx_height):
     key = self.address_to_key(addr)
     txo = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')
     # write the new history
     self.add_key(key + txo, value, tx_height)
     # backlink
     self.db_addr.put(txo, addr)
    def import_transaction(self, txid, tx, block_height, touched_addr):

        undo = {
            'prev_addr': []
        }  # contains the list of pruned items for each address in the tx; also, 'prev_addr' is a list of prev addresses

        prev_addr = []
        for i, x in enumerate(tx.get('inputs')):
            txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'),
                                                      4)).decode('hex')
            addr = self.get_address(txi)
            if addr is not None:
                self.set_spent(addr, txi, txid, i, block_height, undo)
                touched_addr.add(addr)
            prev_addr.append(addr)

        undo['prev_addr'] = prev_addr

        # here I add only the outputs to history; maybe I want to add inputs too (that's in the other loop)
        for x in tx.get('outputs'):
            addr = x.get('address')
            if addr is None: continue
            self.add_to_history(addr, txid, x.get('index'), x.get('value'),
                                block_height)
            touched_addr.add(addr)

        return undo
 def revert_add_to_history(self, addr, tx_hash, tx_pos, value, tx_height):
     key = self.address_to_key(addr)
     txo = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')
     # delete
     self.delete_key(key + txo)
     # backlink
     self.db_addr.delete(txo)
 def set_spent(self, addr, txi, txid, index, height, undo):
     key = self.address_to_key(addr)
     leaf = key + txi
     s = self.delete_key(leaf)
     value = hex_to_int(s[0:8])
     in_height = hex_to_int(s[8:12])
     undo[leaf] = value, in_height
     # delete backlink txi-> addr
     self.db_addr.delete(txi)
     # add to history
     s = self.db_hist.get(addr)
     if s is None: s = ''
     txo = (txid + int_to_hex(index,4) + int_to_hex(height,4)).decode('hex')
     s += txi + int_to_hex(in_height,4).decode('hex') + txo
     s = s[ -80*self.pruning_limit:]
     self.db_hist.put(addr, s)
Example #9
0
    def add_to_history(self, addr, tx_hash, tx_pos, value, tx_height):
        key = self.address_to_key(addr)
        txo = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')

        # write the new history
        self.add_address(key + txo, value, tx_height)

        # backlink
        self.db_addr.put(txo, addr)
Example #10
0
    def revert_add_to_history(self, addr, tx_hash, tx_pos, value, tx_height):
        key = self.address_to_key(addr)
        txo = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')

        # delete
        self.delete_address(key + txo)

        # backlink
        self.db_addr.delete(txo)
    def set_spent(self, addr, txi, txid, index, height, undo):
        key = self.address_to_key(addr)
        leaf = key + txi

        s = self.delete_address(leaf)
        value = hex_to_int(s[0:8])
        in_height = hex_to_int(s[8:12])
        undo[leaf] = value, in_height

        # delete backlink txi-> addr
        self.db_addr.delete(txi)

        # add to history
        s = self.db_hist.get(addr)
        if s is None: s = ''
        txo = (txid + int_to_hex(index,4) + int_to_hex(height,4)).decode('hex')
        s += txi + int_to_hex(in_height,4).decode('hex') + txo
        s = s[ -80*self.pruning_limit:]
        self.db_hist.put(addr, s)
 def set(self, c, h, value):
     if h is None:
         h = chr(0)*32
     vv = int_to_hex(value, 8).decode('hex')
     item = h + vv
     assert len(item) == 40
     if self.has(c):
         self.remove(c)
     x = self.indexof(c)
     self.s = self.s[0:x] + item + self.s[x:]
     self.k |= (1<<ord(c))
     assert self.k != 0
Example #13
0
 def set(self, c, h, value):
     if h is None:
         h = chr(0) * 32
     vv = int_to_hex(value, 8).decode('hex')
     item = h + vv
     assert len(item) == 40
     if self.has(c):
         self.remove(c)
     x = self.indexof(c)
     self.s = self.s[0:x] + item + self.s[x:]
     self.k |= (1 << ord(c))
     assert self.k != 0
Example #14
0
File: base.py Project: std0/pycrypt
    def encrypt(self, text: TextIO, key: str, cipher: TextIO) -> None:
        """Encrypt the text using the key."""
        super().encrypt(text, key, cipher)

        while True:
            text_char = text.read(1)
            if text_char == '':
                break

            text_int = ord(text_char)
            char_int_allowed(text_int)

            cipher_int = self._process(text_int)

            cipher.write(int_to_hex(cipher_int))
    def revert_transaction(self, txid, tx, block_height, touched_addr, undo):
        #print_log("revert tx", txid)
        for x in reversed(tx.get('outputs')):
            addr = x.get('address')
            if addr is None: continue
            self.revert_add_to_history(addr, txid, x.get('index'), x.get('value'), block_height)
            touched_addr.add(addr)

        prev_addr = undo.pop('prev_addr')
        for i, x in reversed(list(enumerate(tx.get('inputs')))):
            addr = prev_addr[i]
            if addr is not None:
                txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
                self.revert_set_spent(addr, txi, undo)
                touched_addr.add(addr)

        assert undo == {}
 def from_dict(klass, d):
     k = 0
     s = ''
     for i in xrange(256):
         if chr(i) in d:
             k += 1<<i
             h, value = d[chr(i)]
             if h is None: h = chr(0)*32
             vv = int_to_hex(value, 8).decode('hex')
             item = h + vv
             assert len(item) == 40
             s += item
     k = "0x%0.64X" % k # 32 bytes
     k = k[2:].decode('hex')
     assert len(k) == 32
     out = k + s
     return Node(out)
    def revert_transaction(self, txid, tx, block_height, touched_addr, undo):
        #print_log("revert tx", txid)
        for x in reversed(tx.get('outputs')):
            addr = x.get('address')
            if addr is None: continue
            self.revert_add_to_history(addr, txid, x.get('index'), x.get('value'), block_height)
            touched_addr.add(addr)

        prev_addr = undo.pop('prev_addr')
        for i, x in reversed(list(enumerate(tx.get('inputs')))):
            addr = prev_addr[i]
            if addr is not None:
                txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
                self.revert_set_spent(addr, txi, undo)
                touched_addr.add(addr)

        assert undo == {}
Example #18
0
 def from_dict(klass, d):
     k = 0
     s = ''
     for i in range(256):
         if chr(i) in d.keys():
             k += 1 << i
             h, value = d[chr(i)]
             if h is None: h = chr(0) * 32
             vv = int_to_hex(value, 8).decode('hex')
             item = h + vv
             assert len(item) == 40
             s += item
     k = "0x%0.64X" % k  # 32 bytes
     k = k[2:].decode('hex')
     assert len(k) == 32
     out = k + s
     return Node(out)
Example #19
0
def messages_route():
    if request.method == 'GET':
        c.execute("SELECT id, data, iv FROM notes WHERE user_id=?",
                  (g.user_id, ))
        notes = []
        for row in c.fetchall():
            notes.append({'id': row[0], 'data': row[1], 'iv': row[2]})
        # TODO: Paginate
        return make_response(json.dumps({"notes": notes}))
    elif request.method == 'PUT':
        js = json.loads(request.data)
        note_id = int_to_hex(cryptrand(64))

        c.execute(
            "INSERT INTO notes (user_id, data, iv, id) VALUES (?, ?, ?, ?)",
            (g.user_id, js['data'], js['iv'], note_id))
        data = {'id': note_id, 'data': js['data'], 'iv': js['iv']}
        return make_response(json.dumps(data), status=200)
    return
Example #20
0
    def put_node(self, key, d, batch=None):
        k = 0
        serialized = ''
        for i in range(256):
            if chr(i) in d.keys():
                k += 1 << i
                h, v = d[chr(i)]
                if h is None: h = chr(0) * 32
                vv = int_to_hex(v, 8).decode('hex')
                item = h + vv
                assert len(item) == 40
                serialized += item

        k = "0x%0.64X" % k  # 32 bytes
        k = k[2:].decode('hex')
        assert len(k) == 32
        out = k + serialized
        if batch:
            batch.put(key, out)
        else:
            self.db_utxo.put(key, out)
    def put_node(self, key, d, batch=None):
        k = 0
        serialized = ''
        for i in range(256):
            if chr(i) in d.keys():
                k += 1<<i
                h, v = d[chr(i)]
                if h is None: h = chr(0)*32
                vv = int_to_hex(v, 8).decode('hex')
                item = h + vv
                assert len(item) == 40
                serialized += item

        k = "0x%0.64X" % k # 32 bytes
        k = k[2:].decode('hex')
        assert len(k) == 32
        out = k + serialized
        if batch:
            batch.put(key, out)
        else:
            self.db_utxo.put(key, out) 
    def import_transaction(self, txid, tx, block_height, touched_addr):

        undo = { 'prev_addr':[] } # contains the list of pruned items for each address in the tx; also, 'prev_addr' is a list of prev addresses
                
        prev_addr = []
        for i, x in enumerate(tx.get('inputs')):
            txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
            addr = self.get_address(txi)
            if addr is not None: 
                self.set_spent(addr, txi, txid, i, block_height, undo)
                touched_addr.add(addr)
            prev_addr.append(addr)

        undo['prev_addr'] = prev_addr 

        # here I add only the outputs to history; maybe I want to add inputs too (that's in the other loop)
        for x in tx.get('outputs'):
            addr = x.get('address')
            if addr is None: continue
            self.add_to_history(addr, txid, x.get('index'), x.get('value'), block_height)
            touched_addr.add(addr)

        return undo
Example #23
0
    def add_address(self, target, value, height):
        assert len(target) == KEYLENGTH

        word = target
        key = ''
        path = ['']
        i = self.db_utxo.iterator()

        while key != target:

            items = self.get_node(key)

            if word[0] in items.keys():

                i.seek(key + word[0])
                new_key, _ = i.next()

                if target.startswith(new_key):
                    # add value to the child node
                    key = new_key
                    word = target[len(key):]
                    if key == target:
                        break
                    else:
                        assert key not in path
                        path.append(key)
                else:
                    # prune current node and add new node
                    prefix = self.common_prefix(new_key, target)
                    index = len(prefix)

                    ## get hash and value of new_key from parent (if it's a leaf)
                    if len(new_key) == KEYLENGTH:
                        parent_key = self.get_parent(new_key)
                        parent = self.get_node(parent_key)
                        z = parent[new_key[len(parent_key)]]
                        self.put_node(prefix, {
                            target[index]: (None, 0),
                            new_key[index]: z
                        })
                    else:
                        # if it is not a leaf, update the hash of new_key because skip_string changed
                        h, v = self.get_node_hash(new_key,
                                                  self.get_node(new_key),
                                                  prefix)
                        self.put_node(prefix, {
                            target[index]: (None, 0),
                            new_key[index]: (h, v)
                        })

                    path.append(prefix)
                    self.parents[new_key] = prefix
                    break

            else:
                assert key in path
                items[word[0]] = (None, 0)
                self.put_node(key, items)
                break

        # write
        s = (int_to_hex(value, 8) + int_to_hex(height, 4)).decode('hex')
        self.db_utxo.put(target, s)
        # the hash of a node is the txid
        _hash = target[20:52]
        self.update_node_hash(target, path, _hash, value)
    def process(self, request, cache_only=False):
        
        message_id = request['id']
        method = request['method']
        params = request.get('params', ())
        result = None
        error = None

        if method == 'blockchain.numblocks.subscribe':
            result = self.storage.height

        elif method == 'blockchain.headers.subscribe':
            result = self.header

        elif method == 'blockchain.address.subscribe':
            address = str(params[0])
            result = self.get_status(address, cache_only)

        elif method == 'blockchain.address.get_history':
            address = str(params[0])
            result = self.get_history(address, cache_only)

        elif method == 'blockchain.address.get_mempool':
            address = str(params[0])
            result = self.get_unconfirmed_history(address)

        elif method == 'blockchain.address.get_balance':
            address = str(params[0])
            confirmed = self.storage.get_balance(address)
            unconfirmed = self.get_unconfirmed_value(address)
            result = { 'confirmed':confirmed, 'unconfirmed':unconfirmed }

        elif method == 'blockchain.address.get_proof':
            address = str(params[0])
            result = self.storage.get_proof(address)

        elif method == 'blockchain.address.listunspent':
            address = str(params[0])
            result = self.storage.listunspent(address)

        elif method == 'blockchain.utxo.get_address':
            txid = str(params[0])
            pos = int(params[1])
            txi = (txid + int_to_hex(pos, 4)).decode('hex')
            result = self.storage.get_address(txi)

        elif method == 'blockchain.block.get_header':
            if cache_only:
                result = -1
            else:
                height = int(params[0])
                result = self.get_header(height)

        elif method == 'blockchain.block.get_chunk':
            if cache_only:
                result = -1
            else:
                index = int(params[0])
                result = self.get_chunk(index)

        elif method == 'blockchain.transaction.broadcast':
            try:
                txo = self.bitcoind('sendrawtransaction', params)
                print_log("sent tx:", txo)
                result = txo
            except BaseException, e:
                error = e.args[0]
                if error["code"] == -26:
                    # If we return anything that's not the transaction hash,
                    #  it's considered an error message
                    message = error["message"]
                    if "non-mandatory-script-verify-flag" in message:
                        result = "Your client produced a transaction that is not accepted by the Bitcoin network any more. Please upgrade to Electrum 2.5.1 or newer\n"
                    else:
                        result = "The transaction was rejected by network rules.(" + message + ")\n" \
                            "[" + params[0] + "]"
                else:
                    result = error["message"]  # do send an error
                print_log("error:", result)
Example #25
0
    def raw_tx(self, inputs, outputs, for_sig=None):
        s = int_to_hex(1, 4)                                 # version
        s += var_int(len(inputs))                            # number of inputs
        for i in range(len(inputs)):
            _, _, p_hash, p_index, p_script, pubkeysig = inputs[i]
            s += p_hash.decode('hex')[::-1].encode('hex')    # prev hash
            s += int_to_hex(p_index, 4)                    # prev index

            if for_sig is None:
                if len(pubkeysig) == 1:
                    pubkey, sig = pubkeysig[0]
                    sig = sig + chr(1)                               # hashtype
                    script = int_to_hex(len(sig))
                    script += sig.encode('hex')
                    script += int_to_hex(len(pubkey))
                    script += pubkey.encode('hex')
                else:
                    pubkey0, sig0 = pubkeysig[0]
                    pubkey1, sig1 = pubkeysig[1]
                    sig0 = sig0 + chr(1)
                    sig1 = sig1 + chr(1)
                    inner_script = self.multisig_script([pubkey0, pubkey1])
                    script = '00'                                    # op_0
                    script += int_to_hex(len(sig0))
                    script += sig0.encode('hex')
                    script += int_to_hex(len(sig1))
                    script += sig1.encode('hex')
                    script += var_int(len(inner_script) / 2)
                    script += inner_script

            elif for_sig == i:
                if len(pubkeysig) > 1:
                    script = self.multisig_script(pubkeysig)  # p2sh uses the
                                                              # inner script
                else:
                    script = p_script                         # scriptsig
            else:
                script = ''
            s += var_int(len(self.tx_filter(script)) / 2)    # script length
            s += script
            s += "ffffffff"                                   # sequence

        s += var_int(len(outputs))                      # number of outputs
        for output in outputs:
            addr, amount = output
            s += int_to_hex(amount, 8)                              # amount
            addrtype, hash_160 = bc_address_to_hash_160(addr)
            if addrtype == 0:
                script = '76a9'                         # op_dup, op_hash_160
                script += '14'                          # push 0x14 bytes
                script += hash_160.encode('hex')
                script += '88ac'                 # op_equalverify, op_checksig
            elif addrtype == 5:
                script = 'a9'                           # op_hash_160
                script += '14'                          # push 0x14 bytes
                script += hash_160.encode('hex')
                script += '87'                          # op_equal
            else:
                raise

            s += var_int(len(self.tx_filter(script)) / 2)  # script length
            s += script                                    # script
        s += int_to_hex(0, 4)                               # lock time
        if for_sig is not None:
            s += int_to_hex(1, 4)      # hash type
        return self.tx_filter(s)
    def memorypool_update(self):
        t0 = time.time()
        mempool_hashes = set(self.bitcoind('getrawmempool'))
        touched_addresses = set()

        # get new transactions
        new_tx = {}
        for tx_hash in mempool_hashes:
            if tx_hash in self.mempool_hashes:
                continue

            tx = self.get_mempool_transaction(tx_hash)
            if not tx:
                continue

            new_tx[tx_hash] = tx

        # remove older entries from mempool_hashes
        self.mempool_hashes = mempool_hashes

        # check all tx outputs
        for tx_hash, tx in new_tx.iteritems():
            mpa = self.mempool_addresses.get(tx_hash, {})
            out_values = []
            for x in tx.get('outputs'):
                addr = x.get('address', '')
                out_values.append((addr, x['value']))
                if not addr:
                    continue
                v = mpa.get(addr, 0)
                v += x['value']
                mpa[addr] = v
                touched_addresses.add(addr)

            self.mempool_addresses[tx_hash] = mpa
            self.mempool_values[tx_hash] = out_values

        # check all inputs
        for tx_hash, tx in new_tx.iteritems():
            mpa = self.mempool_addresses.get(tx_hash, {})
            for x in tx.get('inputs'):
                mpv = self.mempool_values.get(x.get('prevout_hash'))
                if mpv:
                    addr, value = mpv[ x.get('prevout_n')]
                else:
                    txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
                    try:
                        addr = self.storage.get_address(txi)
                        value = self.storage.get_utxo_value(addr,txi)
                    except:
                        print_log("utxo not in database; postponing mempool update")
                        return

                if not addr:
                    continue
                v = mpa.get(addr,0)
                v -= value
                mpa[addr] = v
                touched_addresses.add(addr)

            self.mempool_addresses[tx_hash] = mpa

        # remove deprecated entries from mempool_addresses
        for tx_hash, addresses in self.mempool_addresses.items():
            if tx_hash not in self.mempool_hashes:
                self.mempool_addresses.pop(tx_hash)
                self.mempool_values.pop(tx_hash)
                touched_addresses.update(addresses)

        # remove deprecated entries from mempool_hist
        new_mempool_hist = {}
        for addr in self.mempool_hist.iterkeys():
            h = self.mempool_hist[addr]
            hh = []
            for tx_hash, delta in h:
                if tx_hash in self.mempool_addresses:
                    hh.append((tx_hash, delta))
            if hh:
                new_mempool_hist[addr] = hh
        # add new transactions to mempool_hist
        for tx_hash in new_tx.iterkeys():
            addresses = self.mempool_addresses[tx_hash]
            for addr, delta in addresses.iteritems():
                h = new_mempool_hist.get(addr, [])
                if (tx_hash, delta) not in h:
                    h.append((tx_hash, delta))
                new_mempool_hist[addr] = h

        with self.mempool_lock:
            self.mempool_hist = new_mempool_hist

        # invalidate cache for touched addresses
        for addr in touched_addresses:
            self.invalidate_cache(addr)

        t1 = time.time()
        if t1-t0>1:
            print_log('mempool_update', t1-t0, len(self.mempool_hashes), len(self.mempool_hist))
Example #27
0
    def raw_tx(self, inputs, outputs, for_sig=None):
        s = int_to_hex(1, 4)  # version
        s += var_int(len(inputs))  # number of inputs
        for i in range(len(inputs)):
            _, _, p_hash, p_index, p_script, pubkeysig = inputs[i]
            s += p_hash.decode('hex')[::-1].encode('hex')  # prev hash
            s += int_to_hex(p_index, 4)  # prev index

            if for_sig is None:
                if len(pubkeysig) == 1:
                    pubkey, sig = pubkeysig[0]
                    sig = sig + chr(1)  # hashtype
                    script = int_to_hex(len(sig))
                    script += sig.encode('hex')
                    script += int_to_hex(len(pubkey))
                    script += pubkey.encode('hex')
                else:
                    pubkey0, sig0 = pubkeysig[0]
                    pubkey1, sig1 = pubkeysig[1]
                    sig0 = sig0 + chr(1)
                    sig1 = sig1 + chr(1)
                    inner_script = self.multisig_script([pubkey0, pubkey1])
                    script = '00'  # op_0
                    script += int_to_hex(len(sig0))
                    script += sig0.encode('hex')
                    script += int_to_hex(len(sig1))
                    script += sig1.encode('hex')
                    script += var_int(len(inner_script) / 2)
                    script += inner_script

            elif for_sig == i:
                if len(pubkeysig) > 1:
                    script = self.multisig_script(pubkeysig)  # p2sh uses the
                    # inner script
                else:
                    script = p_script  # scriptsig
            else:
                script = ''
            s += var_int(len(self.tx_filter(script)) / 2)  # script length
            s += script
            s += "ffffffff"  # sequence

        s += var_int(len(outputs))  # number of outputs
        for output in outputs:
            addr, amount = output
            s += int_to_hex(amount, 8)  # amount
            addrtype, hash_160 = bc_address_to_hash_160(addr)
            if addrtype == 0:
                script = '76a9'  # op_dup, op_hash_160
                script += '14'  # push 0x14 bytes
                script += hash_160.encode('hex')
                script += '88ac'  # op_equalverify, op_checksig
            elif addrtype == 5:
                script = 'a9'  # op_hash_160
                script += '14'  # push 0x14 bytes
                script += hash_160.encode('hex')
                script += '87'  # op_equal
            else:
                raise

            s += var_int(len(self.tx_filter(script)) / 2)  # script length
            s += script  # script
        s += int_to_hex(0, 4)  # lock time
        if for_sig is not None:
            s += int_to_hex(1, 4)  # hash type
        return self.tx_filter(s)