use of bisq.core.dao.state.blockchain.RawBlock in project bisq-core by bisq-network.
the class BlockParser method validateIfBlockIsConnecting.
private void validateIfBlockIsConnecting(RawBlock rawBlock) throws BlockNotConnectingException {
LinkedList<Block> blocks = bsqStateService.getBlocks();
if (!isBlockConnecting(rawBlock, blocks)) {
final Block last = blocks.getLast();
log.warn("addBlock called with a not connecting block. New block:\n" + "height()={}, hash()={}, lastBlock.height()={}, lastBlock.hash()={}", rawBlock.getHeight(), rawBlock.getHash(), last != null ? last.getHeight() : "null", last != null ? last.getHash() : "null");
throw new BlockNotConnectingException(rawBlock);
}
}
use of bisq.core.dao.state.blockchain.RawBlock in project bisq-core by bisq-network.
the class FullNodeNetworkService method publishNewBlock.
public void publishNewBlock(Block block) {
log.info("Publish new block at height={} and block hash={}", block.getHeight(), block.getHash());
RawBlock rawBlock = RawBlock.fromBlock(block);
NewBlockBroadcastMessage newBlockBroadcastMessage = new NewBlockBroadcastMessage(rawBlock);
broadcaster.broadcast(newBlockBroadcastMessage, networkNode.getNodeAddress(), null, true);
}
use of bisq.core.dao.state.blockchain.RawBlock in project bisq-core by bisq-network.
the class GetBlocksRequestHandler method onGetBlocksRequest.
// /////////////////////////////////////////////////////////////////////////////////////////
// API
// /////////////////////////////////////////////////////////////////////////////////////////
public void onGetBlocksRequest(GetBlocksRequest getBlocksRequest, final Connection connection) {
Log.traceCall(getBlocksRequest + "\n\tconnection=" + connection);
List<Block> blocks = new LinkedList<>(bsqStateService.getBlocksFromBlockHeight(getBlocksRequest.getFromBlockHeight()));
List<RawBlock> rawBlocks = blocks.stream().map(RawBlock::fromBlock).collect(Collectors.toList());
final GetBlocksResponse getBlocksResponse = new GetBlocksResponse(rawBlocks, getBlocksRequest.getNonce());
log.debug("getBlocksResponse " + getBlocksResponse.getRequestNonce());
if (timeoutTimer == null) {
timeoutTimer = UserThread.runAfter(() -> {
// setup before sending to avoid race conditions
String errorMessage = "A timeout occurred for getBlocksResponse:" + getBlocksResponse + " on connection:" + connection;
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, connection);
}, TIMEOUT, TimeUnit.SECONDS);
}
SettableFuture<Connection> future = networkNode.sendMessage(connection, getBlocksResponse);
Futures.addCallback(future, new FutureCallback<Connection>() {
@Override
public void onSuccess(Connection connection) {
if (!stopped) {
log.trace("Send DataResponse to {} succeeded. getBlocksResponse={}", connection.getPeersNodeAddressOptional(), getBlocksResponse);
cleanup();
listener.onComplete();
} else {
log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call.");
}
}
@Override
public void onFailure(@NotNull Throwable throwable) {
if (!stopped) {
String errorMessage = "Sending getBlocksResponse to " + connection + " failed. That is expected if the peer is offline. getBlocksResponse=" + getBlocksResponse + "." + "Exception: " + throwable.getMessage();
handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, connection);
} else {
log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call.");
}
}
});
}
use of bisq.core.dao.state.blockchain.RawBlock in project bisq-core by bisq-network.
the class BlockParser method parseBlock.
// /////////////////////////////////////////////////////////////////////////////////////////
// API
// /////////////////////////////////////////////////////////////////////////////////////////
/**
* @param rawBlock Contains all transactions of a bitcoin block without any BSQ specific data
* @return Block: Gets created from the rawBlock but contains only BSQ specific transactions.
* @throws BlockNotConnectingException If new block does not connect to previous block
*/
public Block parseBlock(RawBlock rawBlock) throws BlockNotConnectingException {
int blockHeight = rawBlock.getHeight();
log.debug("Parse block at height={} ", blockHeight);
validateIfBlockIsConnecting(rawBlock);
bsqStateService.onNewBlockHeight(blockHeight);
// We create a block from the rawBlock but the transaction list is not set yet (is empty)
final Block block = new Block(blockHeight, rawBlock.getTime(), rawBlock.getHash(), rawBlock.getPreviousBlockHash());
if (isBlockAlreadyAdded(rawBlock)) {
// TODO check how/if that can happen
log.warn("Block was already added.");
DevEnv.logErrorAndThrowIfDevMode("Block was already added. rawBlock=" + rawBlock);
} else {
bsqStateService.onNewBlockWithEmptyTxs(block);
}
// Worst case is that all txs in a block are depending on another, so only one get resolved at each iteration.
// Min tx size is 189 bytes (normally about 240 bytes), 1 MB can contain max. about 5300 txs (usually 2000).
// Realistically we don't expect more then a few recursive calls.
// There are some blocks with testing such dependency chains like block 130768 where at each iteration only
// one get resolved.
// Lately there is a patter with 24 iterations observed
long startTs = System.currentTimeMillis();
List<Tx> txList = block.getTxs();
rawBlock.getRawTxs().forEach(rawTx -> txParser.findTx(rawTx, genesisTxId, genesisBlockHeight, genesisTotalSupply).ifPresent(txList::add));
log.debug("parseBsqTxs took {} ms", rawBlock.getRawTxs().size(), System.currentTimeMillis() - startTs);
bsqStateService.onParseBlockComplete(block);
return block;
}
Aggregations