当钱已发送到本地 regtest 网络上的特定比特币地址时,我如何收到通知?

How can I get notified when money has been sent to a particular Bitcoin address on a local regtest network?

我想以编程方式检测何时有人将比特币发送到某个地址。这发生在我开始使用这个 docker-compose.yml 文件的本地测试网上。

一旦本地测试网 运行s,我使用

创建一个新地址
docker exec -it minimal-crypto-exchange_node_1 bitcoin-cli getnewaddress

说吧returns2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181.

我把这个地址放到下面Java code:

import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.wallet.Wallet;
import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener;

public class WalletObserver {
    public void init() {
        final NetworkParameters netParams = NetworkParameters.fromID(NetworkParameters.ID_REGTEST);

        try {
            final Wallet wallet = Wallet.createBasic(netParams);

            wallet.addWatchedAddress(Address.fromString(netParams, "2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181"));

            wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
                @Override
                public void onCoinsReceived(final Wallet wallet, final Transaction transaction, final Coin prevBalance, final Coin newBalance) {
                    System.out.println("Heyo!");
                }
            });
        }
        catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

然后我用 class.

启动 Java 应用程序

然后我发送一些测试比特币到有问题的地址:

% docker exec -it minimal-crypto-exchange_node_1 bitcoin-cli sendtoaddress 2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181 0.5
068c377bab961356ad9a3919229a764aa929711c68aefd5dbd4c7c348eef3406

如果我去 http://localhost:3002/tx/068c377bab961356ad9a3919229a764aa929711c68aefd5dbd4c7c348eef3406,我会看到交易详情。

然而,侦听器中的断点(onCoinsReceived 方法)永远不会激活。

我需要如何修改我的代码 and/or 我用来发送测试 BTC 的命令,以便每当该帐户收到钱时,都会调用 onCoinsReceived 方法? 有什么地方可以告诉 WalletNetworkParameters 我想连接到本地主机吗?

我使用的是 bitcoinj-core 0.15.10 版。

更新 1:

我修改了 docker-compose.yml 并添加了以下端口映射:

    ports:
      - "51001:50001"
      - "51002:50002"
      - "19001:19001"
      - "19000:19000"
      - "28332:28332"

然后我重写了init方法,这样我就可以连接到localhost并指定端口:

public class WalletObserver {
    public void init() {
        final LocalTestNetParams netParams = new LocalTestNetParams();
        netParams.setPort(50001);
        try {
            final WalletAppKit kit = new WalletAppKit(netParams, new File("."), "_minimalCryptoExchangeBtcWallet");
            kit.setAutoSave(true);
            kit.connectToLocalHost();

            kit.startAsync();
            kit.awaitRunning(); // I never get past this point
            kit.peerGroup().addPeerDiscovery(new DnsDiscovery(netParams));
            kit.wallet().addWatchedAddress(Address.fromString(netParams, "2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181"));

            kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
                @Override
                public void onCoinsReceived(final Wallet wallet, final Transaction transaction, final Coin prevBalance, final Coin newBalance) {
                    System.out.println("Heyo!");
                }
            });
        }
        catch (Exception exception) {
            exception.printStackTrace();
        }
    }

LocalTestNetParams允许指定端口:

package com.dpisarenko.minimalcryptoexchange.logic.btc;

import org.bitcoinj.params.RegTestParams;

public class LocalTestNetParams extends RegTestParams {
    public void setPort(final int newPort) {
        this.port = newPort;
    }
}

我在 netParams.setPort(50001); 中尝试了上述所有端口。

在所有情况下,我都会在 kit.awaitRunning(); 之后收到以下消息:

22:16:34.245 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Attempting connection to [10.10.1.218]:50001     (0 connected, 1 pending, 1 max)
22:16:34.265 [NioClientManager] WARN  org.bitcoinj.net.NioClientManager - Failed to connect with exception: java.net.ConnectException: Connection refused
java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method)
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:579)
    at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:820)
    at org.bitcoinj.net.NioClientManager.handleKey(NioClientManager.java:64)
    at org.bitcoinj.net.NioClientManager.run(NioClientManager.java:122)
    at com.google.common.util.concurrent.AbstractExecutionThreadService.run(AbstractExecutionThreadService.java:66)
    at com.google.common.util.concurrent.Callables.run(Callables.java:119)
    at org.bitcoinj.utils.ContextPropagatingThreadFactory.run(ContextPropagatingThreadFactory.java:51)
    at java.base/java.lang.Thread.run(Thread.java:830)
22:16:34.267 [NioClientManager] INFO  org.bitcoinj.core.PeerGroup - [10.10.1.218]:50001: Peer died      (0 connected, 0 pending, 1 max)
22:16:34.267 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Peer discovery took 21.84 μs and returned 0 items from 0 discoverers
22:16:34.269 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Waiting 1502 ms before next connect attempt to [10.10.1.218]:50001
22:16:35.776 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Attempting connection to [10.10.1.218]:50001     (0 connected, 1 pending, 1 max)
22:16:35.778 [NioClientManager] WARN  org.bitcoinj.net.NioClientManager - Failed to connect with exception: java.net.ConnectException: Connection refused
java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method)
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:579)
    at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:820)
    at org.bitcoinj.net.NioClientManager.handleKey(NioClientManager.java:64)
    at org.bitcoinj.net.NioClientManager.run(NioClientManager.java:122)
    at com.google.common.util.concurrent.AbstractExecutionThreadService.run(AbstractExecutionThreadService.java:66)
    at com.google.common.util.concurrent.Callables.run(Callables.java:119)
    at org.bitcoinj.utils.ContextPropagatingThreadFactory.run(ContextPropagatingThreadFactory.java:51)
    at java.base/java.lang.Thread.run(Thread.java:830)
22:16:35.778 [NioClientManager] INFO  org.bitcoinj.core.PeerGroup - [10.10.1.218]:50001: Peer died      (0 connected, 0 pending, 1 max)
22:16:35.779 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Peer discovery took 8.752 μs and returned 0 items from 0 discoverers

10.10.1.218 似乎是由 InetAddress.getLocalHost()org.bitcoinj.kits.WalletAppKit#connectToLocalHost:

中生成的
    public WalletAppKit connectToLocalHost() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            return this.setPeerNodes(new PeerAddress(this.params, localHost, this.params.getPort()));
        } catch (UnknownHostException var2) {
            throw new RuntimeException(var2);
        }
    }

更新 1:

我尝试使用 network_mode: "host"

如果我将它添加到 node,如

  node:
    image: ulamlabs/bitcoind-custom-regtest:latest
    network_mode: "host"

当我 运行 docker-compose up -d:

时出现以下错误
minimal-crypto-exchange % docker-compose up -d
Creating network "minimal-crypto-exchange_default" with the default driver
Creating minimal-crypto-exchange_postgres_1  ... done
Creating minimal-crypto-exchange_geth_1     ...
Creating minimal-crypto-exchange_node_1     ... done
Creating minimal-crypto-exchange_electrumx_1 ...
Creating minimal-crypto-exchange_electrumx_1 ... error

ERROR: for minimal-crypto-exchange_electrumx_1  Cannot start service electrumx: driver fail
Creating minimal-crypto-exchange_geth_1      ... done
f68d0f25a0512399877bc55434513def810649e4fcf31a5a88ca3292d34): Error starting userland proxy: listen tcp4 0.0.0.0:28332: bind: address already in use
Creating minimal-crypto-exchange_blockscout_1 ... done

ERROR: for electrumx  Cannot start service electrumx: driver failed programming external connectivity on endpoint minimal-crypto-exchange_electrumx_1 (8eaa4f68d0f25a0512399877bc55434513def810649e4fcf31a5a88ca3292d34): Error starting userland proxy: listen tcp4 0.0.0.0:28332: bind: address already in use
ERROR: Encountered errors while bringing up the project.

如果我将它添加到 electrumx 部分,如

  electrumx:
    image: lukechilds/electrumx:latest
    network_mode: "host"

我收到另一个错误:

minimal-crypto-exchange % docker-compose up -d
minimal-crypto-exchange_postgres_1 is up-to-date
minimal-crypto-exchange_geth_1 is up-to-date
Recreating minimal-crypto-exchange_node_1 ...
Recreating minimal-crypto-exchange_node_1 ... done
Recreating minimal-crypto-exchange_electrumx_1 ...

ERROR: for minimal-crypto-exchange_electrumx_1  "host" network_mode is incompatible with port_bindings

ERROR: for electrumx  "host" network_mode is incompatible with port_bindings
Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose/cli/main.py", line 81, in main
  File "compose/cli/main.py", line 203, in perform_command
  File "compose/metrics/decorator.py", line 18, in wrapper
  File "compose/cli/main.py", line 1186, in up
  File "compose/cli/main.py", line 1166, in up
  File "compose/project.py", line 697, in up
  File "compose/parallel.py", line 108, in parallel_execute
  File "compose/parallel.py", line 206, in producer
  File "compose/project.py", line 679, in do
  File "compose/service.py", line 579, in execute_convergence_plan
  File "compose/service.py", line 499, in _execute_convergence_recreate
  File "compose/parallel.py", line 108, in parallel_execute
  File "compose/parallel.py", line 206, in producer
  File "compose/service.py", line 494, in recreate
  File "compose/service.py", line 612, in recreate_container
  File "compose/service.py", line 330, in create_container
  File "compose/service.py", line 939, in _get_container_create_options
  File "compose/service.py", line 1014, in _get_container_host_config
  File "docker/api/container.py", line 598, in create_host_config
  File "docker/types/containers.py", line 338, in __init__
docker.errors.InvalidArgument: "host" network_mode is incompatible with port_bindings
[44262] Failed to execute script docker-compose

更新二:

如果我注释掉

中的端口绑定
  electrumx:
    image: lukechilds/electrumx:latest
    network_mode: host
    links:
      - node
# Port settings see https://github.com/ulamlabs/bitcoind-custom-regtest
#    ports:
#      - "51001:50001"
#      - "51002:50002"
#      - "19001:19001"
#      - "19000:19000"
#      - "28332:28332"

和运行 docker-compose up -d我得到

 % docker-compose up -d
Creating network "minimal-crypto-exchange_default" with the default driver
Creating minimal-crypto-exchange_geth_1 ...
Creating minimal-crypto-exchange_postgres_1  ... done
Creating minimal-crypto-exchange_node_1     ... done
Creating minimal-crypto-exchange_electrumx_1 ... error
Creating minimal-crypto-exchange_geth_1      ... done
ERROR: for minimal-crypto-exchange_electrumx_1  Cannot create container for service electrumx: conflicting options: host type networking can't be used with links. This would result in undefined behavior
Creating minimal-crypto-exchange_blockscout_1 ... done

ERROR: for electrumx  Cannot create container for service electrumx: conflicting options: host type networking can't be used with links. This would result in undefined behavior
ERROR: Encountered errors while bringing up the project.

更新 3: 我假设错误的根源是在我的 Java 代码中我尝试连接到 ElectrumX 服务器而不是实际的比特币节点(nodedocker-compose.yml)。

更新 4:

我改docker-compose.yml如下:

  node:
    image: ulamlabs/bitcoind-custom-regtest:latest
# For ports used by node see
# https://github.com/ulamlabs/bitcoind-custom-regtest/blob/master/bitcoin.conf
    ports:
      - "19001:19001"
      - "19000:19000"
      - "28332:28332"
  electrumx:
    image: lukechilds/electrumx:latest
    links:
      - node
# Port settings see https://github.com/ulamlabs/bitcoind-custom-regtest
    ports:
      - "51001:50001"
      - "51002:50002"
#      - "19001:19001"
#      - "19000:19000"
#      - "28332:28332"

现在我收到不同的错误(完整日志可用 here):

11:33:51.865 [NioClientManager] INFO  org.bitcoinj.core.PeerGroup - [192.168.10.208]:19000: Peer died      (0 connected, 0 pending, 1 max)
11:33:51.865 [NioClientManager] INFO  org.bitcoinj.core.PeerGroup - Not yet setting download peer because there is no clear candidate.
11:33:51.865 [NioClientManager] DEBUG org.bitcoinj.core.BitcoinSerializer - Received 168 byte 'alert' message: 60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50
11:33:51.866 [PeerGroup Thread] INFO  org.bitcoinj.core.PeerGroup - Waiting 999 ms before next connect attempt to [127.0.0.1]:19000
11:33:51.866 [NioClientManager] DEBUG org.bitcoinj.core.Peer - Received alert from peer Peer{[192.168.10.208]:19000, version=70015, subVer=/Satoshi:0.19.1(bitcore)/, services=1033 (NETWORK, WITNESS, NETWORK_LIMITED), time=2021-11-06 11:33:52, height=5}: URGENT: Alert key compromised, upgrade required
11:33:51.867 [NioClientManager] WARN  org.bitcoinj.net.ConnectionHandler - Error handling SelectionKey: java.nio.channels.CancelledKeyException 
java.nio.channels.CancelledKeyException: null
    at java.base/sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:71)
    at java.base/sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:130)
    at java.base/java.nio.channels.SelectionKey.isWritable(SelectionKey.java:377)
    at org.bitcoinj.net.ConnectionHandler.handleKey(ConnectionHandler.java:244)
    at org.bitcoinj.net.NioClientManager.handleKey(NioClientManager.java:86)
    at org.bitcoinj.net.NioClientManager.run(NioClientManager.java:122)
    at com.google.common.util.concurrent.AbstractExecutionThreadService.run(AbstractExecutionThreadService.java:66)
    at com.google.common.util.concurrent.Callables.run(Callables.java:119)
    at org.bitcoinj.utils.ContextPropagatingThreadFactory.run(ContextPropagatingThreadFactory.java:51)
    at java.base/java.lang.Thread.run(Thread.java:830)

更新 5:

有人建议(在现已删除的评论中)在应用程序的输出中有这条 Peer does not support bloom filtering 消息:

11:32:43.482 [NioClientManager] INFO  org.bitcoinj.core.Peer - Peer{[127.0.0.1]:19000, version=70015, subVer=/Satoshi:0.19.1(bitcore)/, services=1033 (NETWORK, WITNESS, NETWORK_LIMITED), time=2021-11-06 11:32:43, height=4}: Peer does not support bloom filtering.

所以我尝试分叉原始图像并更改 bitcoin.conf 文件以启用 Bloom 过滤:

peerbloomfilters=1

当我运行 docker build -t mentiflectax/bitcoind-custom-regtest:latest .时,我得到以下错误信息(剩余输出的一部分可以找到here):

#13 922.4 g++: fatal error: Killed signal terminated program cc1plus
#13 922.4 compilation terminated.
#13 922.4 make[2]: *** [Makefile:8044: libbitcoin_server_a-init.o] Error 1
#13 922.4 make[2]: *** Waiting for unfinished jobs....
#13 965.8 make[2]: Leaving directory '/bitcoin-0.19.1/src'
#13 965.8 make[1]: *** [Makefile:13765: all-recursive] Error 1
#13 965.9 make[1]: Leaving directory '/bitcoin-0.19.1/src'
#13 965.9 make: *** [Makefile:776: all-recursive] Error 1
------
executor failed running [/bin/sh -c tar -xzf *.tar.gz     && cd bitcoin-${BITCOIN_VERSION}     && sed -i 's/consensus.nSubsidyHalvingInterval = 150/consensus.nSubsidyHalvingInterval = 210000/g' src/chainparams.cpp     && ./autogen.sh     && ./configure LDFLAGS=-L`ls -d /opt/db`/lib/ CPPFLAGS=-I`ls -d /opt/db`/include/     --prefix=/opt/bitcoin     --disable-man     --disable-tests     --disable-bench     --disable-ccache     --with-gui=no     --enable-util-cli     --with-daemon     && make -j4     && make install     && strip /opt/bitcoin/bin/bitcoin-cli     && strip /opt/bitcoin/bin/bitcoind]: exit code: 2

更新6:正确的端口好像是19000.

如果我使用端口 19001,在 kit.awaitRunning() 之后会出现以下错误:

INFO  org.bitcoinj.core.PeerSocketHandler - [127.0.0.1]:19001: Timed out

完整的日志输出可用here

我还没有用 electrumxethereum 文件中存在的 ethereum 东西测试你的完整设置,但关于你的问题,以下步骤工作正常,我认为它在您的完整设置中也能发挥作用。

我 运行 和 docker 一个基于你提供的 ulamlabs/bitcoind-custom-regtest:latest 图片的比特币节点:

docker run -p 18444:19000 -d ulamlabs/bitcoind-custom-regtest:latest

如您所见,我将图像内部端口 19000 公开为 RegTestParams18444default port。从我们客户的角度来看,有了这个设置,基本上它看起来就像我们是 运行 主机中的比特币守护进程。使用您的 LocalTestNetParams class 并按照您的指示提供端口 19000 也应该可以解决问题。

然后,根据您在问题中提供的反馈,我使用bashvi手动编辑了/root/.bitcoin/bitcoin.conf中比特币节点的守护程序配置:

docker exec -it 0aa2e863cd9927 bash

并包含以下配置:

peerbloomfilters=1

重启容器后,我得到了一个新地址:

docker exec -it 0aa2e863cd9927 bitcoin-cli -regtest getnewaddress

假设新地址是您在问题中提供的地址:

2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181

然后,按照 Bitcoin documentation 中的建议,为了避免资金不足错误,我生成了 101 个区块到这个地址:

docker exec -it 0aa2e863cd9927 bitcoin-cli -regtest generatetoaddress 101 2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181 

我使用了 generatetoaddress 而不是 generate 因为 since Bitcoin 0.19.0 the option is no longer valid.

接下来,我根据您提供的信息和 Bitcoinj 库文档中的 this example 准备了一个简单的 Java 程序:

import java.io.File;

import org.bitcoinj.core.Address;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.params.RegTestParams;

public class Kit {

  public static void main(String[] args) {
    Kit kit  = new Kit();
    kit.run();
  }

  private synchronized void run(){
    NetworkParameters params = RegTestParams.get();
    WalletAppKit kit = new WalletAppKit(params, new File("."), "walletappkit-example");
    kit.connectToLocalHost();

    kit.startAsync();
    kit.awaitRunning();

    kit.wallet().addWatchedAddress(Address.fromString(params, "2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181"));

    kit.wallet().addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
      System.out.println("-----> coins resceived: " + tx.getTxId());
    });

    while (true) {
      try {
        this.wait(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

我用了一个简单的while循环来保持问题运行;当然,如果在实际设置中可能是不必要的,因为您似乎正在使用 Spring Boot.

然后,如果你发送一些比特币到这个地址:

docker exec -it 0aa2e863cd9927 bitcoin-cli -regtest sendtoaddress 2N23tWAFEtBtTgxNjBNmnwzsiPdLcNek181 0.00001
0f972642713c72ae0fe03fe51818b9ea4d483720b69b90e795f35eb80a587c26

应该调用侦听器:

2021-11-09 23:51:20.537 INFO  [NioClientManager][Wallet] Received a pending transaction 0f972642713c72ae0fe03fe51818b9ea4d483720b69b90e795f35eb80a587c26 that spends 0.00 BTC from our own wallet, and sends us 0.00001 BTC
2021-11-09 23:51:20.537 INFO  [NioClientManager][Wallet] commitTx of 0f972642713c72ae0fe03fe51818b9ea4d483720b69b90e795f35eb80a587c26
...
2021-11-09 23:51:20.537 INFO  [NioClientManager][Wallet] ->pending: 0f972642713c72ae0fe03fe51818b9ea4d483720b69b90e795f35eb80a587c26
2021-11-09 23:51:20.537 INFO  [NioClientManager][Wallet] Estimated balance is now: 0.00001 BTC
-----> coins resceived: 0f972642713c72ae0fe03fe51818b9ea4d483720b69b90e795f35eb80a587c26
2021-11-09 23:51:20.538 INFO  [NioClientManager][WalletFiles] Saving wallet; last seen block is height 165, date 2021-11-09T22:50:48Z, hash 23451521947bc5ff098c088ae0fc445becca8837d39ee8f6dd88f2c47ad5ac23
2021-11-09 23:51:20.543 INFO  [NioClientManager][WalletFiles] Save completed in 4.736 ms

还有一个你提到的问题我没有机会测试,它正在创建一个新的Docker图像,其中peerbloomfilters配置将被正确配置而不需要修改实际的容器状态。我认为您指出的编译问题可能与 this issue 有关,基本上,容器没有足够的资源来执行该过程。如果您使用 macOS 并且 Docker 用于 Mac,请尝试调整容器可用的内存量,这可能会有所帮助。所用基础 alpine 图像的变化也可以激发问题。我也会尝试深入研究这个问题。