Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Segwit for BSQ #5000

Merged
merged 20 commits into from
Mar 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5990fcf
Bring ScryptType enum up to date with latest bitcoind
stejbac Dec 20, 2020
dbe4953
Add replacement bitcoind RPC client using jsonrpc4j
stejbac Dec 20, 2020
b7c7eaf
Add replacement bitcoind block notification daemon
stejbac Dec 20, 2020
863392b
Factor out executor shutdown logic into new Utilities method
stejbac Dec 20, 2020
f34231a
Factor out failure callback logic into new Utilities method
stejbac Dec 21, 2020
4470af8
Add missing copyright headers to new files
stejbac Dec 21, 2020
ac78639
Improve exception handling in BitcoindDaemon
stejbac Dec 21, 2020
8104301
Use new Bitcoind(Client|Daemon) & remove btcd-cli4j
stejbac Dec 21, 2020
6ca42c0
Enable extraction of segwit pubkeys from raw tx inputs
stejbac Dec 21, 2020
93b46e3
Fix Codacy issues & deduplicate code in RpcService
stejbac Dec 25, 2020
796097a
Fix data race in BitcoindDaemonTest
stejbac Jan 2, 2021
a850ada
Make special case for irregular tx with segwit BSQ inputs
stejbac Jan 8, 2021
d595cac
Add getNetworkInfo & getBestBlockHash RPC client methods
stejbac Jan 9, 2021
4b0711b
Add Bitcoin Core version & health check to RpcService
stejbac Jan 9, 2021
1abf4c5
Exclude segwit pubkeys by block height instead of a blacklist
stejbac Jan 18, 2021
a8b0863
Ensure RPC client works with Bitcoin Core 0.21.0
stejbac Jan 19, 2021
e0aa76e
Rename rpc.dto.RawX to RawDtoX to avoid confusion
stejbac Jan 21, 2021
b4ad6bf
Upgrade jsonrpc4j & Jackson; simplify BitcoindClient
stejbac Feb 4, 2021
05ea293
Activate Segwit DAO hard fork 4 weeks after v1.6.0 release
stejbac Mar 20, 2021
f213791
Merge branch 'release/v1.6.0' into implement-segwit-for-bsq
stejbac Mar 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apitest/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@
<appender-ref ref="CONSOLE_APPENDER"/>
</root>

<logger name="com.neemre.btcdcli4j" level="WARN"/>
<logger name="io.grpc.netty" level="WARN"/>
</configuration>
26 changes: 6 additions & 20 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ configure(subprojects) {
ext { // in alphabetical order
bcVersion = '1.63'
bitcoinjVersion = '2a80db4'
btcdCli4jVersion = '27b94333'
codecVersion = '1.13'
easybindVersion = '1.0.3'
easyVersion = '4.0.1'
Expand All @@ -46,14 +45,15 @@ configure(subprojects) {
httpclientVersion = '4.5.12'
httpcoreVersion = '4.4.13'
ioVersion = '2.6'
jacksonVersion = '2.8.10'
jacksonVersion = '2.12.1'
javafxVersion = '11.0.2'
javaxAnnotationVersion = '1.2'
jcsvVersion = '1.4.0'
jetbrainsAnnotationsVersion = '13.0'
jfoenixVersion = '9.0.6'
joptVersion = '5.0.4'
jsonsimpleVersion = '1.1.1'
jsonrpc4jVersion = '1.6.0.bisq.1'
junitVersion = '4.12'
jupiterVersion = '5.7.0'
kotlinVersion = '1.3.41'
Expand Down Expand Up @@ -314,23 +314,9 @@ configure(project(':core')) {
exclude(module: 'commons-codec')
}
compile "com.google.guava:guava:$guavaVersion"
compile("network.bisq.btcd-cli4j:btcd-cli4j-core:$btcdCli4jVersion") {
exclude(module: 'guava')
exclude(module: 'slf4j-api')
exclude(module: 'httpclient')
exclude(module: 'commons-lang3')
exclude(module: 'jackson-core')
exclude(module: 'jackson-annotations')
exclude(module: 'jackson-databind')
}
compile("network.bisq.btcd-cli4j:btcd-cli4j-daemon:$btcdCli4jVersion") {
exclude(module: 'guava')
exclude(module: 'slf4j-api')
exclude(module: 'httpclient')
exclude(module: 'commons-lang3')
exclude(module: 'jackson-core')
exclude(module: 'jackson-annotations')
exclude(module: 'jackson-databind')
compile("com.github.bisq-network:jsonrpc4j:$jsonrpc4jVersion") {
exclude(module: 'base64')
exclude(module: 'httpcore-nio')
}
compile "com.fasterxml.jackson.core:jackson-core:$jacksonVersion"
compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
Expand Down Expand Up @@ -678,7 +664,7 @@ configure(project(':apitest')) {
"${result.skippedTestCount} skipped] html report contains skipped test info")

// Show report link if all tests passed in case you want to see more detail, stdout, skipped, etc.
if(result.resultType == TestResult.ResultType.SUCCESS) {
if (result.resultType == TestResult.ResultType.SUCCESS) {
DirectoryReport htmlReport = getReports().getHtml()
String reportUrl = new org.gradle.internal.logging.ConsoleRenderer()
.asClickableFileUrl(htmlReport.getEntryPoint())
Expand Down
50 changes: 48 additions & 2 deletions common/src/main/java/bisq/common/util/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.gson.GsonBuilder;

import com.google.common.base.Splitter;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
Expand Down Expand Up @@ -60,19 +61,23 @@
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
Expand Down Expand Up @@ -109,22 +114,38 @@ public static ListeningExecutorService getListeningExecutorService(String name,
return MoreExecutors.listeningDecorator(getThreadPoolExecutor(name, corePoolSize, maximumPoolSize, keepAliveTimeInSec));
}

public static ListeningExecutorService getListeningExecutorService(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec,
BlockingQueue<Runnable> workQueue) {
return MoreExecutors.listeningDecorator(getThreadPoolExecutor(name, corePoolSize, maximumPoolSize, keepAliveTimeInSec, workQueue));
}

public static ThreadPoolExecutor getThreadPoolExecutor(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec) {
return getThreadPoolExecutor(name, corePoolSize, maximumPoolSize, keepAliveTimeInSec,
new ArrayBlockingQueue<>(maximumPoolSize));
}

private static ThreadPoolExecutor getThreadPoolExecutor(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec,
BlockingQueue<Runnable> workQueue) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name)
.setDaemon(true)
.build();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeInSec,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory);
TimeUnit.SECONDS, workQueue, threadFactory);
executor.allowCoreThreadTimeOut(true);
executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called"));
return executor;
}


@SuppressWarnings("SameParameterValue")
public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String name,
int corePoolSize,
Expand All @@ -144,6 +165,31 @@ public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String
return executor;
}

// TODO: Can some/all of the uses of this be replaced by guava MoreExecutors.shutdownAndAwaitTermination(..)?
public static void shutdownAndAwaitTermination(ExecutorService executor, long timeout, TimeUnit unit) {
executor.shutdown();
try {
if (!executor.awaitTermination(timeout, unit)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}

public static <V> FutureCallback<V> failureCallback(Consumer<Throwable> errorHandler) {
return new FutureCallback<>() {
@Override
public void onSuccess(V result) {
}

@Override
public void onFailure(@NotNull Throwable t) {
errorHandler.accept(t);
}
};
}

/**
* @return true if <code>defaults read -g AppleInterfaceStyle</code> has an exit status of <code>0</code> (i.e. _not_ returning "key not found").
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@

import javax.inject.Named;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
Expand All @@ -56,8 +55,6 @@

import lombok.extern.slf4j.Slf4j;

import org.jetbrains.annotations.NotNull;

@Slf4j
public class ExportJsonFilesService implements DaoSetupService {
private final DaoStateService daoStateService;
Expand Down Expand Up @@ -160,15 +157,10 @@ public void maybeExportToJson() {
return null;
});

Futures.addCallback(future, new FutureCallback<>() {
public void onSuccess(Void ignore) {
}

public void onFailure(@NotNull Throwable throwable) {
log.error(throwable.toString());
throwable.printStackTrace();
}
}, MoreExecutors.directExecutor());
Futures.addCallback(future, Utilities.failureCallback(throwable -> {
log.error(throwable.toString());
throwable.printStackTrace();
}), MoreExecutors.directExecutor());
}
}

Expand Down
45 changes: 21 additions & 24 deletions core/src/main/java/bisq/core/dao/node/full/FullNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import bisq.core.dao.node.BsqNode;
import bisq.core.dao.node.explorer.ExportJsonFilesService;
import bisq.core.dao.node.full.network.FullNodeNetworkService;
import bisq.core.dao.node.full.rpc.NotificationHandlerException;
import bisq.core.dao.node.parser.BlockParser;
import bisq.core.dao.node.parser.exceptions.BlockHashNotConnectingException;
import bisq.core.dao.node.parser.exceptions.BlockHeightNotConnectingException;
Expand All @@ -34,11 +35,10 @@
import bisq.common.UserThread;
import bisq.common.handlers.ResultHandler;

import com.neemre.btcdcli4j.core.http.HttpLayerException;
import com.neemre.btcdcli4j.daemon.NotificationHandlerException;

import javax.inject.Inject;

import java.net.ConnectException;

import java.util.function.Consumer;

import lombok.extern.slf4j.Slf4j;
Expand All @@ -64,15 +64,14 @@ public class FullNode extends BsqNode {
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////

@SuppressWarnings("WeakerAccess")
@Inject
public FullNode(BlockParser blockParser,
DaoStateService daoStateService,
DaoStateSnapshotService daoStateSnapshotService,
P2PService p2PService,
RpcService rpcService,
ExportJsonFilesService exportJsonFilesService,
FullNodeNetworkService fullNodeNetworkService) {
private FullNode(BlockParser blockParser,
DaoStateService daoStateService,
DaoStateSnapshotService daoStateSnapshotService,
P2PService p2PService,
RpcService rpcService,
ExportJsonFilesService exportJsonFilesService,
FullNodeNetworkService fullNodeNetworkService) {
super(blockParser, daoStateService, daoStateSnapshotService, p2PService, exportJsonFilesService);
this.rpcService = rpcService;

Expand Down Expand Up @@ -150,7 +149,7 @@ protected void onParseBlockChainComplete() {
private void addBlockHandler() {
if (!addBlockHandlerAdded) {
addBlockHandlerAdded = true;
rpcService.addNewBtcBlockHandler(rawBlock -> {
rpcService.addNewDtoBlockHandler(rawBlock -> {
try {
// We need to call that before parsing to have set the chain tip correctly for clients
// which might listen for new blocks on daoStateService. DaoStateListener.onNewBlockHeight
Expand Down Expand Up @@ -238,7 +237,7 @@ private void parseBlockRecursively(int blockHeight,
Consumer<Block> newBlockHandler,
ResultHandler resultHandler,
Consumer<Throwable> errorHandler) {
rpcService.requestBtcBlock(blockHeight,
rpcService.requestDtoBlock(blockHeight,
rawBlock -> {
try {
doParseBlock(rawBlock).ifPresent(newBlockHandler);
Expand Down Expand Up @@ -270,20 +269,18 @@ private void handleError(Throwable throwable) {
if (throwable instanceof RpcException) {
Throwable cause = throwable.getCause();
if (cause != null) {
if (cause instanceof HttpLayerException) {
if (((HttpLayerException) cause).getCode() == 1004004) {
if (warnMessageHandler != null)
warnMessageHandler.accept("You have configured Bisq to run as DAO full node but there is no " +
"localhost Bitcoin Core node detected. You need to have Bitcoin Core started and synced before " +
"starting Bisq. Please restart Bisq with proper DAO full node setup or switch to lite node mode.");
return;
}
if (cause instanceof ConnectException) {
if (warnMessageHandler != null)
warnMessageHandler.accept("You have configured Bisq to run as DAO full node but there is no " +
"localhost Bitcoin Core node detected. You need to have Bitcoin Core started and synced before " +
"starting Bisq. Please restart Bisq with proper DAO full node setup or switch to lite node mode.");
return;
} else if (cause instanceof NotificationHandlerException) {
// Maybe we need to react specifically to errors as in NotificationHandlerException.getError()
// So far only IO_UNKNOWN was observed
log.error("Error type of NotificationHandlerException: " + ((NotificationHandlerException) cause).getError().toString());
log.error("Error from within block notification daemon: {}", cause.getCause().toString());
startReOrgFromLastSnapshot();
return;
} else if (cause instanceof Error) {
throw (Error) cause;
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/java/bisq/core/dao/node/full/RawTx.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,11 @@ public static RawTx fromProto(protobuf.BaseTx protoBaseTx) {
txInputs,
outputs);
}

@Override
public String toString() {
return "RawTx{" +
"\n rawTxOutputs=" + rawTxOutputs +
"\n} " + super.toString();
}
}
Loading