Beispiel #1
0
    async def loading(self):
        self.rpc_batch_limit = 30
        self.worker_tasks = [
            self.loop.create_task(self.start_worker(i))
            for i in range(self.worker_limit)
        ]
        target_height = self.parent.node_last_block - self.parent.deep_sync_limit
        self.height = self.parent.last_block_height + 1

        while self.height < target_height:
            target_height = self.parent.node_last_block - self.parent.deep_sync_limit
            new_requests = 0
            if self.parent.block_preload._store_size < self.parent.block_preload_cache_limit:
                try:
                    for i in self.worker_busy:
                        if not self.worker_busy[i]:
                            self.worker_busy[i] = True
                            if self.height <= self.parent.last_block_height:
                                self.height = self.parent.last_block_height + 1
                            await self.pipe_sent_msg(
                                self.worker[i].writer, b'rpc_batch_limit',
                                int_to_bytes(self.rpc_batch_limit))
                            await self.pipe_sent_msg(self.worker[i].writer,
                                                     b'get',
                                                     int_to_bytes(self.height))
                            self.height += self.rpc_batch_limit
                            new_requests += 1
                    if not new_requests:
                        await asyncio.sleep(1)
                        continue
                    if self.last_batch_size < self.parent.block_preload_batch_size_limit:
                        self.rpc_batch_limit += 40
                    elif self.last_batch_size > self.parent.block_preload_batch_size_limit and self.rpc_batch_limit > 60:
                        self.rpc_batch_limit -= 40
                except asyncio.CancelledError:
                    self.log.info("Loading task terminated")
                    [self.worker[p].terminate() for p in self.worker]
                    for p in self.worker_busy:
                        self.worker_busy[p] = False
                    return
                except Exception as err:
                    self.log.error("Loading task  error %s " % err)
            else:
                await asyncio.sleep(1)

        self.watchdog_task.cancel()
        if self.parent.block_preload._store:
            while next(reversed(
                    self.parent.block_preload._store)) < target_height:
                await asyncio.sleep(1)
            self.log.info("block loader reached target block %s" %
                          target_height)
            self.log.debug("    Cache first block %s; "
                           "cache last block %s;" %
                           (next(iter(self.parent.block_preload._store)),
                            next(reversed(self.parent.block_preload._store))))

        [self.worker[p].terminate() for p in self.worker]
        for p in self.worker_busy:
            self.worker_busy[p] = False
Beispiel #2
0
def op_push_data(data):
    if len(data) <= 0x4b:
        return b''.join([bytes([len(data)]), data])
    elif len(data) <= 0xff:
        return b''.join([OP_PUSHDATA1, bytes([len(data)]), data])
    elif len(data) <= 0xffff:
        return b''.join([OP_PUSHDATA2, int_to_bytes(len(data), byteorder="little"), data])

    else:
        return b''.join([OP_PUSHDATA4, int_to_bytes(len(data), byteorder="little"), data])
Beispiel #3
0
 def leveldb_atomic_batch(self):
     with self.db.write_batch() as batch:
         [batch.delete(k) for k in self.pending_deleted]
         [batch.put(k[0], k[1]) for k in self.utxo_records]
         batch.put(b"last_block", int_to_bytes(self.checkpoint))
Beispiel #4
0
 def rocksdb_atomic_batch(self):
     batch = rocksdb.WriteBatch()
     [batch.delete(k) for k in self.pending_deleted]
     [batch.put(k[0], k[1]) for k in self.utxo_records]
     batch.put(b"last_block", int_to_bytes(self.checkpoint))
     self.db.write(batch)
Beispiel #5
0
    async def load_blocks(self, height, limit):
        start_height = height
        start_limit = limit
        self.destroyed_coins = MRU()
        self.coins = MRU()

        try:
            self.rpc = aiojsonrpc.rpc(self.rpc_url, self.loop, timeout=self.rpc_timeout)
            blocks, missed = dict(), deque()
            v, t, limit = height + limit, 0, 40

            while height < v and height <= self.target_height:
                batch, h_list = list(), list()
                while len(batch) < limit and height < v and height <= self.target_height:
                    batch.append(["getblockhash", height])
                    h_list.append(height)
                    height += 1

                result = await self.rpc.batch(batch)

                h, batch = list(), list()
                for lh, r in zip(h_list, result):
                    if r["result"] is not None:
                        batch.append(["getblock", r["result"], 0])
                        h.append(lh)

                result = await self.rpc.batch(batch)

                for x, y in zip(h, result):
                    if y["result"] is not None:
                        block = decode_block_tx(y["result"])
                        block["p2pkMapHash"] = []
                        if self.option_tx_map: block["txMap"], block["stxo"] = deque(), deque()

                        if self.option_block_filters:
                            block["filter"] = set()


                        if self.option_merkle_proof:
                            mt = merkle_tree(block["rawTx"][i]["txId"] for i in block["rawTx"])

                        coinbase = block["rawTx"][0]["vIn"][0]["scriptSig"]
                        block["miner"] = None
                        for tag in MINER_COINBASE_TAG:
                            if coinbase.find(tag) != -1:
                                block["miner"] = json.dumps(MINER_COINBASE_TAG[tag])
                                break
                        else:
                            try:
                                address_hash = block["rawTx"][0]["vOut"][0]["addressHash"]
                                script_hash = False if block["rawTx"][0]["vOut"][0]["nType"] == 1 else True
                                a = hash_to_address(address_hash, script_hash=script_hash)
                                if a in MINER_PAYOUT_TAG:
                                    block["miner"] = json.dumps(MINER_PAYOUT_TAG[a])
                            except:
                                pass


                        if self.utxo_data:
                            # handle outputs
                            for z in block["rawTx"]:
                                if self.option_merkle_proof:
                                    block["rawTx"][z]["merkleProof"] = b''.join(merkle_proof(mt, z, return_hex=False))

                                for i in block["rawTx"][z]["vOut"]:
                                    out= block["rawTx"][z]["vOut"][i]
                                    o = b"".join((block["rawTx"][z]["txId"], int_to_bytes(i)))
                                    pointer = (x << 39)+(z << 20)+(1 << 19) + i
                                    out_type = out["nType"]

                                    try:
                                        if out_type == 2:
                                            block["p2pkMapHash"].append((out["addressHash"], out["scriptPubKey"]))
                                            raise Exception("P2PK")
                                        address = b"".join((bytes([out_type]), out["addressHash"]))
                                    except:
                                        address = b"".join((bytes([out_type]), out["scriptPubKey"]))

                                    if out_type in (0, 1, 2, 5, 6):
                                        if self.option_block_filters:
                                            e = b"".join((bytes([out_type]),
                                                          z.to_bytes(4, byteorder="little"),
                                                          out["addressHash"][:20]))
                                            block["filter"].add(e)

                                        if self.option_tx_map:
                                                block["txMap"].append((pointer, address, out["value"]))

                                    out["_address"] = address
                                    self.coins[o] = (pointer, out["value"], address)


                            # handle inputs
                            for z in block["rawTx"]:
                                if not block["rawTx"][z]["coinbase"]:
                                    for i  in block["rawTx"][z]["vIn"]:
                                        inp = block["rawTx"][z]["vIn"][i]
                                        outpoint = b"".join((inp["txId"], int_to_bytes(inp["vOut"])))
                                        block["rawTx"][z]["vIn"][i]["_outpoint"] = outpoint

                                        try:
                                           r = self.coins.delete(outpoint)
                                           try:
                                               block["rawTx"][z]["vIn"][i]["_a_"] = r
                                               self.destroyed_coins[r[0]] = True
                                               out_type = r[2][0]

                                               if self.option_block_filters:
                                                   if out_type in (0, 1, 5, 6):
                                                       e = b"".join((bytes([out_type]),
                                                                     z.to_bytes(4, byteorder="little"),
                                                                     r[2][1:21]))
                                                       block["filter"].add(e)
                                                   elif out_type == 2:
                                                       a = parse_script(r[2][1:])["addressHash"]
                                                       e = b"".join((bytes([out_type]),
                                                                     z.to_bytes(4, byteorder="little"),
                                                                     a[:20]))
                                                       block["filter"].add(e)

                                               if self.option_tx_map:
                                                   block["txMap"].append(((x<<39)+(z<<20)+i, r[2], r[1]))
                                                   block["stxo"].append((r[0], (x<<39)+(z<<20)+i))

                                               t += 1
                                           except:
                                               print(traceback.format_exc())

                                        except:
                                            if self.dsn: missed.append(outpoint)

                        blocks[x] = block

            m, n = 0, 0
            if self.utxo_data and missed and self.dsn:
                if self.dsn:
                   async with self.db.acquire() as conn:
                       rows = await conn.fetch("SELECT outpoint, "
                                               "       pointer,"
                                               "       address,"
                                               "       amount "
                                               "FROM connector_utxo "
                                               "WHERE outpoint = ANY($1);", missed)
                   m += len(rows)

                   p = dict()
                   for row in rows:
                        p[row["outpoint"]] = (row["pointer"],  row["amount"], row["address"])

                   for h in  blocks:
                       for z in blocks[h]["rawTx"]:
                           if not blocks[h]["rawTx"][z]["coinbase"]:
                               for i in blocks[h]["rawTx"][z]["vIn"]:
                                   outpoint = blocks[h]["rawTx"][z]["vIn"][i]["_outpoint"]
                                   try:
                                       blocks[h]["rawTx"][z]["vIn"][i]["_l_"] = p[outpoint]
                                       try:
                                           out_type = p[outpoint][2][0]
                                           if self.option_block_filters:
                                               if out_type in (0, 1, 5, 6):
                                                   e = b"".join((bytes([out_type]),
                                                                 z.to_bytes(4, byteorder="little"),
                                                                 p[outpoint][2][1:21]))
                                                   blocks[h]["filter"].add(e)
                                               elif out_type == 2:
                                                   a = parse_script(p[outpoint][2][1:])["addressHash"]
                                                   e = b"".join((bytes([out_type]),
                                                                 z.to_bytes(4, byteorder="little"),
                                                                 a[:20]))
                                                   blocks[h]["filter"].add(e)


                                           if self.option_tx_map:
                                               blocks[h]["txMap"].append(((h<<39)+(z<<20)+i,
                                                                          p[outpoint][2], p[outpoint][1]))
                                               blocks[h]["stxo"].append((p[outpoint][0], (h<<39)+(z<<20)+i))

                                           t += 1
                                           n += 1

                                       except:
                                           print(traceback.format_exc())
                                   except:
                                       pass

            if self.utxo_data and blocks:
                blocks[x]["checkpoint"] = x

            for x in blocks:
                if self.utxo_data:
                    for y in blocks[x]["rawTx"]:
                        for i in blocks[x]["rawTx"][y]["vOut"]:
                            try:
                                r = self.destroyed_coins.delete((x<<39)+(y<<20)+(1<<19)+i)
                                blocks[x]["rawTx"][y]["vOut"][i]["_s_"] = r
                            except: pass

                if self.option_block_filters:
                    blocks[x]["filter"] = bytearray(b"".join(blocks[x]["filter"]))


                blocks[x] = pickle.dumps(blocks[x])
            await self.pipe_sent_msg(b'result', pickle.dumps(blocks))
        except concurrent.futures.CancelledError:
            pass
        except Exception as err:
            self.log.error("block loader restarting: %s" % err)
            print(traceback.format_exc())
            await asyncio.sleep(1)
            self.loop.create_task(self.load_blocks(start_height, start_limit))
        finally:
            try: await self.rpc.close()
            except: pass
Beispiel #6
0
    async def load_blocks(self, height, limit):
        start_height = height
        try:
            x = None
            blocks = dict()
            missed = deque()
            t = 0
            e = height + limit
            limit = 40
            while height < e:

                batch, h_list = list(), list()
                while len(batch) < limit and height < e:
                    batch.append(["getblockhash", height])
                    h_list.append(height)
                    height += 1

                result = await self.rpc.batch(batch)

                h, batch = list(), list()
                for lh, r in zip(h_list, result):
                    if r["result"] is not None:
                        batch.append(["getblock", r["result"], 0])
                        h.append(lh)

                result = await self.rpc.batch(batch)

                for x, y in zip(h, result):
                    if y["result"] is not None:
                        block = decode_block_tx(y["result"])
                        for z in block["rawTx"]:
                            for i in block["rawTx"][z]["vOut"]:
                                o = b"".join((block["rawTx"][z]["txId"],
                                              int_to_bytes(i)))
                                pointer = (x << 39) + (z << 20) + (1 << 19) + i
                                try:
                                    address = b"".join((bytes([
                                        block["rawTx"][z]["vOut"][i]["nType"]
                                    ]), block["rawTx"][z]["vOut"][i]
                                                        ["addressHash"]))
                                except:
                                    address = b"".join((bytes([
                                        block["rawTx"][z]["vOut"][i]["nType"]
                                    ]), block["rawTx"][z]["vOut"][i]
                                                        ["scriptPubKey"]))
                                self.coins[o] = (
                                    pointer,
                                    block["rawTx"][z]["vOut"][i]["value"],
                                    address)

                            if not block["rawTx"][z]["coinbase"]:
                                for i in block["rawTx"][z]["vIn"]:
                                    inp = block["rawTx"][z]["vIn"][i]
                                    outpoint = b"".join(
                                        (inp["txId"],
                                         int_to_bytes(inp["vOut"])))
                                    try:
                                        r = self.coins.delete(outpoint)
                                        if r[0] >> 39 >= start_height and r[
                                                0] >> 39 < height:
                                            block["rawTx"][z]["vIn"][i][
                                                "_a_"] = r
                                        else:
                                            block["rawTx"][z]["vIn"][i][
                                                "_c_"] = r
                                        t += 1
                                        self.destroyed_coins[r[0]] = True
                                        assert r is not None
                                    except:
                                        if self.dsn:
                                            missed.append(outpoint)

                        blocks[x] = block

            m = 0
            n = 0
            if missed and self.dsn:
                if self.dsn:
                    async with self.db.acquire() as conn:
                        rows = await conn.fetch(
                            "SELECT outpoint, "
                            "       pointer,"
                            "       address,"
                            "       amount "
                            "FROM connector_utxo "
                            "WHERE outpoint = ANY($1);", missed)
                    m += len(rows)
                    p = dict()
                    for row in rows:
                        p[row["outpoint"]] = (row["pointer"], row["amount"],
                                              row["address"])
                    for block in blocks:
                        for z in blocks[block]["rawTx"]:
                            if not blocks[block]["rawTx"][z]["coinbase"]:
                                for i in blocks[block]["rawTx"][z]["vIn"]:
                                    inp = blocks[block]["rawTx"][z]["vIn"][i]
                                    outpoint = b"".join(
                                        (inp["txId"],
                                         int_to_bytes(inp["vOut"])))
                                    try:
                                        blocks[block]["rawTx"][z]["vIn"][i][
                                            "_l_"] = p[outpoint]
                                        assert p[outpoint] is not None
                                        t += 1
                                        n += 1
                                    except:
                                        pass
            if blocks:
                blocks[x]["checkpoint"] = x
            for x in blocks:
                for y in blocks[x]["rawTx"]:
                    for i in blocks[x]["rawTx"][y]["vOut"]:
                        try:
                            r = self.destroyed_coins.delete((x << 39) +
                                                            (y << 20) +
                                                            (1 << 19) + i)
                            blocks[x]["rawTx"][y]["vOut"][i]["_s_"] = r
                            assert r is not None
                        except:
                            pass

                blocks[x] = pickle.dumps(blocks[x])
            await self.pipe_sent_msg(b'result', pickle.dumps(blocks))
        except Exception as err:
            self.log.debug("load blocks error: %s" % str(err))
            await self.pipe_sent_msg(b'result', pickle.dumps([]))
            await self.pipe_sent_msg(b'failed', pickle.dumps(start_height))