electrum-obelisk

Electrum server using libbitcoin as its backend
git clone https://git.parazyd.org/electrum-obelisk
Log | Files | Refs | README | LICENSE

query.py (2853B)


      1 #!/usr/bin/env python3
      2 # electrum-obelisk
      3 # Copyright (C) 2020-2021 Ivan J. <parazyd@dyne.org>
      4 #
      5 # This program is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Affero General Public License as published by
      7 # the Free Software Foundation, either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Affero General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Affero General Public License
     16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 """ zmq interfacing """
     18 from binascii import unhexlify
     19 from struct import pack, unpack
     20 
     21 import zmq
     22 
     23 
     24 def q_fetch_header_by_height(endp, height):
     25     """ Fetch and return a block header at height as raw bytes """
     26     context = zmq.Context()
     27     socket = context.socket(zmq.REQ)  # pylint: disable=E1101
     28     socket.connect(endp)
     29     socket.send(b'blockchain.fetch_block_header', zmq.SNDMORE)
     30     socket.send(pack('I', 42), zmq.SNDMORE)
     31     socket.send(pack('I', int(height)))
     32     _ = socket.recv()
     33     _ = socket.recv()
     34     response_body = socket.recv()
     35     _ec = unpack('<I', response_body[0:4])[0]
     36     if _ec != 0:
     37         return None
     38     return response_body[4:]
     39 
     40 
     41 def q_fetch_headers_by_height_count(endp, start_height, count):
     42     """ Fetch and return count concatenated headers by height as raw bytes """
     43     # Implemented to reuse the socket rather than opening a new one
     44     # for each header requested (e.g. by looping q_fetch_header_by_height()).
     45     context = zmq.Context()
     46     socket = context.socket(zmq.REQ)  # pylint: disable=E1101
     47     socket.connect(endp)
     48     _id = 42
     49     res = bytearray()
     50     for i in range(count):
     51         socket.send(b'blockchain.fetch_block_header', zmq.SNDMORE)
     52         socket.send(pack('I', _id), zmq.SNDMORE)
     53         socket.send(pack('I', start_height+i))
     54         _ = socket.recv()
     55         _ = socket.recv()
     56         response_body = socket.recv()
     57         _ec = unpack('<I', response_body[0:4])[0]
     58         if not response_body or _ec != 0:
     59             break
     60         res.extend(response_body[4:])
     61     return res
     62 
     63 
     64 def q_fetch_tx_by_txid(endp, txid):
     65     """ Fetch and return a transaction by txid as raw bytes """
     66     context = zmq.Context()
     67     socket = context.socket(zmq.REQ)  # pylint: disable=E1101
     68     socket.connect(endp)
     69     socket.send(b'blockchain.fetch_transaction2', zmq.SNDMORE)
     70     socket.send(pack('I', 42), zmq.SNDMORE)
     71     socket.send(unhexlify(txid)[::-1])
     72     _ = socket.recv()
     73     _ = socket.recv()
     74     response_body = socket.recv()
     75     _ec = unpack('<I', response_body[0:4])[0]
     76     if _ec != 0:
     77         return None
     78     return response_body[4:]