自建 Monero(XMR) 交易查询 API - Monero Blockchain Explorer

之前自建了 XMR 收款中间件,使用了 xmrchain.net 免费的交易查询 API,但是近期 xmrchain.net 关闭了 API,只能自己拿源代码自建了,官方文档似乎很久没更新了,编译总是失败,摸索了一番终于成功,记录一下过程。

服务器准备

因为 Monero(XMR) 同步的区块数据很大,服务器至少需要 4核、 80GB 存储。

我这里准备的是 Vutlr 的 8核、32GB内存、160GB存储 的 Optimized Cloud Compute 。

1.克隆项目源代码

# download the source code 
git clone https://github.com/moneroexamples/onion-monero-blockchain-explorer.git

2.修改其中的 Dockerfile

a. 修改 MONERO_BRANCH 为最新发行分支

ARG MONERO_BRANCH=release-v0.18

b. 安装最新 MONERO 需要的依赖

...
RUN apt update && apt install -y --no-install-recommends build-essential \
cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev \
liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev \
libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev \
libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev \
libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev \
python3 ccache doxygen graphviz
...

完整如下:

# Use ubuntu:20.04 as base for builder stage image
FROM ubuntu:20.04 as builder

# Set Monero branch/tag to be used for monerod compilation

ARG MONERO_BRANCH=release-v0.18

# Added DEBIAN_FRONTEND=noninteractive to workaround tzdata prompt on installation
ENV DEBIAN_FRONTEND="noninteractive"

# Install dependencies for monerod and xmrblocks compilation
RUN apt-get update \
    && apt-get upgrade -y \
    && apt-get install -y --no-install-recommends \
    git \
    build-essential \
    cmake \
    miniupnpc \
    graphviz \
    doxygen \
    pkg-config \
    ca-certificates \
    zip \
    libboost-all-dev \
    libunbound-dev \
    libunwind8-dev \
    libssl-dev \
    libcurl4-openssl-dev \
    libgtest-dev \
    libreadline-dev \
    libzmq3-dev \
    libsodium-dev \
    libhidapi-dev \
    libhidapi-libusb0 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN apt update && apt install -y --no-install-recommends build-essential \
   cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev \
   liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev \
   libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev \
   libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev \
   libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev \
   python3 ccache doxygen graphviz

# Set compilation environment variables
ENV CFLAGS='-fPIC'
ENV CXXFLAGS='-fPIC'
ENV USE_SINGLE_BUILDDIR 1
ENV BOOST_DEBUG         1

WORKDIR /root

# Clone and compile monerod with all available threads
ARG NPROC
RUN git clone --recursive --branch ${MONERO_BRANCH} https://github.com/monero-project/monero.git \
    && cd monero \
    && test -z "$NPROC" && nproc > /nproc || echo -n "$NPROC" > /nproc && make -j"$(cat /nproc)"


# Copy and cmake/make xmrblocks with all available threads
COPY . /root/onion-monero-blockchain-explorer/
WORKDIR /root/onion-monero-blockchain-explorer/build
RUN cmake .. && make -j"$(cat /nproc)"

# Use ldd and awk to bundle up dynamic libraries for the final image
RUN zip /lib.zip $(ldd xmrblocks | grep -E '/[^\ ]' -o)

# Use ubuntu:20.04 as base for final image
FROM ubuntu:20.04

# Added DEBIAN_FRONTEND=noninteractive to workaround tzdata prompt on installation
ENV DEBIAN_FRONTEND="noninteractive"

# Install unzip to handle bundled libs from builder stage
RUN apt-get update \
    && apt-get upgrade -y \
    && apt-get install -y --no-install-recommends unzip \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /lib.zip .
RUN unzip -o lib.zip && rm -rf lib.zip

# Add user and setup directories for monerod and xmrblocks
RUN useradd -ms /bin/bash monero \
    && mkdir -p /home/monero/.bitmonero \
    && chown -R monero:monero /home/monero/.bitmonero
USER monero

# Switch to home directory and install newly built xmrblocks binary
WORKDIR /home/monero
COPY --chown=monero:monero --from=builder /root/onion-monero-blockchain-explorer/build/xmrblocks .
COPY --chown=monero:monero --from=builder /root/onion-monero-blockchain-explorer/build/templates ./templates/

# Expose volume used for lmdb access by xmrblocks
VOLUME /home/monero/.bitmonero

# Expose default explorer http port
EXPOSE 8081

ENTRYPOINT ["/bin/sh", "-c"]

# Set sane defaults that are overridden if the user passes any commands
CMD ["./xmrblocks --enable-json-api --enable-autorefresh-option  --enable-pusher"]

3.编辑 docker-compose.yml,放到 onion-monero-blockchain-explorer 同级目录

需要添加一下 --sync-pruned-blocks 同步裁剪后区块,体积小点。

version: '3'
services:
  monerod:
    image: sethsimmons/simple-monerod:latest
    restart: unless-stopped
    container_name: monerod
    volumes:
      - xmrdata:/home/monero/.bitmonero
    ports:
      - 18080:18080
      - 18089:18089
    command:
      - "--rpc-restricted-bind-ip=0.0.0.0"
      - "--rpc-restricted-bind-port=18089"
      - "--public-node"
      - "--no-igd"
      - "--enable-dns-blocklist"
      - "--prune-blockchain"
      - "--sync-pruned-blocks"

  explore:
    image: xmrblocks:latest
    build: ./onion-monero-blockchain-explorer
    container_name: explore
    restart: unless-stopped
    volumes:
      - xmrdata:/home/monero/.bitmonero
    ports:
      - 8081:8081
    command: ["./xmrblocks --daemon-url=monerod:18089 --enable-json-api --enable-autorefresh-option --enable-emission-monitor --enable-pusher"]

volumes:
    xmrdata:

4.编译 Docker 镜像

docker compose build

5.运行

docker compose up -d

时间比较久大概需要同步 7 个小时。同步完成后,可能会有目录权限问题,销毁一下容器重建一下就好。

docker compose down
docker compose up -d

完成

打开 ip:8081 就可以访问了。

根据 address 和 viewkey 查询最近交易的接口

api/outputsblocks

Search for our outputs in last few blocks (up to 5 blocks), using provided address and viewkey.

# testnet address
curl  -w "\n" -X GET http://127.0.0.1:8081/api/outputsblocks?address=9sDyNU82ih1gdhDgrqHbEcfSDFASjFgxL9B9v5f1AytFUrYsVEj7bD9Pyx5Sw2qLk8HgGdFM8qj5DNecqGhm24Ce6QwEGDi&viewkey=807079280293998634d66e745562edaaca45c0a75c8290603578b54e9397e90a&limit=5&mempool=1

Example result:

{
  "data": {
    "address": "0182d5be0f708cecf2b6f9889738bde5c930fad846d5b530e021afd1ae7e24a687ad50af3a5d38896655669079ad0163b4a369f6c852cc816dace5fc7792b72f",
    "height": 960526,
    "limit": "5",
    "mempool": true,
    "outputs": [
      {
        "amount": 33000000000000,
        "block_no": 0,
        "in_mempool": true,
        "output_idx": 1,
        "output_pubkey": "2417b24fc99b2cbd9459278b532b37f15eab6b09bbfc44f9d17e15cd25d5b44f",
        "payment_id": "",
        "tx_hash": "9233708004c51d15f44e86ac1a3b99582ed2bede4aaac6e2dd71424a9147b06f"
      },
      {
        "amount": 2000000000000,
        "block_no": 960525,
        "in_mempool": false,
        "output_idx": 0,
        "output_pubkey": "9984101f5471dda461f091962f1f970b122d4469077aed6b978a910dc3ed4576",
        "payment_id": "0000000000000055",
        "tx_hash": "37825d0feb2e96cd10fa9ec0b990ac2e97d2648c0f23e4f7d68d2298996acefd"
      },
      {
        "amount": 96947454120000,
        "block_no": 960525,
        "in_mempool": false,
        "output_idx": 1,
        "output_pubkey": "e4bded8e2a9ec4d41682a34d0a37596ec62742b28e74b897fcc00a47fcaa8629",
        "payment_id": "0000000000000000000000000000000000000000000000000000000000001234",
        "tx_hash": "4fad5f2bdb6dbd7efc2ce7efa3dd20edbd2a91640ce35e54c6887f0ee5a1a679"
      }
    ],
    "viewkey": "807079280293998634d66e745562edaaca45c0a75c8290603578b54e9397e90a"
  },
  "status": "success"
}