obelisk

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

commit b9a1e2f05c4871e9d7a3fa90e01a6548152bf65f
parent 7d3865cc4ee1682c4188707594389f92c3287838
Author: parazyd <parazyd@dyne.org>
Date:   Thu, 15 Apr 2021 12:35:36 +0200

Fix logic bug in blockchain.block.headers and implement cp_height.

Diffstat:
Mobelisk/protocol.py | 27+++++++++++++++++++++++++--
Mtests/test_electrum_protocol.py | 2+-
2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/obelisk/protocol.py b/obelisk/protocol.py @@ -251,6 +251,7 @@ class ElectrumProtocol(asyncio.Protocol): # pylint: disable=R0904,R0902 cp_headers.append(data) # TODO: Review + # TODO: Is index is 0 or last elem? branch, root = merkle_branch_and_root(cp_headers, 0) return { "result": { @@ -268,20 +269,22 @@ class ElectrumProtocol(asyncio.Protocol): # pylint: disable=R0904,R0902 return JsonRPCError.invalidparams() # Electrum doesn't allow max_chunk_size to be less than 2016 # gopher://bitreich.org/9/memecache/convenience-store.mkv - # TODO: cp_height max_chunk_size = 2016 start_height = query["params"][0] count = query["params"][1] + cp_height = query["params"][2] if len(query["params"]) == 3 else 0 if not is_non_negative_integer(start_height): return JsonRPCError.invalidparams() if not is_non_negative_integer(count): return JsonRPCError.invalidparams() + if cp_height != 0 and not start_height + (count - 1) <= cp_height: + return JsonRPCError.invalidparams() count = min(count, max_chunk_size) headers = bytearray() for i in range(count): - _ec, data = await self.bx.fetch_block_header(i) + _ec, data = await self.bx.fetch_block_header(start_height + i) if _ec and _ec != 0: self.log.debug("Got error: %s", repr(_ec)) return JsonRPCError.internalerror() @@ -292,6 +295,26 @@ class ElectrumProtocol(asyncio.Protocol): # pylint: disable=R0904,R0902 "count": len(headers) // 80, "max": max_chunk_size, } + + # The assumption is to fetch more headers if necessary. + # TODO: Review + if cp_height > 0 and cp_height - start_height > count: + for i in range(cp_height - start_height): + _ec, data = await self.bx.fetch_block_header(start_height + + count + i) + if _ec and _ec != 0: + self.log.debug("Got error: %s", repr(_ec)) + return JsonRPCError.internalerror() + headers.extend(data) + + # TODO: Review + # TODO: Is index is 0 or last elem? + hdr_lst = [headers[i:i + 80] for i in range(0, len(headers), 80)] + print(hdr_lst) + branch, root = merkle_branch_and_root(hdr_lst, 0) + resp["branch"] = [safe_hexlify(i) for i in branch] + resp["root"] = safe_hexlify(root) + return {"result": resp} async def blockchain_estimatefee(self, writer, query): # pylint: disable=W0613 diff --git a/tests/test_electrum_protocol.py b/tests/test_electrum_protocol.py @@ -40,7 +40,7 @@ async def test_blockchain_block_header(protocol, writer): async def test_blockchain_block_headers(protocol, writer): - expect = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534" + expect = "01000000c54675276e0401706aa93db6494dd7d1058b19424f23c8d7c01076da000000001c4375c8056b0ded0fa3d7fc1b5511eaf53216aed72ea95e1b5d19eccbe855f91a184a4dffff001d0336a22601000000bca72b7ccb44f1f0dd803f2c321143c9dda7f5a2a6ed87c76aac918a000000004266985f02f11bdffa559a233f5600c95c04bd70340e75673cadaf3ef6ac72b448194a4dffff001d035c84d801000000769d6d6e4672a620669baa56dd39d066523e461762ad3610fb2055b400000000c50652340352ad79b799b870e3fa2c80804d0fc54063b413e0e2d6dc66ca3f9a55194a4dffff001d022510a4" query = {"params": [123, 3]} data = await protocol.blockchain_block_headers(writer, query) assert data["result"]["hex"] == expect