electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit b0277d542657f2a985f16fb6fdeba95f766e3c81
parent b2116d87eaf81ec512689174db5966f2644205ec
Author: ThomasV <thomasv@electrum.org>
Date:   Mon, 17 Jul 2017 08:44:09 +0200

blockchain: size method, various fixes

Diffstat:
Mlib/blockchain.py | 58+++++++++++++++++++++++++++++-----------------------------
Mlib/network.py | 25++++++++++++++++---------
2 files changed, 45 insertions(+), 38 deletions(-)

diff --git a/lib/blockchain.py b/lib/blockchain.py @@ -66,19 +66,17 @@ blockchains = {} def read_blockchains(config): blockchains[0] = Blockchain(config, 'blockchain_headers') # fixme: sort - for x in os.listdir(config.path): - if x.startswith('fork_'): - b = Blockchain(config, x) - blockchains[b.checkpoint] = b + l = sorted(filter(lambda x: x.startswith('fork_'), os.listdir(config.path))) + for x in l: + b = Blockchain(config, x) + blockchains[b.checkpoint] = b return blockchains def get_blockchain(header): if type(header) is not dict: return False - header_hash = hash_header(header) - height = header.get('block_height') for b in blockchains.values(): - if header_hash == b.get_hash(height): + if b.check_header(header): return b return False @@ -102,19 +100,27 @@ class Blockchain(util.PrintError): self.checkpoint = int(filename.split('_')[2]) else: raise BaseException('') - self.set_local_height() + + def check_header(self, header): + header_hash = hash_header(header) + height = header.get('block_height') + return header_hash == self.get_hash(height) def fork(parent, checkpoint): filename = 'fork_%d_%d'%(parent.checkpoint, checkpoint) self = Blockchain(parent.config, filename) self.is_saved = False - self.parent = parent - self.checkpoint = checkpoint return self def height(self): - local = self.local_height if self.is_saved else len(self.headers) - 1 - return self.checkpoint + local + return self.checkpoint + self.size() - 1 + + def size(self): + if self.is_saved: + p = self.path() + return os.path.getsize(p)/80 if os.path.exists(p) else 0 + else: + return len(self.headers) def verify_header(self, header, prev_header, bits, target): prev_hash = hash_header(prev_header) @@ -157,11 +163,13 @@ class Blockchain(util.PrintError): if not self.is_saved: self.save() filename = self.path() + d = (index * 2016 - self.checkpoint) * 80 + if d < 0: + chunk = chunk[-d:] + d = 0 with open(filename, 'rb+') as f: - f.seek(index * 2016 * 80) - f.truncate() - h = f.write(chunk) - self.set_local_height() + f.seek(d) + f.write(chunk) def save(self): # recursively save parents if they have not been saved @@ -179,28 +187,20 @@ class Blockchain(util.PrintError): if not self.is_saved: assert height == self.checkpoint + len(self.headers) self.headers.append(header) - if len(self.headers) > 10: + if len(self.headers) > 10 and self.parent.size() > 10: self.save() return self.write_header(header) def write_header(self, header): + filename = self.path() delta = header.get('block_height') - self.checkpoint data = serialize_header(header).decode('hex') + assert delta * 80 == os.path.getsize(filename) assert len(data) == 80 - filename = self.path() with open(filename, 'rb+') as f: f.seek(delta * 80) - f.truncate() - h = f.write(data) - self.set_local_height() - - def set_local_height(self): - self.local_height = 0 - name = self.path() - if os.path.exists(name): - h = os.path.getsize(name)/80 - 1 - self.local_height = h + f.write(data) def read_header(self, height): if height < self.checkpoint: @@ -219,7 +219,7 @@ class Blockchain(util.PrintError): h = f.read(80) f.close() if len(h) == 80: - h = deserialize_header(h, delta) + h = deserialize_header(h, height) return h def get_hash(self, height): diff --git a/lib/network.py b/lib/network.py @@ -851,14 +851,22 @@ class Network(util.DaemonThread): else: interface.print_error("can connect at %d"% interface.good) b = self.blockchains.get(interface.good) - if b is None: - b = interface.blockchain.fork(interface.good) - b.catch_up = interface.server - interface.print_error("catching up with new chain") - self.blockchains[interface.good] = b - interface.mode = 'catch_up' - next_height = interface.good - interface.blockchain = b + # if there is a reorg we connect to the parent + if b is not None and interface.good == b.checkpoint: + interface.print_error('reorg', interface.good, interface.tip) + interface.blockchain = b.parent + interface.mode = 'default' + next_height = interface.tip + else: + if b is None: + b = interface.blockchain.fork(interface.good) + self.blockchains[interface.good] = b + interface.print_error("catching up on new blockchain", b.filename) + if b.catch_up is None: + b.catch_up = interface.server + interface.blockchain = b + interface.mode = 'catch_up' + next_height = interface.good # todo: garbage collect blockchain objects self.notify('updated') @@ -944,7 +952,6 @@ class Network(util.DaemonThread): self.print_error("download failed. creating file", filename) open(filename, 'wb+').close() self.downloading_headers = False - self.blockchains[0].set_local_height() self.downloading_headers = True t = threading.Thread(target = download_thread) t.daemon = True