Browse Source

Merge branch 'develop'

master
Neil Booth 8 years ago
parent
commit
ef9ce91027
  1. 42
      query.py
  2. 55
      server/db.py
  3. 37
      server/server.py

42
query.py

@ -0,0 +1,42 @@
#!/usr/bin/env python3
# See the file "LICENSE" for information about the copyright
# and warranty status of this software.
import os
import sys
from server.env import Env
from server.db import DB
def main():
env = Env()
os.chdir(env.db_dir)
db = DB(env)
coin = db.coin
argc = 1
try:
limit = int(sys.argv[argc])
argc += 1
except:
limit = 10
for addr in sys.argv[argc:]:
print('Address: ', addr)
hash160 = coin.address_to_hash160(addr)
n = None
for n, (tx_hash, height) in enumerate(db.get_history(hash160, limit)):
print('History #{:d}: hash: {} height: {:d}'
.format(n + 1, bytes(reversed(tx_hash)).hex(), height))
if n is None:
print('No history')
n = None
for n, utxo in enumerate(db.get_utxos(hash160, limit)):
print('UTXOs #{:d}: hash: {} pos: {:d} height: {:d} value: {:d}'
.format(n, bytes(reversed(utxo.tx_hash)).hex(),
utxo.tx_pos, utxo.height, utxo.value))
if n is None:
print('No UTXOs')
if __name__ == '__main__':
main()

55
server/db.py

@ -433,27 +433,41 @@ class DB(object):
return tx_hash, height return tx_hash, height
def get_balance(self, hash160): @staticmethod
'''Returns the confirmed balance of an address.''' def resolve_limit(limit):
utxos = self.get_utxos(hash_160) if limit is None:
return sum(utxo.value for utxo in utxos) return -1
assert isinstance(limit, int) and limit >= 0
def get_history(self, hash160): return limit
'''Returns an unpruned, sorted list of (tx_hash, height) tuples of
transactions that touched the address, earliest in the def get_history(self, hash160, limit=1000):
blockchain first. Includes both spending and receiving '''Generator that returns an unpruned, sorted list of (tx_hash,
transactions. height) tuples of transactions that touched the address,
earliest in the blockchain first. Includes both spending and
receiving transactions. By default yields at most 1000 entries.
Set limit to None to get them all.
''' '''
limit = self.resolve_limit(limit)
prefix = b'H' + hash160 prefix = b'H' + hash160
a = array.array('I')
for key, hist in self.db.iterator(prefix=prefix): for key, hist in self.db.iterator(prefix=prefix):
a = array.array('I')
a.frombytes(hist) a.frombytes(hist)
return [self.get_tx_hash(tx_num) for tx_num in a] for tx_num in a:
if limit == 0:
return
yield self.get_tx_hash(tx_num)
limit -= 1
def get_balance(self, hash160):
'''Returns the confirmed balance of an address.'''
return sum(utxo.value for utxo in self.get_utxos(hash_160, limit=None))
def get_utxos(self, hash160): def get_utxos(self, hash160, limit=1000):
'''Returns all UTXOs for an address sorted such that the earliest '''Generator that yields all UTXOs for an address sorted in no
in the blockchain comes first. particular order. By default yields at most 1000 entries.
Set limit to None to get them all.
''' '''
limit = self.resolve_limit(limit)
unpack = struct.unpack unpack = struct.unpack
prefix = b'u' + hash160 prefix = b'u' + hash160
utxos = [] utxos = []
@ -461,10 +475,15 @@ class DB(object):
(tx_pos, ) = unpack('<H', k[-2:]) (tx_pos, ) = unpack('<H', k[-2:])
for n in range(0, len(v), 12): for n in range(0, len(v), 12):
if limit == 0:
return
(tx_num, ) = unpack('<I', v[n:n+4]) (tx_num, ) = unpack('<I', v[n:n+4])
(value, ) = unpack('<Q', v[n+4:n+12]) (value, ) = unpack('<Q', v[n+4:n+12])
tx_hash, height = self.get_tx_hash(tx_num) tx_hash, height = self.get_tx_hash(tx_num)
utxos.append(UTXO(tx_num, tx_pos, tx_hash, height, value)) yield UTXO(tx_num, tx_pos, tx_hash, height, value)
limit -= 1
# Sorted by height and block position. def get_utxos_sorted(self, hash160):
return sorted(utxos) '''Returns all the UTXOs for an address sorted by height and
position in the block.'''
return sorted(self.get_utxos(hash160, limit=None))

37
server/server.py

@ -15,11 +15,11 @@ from server.db import DB
class Server(object): class Server(object):
def __init__(self, env, loop): def __init__(self, env):
self.env = env self.env = env
self.db = DB(env) self.db = DB(env)
self.rpc = RPC(env) self.rpc = RPC(env)
self.block_cache = BlockCache(env, self.db, self.rpc, loop) self.block_cache = BlockCache(env, self.db, self.rpc)
def async_tasks(self): def async_tasks(self):
return [ return [
@ -32,7 +32,7 @@ class BlockCache(object):
'''Requests blocks ahead of time from the daemon. Serves them '''Requests blocks ahead of time from the daemon. Serves them
to the blockchain processor.''' to the blockchain processor.'''
def __init__(self, env, db, rpc, loop): def __init__(self, env, db, rpc):
self.logger = logging.getLogger('BlockCache') self.logger = logging.getLogger('BlockCache')
self.logger.setLevel(logging.INFO) self.logger.setLevel(logging.INFO)
@ -47,6 +47,8 @@ class BlockCache(object):
self.blocks = [] self.blocks = []
self.recent_sizes = [] self.recent_sizes = []
self.ave_size = 0 self.ave_size = 0
loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'): for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame), loop.add_signal_handler(getattr(signal, signame),
partial(self.on_signal, signame)) partial(self.on_signal, signame))
@ -201,32 +203,3 @@ class RPC(object):
self.logger.info('sleeping 1 second and trying again...') self.logger.info('sleeping 1 second and trying again...')
await asyncio.sleep(1) await asyncio.sleep(1)
# for addr in [
# # '1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp',
# # '1HYBcza9tVquCCvCN1hUZkYT9RcM6GfLot',
# # '1BNwxHGaFbeUBitpjy2AsKpJ29Ybxntqvb',
# # '1ARanTkswPiVM6tUEYvbskyqDsZpweiciu',
# # '1VayNert3x1KzbpzMGt2qdqrAThiRovi8',
# # '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
# # '1XPTgDRhN8RFnzniWCddobD9iKZatrvH4',
# # '153h6eE6xRhXuN3pE53gWVfXacAtfyBF8g',
# ]:
# print('Address: ', addr)
# hash160 = coin.address_to_hash160(addr)
# utxos = self.db.get_utxos(hash160)
# for n, utxo in enumerate(utxos):
# print('UTXOs #{:d}: hash: {} pos: {:d} height: {:d} value: {:d}'
# .format(n, bytes(reversed(utxo.tx_hash)).hex(),
# utxo.tx_pos, utxo.height, utxo.value))
# for addr in [
# '19k8nToWwMGuF4HkNpzgoVAYk4viBnEs5D',
# '1HaHTfmvoUW6i6nhJf8jJs6tU4cHNmBQHQ',
# '1XPTgDRhN8RFnzniWCddobD9iKZatrvH4',
# ]:
# print('Address: ', addr)
# hash160 = coin.address_to_hash160(addr)
# for n, (tx_hash, height) in enumerate(self.db.get_history(hash160)):
# print('History #{:d}: hash: {} height: {:d}'
# .format(n + 1, bytes(reversed(tx_hash)).hex(), height))

Loading…
Cancel
Save