else:
# some inputs are mine:
fee = None
- v = v_out_mine - v_in
+ if is_send:
+ v = v_out_mine - v_out
+ else:
+ # no input is mine
+ v = v_out_mine
return is_send, v, fee
+ "Status: %d confirmations\n"%conf
if is_mine:
if fee:
- tx_details += "Amount sent: %s\n"% format_satoshis(v+fee, False) \
+ tx_details += "Amount sent: %s\n"% format_satoshis(v-fee, False) \
+ "Transaction fee: %s\n"% format_satoshis(fee, False)
else:
tx_details += "Amount sent: %s\n"% format_satoshis(v, False) \
def receive_history_callback(self, addr, hist):
- if hist != ['*']:
- if not self.check_new_history(addr, hist):
- raise BaseException("error: received history for %s is not consistent with known transactions"%addr)
+ if not self.check_new_history(addr, hist):
+ raise BaseException("error: received history for %s is not consistent with known transactions"%addr)
with self.lock:
self.history[addr] = hist
tx_hash = tx['tx_hash']
timestamp = tx.get('timestamp')
conf = self.verifier.get_confirmations(tx_hash) if self.verifier else None
- is_mine, v, fee = self.get_tx_value(tx_hash)
- if v is not None:
- balance += v
- value = v + fee if fee is not None else v
- else:
- value = None
+ is_mine, value, fee = self.get_tx_value(tx_hash)
+ if value is not None:
+ balance += value
result.append( (tx_hash, conf, is_mine, value, fee, balance, timestamp) )
def check_new_history(self, addr, hist):
- # - check that all tx in hist are relevant
- for tx_hash, height in hist:
- tx = self.transactions.get(tx_hash)
- if not tx: continue
- if not self.is_addr_in_tx(addr,tx):
- return False
-
- # todo: check that we are not "orphaning" a transaction
- # if we are, reject tx if unconfirmed, else reject the server
+
+ # check that all tx in hist are relevant
+ if hist != ['*']:
+ for tx_hash, height in hist:
+ tx = self.transactions.get(tx_hash)
+ if not tx: continue
+ if not self.is_addr_in_tx(addr,tx):
+ return False
+
+ # check that we are not "orphaning" a transaction
+ old_hist = self.history.get(addr)
+ if old_hist == ['*']: return True
+
+ for tx_hash, height in old_hist:
+ if tx_hash in map(lambda x:x[0], hist): continue
+ found = False
+ for _addr, _hist in self.history.items():
+ if _addr == addr: continue
+ if _hist == ['*']: continue
+ _tx_hist = map(lambda x:x[0], _hist)
+ if tx_hash in _tx_hist:
+ found = True
+ break
+
+ if not found:
+ tx = self.transactions.get(tx_hash)
+ # already verified?
+ if tx.get('height'):
+ continue
+ # unconfirmed tx
+ print_error("new history is orphaning transaction:", tx_hash)
+ # check that all outputs are not mine, request histories
+ ext_requests = []
+ for o in tx.get('outputs'):
+ _addr = o.get('address')
+ assert not self.is_mine(_addr)
+ ext_requests.append( ('blockchain.address.get_history', [_addr]) )
+
+ ext_h = self.interface.synchronous_get(ext_requests)
+ height = None
+ for h in ext_h:
+ if h == ['*']: continue
+ for item in h:
+ if item.get('tx_hash') == tx_hash:
+ height = item.get('height')
+ if height:
+ print_error("found height for", tx_hash, height)
+ self.verifier.add(tx_hash, height)
+ else:
+ print_error("removing orphaned tx from history", tx_hash)
+ self.transactions.pop(tx_hash)
return True