/** * <p>Construct a peer that reads/writes from the given chain. Automatically creates a VersionMessage for you from * the given software name/version strings, which should be something like "MySimpleTool", "1.0" and which will tell * the remote node to relay transaction inv messages before it has received a filter.</p> * * <p>Note that this does <b>NOT</b> make a connection to the given remoteAddress, it only creates a handler for a * connection. If you want to create a one-off connection, create a Peer and pass it to * {@link org.bitcoinj.net.NioClientManager#openConnection(java.net.SocketAddress, StreamConnection)} * or * {@link org.bitcoinj.net.NioClient#NioClient(java.net.SocketAddress, StreamConnection, int)}.</p> * * <p>The remoteAddress provided should match the remote address of the peer which is being connected to, and is * used to keep track of which peers relayed transactions and offer more descriptive logging.</p> */ public Peer(NetworkParameters params, AbstractBlockChain blockChain, PeerAddress peerAddress, String thisSoftwareName, String thisSoftwareVersion) { this(params, new VersionMessage(params, blockChain.getBestChainHeight()), blockChain, peerAddress); this.versionMessage.appendToSubVer(thisSoftwareName, thisSoftwareVersion, null); }
/** * Appends the given user-agent information to the subVer field. The subVer is composed of a series of * name:version pairs separated by slashes in the form of a path. For example a typical subVer field for bitcoinj * users might look like "/bitcoinj:0.13/MultiBit:1.2/" where libraries come further to the left.<p> * * There can be as many components as you feel a need for, and the version string can be anything, but it is * recommended to use A.B.C where A = major, B = minor and C = revision for software releases, and dates for * auto-generated source repository snapshots. A valid subVer begins and ends with a slash, therefore name * and version are not allowed to contain such characters. <p> * * Anything put in the "comments" field will appear in brackets and may be used for platform info, or anything * else. For example, calling <tt>appendToSubVer("MultiBit", "1.0", "Windows")</tt> will result in a subVer being * set of "/bitcoinj:1.0/MultiBit:1.0(Windows)/". Therefore the / ( and ) characters are reserved in all these * components. If you don't want to add a comment (recommended), pass null.<p> * * See <a href="https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki">BIP 14</a> for more information. * * @param comments Optional (can be null) platform or other node specific information. * @throws IllegalArgumentException if name, version or comments contains invalid characters. */ public void appendToSubVer(String name, String version, @Nullable String comments) { checkSubVerComponent(name); checkSubVerComponent(version); if (comments != null) { checkSubVerComponent(comments); subVer = subVer.concat(String.format(Locale.US, "%s:%s(%s)/", name, version, comments)); } else { subVer = subVer.concat(String.format(Locale.US, "%s:%s/", name, version)); } }
@Override protected void parse() throws ProtocolException { clientVersion = (int) readUint32(); localServices = readUint64().longValue(); time = readUint64().longValue(); myAddr = new PeerAddress(params, payload, cursor, 0); cursor += myAddr.getMessageSize(); readUint64(); try { bestHeight = 0; relayTxesBeforeFilter = true; if (!hasMoreBytes()) return; subVer = readStr(); if (!hasMoreBytes()) return; bestHeight = readUint32(); if (!hasMoreBytes()) return; relayTxesBeforeFilter = readBytes(1)[0] != 0; } finally { length = cursor - offset;
public VersionMessage duplicate() { VersionMessage v = new VersionMessage(params, (int) bestHeight); v.clientVersion = clientVersion; v.localServices = localServices; v.time = time; v.myAddr = myAddr; v.theirAddr = theirAddr; v.subVer = subVer; v.relayTxesBeforeFilter = relayTxesBeforeFilter; return v; }
VersionMessage ver = new VersionMessage(params, 42); ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null); ver.localServices = VersionMessage.NODE_NETWORK; final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)), new PeerAddress(params, InetAddress.getLocalHost())); Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain()); if (bitcoind.getPeerVersionMessage().isGetUTXOsSupported()) { UTXORule r = (UTXORule) rule; UTXOsMessage result = bitcoind.getUTXOs(r.query).get();
if (!vPeerVersionMessage.hasBlockChain() || (!params.allowEmptyPeerChain() && vPeerVersionMessage.bestHeight == 0)) {
/** * <p>Sets a Bloom filter on this connection. This will cause the given {@link BloomFilter} object to be sent to the * remote peer and if requested, a {@link MemoryPoolMessage} is sent as well to trigger downloading of any * pending transactions that may be relevant.</p> * * <p>The Peer does not automatically request filters from any wallets added using {@link Peer#addWallet(Wallet)}. * This is to allow callers to avoid redundantly recalculating the same filter repeatedly when using multiple peers * and multiple wallets together.</p> * * <p>Therefore, you should not use this method if your app uses a {@link PeerGroup}. It is called for you.</p> * * <p>If the remote peer doesn't support Bloom filtering, then this call is ignored. Once set you presently cannot * unset a filter, though the underlying p2p protocol does support it.</p> */ public void setBloomFilter(BloomFilter filter, boolean andQueryMemPool) { checkNotNull(filter, "Clearing filters is not currently supported"); final VersionMessage ver = vPeerVersionMessage; if (ver == null || !ver.isBloomFilteringSupported()) return; vBloomFilter = filter; log.debug("{}: Sending Bloom filter{}", this, andQueryMemPool ? " and querying mempool" : ""); sendMessage(filter); if (andQueryMemPool) sendMessage(new MemoryPoolMessage()); maybeRestartChainDownload(); }
} else { log.debug("{}: getdata on tx {}", getAddress(), item.hash); getdata.addItem(vPeerVersionMessage.isWitnessSupported() ? item.toWitnessItem() : item); if (vPeerVersionMessage.isBloomFilteringSupported() && useFilteredBlocks) { getdata.addFilteredBlock(item.hash); pingAfterGetData = true; } else { getdata.addItem(vPeerVersionMessage.isWitnessSupported() ? item.toWitnessItem() : item);
protected ListenableFuture<Long> ping(long nonce) throws ProtocolException { final VersionMessage ver = vPeerVersionMessage; if (!ver.isPingPongSupported()) throw new ProtocolException("Peer version is too low for measurable pings: " + ver); PendingPing pendingPing = new PendingPing(nonce); pendingPings.add(pendingPing); sendMessage(new Ping(pendingPing.nonce)); return pendingPing.future; }
protected Peer connectTo(PeerAddress address, boolean incrementMaxConnections, int connectTimeoutMillis) { checkState(lock.isHeldByCurrentThread()); VersionMessage ver = getVersionMessage().duplicate(); ver.bestHeight = chain == null ? 0 : chain.getBestChainHeight(); ver.time = Utils.currentTimeSeconds();
public VersionMessage duplicate() { VersionMessage v = new VersionMessage(params, (int) bestHeight); v.clientVersion = clientVersion; v.localServices = localServices; v.time = time; v.myAddr = myAddr; v.theirAddr = theirAddr; v.subVer = subVer; v.relayTxesBeforeFilter = relayTxesBeforeFilter; return v; }
if (!vPeerVersionMessage.hasBlockChain() || (!params.allowEmptyPeerChain() && vPeerVersionMessage.bestHeight == 0)) {
/** * <p>Sets a Bloom filter on this connection. This will cause the given {@link BloomFilter} object to be sent to the * remote peer and if requested, a {@link MemoryPoolMessage} is sent as well to trigger downloading of any * pending transactions that may be relevant.</p> * * <p>The Peer does not automatically request filters from any wallets added using {@link Peer#addWallet(Wallet)}. * This is to allow callers to avoid redundantly recalculating the same filter repeatedly when using multiple peers * and multiple wallets together.</p> * * <p>Therefore, you should not use this method if your app uses a {@link PeerGroup}. It is called for you.</p> * * <p>If the remote peer doesn't support Bloom filtering, then this call is ignored. Once set you presently cannot * unset a filter, though the underlying p2p protocol does support it.</p> */ public void setBloomFilter(BloomFilter filter, boolean andQueryMemPool) { checkNotNull(filter, "Clearing filters is not currently supported"); final VersionMessage ver = vPeerVersionMessage; if (ver == null || !ver.isBloomFilteringSupported()) return; vBloomFilter = filter; log.debug("{}: Sending Bloom filter{}", this, andQueryMemPool ? " and querying mempool" : ""); sendMessage(filter); if (andQueryMemPool) sendMessage(new MemoryPoolMessage()); maybeRestartChainDownload(); }
} else { log.debug("{}: getdata on tx {}", getAddress(), item.hash); getdata.addItem(vPeerVersionMessage.isWitnessSupported() ? item.toWitnessItem() : item); if (vPeerVersionMessage.isBloomFilteringSupported() && useFilteredBlocks) { getdata.addFilteredBlock(item.hash); pingAfterGetData = true; } else { getdata.addItem(vPeerVersionMessage.isWitnessSupported() ? item.toWitnessItem() : item);
protected ListenableFuture<Long> ping(long nonce) throws ProtocolException { final VersionMessage ver = vPeerVersionMessage; if (!ver.isPingPongSupported()) throw new ProtocolException("Peer version is too low for measurable pings: " + ver); PendingPing pendingPing = new PendingPing(nonce); pendingPings.add(pendingPing); sendMessage(new Ping(pendingPing.nonce)); return pendingPing.future; }
protected Peer connectTo(PeerAddress address, boolean incrementMaxConnections, int connectTimeoutMillis) { checkState(lock.isHeldByCurrentThread()); VersionMessage ver = getVersionMessage().duplicate(); ver.bestHeight = chain == null ? 0 : chain.getBestChainHeight(); ver.time = Utils.currentTimeSeconds();
/** * <p>Construct a peer that reads/writes from the given chain. Automatically creates a VersionMessage for you from * the given software name/version strings, which should be something like "MySimpleTool", "1.0" and which will tell * the remote node to relay transaction inv messages before it has received a filter.</p> * * <p>Note that this does <b>NOT</b> make a connection to the given remoteAddress, it only creates a handler for a * connection. If you want to create a one-off connection, create a Peer and pass it to * {@link org.bitcoinj.net.NioClientManager#openConnection(java.net.SocketAddress, StreamConnection)} * or * {@link org.bitcoinj.net.NioClient#NioClient(java.net.SocketAddress, StreamConnection, int)}.</p> * * <p>The remoteAddress provided should match the remote address of the peer which is being connected to, and is * used to keep track of which peers relayed transactions and offer more descriptive logging.</p> */ public Peer(NetworkParameters params, AbstractBlockChain blockChain, PeerAddress peerAddress, String thisSoftwareName, String thisSoftwareVersion) { this(params, new VersionMessage(params, blockChain.getBestChainHeight()), blockChain, peerAddress); this.versionMessage.appendToSubVer(thisSoftwareName, thisSoftwareVersion, null); }
@Override protected void parse() throws ProtocolException { clientVersion = (int) readUint32(); localServices = readUint64().longValue(); time = readUint64().longValue(); myAddr = new PeerAddress(params, payload, cursor, 0); cursor += myAddr.getMessageSize(); readUint64(); try { bestHeight = 0; relayTxesBeforeFilter = true; if (!hasMoreBytes()) return; subVer = readStr(); if (!hasMoreBytes()) return; bestHeight = readUint32(); if (!hasMoreBytes()) return; relayTxesBeforeFilter = readBytes(1)[0] != 0; } finally { length = cursor - offset;
public VersionMessage duplicate() { VersionMessage v = new VersionMessage(params, (int) bestHeight); v.clientVersion = clientVersion; v.localServices = localServices; v.time = time; v.myAddr = myAddr; v.theirAddr = theirAddr; v.subVer = subVer; v.relayTxesBeforeFilter = relayTxesBeforeFilter; return v; }
if (!vPeerVersionMessage.hasBlockChain() || (!params.allowEmptyPeerChain() && vPeerVersionMessage.bestHeight == 0)) {