@ -5,12 +5,13 @@ import com.google.gson.annotations.SerializedName;
import com.sparrowwallet.drongo.KeyPurpose ;
import com.sparrowwallet.drongo.Network ;
import com.sparrowwallet.drongo.OutputDescriptor ;
import com.sparrowwallet.drongo.wallet.BlockTransactionHash ;
import com.sparrowwallet.drongo.wallet.Wallet ;
import com.sparrowwallet.sparrow.EventManager ;
import com.sparrowwallet.sparrow.event.* ;
import com.sparrowwallet.sparrow.io.Config ;
import dev.bwt.daemon.CallbackNotifier ;
import dev.bwt.daemon.NativeBwtDaemon ;
import dev.bwt.libbwt. daemon.CallbackNotifier ;
import dev.bwt.libbwt. daemon.NativeBwtDaemon ;
import javafx.application.Platform ;
import javafx.concurrent.Service ;
import javafx.concurrent.Task ;
@ -18,20 +19,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory ;
import java.io.IOException ;
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.Date ;
import java.util.List ;
import java.util.* ;
public class Bwt {
private static final Logger log = LoggerFactory . getLogger ( Bwt . class ) ;
private Long shutdownPtr ;
private boolean terminating ;
static {
try {
org . controlsfx . tools . Platform platform = org . controlsfx . tools . Platform . getCurrent ( ) ;
if ( platform = = org . controlsfx . tools . Platform . OSX ) {
NativeUtils . loadLibraryFromJar ( "/native/osx/x64/libbwt.dylib" ) ;
NativeUtils . loadLibraryFromJar ( "/native/osx/x64/libbwt_jni .dylib" ) ;
} else if ( platform = = org . controlsfx . tools . Platform . WINDOWS ) {
NativeUtils . loadLibraryFromJar ( "/native/windows/x64/bwt.dll" ) ;
} else {
@ -43,9 +42,7 @@ public class Bwt {
}
private void start ( CallbackNotifier callback ) {
List < String > descriptors = List . of ( "pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)" ) ;
Date now = new Date ( ) ;
start ( descriptors , ( int ) ( now . getTime ( ) / 1000 ) , null , callback ) ;
start ( Collections . emptyList ( ) , null , null , null , callback ) ;
}
private void start ( Collection < Wallet > wallets , CallbackNotifier callback ) {
@ -57,10 +54,18 @@ public class Bwt {
outputDescriptors . add ( changeOutputDescriptor . toString ( false , false ) ) ;
}
int rescanSince = wallets . stream ( ) . filter ( wallet - > wallet . getBirthDate ( ) ! = null ) . mapToInt ( wallet - > ( int ) ( wallet . getBirthDate ( ) . getTime ( ) / 1000 ) ) . min ( ) . orElse ( 0 ) ;
int rescanSince = wallets . stream ( ) . filter ( wallet - > wallet . getBirthDate ( ) ! = null ) . mapToInt ( wallet - > ( int ) ( wallet . getBirthDate ( ) . getTime ( ) / 1000 ) ) . min ( ) . orElse ( - 1 ) ;
int gapLimit = wallets . stream ( ) . filter ( wallet - > wallet . getGapLimit ( ) > 0 ) . mapToInt ( Wallet : : getGapLimit ) . max ( ) . orElse ( Wallet . DEFAULT_LOOKAHEAD ) ;
start ( outputDescriptors , rescanSince , gapLimit , callback ) ;
boolean forceRescan = false ;
for ( Wallet wallet : wallets ) {
Date txBirthDate = wallet . getTransactions ( ) . values ( ) . stream ( ) . map ( BlockTransactionHash : : getDate ) . filter ( Objects : : nonNull ) . min ( Date : : compareTo ) . orElse ( null ) ;
if ( ( wallet . getBirthDate ( ) ! = null & & txBirthDate ! = null & & wallet . getBirthDate ( ) . before ( txBirthDate ) ) | | ( txBirthDate = = null & & wallet . getStoredBlockHeight ( ) = = 0 ) ) {
forceRescan = true ;
}
}
start ( outputDescriptors , rescanSince , forceRescan , gapLimit , callback ) ;
}
/ * *
@ -72,13 +77,24 @@ public class Bwt {
* @param gapLimit desired gap limit beyond last used address
* @param callback object receiving notifications
* /
private void start ( List < String > outputDescriptors , Integer rescanSince , Integer gapLimit , CallbackNotifier callback ) {
private void start ( List < String > outputDescriptors , Integer rescanSince , Boolean forceRescan , Integer gapLimit , CallbackNotifier callback ) {
BwtConfig bwtConfig = new BwtConfig ( ) ;
bwtConfig . network = Network . get ( ) = = Network . MAINNET ? "bitcoin" : Network . get ( ) . getName ( ) ;
bwtConfig . descriptors = outputDescriptors ;
bwtConfig . rescanSince = rescanSince ;
bwtConfig . gapLimit = gapLimit ;
if ( ! outputDescriptors . isEmpty ( ) ) {
bwtConfig . descriptors = outputDescriptors ;
bwtConfig . rescanSince = ( rescanSince = = null | | rescanSince < 0 ? "now" : rescanSince ) ;
bwtConfig . forceRescan = forceRescan ;
bwtConfig . gapLimit = gapLimit ;
} else {
bwtConfig . requireAddresses = false ;
}
bwtConfig . verbose = log . isDebugEnabled ( ) ? 2 : 0 ;
if ( ! log . isInfoEnabled ( ) ) {
bwtConfig . setupLogger = false ;
}
bwtConfig . electrumAddr = "127.0.0.1:0" ;
bwtConfig . electrumSkipMerkle = true ;
@ -95,6 +111,7 @@ public class Bwt {
Gson gson = new Gson ( ) ;
String jsonConfig = gson . toJson ( bwtConfig ) ;
log . debug ( "Configuring bwt: " + jsonConfig ) ;
NativeBwtDaemon . start ( jsonConfig , callback ) ;
}
@ -102,16 +119,26 @@ public class Bwt {
/ * *
* Shut down the BWT daemon
*
* @param shutdownPtr the pointer provided on startup
* /
private void shutdown ( long shutdownPtr ) {
private void shutdown ( ) {
if ( shutdownPtr = = null ) {
terminating = true ;
return ;
}
NativeBwtDaemon . shutdown ( shutdownPtr ) ;
this . shutdownPtr = null ;
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtShutdownEvent ( ) ) ) ;
}
public boolean isRunning ( ) {
return shutdownPtr ! = null ;
}
public boolean isTerminating ( ) {
return terminating ;
}
public ConnectionService getConnectionService ( Collection < Wallet > wallets ) {
return wallets ! = null ? new ConnectionService ( wallets ) : new ConnectionService ( ) ;
}
@ -146,11 +173,17 @@ public class Bwt {
public String xpubs ;
@SerializedName ( "rescan_since" )
public Integer rescanSince ;
public Object rescanSince ;
@SerializedName ( "force_rescan" )
public Boolean forceRescan ;
@SerializedName ( "gap_limit" )
public Integer gapLimit ;
@SerializedName ( "initial_import_size" )
public Integer initialImportSize ;
@SerializedName ( "verbose" )
public Integer verbose ;
@ -159,6 +192,12 @@ public class Bwt {
@SerializedName ( "electrum_skip_merkle" )
public Boolean electrumSkipMerkle ;
@SerializedName ( "require_addresses" )
public Boolean requireAddresses ;
@SerializedName ( "setup_logger" )
public Boolean setupLogger ;
}
public final class ConnectionService extends Service < Void > {
@ -179,25 +218,37 @@ public class Bwt {
CallbackNotifier notifier = new CallbackNotifier ( ) {
@Override
public void onBooting ( ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtStatusEvent ( "Starting bwt" ) ) ) ;
log . debug ( "Booting bwt" ) ;
if ( ! terminating ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtStatusEvent ( "Starting bwt" ) ) ) ;
}
}
@Override
public void onSyncProgress ( float progress , int tip ) {
int percent = ( int ) ( progress * 100 . 0 ) ;
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtSyncStatusEvent ( "Syncing (" + percent + "%)" , percent , tip ) ) ) ;
log . debug ( "Syncing " + percent + "%" ) ;
if ( ! terminating ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtSyncStatusEvent ( "Syncing" + ( percent < 100 ? " (" + percent + "%)" : "" ) , percent , tip ) ) ) ;
}
}
@Override
public void onScanProgress ( float progress , int eta ) {
int percent = ( int ) ( progress * 100 . 0 ) ;
Date date = new Date ( ( long ) eta * 1000 ) ;
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtScanStatusEvent ( "Scanning (" + percent + "%)" , percent , date ) ) ) ;
log . debug ( "Scanning " + percent + "%" ) ;
if ( ! terminating ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtScanStatusEvent ( "Scanning" + ( percent < 100 ? " (" + percent + "%)" : "" ) , percent , date ) ) ) ;
}
}
@Override
public void onElectrumReady ( String addr ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtElectrumReadyStatusEvent ( "Electrum server ready" , addr ) ) ) ;
log . debug ( "Electrum ready" ) ;
if ( ! terminating ) {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtElectrumReadyStatusEvent ( "Electrum server ready" , addr ) ) ) ;
}
}
@Override
@ -207,8 +258,14 @@ public class Bwt {
@Override
public void onReady ( long shutdownPtr ) {
log . debug ( "Bwt ready" ) ;
Bwt . this . shutdownPtr = shutdownPtr ;
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtReadyStatusEvent ( "Server ready" , shutdownPtr ) ) ) ;
if ( terminating ) {
Bwt . this . shutdown ( ) ;
terminating = false ;
} else {
Platform . runLater ( ( ) - > EventManager . get ( ) . post ( new BwtReadyStatusEvent ( "Server ready" , shutdownPtr ) ) ) ;
}
}
} ;
@ -229,12 +286,7 @@ public class Bwt {
protected Task < Void > createTask ( ) {
return new Task < > ( ) {
protected Void call ( ) {
if ( shutdownPtr = = null ) {
throw new IllegalStateException ( "Bwt has not been started" ) ;
}
Bwt . this . shutdown ( shutdownPtr ) ;
shutdownPtr = null ;
Bwt . this . shutdown ( ) ;
return null ;
}
} ;