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 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)
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)
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)
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
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
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 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)
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
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
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)
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))