Browse Source

Add merkle proof functions to BitcoinCoreInterface

master
chris-belcher 6 years ago
parent
commit
255d15562d
No known key found for this signature in database
GPG Key ID: EF734EA677F31129
  1. 25
      jmclient/jmclient/blockchaininterface.py
  2. 40
      jmclient/jmclient/wallet_service.py

25
jmclient/jmclient/blockchaininterface.py

@ -4,6 +4,7 @@ import random
import sys
import time
from decimal import Decimal
import binascii
from twisted.internet import reactor, task
import jmbitcoin as btc
@ -406,6 +407,30 @@ class BitcoinCoreInterface(BlockchainInterface):
except JsonRpcError:
return self.rpc('getblock', [blockhash])['time']
def get_tx_merkle_branch(self, txid, blockhash=None):
if not blockhash:
tx = self.rpc("gettransaction", [txid])
if tx["confirmations"] < 1:
raise ValueError("Transaction not in block")
blockhash = tx["blockhash"]
try:
core_proof = self.rpc("gettxoutproof", [[txid], blockhash])
except JsonRpcError:
raise ValueError("Block containing transaction is pruned")
return self.core_proof_to_merkle_branch(core_proof)
def core_proof_to_merkle_branch(self, core_proof):
core_proof = binascii.unhexlify(core_proof)
#first 80 bytes of a proof given by core are just a block header
#so we can save space by replacing it with a 4-byte block height
return core_proof[80:]
def verify_tx_merkle_branch(self, txid, block_height, merkle_branch):
block_hash = self.rpc("getblockhash", [block_height])
core_proof = self.rpc("getblockheader", [block_hash, False]) + \
binascii.hexlify(merkle_branch).decode()
ret = self.rpc("verifytxoutproof", [core_proof])
return len(ret) == 1 and ret[0] == txid
class RegtestBitcoinCoreMixin():
"""

40
jmclient/jmclient/wallet_service.py

@ -537,6 +537,46 @@ class WalletService(Service):
jmprint(restart_msg, "important")
sys.exit(EXIT_SUCCESS)
def sync_burner_outputs(self, burner_txes):
mixdepth = FidelityBondMixin.FIDELITY_BOND_MIXDEPTH
address_type = FidelityBondMixin.BIP32_BURN_ID
self.wallet.set_next_index(mixdepth, address_type, self.wallet.gap_limit,
force=True)
highest_used_index = 0
known_burner_outputs = self.wallet.get_burner_outputs()
for index in range(self.wallet.gap_limit):
path = self.wallet.get_path(mixdepth, address_type, index)
path_privkey, engine = self.wallet._get_priv_from_path(path)
path_pubkey = engine.privkey_to_pubkey(path_privkey)
path_pubkeyhash = btc.bin_hash160(path_pubkey)
for burner_tx in burner_txes:
burner_pubkeyhash, gettx = burner_tx
if burner_pubkeyhash != path_pubkeyhash:
continue
highest_used_index = index
path_repr = self.wallet.get_path_repr(path)
if path_repr.encode() in known_burner_outputs:
continue
txid = gettx["txid"]
jlog.info("Found a burner transaction txid=" + txid + " path = "
+ path_repr)
try:
merkle_branch = self.bci.get_tx_merkle_branch(txid, gettx["blockhash"])
except ValueError as e:
jlog.warning(repr(e))
jlog.warning("Merkle branch likely not available, use "
+ "wallet-tool `addtxoutproof`")
merkle_branch = None
block_height = self.bci.rpc("getblockheader", [gettx["blockhash"]])["height"]
if merkle_branch:
assert self.bci.verify_tx_merkle_branch(txid, block_height, merkle_branch)
self.wallet.add_burner_output(path_repr, gettx["hex"], block_height,
merkle_branch, gettx["blockindex"])
self.wallet.set_next_index(mixdepth, address_type, highest_used_index + 1)
def sync_addresses(self):
""" Triggered by use of --recoversync option in scripts,
attempts a full scan of the blockchain without assuming

Loading…
Cancel
Save