mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 10:15:52 +00:00
Fix some bugs that happen in chainless operation. Make Peer.getBestChainHeight() more accurate by taking into account blocks announced after a peer is connected, not just what it announced in the initial version message.
This commit is contained in:
parent
5cc9710e1f
commit
3f89eda933
@ -61,10 +61,14 @@ public class Peer {
|
|||||||
// Whether to try and download blocks and transactions from this peer. Set to false by PeerGroup if not the
|
// Whether to try and download blocks and transactions from this peer. Set to false by PeerGroup if not the
|
||||||
// primary peer. This is to avoid redundant work and concurrency problems with downloading the same chain
|
// primary peer. This is to avoid redundant work and concurrency problems with downloading the same chain
|
||||||
// in parallel.
|
// in parallel.
|
||||||
private boolean downloadData = true;
|
private boolean downloadData = false;
|
||||||
// The version data to announce to the other side of the connections we make: useful for setting our "user agent"
|
// The version data to announce to the other side of the connections we make: useful for setting our "user agent"
|
||||||
// equivalent and other things.
|
// equivalent and other things.
|
||||||
private VersionMessage versionMessage;
|
private VersionMessage versionMessage;
|
||||||
|
// How many block messages the peer has announced to us. Peers only announce blocks that attach to their best chain
|
||||||
|
// so we can use this to calculate the height of the peers chain, by adding it to the initial height in the version
|
||||||
|
// message. This method can go wrong if the peer re-orgs onto a shorter (but harder) chain, however, this is rare.
|
||||||
|
private int blocksAnnounced;
|
||||||
// A class that tracks recent transactions that have been broadcast across the network, counts how many
|
// A class that tracks recent transactions that have been broadcast across the network, counts how many
|
||||||
// peers announced them and updates the transaction confidence data. It is passed to each Peer.
|
// peers announced them and updates the transaction confidence data. It is passed to each Peer.
|
||||||
private MemoryPool memoryPool;
|
private MemoryPool memoryPool;
|
||||||
@ -98,6 +102,7 @@ public class Peer {
|
|||||||
this.params = Preconditions.checkNotNull(params);
|
this.params = Preconditions.checkNotNull(params);
|
||||||
this.versionMessage = Preconditions.checkNotNull(ver);
|
this.versionMessage = Preconditions.checkNotNull(ver);
|
||||||
this.blockChain = chain; // Allowed to be null.
|
this.blockChain = chain; // Allowed to be null.
|
||||||
|
this.downloadData = chain != null;
|
||||||
this.pendingGetBlockFutures = new ArrayList<GetDataFuture<Block>>();
|
this.pendingGetBlockFutures = new ArrayList<GetDataFuture<Block>>();
|
||||||
this.eventListeners = new CopyOnWriteArrayList<PeerEventListener>();
|
this.eventListeners = new CopyOnWriteArrayList<PeerEventListener>();
|
||||||
this.lifecycleListeners = new CopyOnWriteArrayList<PeerLifecycleListener>();
|
this.lifecycleListeners = new CopyOnWriteArrayList<PeerLifecycleListener>();
|
||||||
@ -438,6 +443,20 @@ public class Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transactions.size() == 0 && blocks.size() == 1) {
|
||||||
|
// Single block announcement. If we're downloading the chain this is just a tickle to make us continue
|
||||||
|
// (the block chain download protocol is very implicit and not well thought out). If we're not downloading
|
||||||
|
// the chain then this probably means a new block was solved and the peer believes it connects to the best
|
||||||
|
// chain, so count it. This way getBestChainHeight() can be accurate.
|
||||||
|
if (downloadData) {
|
||||||
|
if (!blockChain.isOrphan(blocks.get(0).hash)) {
|
||||||
|
blocksAnnounced++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blocksAnnounced++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GetDataMessage getdata = new GetDataMessage(params);
|
GetDataMessage getdata = new GetDataMessage(params);
|
||||||
|
|
||||||
Iterator<InventoryItem> it = transactions.iterator();
|
Iterator<InventoryItem> it = transactions.iterator();
|
||||||
@ -811,7 +830,7 @@ public class Peer {
|
|||||||
*/
|
*/
|
||||||
public int getPeerBlockHeightDifference() {
|
public int getPeerBlockHeightDifference() {
|
||||||
// Chain will overflow signed int blocks in ~41,000 years.
|
// Chain will overflow signed int blocks in ~41,000 years.
|
||||||
int chainHeight = (int) peerVersionMessage.bestHeight;
|
int chainHeight = (int) getBestHeight();
|
||||||
// chainHeight should not be zero/negative because we shouldn't have given the user a Peer that is to another
|
// chainHeight should not be zero/negative because we shouldn't have given the user a Peer that is to another
|
||||||
// client-mode node, nor should it be unconnected. If that happens it means the user overrode us somewhere or
|
// client-mode node, nor should it be unconnected. If that happens it means the user overrode us somewhere or
|
||||||
// there is a bug in the peer management code.
|
// there is a bug in the peer management code.
|
||||||
@ -857,9 +876,9 @@ public class Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the height of the best chain as claimed by peer.
|
* @return the height of the best chain as claimed by peer: sum of its ver announcement and blocks announced since.
|
||||||
*/
|
*/
|
||||||
public long getBestHeight() {
|
public long getBestHeight() {
|
||||||
return peerVersionMessage.bestHeight;
|
return peerVersionMessage.bestHeight + blocksAnnounced;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,7 @@ public class PeerGroup {
|
|||||||
ExecutorService workerExecutor = Executors.newCachedThreadPool(new PeerGroupThreadFactory());
|
ExecutorService workerExecutor = Executors.newCachedThreadPool(new PeerGroupThreadFactory());
|
||||||
NioClientSocketChannelFactory channelFactory = new NioClientSocketChannelFactory(bossExecutor, workerExecutor);
|
NioClientSocketChannelFactory channelFactory = new NioClientSocketChannelFactory(bossExecutor, workerExecutor);
|
||||||
ClientBootstrap bs = new ClientBootstrap(channelFactory);
|
ClientBootstrap bs = new ClientBootstrap(channelFactory);
|
||||||
|
bs.setOption("connectionTimeoutMillis", 2000);
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,6 +756,8 @@ public class PeerGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setDownloadPeer(Peer peer) {
|
private synchronized void setDownloadPeer(Peer peer) {
|
||||||
|
if (chain == null)
|
||||||
|
return;
|
||||||
if (downloadPeer != null) {
|
if (downloadPeer != null) {
|
||||||
log.info("Unsetting download peer: {}", downloadPeer);
|
log.info("Unsetting download peer: {}", downloadPeer);
|
||||||
downloadPeer.setDownloadData(false);
|
downloadPeer.setDownloadData(false);
|
||||||
|
@ -41,6 +41,8 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
import static org.jboss.netty.channel.Channels.write;
|
import static org.jboss.netty.channel.Channels.write;
|
||||||
|
|
||||||
|
// TODO: Remove this class and refactor the way we build Netty pipelines.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A {@code TCPNetworkConnection} is used for connecting to a Bitcoin node over the standard TCP/IP protocol.<p>
|
* <p>A {@code TCPNetworkConnection} is used for connecting to a Bitcoin node over the standard TCP/IP protocol.<p>
|
||||||
*
|
*
|
||||||
|
@ -37,6 +37,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||||||
private Peer peer;
|
private Peer peer;
|
||||||
private Capture<DownstreamMessageEvent> event;
|
private Capture<DownstreamMessageEvent> event;
|
||||||
private PeerHandler handler;
|
private PeerHandler handler;
|
||||||
|
private static final int OTHER_PEER_CHAIN_HEIGHT = 110;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Before
|
@Before
|
||||||
@ -58,7 +59,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||||||
|
|
||||||
private void connect(PeerHandler handler, Channel channel, ChannelHandlerContext ctx) throws Exception {
|
private void connect(PeerHandler handler, Channel channel, ChannelHandlerContext ctx) throws Exception {
|
||||||
handler.connectRequested(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, socketAddress));
|
handler.connectRequested(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, socketAddress));
|
||||||
VersionMessage peerVersion = new VersionMessage(unitTestParams, 110);
|
VersionMessage peerVersion = new VersionMessage(unitTestParams, OTHER_PEER_CHAIN_HEIGHT);
|
||||||
DownstreamMessageEvent versionEvent =
|
DownstreamMessageEvent versionEvent =
|
||||||
new DownstreamMessageEvent(channel, Channels.future(channel), peerVersion, null);
|
new DownstreamMessageEvent(channel, Channels.future(channel), peerVersion, null);
|
||||||
handler.messageReceived(ctx, versionEvent);
|
handler.messageReceived(ctx, versionEvent);
|
||||||
@ -309,15 +310,20 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||||||
inv.addItem(item);
|
inv.addItem(item);
|
||||||
expect(listener.onPreMessageReceived(eq(peer), eq(inv))).andReturn(inv);
|
expect(listener.onPreMessageReceived(eq(peer), eq(inv))).andReturn(inv);
|
||||||
expect(listener.onPreMessageReceived(eq(peer), eq(b2))).andReturn(b2);
|
expect(listener.onPreMessageReceived(eq(peer), eq(b2))).andReturn(b2);
|
||||||
listener.onBlocksDownloaded(eq(peer), anyObject(Block.class), eq(108));
|
// We have two blocks in our chain (genesis and b1), so our height is 2. The other peer starts at
|
||||||
|
// OTHER_PEER_CHAIN_HEIGHT and then when it announces an inv, its height is + 1, so the difference
|
||||||
|
// between our height and theirs is OTHER_PEER_CHAIN_HEIGHT + 1 - 2.
|
||||||
|
listener.onBlocksDownloaded(eq(peer), anyObject(Block.class), eq(OTHER_PEER_CHAIN_HEIGHT + 1 - 2));
|
||||||
expectLastCall();
|
expectLastCall();
|
||||||
|
|
||||||
control.replay();
|
control.replay();
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
peer.addEventListener(listener);
|
peer.addEventListener(listener);
|
||||||
|
long height = peer.getBestHeight();
|
||||||
|
|
||||||
inbound(peer, inv);
|
inbound(peer, inv);
|
||||||
|
assertEquals(height + 1, peer.getBestHeight());
|
||||||
// Response to the getdata message.
|
// Response to the getdata message.
|
||||||
inbound(peer, b2);
|
inbound(peer, b2);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user