mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
Merge branch 'master' into master
This commit is contained in:
commit
cca3bc9754
61
.github/workflows/build.yml
vendored
61
.github/workflows/build.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-13, windows-latest]
|
os: [ubuntu-22.04, macos-13, windows-latest]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@ -37,7 +37,7 @@ jobs:
|
|||||||
name: cached-localnet
|
name: cached-localnet
|
||||||
path: .localnet
|
path: .localnet
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y rpm flatpak flatpak-builder appstream
|
sudo apt install -y rpm flatpak flatpak-builder appstream
|
||||||
@ -56,7 +56,7 @@ jobs:
|
|||||||
|
|
||||||
# get version from jar
|
# get version from jar
|
||||||
- name: Set Version Unix
|
- name: Set Version Unix
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-13' }}
|
if: ${{ matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-13' }}
|
||||||
run: |
|
run: |
|
||||||
export VERSION=$(ls desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 | grep -Eo 'desktop-[0-9]+\.[0-9]+\.[0-9]+' | sed 's/desktop-//')
|
export VERSION=$(ls desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 | grep -Eo 'desktop-[0-9]+\.[0-9]+\.[0-9]+' | sed 's/desktop-//')
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
@ -66,55 +66,64 @@ jobs:
|
|||||||
$VERSION = (Get-ChildItem -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256).Name -replace 'desktop-', '' -replace '-.*', ''
|
$VERSION = (Get-ChildItem -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256).Name -replace 'desktop-', '' -replace '-.*', ''
|
||||||
"VERSION=$VERSION" | Out-File -FilePath $env:GITHUB_ENV -Append
|
"VERSION=$VERSION" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
shell: powershell
|
shell: powershell
|
||||||
|
|
||||||
- name: Move Release Files on Unix
|
- name: Move Release Files on Unix
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-13' }}
|
if: ${{ matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-13' }}
|
||||||
run: |
|
run: |
|
||||||
mkdir ${{ github.workspace }}/release
|
mkdir ${{ github.workspace }}/release
|
||||||
if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then
|
if [ "${{ matrix.os }}" == "ubuntu-22.04" ]; then
|
||||||
mv desktop/build/temp-*/binaries/haveno-*.rpm ${{ github.workspace }}/release
|
mkdir ${{ github.workspace }}/release-rpm
|
||||||
mv desktop/build/temp-*/binaries/haveno_*.deb ${{ github.workspace }}/release
|
mkdir ${{ github.workspace }}/release-deb
|
||||||
mv desktop/build/temp-*/binaries/*.flatpak ${{ github.workspace }}/release
|
mkdir ${{ github.workspace }}/release-flat
|
||||||
|
mv desktop/build/temp-*/binaries/haveno-*.rpm ${{ github.workspace }}/release-rpm/Haveno-${{ env.VERSION }}-x86_64.rpm
|
||||||
|
mv desktop/build/temp-*/binaries/haveno_*.deb ${{ github.workspace }}/release-deb/Haveno-${{ env.VERSION }}-x86_64.deb
|
||||||
|
mv desktop/build/temp-*/binaries/*.flatpak ${{ github.workspace }}/release-flat
|
||||||
|
|
||||||
else
|
else
|
||||||
mv desktop/build/temp-*/binaries/Haveno-*.dmg ${{ github.workspace }}/release
|
mv desktop/build/temp-*/binaries/Haveno-*.dmg ${{ github.workspace }}/release/Haveno-${{ env.VERSION }}.dmg
|
||||||
fi
|
fi
|
||||||
mv desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release
|
cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-flat
|
||||||
|
cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-deb
|
||||||
|
cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-rpm
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Move Release Files on Windows
|
- name: Move Release Files on Windows
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
run: |
|
run: |
|
||||||
mkdir ${{ github.workspace }}/release
|
mkdir ${{ github.workspace }}/release
|
||||||
Move-Item -Path desktop\build\temp-*/binaries\Haveno-*.exe -Destination ${{ github.workspace }}/release
|
Move-Item -Path desktop\build\temp-*/binaries\Haveno-*.exe -Destination ${{ github.workspace }}/release/Haveno-${{ env.VERSION }}.exe
|
||||||
Move-Item -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256 -Destination ${{ github.workspace }}/release
|
Move-Item -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256 -Destination ${{ github.workspace }}/release
|
||||||
shell: powershell
|
shell: powershell
|
||||||
|
|
||||||
|
|
||||||
# do all files manually and use version too
|
|
||||||
# win
|
# win
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
name: "Windows - exe artifact"
|
name: "Windows artifacts"
|
||||||
|
if: ${{ matrix.os == 'windows-latest'}}
|
||||||
with:
|
with:
|
||||||
name: windows-haveno-${{ env.VERSION }}.exe
|
name: haveno-windows
|
||||||
path: ${{ github.workspace }}/release/Haveno-*.exe
|
path: ${{ github.workspace }}/release
|
||||||
# macos
|
# macos
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
name: "MacOS - dmg artifact"
|
name: "macOS artifacts"
|
||||||
|
if: ${{ matrix.os == 'macos-13' }}
|
||||||
with:
|
with:
|
||||||
name: macos-haveno-${{ env.VERSION }}.dmg
|
name: haveno-macos
|
||||||
path: ${{ github.workspace }}/release/Haveno-*.dmg
|
path: ${{ github.workspace }}/release
|
||||||
# linux
|
# linux
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
name: "Linux - deb artifact"
|
name: "Linux - deb artifact"
|
||||||
|
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||||
with:
|
with:
|
||||||
name: linux-haveno-${{ env.VERSION }}.deb
|
name: haveno-linux-deb
|
||||||
path: ${{ github.workspace }}/release/haveno_*.deb
|
path: ${{ github.workspace }}/release-deb
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
name: "Linux - rpm artifact"
|
name: "Linux - rpm artifact"
|
||||||
|
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||||
with:
|
with:
|
||||||
name: linux-haveno-${{ env.VERSION }}.rpm
|
name: haveno-linux-rpm
|
||||||
path: ${{ github.workspace }}/release/haveno-*.rpm
|
path: ${{ github.workspace }}/release-rpm
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
name: "Linux - flatpak artifact"
|
name: "Linux - flatpak artifact"
|
||||||
|
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||||
with:
|
with:
|
||||||
name: linux-haveno-${{ env.VERSION }}.flatpak
|
name: haveno-linux-flatpak
|
||||||
path: ${{ github.workspace }}/release/*.flatpak
|
path: ${{ github.workspace }}/release-flat
|
||||||
|
@ -72,7 +72,7 @@ To bring Haveno to life, we need resources. If you have the possibility, please
|
|||||||
### Monero
|
### Monero
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_monero.png" alt="Donate Monero" width="150" height="150"><br>
|
<img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_monero.png" alt="Donate Monero" width="115" height="115"><br>
|
||||||
<code>42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F</code>
|
<code>42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F</code>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -81,6 +81,6 @@ If you are using a wallet that supports OpenAlias (like the 'official' CLI and G
|
|||||||
### Bitcoin
|
### Bitcoin
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_bitcoin.png" alt="Donate Bitcoin" width="150" height="150"><br>
|
<img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_bitcoin.png" alt="Donate Bitcoin" width="115" height="115"><br>
|
||||||
<code>1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ</code>
|
<code>1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ</code>
|
||||||
</p>
|
</p>
|
||||||
|
@ -78,7 +78,7 @@ public class ApiTestMain {
|
|||||||
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
err.println("Fault: An unexpected error occurred. " +
|
err.println("Fault: An unexpected error occurred. " +
|
||||||
"Please file a report at https://haveno.exchange/issues");
|
"Please file a report at https://github.com/haveno-dex/haveno/issues");
|
||||||
ex.printStackTrace(err);
|
ex.printStackTrace(err);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ configure(subprojects) {
|
|||||||
gsonVersion = '2.8.5'
|
gsonVersion = '2.8.5'
|
||||||
guavaVersion = '32.1.1-jre'
|
guavaVersion = '32.1.1-jre'
|
||||||
guiceVersion = '7.0.0'
|
guiceVersion = '7.0.0'
|
||||||
moneroJavaVersion = '0.8.31'
|
moneroJavaVersion = '0.8.33'
|
||||||
httpclient5Version = '5.0'
|
httpclient5Version = '5.0'
|
||||||
hamcrestVersion = '2.2'
|
hamcrestVersion = '2.2'
|
||||||
httpclientVersion = '4.5.12'
|
httpclientVersion = '4.5.12'
|
||||||
@ -334,6 +334,7 @@ configure(project(':p2p')) {
|
|||||||
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
||||||
implementation "org.fxmisc.easybind:easybind:$easybindVersion"
|
implementation "org.fxmisc.easybind:easybind:$easybindVersion"
|
||||||
implementation "org.slf4j:slf4j-api:$slf4jVersion"
|
implementation "org.slf4j:slf4j-api:$slf4jVersion"
|
||||||
|
implementation "org.apache.commons:commons-lang3:$langVersion"
|
||||||
implementation("com.github.haveno-dex.netlayer:tor.external:$netlayerVersion") {
|
implementation("com.github.haveno-dex.netlayer:tor.external:$netlayerVersion") {
|
||||||
exclude(module: 'slf4j-api')
|
exclude(module: 'slf4j-api')
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import ch.qos.logback.classic.Level;
|
|||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
|
import ch.qos.logback.classic.filter.ThresholdFilter;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
|
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
|
||||||
import ch.qos.logback.core.rolling.RollingFileAppender;
|
import ch.qos.logback.core.rolling.RollingFileAppender;
|
||||||
@ -52,11 +53,12 @@ public class Log {
|
|||||||
|
|
||||||
SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
||||||
triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
|
triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
|
||||||
|
triggeringPolicy.setContext(loggerContext);
|
||||||
triggeringPolicy.start();
|
triggeringPolicy.start();
|
||||||
|
|
||||||
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||||
encoder.setContext(loggerContext);
|
encoder.setContext(loggerContext);
|
||||||
encoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n");
|
encoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg%n");
|
||||||
encoder.start();
|
encoder.start();
|
||||||
|
|
||||||
appender.setEncoder(encoder);
|
appender.setEncoder(encoder);
|
||||||
@ -64,25 +66,43 @@ public class Log {
|
|||||||
appender.setTriggeringPolicy(triggeringPolicy);
|
appender.setTriggeringPolicy(triggeringPolicy);
|
||||||
appender.start();
|
appender.start();
|
||||||
|
|
||||||
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
|
||||||
logbackLogger.addAppender(appender);
|
|
||||||
logbackLogger.setLevel(Level.INFO);
|
|
||||||
|
|
||||||
// log errors in separate file
|
// log errors in separate file
|
||||||
// not working as expected still.... damn logback...
|
PatternLayoutEncoder errorEncoder = new PatternLayoutEncoder();
|
||||||
/* FileAppender errorAppender = new FileAppender();
|
errorEncoder.setContext(loggerContext);
|
||||||
errorAppender.setEncoder(encoder);
|
errorEncoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger: %msg%n%ex");
|
||||||
|
errorEncoder.start();
|
||||||
|
|
||||||
|
RollingFileAppender<ILoggingEvent> errorAppender = new RollingFileAppender<>();
|
||||||
|
errorAppender.setEncoder(errorEncoder);
|
||||||
errorAppender.setName("Error");
|
errorAppender.setName("Error");
|
||||||
errorAppender.setContext(loggerContext);
|
errorAppender.setContext(loggerContext);
|
||||||
errorAppender.setFile(fileName + "_error.log");
|
errorAppender.setFile(fileName + "_error.log");
|
||||||
LevelFilter levelFilter = new LevelFilter();
|
|
||||||
levelFilter.setLevel(Level.ERROR);
|
FixedWindowRollingPolicy errorRollingPolicy = new FixedWindowRollingPolicy();
|
||||||
levelFilter.setOnMatch(FilterReply.ACCEPT);
|
errorRollingPolicy.setContext(loggerContext);
|
||||||
levelFilter.setOnMismatch(FilterReply.DENY);
|
errorRollingPolicy.setParent(errorAppender);
|
||||||
levelFilter.start();
|
errorRollingPolicy.setFileNamePattern(fileName + "_error_%i.log");
|
||||||
errorAppender.addFilter(levelFilter);
|
errorRollingPolicy.setMinIndex(1);
|
||||||
|
errorRollingPolicy.setMaxIndex(20);
|
||||||
|
errorRollingPolicy.start();
|
||||||
|
|
||||||
|
SizeBasedTriggeringPolicy<ILoggingEvent> errorTriggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
||||||
|
errorTriggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
|
||||||
|
errorTriggeringPolicy.start();
|
||||||
|
|
||||||
|
ThresholdFilter thresholdFilter = new ThresholdFilter();
|
||||||
|
thresholdFilter.setLevel("WARN");
|
||||||
|
thresholdFilter.start();
|
||||||
|
|
||||||
|
errorAppender.setRollingPolicy(errorRollingPolicy);
|
||||||
|
errorAppender.setTriggeringPolicy(errorTriggeringPolicy);
|
||||||
|
errorAppender.addFilter(thresholdFilter);
|
||||||
errorAppender.start();
|
errorAppender.start();
|
||||||
logbackLogger.addAppender(errorAppender);*/
|
|
||||||
|
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
||||||
|
logbackLogger.addAppender(errorAppender);
|
||||||
|
logbackLogger.addAppender(appender);
|
||||||
|
logbackLogger.setLevel(Level.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCustomLogLevel(String pattern, Level logLevel) {
|
public static void setCustomLogLevel(String pattern, Level logLevel) {
|
||||||
|
@ -68,8 +68,7 @@ public class FileUtil {
|
|||||||
|
|
||||||
pruneBackup(backupFileDir, numMaxBackupFiles);
|
pruneBackup(backupFileDir, numMaxBackupFiles);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Backup key failed: " + e.getMessage());
|
log.error("Backup key failed: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +96,7 @@ public class FileUtil {
|
|||||||
try {
|
try {
|
||||||
FileUtils.deleteDirectory(backupFileDir);
|
FileUtils.deleteDirectory(backupFileDir);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
log.error("Delete backup key failed: {}\n", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,8 +172,7 @@ public class FileUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error(t.toString());
|
log.error("Could not delete file, error={}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
throw new IOException(t);
|
throw new IOException(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,7 @@ public class CommonSetup {
|
|||||||
"The system tray is not supported on the current platform.".equals(throwable.getMessage())) {
|
"The system tray is not supported on the current platform.".equals(throwable.getMessage())) {
|
||||||
log.warn(throwable.getMessage());
|
log.warn(throwable.getMessage());
|
||||||
} else {
|
} else {
|
||||||
log.error("Uncaught Exception from thread " + Thread.currentThread().getName());
|
log.error("Uncaught Exception from thread {}, error={}\n", Thread.currentThread().getName(), throwable.getMessage(), throwable);
|
||||||
log.error("throwableMessage= " + throwable.getMessage());
|
|
||||||
log.error("throwableClass= " + throwable.getClass());
|
|
||||||
log.error("Stack trace:\n" + ExceptionUtils.getStackTrace(throwable));
|
|
||||||
throwable.printStackTrace();
|
|
||||||
UserThread.execute(() -> uncaughtExceptionHandler.handleUncaughtException(throwable, false));
|
UserThread.execute(() -> uncaughtExceptionHandler.handleUncaughtException(throwable, false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -113,8 +109,7 @@ public class CommonSetup {
|
|||||||
if (!pathOfCodeSource.endsWith("classes"))
|
if (!pathOfCodeSource.endsWith("classes"))
|
||||||
log.info("Path to Haveno jar file: " + pathOfCodeSource);
|
log.info("Path to Haveno jar file: " + pathOfCodeSource);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
log.error(e.toString());
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TaskRunner<T extends Model> {
|
public class TaskRunner<T extends Model> {
|
||||||
private final Queue<Class<? extends Task<T>>> tasks = new LinkedBlockingQueue<>();
|
private final Queue<Class<? extends Task<T>>> tasks = new LinkedBlockingQueue<>();
|
||||||
@ -67,8 +69,8 @@ public class TaskRunner<T extends Model> {
|
|||||||
log.info("Run task: " + currentTask.getSimpleName());
|
log.info("Run task: " + currentTask.getSimpleName());
|
||||||
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModelClass).newInstance(this, sharedModel).run();
|
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModelClass).newInstance(this, sharedModel).run();
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(throwable));
|
||||||
handleErrorMessage("Error at taskRunner: " + throwable.getMessage());
|
handleErrorMessage("Error at taskRunner, error=" + throwable.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
|
@ -331,8 +331,7 @@ public class Utilities {
|
|||||||
clipboard.setContent(clipboardContent);
|
clipboard.setContent(clipboardContent);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error("copyToClipboard failed " + e.getMessage());
|
log.error("copyToClipboard failed: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,11 +260,11 @@ public class CoreApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startXmrNode(XmrNodeSettings settings) throws IOException {
|
public void startXmrNode(XmrNodeSettings settings) throws IOException {
|
||||||
xmrLocalNode.startNode(settings);
|
xmrLocalNode.start(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopXmrNode() {
|
public void stopXmrNode() {
|
||||||
xmrLocalNode.stopNode();
|
xmrLocalNode.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -52,6 +52,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
@ -204,7 +207,7 @@ public class CoreDisputesService {
|
|||||||
throw new IllegalStateException(errMessage, err);
|
throw new IllegalStateException(errMessage, err);
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
throw new IllegalStateException(e.getMessage() == null ? ("Error resolving dispute for trade " + trade.getId()) : e.getMessage());
|
throw new IllegalStateException(e.getMessage() == null ? ("Error resolving dispute for trade " + trade.getId()) : e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@ package haveno.core.api;
|
|||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import haveno.core.api.model.TradeInfo;
|
import haveno.core.api.model.TradeInfo;
|
||||||
import haveno.core.support.messages.ChatMessage;
|
import haveno.core.support.messages.ChatMessage;
|
||||||
|
import haveno.core.trade.HavenoUtils;
|
||||||
|
import haveno.core.trade.MakerTrade;
|
||||||
|
import haveno.core.trade.SellerTrade;
|
||||||
import haveno.core.trade.Trade;
|
import haveno.core.trade.Trade;
|
||||||
|
import haveno.core.trade.Trade.Phase;
|
||||||
import haveno.proto.grpc.NotificationMessage;
|
import haveno.proto.grpc.NotificationMessage;
|
||||||
import haveno.proto.grpc.NotificationMessage.NotificationType;
|
import haveno.proto.grpc.NotificationMessage.NotificationType;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -46,7 +50,15 @@ public class CoreNotificationService {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendTradeNotification(Trade trade, String title, String message) {
|
public void sendTradeNotification(Trade trade, Phase phase, String title, String message) {
|
||||||
|
|
||||||
|
// play chime when maker's trade is taken
|
||||||
|
if (trade instanceof MakerTrade && phase == Trade.Phase.DEPOSITS_PUBLISHED) HavenoUtils.playChimeSound();
|
||||||
|
|
||||||
|
// play chime when seller sees buyer confirm payment sent
|
||||||
|
if (trade instanceof SellerTrade && phase == Trade.Phase.PAYMENT_SENT) HavenoUtils.playChimeSound();
|
||||||
|
|
||||||
|
// send notification
|
||||||
sendNotification(NotificationMessage.newBuilder()
|
sendNotification(NotificationMessage.newBuilder()
|
||||||
.setType(NotificationType.TRADE_UPDATE)
|
.setType(NotificationType.TRADE_UPDATE)
|
||||||
.setTrade(TradeInfo.toTradeInfo(trade).toProtoMessage())
|
.setTrade(TradeInfo.toTradeInfo(trade).toProtoMessage())
|
||||||
@ -57,6 +69,7 @@ public class CoreNotificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendChatNotification(ChatMessage chatMessage) {
|
public void sendChatNotification(ChatMessage chatMessage) {
|
||||||
|
HavenoUtils.playChimeSound();
|
||||||
sendNotification(NotificationMessage.newBuilder()
|
sendNotification(NotificationMessage.newBuilder()
|
||||||
.setType(NotificationType.CHAT_MESSAGE)
|
.setType(NotificationType.CHAT_MESSAGE)
|
||||||
.setTimestamp(System.currentTimeMillis())
|
.setTimestamp(System.currentTimeMillis())
|
||||||
|
@ -66,6 +66,8 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -161,7 +163,7 @@ class CoreTradesService {
|
|||||||
errorMessageHandler
|
errorMessageHandler
|
||||||
);
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
errorMessageHandler.handleErrorMessage(e.getMessage());
|
errorMessageHandler.handleErrorMessage(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.LongProperty;
|
import javafx.beans.property.LongProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
@ -464,7 +467,7 @@ public final class XmrConnectionService {
|
|||||||
log.info(getClass() + ".onAccountOpened() called");
|
log.info(getClass() + ".onAccountOpened() called");
|
||||||
initialize();
|
initialize();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Error initializing connection service after account opened, error={}\n", e.getMessage(), e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,10 +623,9 @@ public final class XmrConnectionService {
|
|||||||
if (connectionManager.getConnection() != null && xmrLocalNode.equalsUri(connectionManager.getConnection().getUri()) && !xmrLocalNode.isDetected() && !xmrLocalNode.shouldBeIgnored()) {
|
if (connectionManager.getConnection() != null && xmrLocalNode.equalsUri(connectionManager.getConnection().getUri()) && !xmrLocalNode.isDetected() && !xmrLocalNode.shouldBeIgnored()) {
|
||||||
try {
|
try {
|
||||||
log.info("Starting local node");
|
log.info("Starting local node");
|
||||||
xmrLocalNode.startMoneroNode();
|
xmrLocalNode.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Unable to start local monero node: " + e.getMessage());
|
log.error("Unable to start local monero node, error={}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -721,8 +723,8 @@ public final class XmrConnectionService {
|
|||||||
|
|
||||||
// log error message periodically
|
// log error message periodically
|
||||||
if (lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) {
|
if (lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) {
|
||||||
log.warn("Failed to fetch daemon info, trying to switch to best connection: " + e.getMessage());
|
log.warn("Failed to fetch daemon info, trying to switch to best connection, error={}", e.getMessage());
|
||||||
if (DevEnv.isDevMode()) e.printStackTrace();
|
if (DevEnv.isDevMode()) log.error(ExceptionUtils.getStackTrace(e));
|
||||||
lastLogPollErrorTimestamp = System.currentTimeMillis();
|
lastLogPollErrorTimestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,6 +736,12 @@ public final class XmrConnectionService {
|
|||||||
// connected to daemon
|
// connected to daemon
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
|
|
||||||
|
// determine if blockchain is syncing locally
|
||||||
|
boolean blockchainSyncing = lastInfo.getHeight().equals(lastInfo.getHeightWithoutBootstrap()) || (lastInfo.getTargetHeight().equals(0l) && lastInfo.getHeightWithoutBootstrap().equals(0l)); // blockchain is syncing if height equals height without bootstrap, or target height and height without bootstrap both equal 0
|
||||||
|
|
||||||
|
// write sync status to preferences
|
||||||
|
preferences.getXmrNodeSettings().setSyncBlockchain(blockchainSyncing);
|
||||||
|
|
||||||
// throttle warnings if daemon not synced
|
// throttle warnings if daemon not synced
|
||||||
if (!isSyncedWithinTolerance() && System.currentTimeMillis() - lastLogDaemonNotSyncedTimestamp > HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) {
|
if (!isSyncedWithinTolerance() && System.currentTimeMillis() - lastLogDaemonNotSyncedTimestamp > HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) {
|
||||||
log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), getTargetHeight());
|
log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), getTargetHeight());
|
||||||
|
@ -150,16 +150,16 @@ public class XmrLocalNode {
|
|||||||
/**
|
/**
|
||||||
* Start a local Monero node from settings.
|
* Start a local Monero node from settings.
|
||||||
*/
|
*/
|
||||||
public void startMoneroNode() throws IOException {
|
public void start() throws IOException {
|
||||||
var settings = preferences.getXmrNodeSettings();
|
var settings = preferences.getXmrNodeSettings();
|
||||||
this.startNode(settings);
|
this.start(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start local Monero node. Throws MoneroError if the node cannot be started.
|
* Start local Monero node. Throws MoneroError if the node cannot be started.
|
||||||
* Persist the settings to preferences if the node started successfully.
|
* Persist the settings to preferences if the node started successfully.
|
||||||
*/
|
*/
|
||||||
public void startNode(XmrNodeSettings settings) throws IOException {
|
public void start(XmrNodeSettings settings) throws IOException {
|
||||||
if (isDetected()) throw new IllegalStateException("Local Monero node already online");
|
if (isDetected()) throw new IllegalStateException("Local Monero node already online");
|
||||||
|
|
||||||
log.info("Starting local Monero node: " + settings);
|
log.info("Starting local Monero node: " + settings);
|
||||||
@ -177,6 +177,11 @@ public class XmrLocalNode {
|
|||||||
args.add("--bootstrap-daemon-address=" + bootstrapUrl);
|
args.add("--bootstrap-daemon-address=" + bootstrapUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var syncBlockchain = settings.getSyncBlockchain();
|
||||||
|
if (syncBlockchain != null && !syncBlockchain) {
|
||||||
|
args.add("--no-sync");
|
||||||
|
}
|
||||||
|
|
||||||
var flags = settings.getStartupFlags();
|
var flags = settings.getStartupFlags();
|
||||||
if (flags != null) {
|
if (flags != null) {
|
||||||
args.addAll(flags);
|
args.addAll(flags);
|
||||||
@ -191,7 +196,7 @@ public class XmrLocalNode {
|
|||||||
* Stop the current local Monero node if we own its process.
|
* Stop the current local Monero node if we own its process.
|
||||||
* Does not remove the last XmrNodeSettings.
|
* Does not remove the last XmrNodeSettings.
|
||||||
*/
|
*/
|
||||||
public void stopNode() {
|
public void stop() {
|
||||||
if (!isDetected()) throw new IllegalStateException("Local Monero node is not running");
|
if (!isDetected()) throw new IllegalStateException("Local Monero node is not running");
|
||||||
if (daemon.getProcess() == null || !daemon.getProcess().isAlive()) throw new IllegalStateException("Cannot stop local Monero node because we don't own its process"); // TODO (woodser): remove isAlive() check after monero-java 0.5.4 which nullifies internal process
|
if (daemon.getProcess() == null || !daemon.getProcess().isAlive()) throw new IllegalStateException("Cannot stop local Monero node because we don't own its process"); // TODO (woodser): remove isAlive() check after monero-java 0.5.4 which nullifies internal process
|
||||||
daemon.stopProcess();
|
daemon.stopProcess();
|
||||||
|
@ -98,7 +98,7 @@ public class XmrBalanceInfo implements Payload {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "XmrBalanceInfo{" +
|
return "XmrBalanceInfo{" +
|
||||||
"balance=" + balance +
|
"balance=" + balance +
|
||||||
"unlockedBalance=" + availableBalance +
|
", unlockedBalance=" + availableBalance +
|
||||||
", lockedBalance=" + pendingBalance +
|
", lockedBalance=" + pendingBalance +
|
||||||
", reservedOfferBalance=" + reservedOfferBalance +
|
", reservedOfferBalance=" + reservedOfferBalance +
|
||||||
", reservedTradeBalance=" + reservedTradeBalance +
|
", reservedTradeBalance=" + reservedTradeBalance +
|
||||||
|
@ -127,7 +127,7 @@ public abstract class HavenoExecutable
|
|||||||
System.exit(EXIT_FAILURE);
|
System.exit(EXIT_FAILURE);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
System.err.println("fault: An unexpected error occurred. " +
|
System.err.println("fault: An unexpected error occurred. " +
|
||||||
"Please file a report at https://haveno.exchange/issues");
|
"Please file a report at https://github.com/haveno-dex/haveno/issues");
|
||||||
ex.printStackTrace(System.err);
|
ex.printStackTrace(System.err);
|
||||||
System.exit(EXIT_FAILURE);
|
System.exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -204,8 +204,7 @@ public abstract class HavenoExecutable
|
|||||||
startApplication();
|
startApplication();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
log.error("An error occurred: {}", e.getMessage());
|
log.error("An error occurred: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -365,7 +364,7 @@ public abstract class HavenoExecutable
|
|||||||
try {
|
try {
|
||||||
ThreadUtils.awaitTasks(tasks, tasks.size(), 90000l); // run in parallel with timeout
|
ThreadUtils.awaitTasks(tasks, tasks.size(), 90000l); // run in parallel with timeout
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Failed to notify all services to prepare for shutdown: {}\n", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
injector.getInstance(TradeManager.class).shutDown();
|
injector.getInstance(TradeManager.class).shutDown();
|
||||||
@ -400,8 +399,7 @@ public abstract class HavenoExecutable
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error("App shutdown failed with exception {}", t.toString());
|
log.error("App shutdown failed with exception: {}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
completeShutdown(resultHandler, EXIT_FAILURE, systemExit);
|
completeShutdown(resultHandler, EXIT_FAILURE, systemExit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ import haveno.core.alert.Alert;
|
|||||||
import haveno.core.alert.AlertManager;
|
import haveno.core.alert.AlertManager;
|
||||||
import haveno.core.alert.PrivateNotificationManager;
|
import haveno.core.alert.PrivateNotificationManager;
|
||||||
import haveno.core.alert.PrivateNotificationPayload;
|
import haveno.core.alert.PrivateNotificationPayload;
|
||||||
|
import haveno.core.api.CoreContext;
|
||||||
import haveno.core.api.XmrConnectionService;
|
import haveno.core.api.XmrConnectionService;
|
||||||
import haveno.core.api.XmrLocalNode;
|
import haveno.core.api.XmrLocalNode;
|
||||||
import haveno.core.locale.Res;
|
import haveno.core.locale.Res;
|
||||||
@ -131,7 +132,10 @@ public class HavenoSetup {
|
|||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private final User user;
|
private final User user;
|
||||||
private final AlertManager alertManager;
|
private final AlertManager alertManager;
|
||||||
|
@Getter
|
||||||
private final Config config;
|
private final Config config;
|
||||||
|
@Getter
|
||||||
|
private final CoreContext coreContext;
|
||||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||||
private final TorSetup torSetup;
|
private final TorSetup torSetup;
|
||||||
private final CoinFormatter formatter;
|
private final CoinFormatter formatter;
|
||||||
@ -228,6 +232,7 @@ public class HavenoSetup {
|
|||||||
User user,
|
User user,
|
||||||
AlertManager alertManager,
|
AlertManager alertManager,
|
||||||
Config config,
|
Config config,
|
||||||
|
CoreContext coreContext,
|
||||||
AccountAgeWitnessService accountAgeWitnessService,
|
AccountAgeWitnessService accountAgeWitnessService,
|
||||||
TorSetup torSetup,
|
TorSetup torSetup,
|
||||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||||
@ -253,6 +258,7 @@ public class HavenoSetup {
|
|||||||
this.user = user;
|
this.user = user;
|
||||||
this.alertManager = alertManager;
|
this.alertManager = alertManager;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.coreContext = coreContext;
|
||||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||||
this.torSetup = torSetup;
|
this.torSetup = torSetup;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
@ -263,6 +269,7 @@ public class HavenoSetup {
|
|||||||
this.arbitrationManager = arbitrationManager;
|
this.arbitrationManager = arbitrationManager;
|
||||||
|
|
||||||
HavenoUtils.havenoSetup = this;
|
HavenoUtils.havenoSetup = this;
|
||||||
|
HavenoUtils.preferences = preferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -376,8 +383,7 @@ public class HavenoSetup {
|
|||||||
moneroWalletRpcFile.setExecutable(true);
|
moneroWalletRpcFile.setExecutable(true);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Failed to install Monero binaries: {}\n", e.getMessage(), e);
|
||||||
log.warn("Failed to install Monero binaries: " + e.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -48,8 +51,7 @@ public class TorSetup {
|
|||||||
if (resultHandler != null)
|
if (resultHandler != null)
|
||||||
resultHandler.run();
|
resultHandler.run();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
log.error(e.toString());
|
|
||||||
if (errorMessageHandler != null)
|
if (errorMessageHandler != null)
|
||||||
errorMessageHandler.handleErrorMessage(e.toString());
|
errorMessageHandler.handleErrorMessage(e.toString());
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ public abstract class ExecutableForAppWithP2p extends HavenoExecutable {
|
|||||||
try {
|
try {
|
||||||
ThreadUtils.awaitTasks(tasks, tasks.size(), 120000l); // run in parallel with timeout
|
ThreadUtils.awaitTasks(tasks, tasks.size(), 120000l); // run in parallel with timeout
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Error awaiting tasks to complete: {}\n", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonFileManager.shutDownAllInstances();
|
JsonFileManager.shutDownAllInstances();
|
||||||
@ -177,8 +177,7 @@ public abstract class ExecutableForAppWithP2p extends HavenoExecutable {
|
|||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.debug("App shutdown failed with exception");
|
log.info("App shutdown failed with exception: {}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
PersistenceManager.flushAllDataToDiskAtShutdown(() -> {
|
PersistenceManager.flushAllDataToDiskAtShutdown(() -> {
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
log.info("Graceful shutdown resulted in an error. Exiting now.");
|
log.info("Graceful shutdown resulted in an error. Exiting now.");
|
||||||
|
@ -977,7 +977,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
// handle result
|
// handle result
|
||||||
resultHandler.handleResult(null);
|
resultHandler.handleResult(null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (!openOffer.isCanceled()) e.printStackTrace();
|
if (!openOffer.isCanceled()) log.error("Error processing pending offer: {}\n", e.getMessage(), e);
|
||||||
errorMessageHandler.handleErrorMessage(e.getMessage());
|
errorMessageHandler.handleErrorMessage(e.getMessage());
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
@ -1365,9 +1365,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
});
|
});
|
||||||
result = true;
|
result = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
|
||||||
errorMessage = "Exception at handleSignOfferRequest " + e.getMessage();
|
errorMessage = "Exception at handleSignOfferRequest " + e.getMessage();
|
||||||
log.error(errorMessage);
|
log.error(errorMessage + "\n", e);
|
||||||
} finally {
|
} finally {
|
||||||
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage);
|
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage);
|
||||||
}
|
}
|
||||||
@ -1519,8 +1518,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
result = true;
|
result = true;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
errorMessage = "Exception at handleRequestIsOfferAvailableMessage " + t.getMessage();
|
errorMessage = "Exception at handleRequestIsOfferAvailableMessage " + t.getMessage();
|
||||||
log.error(errorMessage);
|
log.error(errorMessage + "\n", t);
|
||||||
t.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage);
|
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage);
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,7 @@ public class FeeProvider extends HttpClientProvider {
|
|||||||
map.put(Config.BTC_TX_FEE, btcTxFee);
|
map.put(Config.BTC_TX_FEE, btcTxFee);
|
||||||
map.put(Config.BTC_MIN_TX_FEE, btcMinTxFee);
|
map.put(Config.BTC_MIN_TX_FEE, btcMinTxFee);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error(t.toString());
|
log.error("Error getting fees: {}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return new Tuple2<>(tsMap, map);
|
return new Tuple2<>(tsMap, map);
|
||||||
}
|
}
|
||||||
|
@ -68,8 +68,7 @@ public class PriceProvider extends HttpClientProvider {
|
|||||||
long timestampSec = MathUtils.doubleToLong((Double) treeMap.get("timestampSec"));
|
long timestampSec = MathUtils.doubleToLong((Double) treeMap.get("timestampSec"));
|
||||||
marketPriceMap.put(currencyCode, new MarketPrice(currencyCode, price, timestampSec, true));
|
marketPriceMap.put(currencyCode, new MarketPrice(currencyCode, price, timestampSec, true));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error(t.toString());
|
log.error("Error getting all prices: {}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -199,7 +199,7 @@ public abstract class SupportManager {
|
|||||||
if (dispute.isClosed()) dispute.reOpen();
|
if (dispute.isClosed()) dispute.reOpen();
|
||||||
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
||||||
} else if (dispute.isClosed()) {
|
} else if (dispute.isClosed()) {
|
||||||
trade.pollWalletNormallyForMs(30000); // sync to check for payout
|
trade.pollWalletNormallyForMs(60000); // sync to check for payout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,9 @@ import monero.wallet.model.MoneroTxConfig;
|
|||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.wallet.model.MoneroTxWallet;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@ -523,7 +526,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
DisputeValidation.validateSenderNodeAddress(dispute, message.getSenderNodeAddress(), config);
|
DisputeValidation.validateSenderNodeAddress(dispute, message.getSenderNodeAddress(), config);
|
||||||
//DisputeValidation.testIfDisputeTriesReplay(dispute, disputeList.getList());
|
//DisputeValidation.testIfDisputeTriesReplay(dispute, disputeList.getList());
|
||||||
} catch (DisputeValidation.ValidationException e) {
|
} catch (DisputeValidation.ValidationException e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
validationExceptions.add(e);
|
validationExceptions.add(e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -532,9 +535,9 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
try {
|
try {
|
||||||
DisputeValidation.validatePaymentAccountPayload(dispute); // TODO: add field to dispute details: valid, invalid, missing
|
DisputeValidation.validatePaymentAccountPayload(dispute); // TODO: add field to dispute details: valid, invalid, missing
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
log.warn(e.getMessage());
|
|
||||||
trade.prependErrorMessage(e.getMessage());
|
trade.prependErrorMessage(e.getMessage());
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get sender
|
// get sender
|
||||||
@ -606,9 +609,8 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
errorMessage = e.getMessage();
|
errorMessage = e.getMessage();
|
||||||
log.warn(errorMessage);
|
|
||||||
if (trade != null) trade.setErrorMessage(errorMessage);
|
if (trade != null) trade.setErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +854,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
disputeResult.getChatMessage().setArrived(true);
|
disputeResult.getChatMessage().setArrived(true);
|
||||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
||||||
trade.pollWalletNormallyForMs(30000);
|
trade.pollWalletNormallyForMs(60000);
|
||||||
requestPersistence(trade);
|
requestPersistence(trade);
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ public class DisputeSummaryVerification {
|
|||||||
disputeAgent = arbitratorManager.getDisputeAgentByNodeAddress(nodeAddress).orElse(null);
|
disputeAgent = arbitratorManager.getDisputeAgentByNodeAddress(nodeAddress).orElse(null);
|
||||||
checkNotNull(disputeAgent, "Dispute agent is null");
|
checkNotNull(disputeAgent, "Dispute agent is null");
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
log.error("Error verifying signature: {}\n", e.getMessage(), e);
|
||||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ public class DisputeSummaryVerification {
|
|||||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed"));
|
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed"));
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
log.error("Error verifying signature with agent pub key ring: {}\n", e.getMessage(), e);
|
||||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,8 @@ import java.util.Map;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -355,11 +357,11 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||||||
requestPersistence(trade);
|
requestPersistence(trade);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error processing dispute closed message: {}", e.getMessage());
|
log.warn("Error processing dispute closed message: {}", e.getMessage());
|
||||||
e.printStackTrace();
|
log.warn(ExceptionUtils.getStackTrace(e));
|
||||||
requestPersistence(trade);
|
requestPersistence(trade);
|
||||||
|
|
||||||
// nack bad message and do not reprocess
|
// nack bad message and do not reprocess
|
||||||
if (e instanceof IllegalArgumentException || e instanceof IllegalStateException) {
|
if (HavenoUtils.isIllegal(e)) {
|
||||||
trade.getArbitrator().setDisputeClosedMessage(null); // message is processed
|
trade.getArbitrator().setDisputeClosedMessage(null); // message is processed
|
||||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
|
trade.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
|
||||||
String warningMsg = "Error processing dispute closed message: " + e.getMessage() + "\n\nOpen another dispute to try again (ctrl+o).";
|
String warningMsg = "Error processing dispute closed message: " + e.getMessage() + "\n\nOpen another dispute to try again (ctrl+o).";
|
||||||
@ -489,8 +491,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||||||
try {
|
try {
|
||||||
feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false);
|
feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Could not recreate dispute payout tx to verify fee: {}\n", e.getMessage(), e);
|
||||||
log.warn("Could not recreate dispute payout tx to verify fee: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
if (feeEstimateTx != null) {
|
if (feeEstimateTx != null) {
|
||||||
BigInteger feeEstimate = feeEstimateTx.getFee();
|
BigInteger feeEstimate = feeEstimateTx.getFee();
|
||||||
|
@ -27,7 +27,9 @@ import haveno.common.crypto.Hash;
|
|||||||
import haveno.common.crypto.KeyRing;
|
import haveno.common.crypto.KeyRing;
|
||||||
import haveno.common.crypto.PubKeyRing;
|
import haveno.common.crypto.PubKeyRing;
|
||||||
import haveno.common.crypto.Sig;
|
import haveno.common.crypto.Sig;
|
||||||
|
import haveno.common.file.FileUtil;
|
||||||
import haveno.common.util.Utilities;
|
import haveno.common.util.Utilities;
|
||||||
|
import haveno.core.api.CoreNotificationService;
|
||||||
import haveno.core.api.XmrConnectionService;
|
import haveno.core.api.XmrConnectionService;
|
||||||
import haveno.core.app.HavenoSetup;
|
import haveno.core.app.HavenoSetup;
|
||||||
import haveno.core.offer.OfferPayload;
|
import haveno.core.offer.OfferPayload;
|
||||||
@ -36,9 +38,12 @@ import haveno.core.support.dispute.arbitration.ArbitrationManager;
|
|||||||
import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
||||||
import haveno.core.trade.messages.PaymentReceivedMessage;
|
import haveno.core.trade.messages.PaymentReceivedMessage;
|
||||||
import haveno.core.trade.messages.PaymentSentMessage;
|
import haveno.core.trade.messages.PaymentSentMessage;
|
||||||
|
import haveno.core.user.Preferences;
|
||||||
import haveno.core.util.JsonUtil;
|
import haveno.core.util.JsonUtil;
|
||||||
import haveno.core.xmr.wallet.XmrWalletService;
|
import haveno.core.xmr.wallet.XmrWalletService;
|
||||||
import haveno.network.p2p.NodeAddress;
|
import haveno.network.p2p.NodeAddress;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
@ -53,6 +58,13 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFormat;
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import javax.sound.sampled.DataLine;
|
||||||
|
import javax.sound.sampled.SourceDataLine;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.common.MoneroRpcConnection;
|
import monero.common.MoneroRpcConnection;
|
||||||
import monero.daemon.model.MoneroOutput;
|
import monero.daemon.model.MoneroOutput;
|
||||||
@ -110,11 +122,18 @@ public class HavenoUtils {
|
|||||||
public static XmrWalletService xmrWalletService;
|
public static XmrWalletService xmrWalletService;
|
||||||
public static XmrConnectionService xmrConnectionService;
|
public static XmrConnectionService xmrConnectionService;
|
||||||
public static OpenOfferManager openOfferManager;
|
public static OpenOfferManager openOfferManager;
|
||||||
|
public static CoreNotificationService notificationService;
|
||||||
|
public static Preferences preferences;
|
||||||
|
|
||||||
public static boolean isSeedNode() {
|
public static boolean isSeedNode() {
|
||||||
return havenoSetup == null;
|
return havenoSetup == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDaemon() {
|
||||||
|
if (isSeedNode()) return true;
|
||||||
|
return havenoSetup.getCoreContext().isApiUser();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static Date getReleaseDate() {
|
public static Date getReleaseDate() {
|
||||||
if (RELEASE_DATE == null) return null;
|
if (RELEASE_DATE == null) return null;
|
||||||
@ -510,19 +529,83 @@ public class HavenoUtils {
|
|||||||
havenoSetup.getTopErrorMsg().set(msg);
|
havenoSetup.getTopErrorMsg().set(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isConnectionRefused(Exception e) {
|
public static boolean isConnectionRefused(Throwable e) {
|
||||||
return e != null && e.getMessage().contains("Connection refused");
|
return e != null && e.getMessage().contains("Connection refused");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReadTimeout(Exception e) {
|
public static boolean isReadTimeout(Throwable e) {
|
||||||
return e != null && e.getMessage().contains("Read timed out");
|
return e != null && e.getMessage().contains("Read timed out");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isUnresponsive(Exception e) {
|
public static boolean isUnresponsive(Throwable e) {
|
||||||
return isConnectionRefused(e) || isReadTimeout(e);
|
return isConnectionRefused(e) || isReadTimeout(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNotEnoughSigners(Exception e) {
|
public static boolean isNotEnoughSigners(Throwable e) {
|
||||||
return e != null && e.getMessage().contains("Not enough signers");
|
return e != null && e.getMessage().contains("Not enough signers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isTransactionRejected(Throwable e) {
|
||||||
|
return e != null && e.getMessage().contains("was rejected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isIllegal(Throwable e) {
|
||||||
|
return e instanceof IllegalArgumentException || e instanceof IllegalStateException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playChimeSound() {
|
||||||
|
playAudioFile("chime.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playCashRegisterSound() {
|
||||||
|
playAudioFile("cash_register.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void playAudioFile(String fileName) {
|
||||||
|
if (isDaemon()) return; // ignore if running as daemon
|
||||||
|
if (!preferences.getUseSoundForNotificationsProperty().get()) return; // ignore if sounds disabled
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// get audio file
|
||||||
|
File wavFile = new File(havenoSetup.getConfig().appDataDir, fileName);
|
||||||
|
if (!wavFile.exists()) FileUtil.resourceToFile(fileName, wavFile);
|
||||||
|
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(wavFile);
|
||||||
|
|
||||||
|
// get original format
|
||||||
|
AudioFormat baseFormat = audioInputStream.getFormat();
|
||||||
|
|
||||||
|
// set target format: PCM_SIGNED, 16-bit
|
||||||
|
AudioFormat targetFormat = new AudioFormat(
|
||||||
|
AudioFormat.Encoding.PCM_SIGNED,
|
||||||
|
baseFormat.getSampleRate(),
|
||||||
|
16, // 16-bit instead of 32-bit float
|
||||||
|
baseFormat.getChannels(),
|
||||||
|
baseFormat.getChannels() * 2, // Frame size: 2 bytes per channel (16-bit)
|
||||||
|
baseFormat.getSampleRate(),
|
||||||
|
false // Little-endian
|
||||||
|
);
|
||||||
|
|
||||||
|
// convert audio to target format
|
||||||
|
AudioInputStream convertedStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream);
|
||||||
|
|
||||||
|
// play audio
|
||||||
|
DataLine.Info info = new DataLine.Info(SourceDataLine.class, targetFormat);
|
||||||
|
SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(info);
|
||||||
|
sourceLine.open(targetFormat);
|
||||||
|
sourceLine.start();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead = 0;
|
||||||
|
while ((bytesRead = convertedStream.read(buffer, 0, buffer.length)) != -1) {
|
||||||
|
sourceLine.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
sourceLine.drain();
|
||||||
|
sourceLine.close();
|
||||||
|
convertedStream.close();
|
||||||
|
audioInputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,6 +649,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
ThreadUtils.submitToPool(() -> {
|
ThreadUtils.submitToPool(() -> {
|
||||||
if (newValue == Trade.Phase.DEPOSIT_REQUESTED) startPolling();
|
if (newValue == Trade.Phase.DEPOSIT_REQUESTED) startPolling();
|
||||||
if (newValue == Trade.Phase.DEPOSITS_PUBLISHED) onDepositsPublished();
|
if (newValue == Trade.Phase.DEPOSITS_PUBLISHED) onDepositsPublished();
|
||||||
|
if (newValue == Trade.Phase.PAYMENT_SENT) onPaymentSent();
|
||||||
if (isDepositsPublished() && !isPayoutUnlocked()) updatePollPeriod();
|
if (isDepositsPublished() && !isPayoutUnlocked()) updatePollPeriod();
|
||||||
if (isPaymentReceived()) {
|
if (isPaymentReceived()) {
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
@ -999,8 +1000,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
xmrWalletService.deleteWallet(getWalletName());
|
xmrWalletService.deleteWallet(getWalletName());
|
||||||
xmrWalletService.deleteWalletBackups(getWalletName());
|
xmrWalletService.deleteWalletBackups(getWalletName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn(e.getMessage());
|
log.warn("Error deleting wallet for {} {}: {}\n", getClass().getSimpleName(), getId(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
setErrorMessage(e.getMessage());
|
setErrorMessage(e.getMessage());
|
||||||
processModel.getTradeManager().getNotificationService().sendErrorNotification("Error", e.getMessage());
|
processModel.getTradeManager().getNotificationService().sendErrorNotification("Error", e.getMessage());
|
||||||
}
|
}
|
||||||
@ -1051,7 +1051,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
synchronized (HavenoUtils.getWalletFunctionLock()) {
|
synchronized (HavenoUtils.getWalletFunctionLock()) {
|
||||||
MoneroTxWallet tx = wallet.createTx(txConfig);
|
MoneroTxWallet tx = wallet.createTx(txConfig);
|
||||||
exportMultisigHex();
|
exportMultisigHex();
|
||||||
requestSaveWallet();
|
saveWallet();
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1152,14 +1152,14 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestSaveWallet();
|
saveWallet();
|
||||||
}
|
}
|
||||||
log.info("Done importing multisig hexes for {} {} in {} ms, count={}", getClass().getSimpleName(), getShortId(), System.currentTimeMillis() - startTime, multisigHexes.size());
|
log.info("Done importing multisig hexes for {} {} in {} ms, count={}", getClass().getSimpleName(), getShortId(), System.currentTimeMillis() - startTime, multisigHexes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) {
|
private void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) {
|
||||||
if (HavenoUtils.isUnresponsive(e)) forceCloseWallet(); // wallet can be stuck a while
|
if (HavenoUtils.isUnresponsive(e)) forceCloseWallet(); // wallet can be stuck a while
|
||||||
if (xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection);
|
if (!HavenoUtils.isIllegal(e) && xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection);
|
||||||
getWallet(); // re-open wallet
|
getWallet(); // re-open wallet
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,7 +1279,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
|
log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage(), e);
|
||||||
handleWalletError(e, sourceConnection);
|
handleWalletError(e, sourceConnection);
|
||||||
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
|
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
|
||||||
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
|
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
|
||||||
@ -1351,20 +1351,20 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
try {
|
try {
|
||||||
MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex);
|
MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex);
|
||||||
if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null");
|
if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null");
|
||||||
payoutTxHex = result.getSignedMultisigTxHex();
|
setPayoutTxHex(result.getSignedMultisigTxHex());
|
||||||
setPayoutTxHex(payoutTxHex);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// describe result
|
// describe result
|
||||||
describedTxSet = wallet.describeMultisigTxSet(payoutTxHex);
|
describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex());
|
||||||
payoutTx = describedTxSet.getTxs().get(0);
|
payoutTx = describedTxSet.getTxs().get(0);
|
||||||
updatePayout(payoutTx);
|
updatePayout(payoutTx);
|
||||||
|
|
||||||
// verify fee is within tolerance by recreating payout tx
|
// verify fee is within tolerance by recreating payout tx
|
||||||
// TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated?
|
// TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated?
|
||||||
log.info("Creating fee estimate tx for {} {}", getClass().getSimpleName(), getId());
|
log.info("Creating fee estimate tx for {} {}", getClass().getSimpleName(), getId());
|
||||||
|
saveWallet(); // save wallet before creating fee estimate tx
|
||||||
MoneroTxWallet feeEstimateTx = createPayoutTx();
|
MoneroTxWallet feeEstimateTx = createPayoutTx();
|
||||||
BigInteger feeEstimate = feeEstimateTx.getFee();
|
BigInteger feeEstimate = feeEstimateTx.getFee();
|
||||||
double feeDiff = payoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal?
|
double feeDiff = payoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal?
|
||||||
@ -1373,17 +1373,20 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save trade state
|
// save trade state
|
||||||
|
saveWallet();
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
|
||||||
// submit payout tx
|
// submit payout tx
|
||||||
if (publish) {
|
boolean doPublish = publish && !isPayoutPublished();
|
||||||
|
if (doPublish) {
|
||||||
try {
|
try {
|
||||||
wallet.submitMultisigTxHex(payoutTxHex);
|
wallet.submitMultisigTxHex(getPayoutTxHex());
|
||||||
setPayoutStatePublished();
|
setPayoutStatePublished();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (isPayoutPublished()) throw new IllegalStateException("Payout tx already published for " + getClass().getSimpleName() + " " + getShortId());
|
if (!isPayoutPublished()) {
|
||||||
if (HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e);
|
if (HavenoUtils.isTransactionRejected(e) || HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e);
|
||||||
throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId(), e);
|
throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId() + ", error=" + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1536,8 +1539,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
try {
|
try {
|
||||||
ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS);
|
ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error shutting down {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage());
|
log.warn("Error shutting down {} {}: {}\n", getClass().getSimpleName(), getId(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
// force close wallet
|
// force close wallet
|
||||||
forceCloseWallet();
|
forceCloseWallet();
|
||||||
@ -2817,8 +2819,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
processing = false;
|
processing = false;
|
||||||
if (!isInitialized || isShutDownStarted) return;
|
if (!isInitialized || isShutDownStarted) return;
|
||||||
if (isWalletConnectedToDaemon()) {
|
if (isWalletConnectedToDaemon()) {
|
||||||
e.printStackTrace();
|
log.warn("Error polling idle trade for {} {}: {}. Monerod={}\n", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getXmrConnectionService().getConnection(), e);
|
||||||
log.warn("Error polling idle trade for {} {}: {}. Monerod={}", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getXmrConnectionService().getConnection());
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, getId());
|
}, getId());
|
||||||
@ -2833,6 +2834,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
// close open offer or reset address entries
|
// close open offer or reset address entries
|
||||||
if (this instanceof MakerTrade) {
|
if (this instanceof MakerTrade) {
|
||||||
processModel.getOpenOfferManager().closeOpenOffer(getOffer());
|
processModel.getOpenOfferManager().closeOpenOffer(getOffer());
|
||||||
|
HavenoUtils.notificationService.sendTradeNotification(this, Phase.DEPOSITS_PUBLISHED, "Offer Taken", "Your offer " + offer.getId() + " has been accepted"); // TODO (woodser): use language translation
|
||||||
} else {
|
} else {
|
||||||
getXmrWalletService().resetAddressEntriesForOpenOffer(getId());
|
getXmrWalletService().resetAddressEntriesForOpenOffer(getId());
|
||||||
}
|
}
|
||||||
@ -2841,6 +2843,12 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
|||||||
ThreadUtils.submitToPool(() -> xmrWalletService.freezeOutputs(getSelf().getReserveTxKeyImages()));
|
ThreadUtils.submitToPool(() -> xmrWalletService.freezeOutputs(getSelf().getReserveTxKeyImages()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onPaymentSent() {
|
||||||
|
if (this instanceof SellerTrade) {
|
||||||
|
HavenoUtils.notificationService.sendTradeNotification(this, Phase.PAYMENT_SENT, "Payment Sent", "The buyer has sent the payment"); // TODO (woodser): use language translation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// PROTO BUFFER
|
// PROTO BUFFER
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -68,7 +68,6 @@ import haveno.core.support.dispute.mediation.mediator.MediatorManager;
|
|||||||
import haveno.core.support.dispute.messages.DisputeClosedMessage;
|
import haveno.core.support.dispute.messages.DisputeClosedMessage;
|
||||||
import haveno.core.support.dispute.messages.DisputeOpenedMessage;
|
import haveno.core.support.dispute.messages.DisputeOpenedMessage;
|
||||||
import haveno.core.trade.Trade.DisputeState;
|
import haveno.core.trade.Trade.DisputeState;
|
||||||
import haveno.core.trade.Trade.Phase;
|
|
||||||
import haveno.core.trade.failed.FailedTradesManager;
|
import haveno.core.trade.failed.FailedTradesManager;
|
||||||
import haveno.core.trade.handlers.TradeResultHandler;
|
import haveno.core.trade.handlers.TradeResultHandler;
|
||||||
import haveno.core.trade.messages.DepositRequest;
|
import haveno.core.trade.messages.DepositRequest;
|
||||||
@ -134,7 +133,6 @@ import lombok.Setter;
|
|||||||
import monero.daemon.model.MoneroTx;
|
import monero.daemon.model.MoneroTx;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -258,7 +256,9 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
|
|
||||||
failedTradesManager.setUnFailTradeCallback(this::unFailTrade);
|
failedTradesManager.setUnFailTradeCallback(this::unFailTrade);
|
||||||
|
|
||||||
xmrWalletService.setTradeManager(this);
|
// TODO: better way to set references
|
||||||
|
xmrWalletService.setTradeManager(this); // TODO: set reference in HavenoUtils for consistency
|
||||||
|
HavenoUtils.notificationService = notificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -366,8 +366,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
trade.onShutDownStarted();
|
trade.onShutDownStarted();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e.getMessage() != null && e.getMessage().contains("Connection reset")) return; // expected if shut down with ctrl+c
|
if (e.getMessage() != null && e.getMessage().contains("Connection reset")) return; // expected if shut down with ctrl+c
|
||||||
log.warn("Error notifying {} {} that shut down started {}", trade.getClass().getSimpleName(), trade.getId());
|
log.warn("Error notifying {} {} that shut down started: {}\n", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@ -396,15 +395,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
trade.shutDown();
|
trade.shutDown();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e.getMessage() != null && (e.getMessage().contains("Connection reset") || e.getMessage().contains("Connection refused"))) return; // expected if shut down with ctrl+c
|
if (e.getMessage() != null && (e.getMessage().contains("Connection reset") || e.getMessage().contains("Connection refused"))) return; // expected if shut down with ctrl+c
|
||||||
log.warn("Error closing {} {}", trade.getClass().getSimpleName(), trade.getId());
|
log.warn("Error closing {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
ThreadUtils.awaitTasks(tasks);
|
ThreadUtils.awaitTasks(tasks);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error shutting down trades: {}", e.getMessage());
|
log.warn("Error shutting down trades: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,8 +459,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (!isShutDownStarted) {
|
if (!isShutDownStarted) {
|
||||||
e.printStackTrace();
|
log.warn("Error initializing {} {}: {}\n", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e);
|
||||||
log.warn("Error initializing {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage());
|
|
||||||
trade.setInitError(e);
|
trade.setInitError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,14 +599,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
initTradeAndProtocol(trade, createTradeProtocol(trade));
|
initTradeAndProtocol(trade, createTradeProtocol(trade));
|
||||||
addTrade(trade);
|
addTrade(trade);
|
||||||
|
|
||||||
// notify on phase changes
|
|
||||||
// TODO (woodser): save subscription, bind on startup
|
|
||||||
EasyBind.subscribe(trade.statePhaseProperty(), phase -> {
|
|
||||||
if (phase == Phase.DEPOSITS_PUBLISHED) {
|
|
||||||
notificationService.sendTradeNotification(trade, "Offer Taken", "Your offer " + offer.getId() + " has been accepted"); // TODO (woodser): use language translation
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// process with protocol
|
// process with protocol
|
||||||
((MakerProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> {
|
((MakerProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> {
|
||||||
log.warn("Maker error during trade initialization: " + errorMessage);
|
log.warn("Maker error during trade initialization: " + errorMessage);
|
||||||
|
@ -68,7 +68,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
|
|||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
this.error = t;
|
this.error = t;
|
||||||
t.printStackTrace();
|
log.error("Error processing deposit request for trade {}: {}\n", trade.getId(), t.getMessage(), t);
|
||||||
trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED);
|
trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED);
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
@ -155,15 +155,14 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
|
|||||||
log.info("Arbitrator published deposit txs for trade " + trade.getId());
|
log.info("Arbitrator published deposit txs for trade " + trade.getId());
|
||||||
trade.setStateIfValidTransitionTo(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS);
|
trade.setStateIfValidTransitionTo(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Arbitrator error publishing deposit txs for trade {} {}: {}", trade.getClass().getSimpleName(), trade.getShortId(), e.getMessage());
|
log.warn("Arbitrator error publishing deposit txs for trade {} {}: {}\n", trade.getClass().getSimpleName(), trade.getShortId(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
if (!depositTxsRelayed) {
|
if (!depositTxsRelayed) {
|
||||||
|
|
||||||
// flush txs from pool
|
// flush txs from pool
|
||||||
try {
|
try {
|
||||||
daemon.flushTxPool(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash());
|
daemon.flushTxPool(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash());
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
e2.printStackTrace();
|
log.warn("Error flushing deposit txs from pool for trade {}: {}\n", trade.getId(), e2.getMessage(), e2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -29,6 +29,8 @@ import monero.daemon.model.MoneroTx;
|
|||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arbitrator verifies reserve tx from maker or taker.
|
* Arbitrator verifies reserve tx from maker or taker.
|
||||||
*
|
*
|
||||||
@ -73,7 +75,7 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
|||||||
request.getReserveTxKey(),
|
request.getReserveTxKey(),
|
||||||
null);
|
null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + processModel.getTempTradePeerNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + processModel.getTempTradePeerNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public class MaybeResendDisputeClosedMessageWithPayout extends TradeTask {
|
|||||||
HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), () -> {
|
HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), () -> {
|
||||||
completeAux();
|
completeAux();
|
||||||
}, (errMessage, err) -> {
|
}, (errMessage, err) -> {
|
||||||
err.printStackTrace();
|
log.error("Failed to close dispute ticket for trade {}: {}\n", trade.getId(), errMessage, err);
|
||||||
failed(err);
|
failed(err);
|
||||||
});
|
});
|
||||||
ticketClosed = true;
|
ticketClosed = true;
|
||||||
|
@ -70,7 +70,7 @@ public class ProcessDepositsConfirmedMessage extends TradeTask {
|
|||||||
try {
|
try {
|
||||||
trade.importMultisigHex();
|
trade.importMultisigHex();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Error importing multisig hex on deposits confirmed for trade " + trade.getId() + ": " + e.getMessage() + "\n", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import haveno.network.p2p.NodeAddress;
|
|||||||
import haveno.network.p2p.SendDirectMessageListener;
|
import haveno.network.p2p.SendDirectMessageListener;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.MoneroWallet;
|
import monero.wallet.MoneroWallet;
|
||||||
|
import monero.wallet.model.MoneroMultisigInfo;
|
||||||
import monero.wallet.model.MoneroMultisigInitResult;
|
import monero.wallet.model.MoneroMultisigInitResult;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -118,8 +119,17 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
|||||||
if (processModel.getMultisigAddress() == null && peers[0].getExchangedMultisigHex() != null && peers[1].getExchangedMultisigHex() != null) {
|
if (processModel.getMultisigAddress() == null && peers[0].getExchangedMultisigHex() != null && peers[1].getExchangedMultisigHex() != null) {
|
||||||
log.info("Importing exchanged multisig hex for trade {}", trade.getId());
|
log.info("Importing exchanged multisig hex for trade {}", trade.getId());
|
||||||
MoneroMultisigInitResult result = multisigWallet.exchangeMultisigKeys(Arrays.asList(peers[0].getExchangedMultisigHex(), peers[1].getExchangedMultisigHex()), xmrWalletService.getWalletPassword());
|
MoneroMultisigInitResult result = multisigWallet.exchangeMultisigKeys(Arrays.asList(peers[0].getExchangedMultisigHex(), peers[1].getExchangedMultisigHex()), xmrWalletService.getWalletPassword());
|
||||||
|
|
||||||
|
// check multisig state
|
||||||
|
MoneroMultisigInfo multisigInfo = multisigWallet.getMultisigInfo();
|
||||||
|
if (!multisigInfo.isMultisig()) throw new RuntimeException("Multisig wallet is not multisig on completion");
|
||||||
|
if (!multisigInfo.isReady()) throw new RuntimeException("Multisig wallet is not ready on completion");
|
||||||
|
if (multisigInfo.getThreshold() != 2) throw new RuntimeException("Multisig wallet has unexpected threshold: " + multisigInfo.getThreshold());
|
||||||
|
if (multisigInfo.getNumParticipants() != 3) throw new RuntimeException("Multisig wallet has unexpected number of participants: " + multisigInfo.getNumParticipants());
|
||||||
|
|
||||||
|
// set final address and save
|
||||||
processModel.setMultisigAddress(result.getAddress());
|
processModel.setMultisigAddress(result.getAddress());
|
||||||
new Thread(() -> trade.saveWallet()).start(); // save multisig wallet off thread on completion
|
trade.saveWallet();
|
||||||
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED);
|
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
||||||
// do not reprocess illegal argument
|
// do not reprocess illegal argument
|
||||||
if (t instanceof IllegalArgumentException) {
|
if (HavenoUtils.isIllegal(t)) {
|
||||||
trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess
|
trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess
|
||||||
trade.requestPersistence();
|
trade.requestPersistence();
|
||||||
}
|
}
|
||||||
@ -151,6 +151,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||||||
boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
|
boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
|
||||||
if (deferSignAndPublish) {
|
if (deferSignAndPublish) {
|
||||||
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||||
|
trade.pollWalletNormallyForMs(60000);
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
if (trade.isPayoutPublished()) break;
|
if (trade.isPayoutPublished()) break;
|
||||||
HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5);
|
HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5);
|
||||||
|
@ -65,10 +65,10 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
|
|||||||
trade.processPayoutTx(trade.getPayoutTxHex(), false, true);
|
trade.processPayoutTx(trade.getPayoutTxHex(), false, true);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
log.warn("Illegal state or argument verifying, signing, and publishing payout tx for {} {}: {}. Creating new unsigned payout tx", trade.getClass().getSimpleName(), trade.getId(), e.getMessage());
|
log.warn("Illegal state or argument verifying, signing, and publishing payout tx for {} {}: {}. Creating new unsigned payout tx", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e);
|
||||||
createUnsignedPayoutTx();
|
createUnsignedPayoutTx();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}", trade.getId(), e.getMessage());
|
log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}", trade.getId(), e.getMessage(), e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ public abstract class TradeTask extends Task<Trade> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void failed(Throwable t) {
|
protected void failed(Throwable t) {
|
||||||
t.printStackTrace();
|
log.error("Trade task failed, error={}\n", t.getMessage(), t);
|
||||||
appendExceptionToErrorMessage(t);
|
appendExceptionToErrorMessage(t);
|
||||||
trade.setErrorMessage(errorMessage);
|
trade.setErrorMessage(errorMessage);
|
||||||
processModel.getTradeManager().requestPersistence();
|
processModel.getTradeManager().requestPersistence();
|
||||||
|
@ -132,6 +132,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
private final String xmrNodesFromOptions;
|
private final String xmrNodesFromOptions;
|
||||||
@Getter
|
@Getter
|
||||||
private final BooleanProperty useStandbyModeProperty = new SimpleBooleanProperty(prefPayload.isUseStandbyMode());
|
private final BooleanProperty useStandbyModeProperty = new SimpleBooleanProperty(prefPayload.isUseStandbyMode());
|
||||||
|
@Getter
|
||||||
|
private final BooleanProperty useSoundForNotificationsProperty = new SimpleBooleanProperty(prefPayload.isUseSoundForNotifications());
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
@ -162,6 +164,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
requestPersistence();
|
requestPersistence();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useSoundForNotificationsProperty.addListener((ov) -> {
|
||||||
|
prefPayload.setUseSoundForNotifications(useSoundForNotificationsProperty.get());
|
||||||
|
requestPersistence();
|
||||||
|
});
|
||||||
|
|
||||||
traditionalCurrenciesAsObservable.addListener((javafx.beans.Observable ov) -> {
|
traditionalCurrenciesAsObservable.addListener((javafx.beans.Observable ov) -> {
|
||||||
prefPayload.getTraditionalCurrencies().clear();
|
prefPayload.getTraditionalCurrencies().clear();
|
||||||
prefPayload.getTraditionalCurrencies().addAll(traditionalCurrenciesAsObservable);
|
prefPayload.getTraditionalCurrencies().addAll(traditionalCurrenciesAsObservable);
|
||||||
@ -259,6 +266,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
// set all properties
|
// set all properties
|
||||||
useAnimationsProperty.set(prefPayload.isUseAnimations());
|
useAnimationsProperty.set(prefPayload.isUseAnimations());
|
||||||
useStandbyModeProperty.set(prefPayload.isUseStandbyMode());
|
useStandbyModeProperty.set(prefPayload.isUseStandbyMode());
|
||||||
|
useSoundForNotificationsProperty.set(prefPayload.isUseSoundForNotifications());
|
||||||
cssThemeProperty.set(prefPayload.getCssTheme());
|
cssThemeProperty.set(prefPayload.getCssTheme());
|
||||||
|
|
||||||
|
|
||||||
@ -697,6 +705,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
this.useStandbyModeProperty.set(useStandbyMode);
|
this.useStandbyModeProperty.set(useStandbyMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUseSoundForNotifications(boolean useSoundForNotifications) {
|
||||||
|
this.useSoundForNotificationsProperty.set(useSoundForNotifications);
|
||||||
|
}
|
||||||
|
|
||||||
public void setTakeOfferSelectedPaymentAccountId(String value) {
|
public void setTakeOfferSelectedPaymentAccountId(String value) {
|
||||||
prefPayload.setTakeOfferSelectedPaymentAccountId(value);
|
prefPayload.setTakeOfferSelectedPaymentAccountId(value);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
@ -946,6 +958,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
|
|
||||||
void setUseStandbyMode(boolean useStandbyMode);
|
void setUseStandbyMode(boolean useStandbyMode);
|
||||||
|
|
||||||
|
void setUseSoundForNotifications(boolean useSoundForNotifications);
|
||||||
|
|
||||||
void setTakeOfferSelectedPaymentAccountId(String value);
|
void setTakeOfferSelectedPaymentAccountId(String value);
|
||||||
|
|
||||||
void setIgnoreDustThreshold(int value);
|
void setIgnoreDustThreshold(int value);
|
||||||
|
@ -108,6 +108,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||||||
private boolean useMarketNotifications = true;
|
private boolean useMarketNotifications = true;
|
||||||
private boolean usePriceNotifications = true;
|
private boolean usePriceNotifications = true;
|
||||||
private boolean useStandbyMode = false;
|
private boolean useStandbyMode = false;
|
||||||
|
private boolean useSoundForNotifications = true;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String rpcUser;
|
private String rpcUser;
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -185,6 +186,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||||||
.setUseMarketNotifications(useMarketNotifications)
|
.setUseMarketNotifications(useMarketNotifications)
|
||||||
.setUsePriceNotifications(usePriceNotifications)
|
.setUsePriceNotifications(usePriceNotifications)
|
||||||
.setUseStandbyMode(useStandbyMode)
|
.setUseStandbyMode(useStandbyMode)
|
||||||
|
.setUseSoundForNotifications(useSoundForNotifications)
|
||||||
.setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent)
|
.setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent)
|
||||||
.setIgnoreDustThreshold(ignoreDustThreshold)
|
.setIgnoreDustThreshold(ignoreDustThreshold)
|
||||||
.setClearDataAfterDays(clearDataAfterDays)
|
.setClearDataAfterDays(clearDataAfterDays)
|
||||||
@ -280,6 +282,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||||||
proto.getUseMarketNotifications(),
|
proto.getUseMarketNotifications(),
|
||||||
proto.getUsePriceNotifications(),
|
proto.getUsePriceNotifications(),
|
||||||
proto.getUseStandbyMode(),
|
proto.getUseStandbyMode(),
|
||||||
|
proto.getUseSoundForNotifications(),
|
||||||
proto.getRpcUser().isEmpty() ? null : proto.getRpcUser(),
|
proto.getRpcUser().isEmpty() ? null : proto.getRpcUser(),
|
||||||
proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(),
|
proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(),
|
||||||
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(),
|
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(),
|
||||||
|
@ -111,6 +111,7 @@ public class Balances {
|
|||||||
|
|
||||||
public XmrBalanceInfo getBalances() {
|
public XmrBalanceInfo getBalances() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
if (availableBalance == null) return null;
|
||||||
return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(),
|
return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(),
|
||||||
availableBalance.longValue(),
|
availableBalance.longValue(),
|
||||||
pendingBalance.longValue(),
|
pendingBalance.longValue(),
|
||||||
@ -127,6 +128,9 @@ public class Balances {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
synchronized (HavenoUtils.xmrWalletService.getWalletLock()) {
|
synchronized (HavenoUtils.xmrWalletService.getWalletLock()) {
|
||||||
|
|
||||||
|
// get non-trade balance before
|
||||||
|
BigInteger balanceSumBefore = getNonTradeBalanceSum();
|
||||||
|
|
||||||
// get wallet balances
|
// get wallet balances
|
||||||
BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance();
|
BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance();
|
||||||
availableBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getAvailableBalance();
|
availableBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getAvailableBalance();
|
||||||
@ -160,8 +164,25 @@ public class Balances {
|
|||||||
reservedBalance = reservedOfferBalance.add(reservedTradeBalance);
|
reservedBalance = reservedOfferBalance.add(reservedTradeBalance);
|
||||||
|
|
||||||
// notify balance update
|
// notify balance update
|
||||||
UserThread.execute(() -> updateCounter.set(updateCounter.get() + 1));
|
UserThread.execute(() -> {
|
||||||
|
|
||||||
|
// check if funds received
|
||||||
|
boolean fundsReceived = balanceSumBefore != null && getNonTradeBalanceSum().compareTo(balanceSumBefore) > 0;
|
||||||
|
if (fundsReceived) {
|
||||||
|
HavenoUtils.playCashRegisterSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// increase counter to notify listeners
|
||||||
|
updateCounter.set(updateCounter.get() + 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BigInteger getNonTradeBalanceSum() {
|
||||||
|
synchronized (this) {
|
||||||
|
if (availableBalance == null) return null;
|
||||||
|
return availableBalance.add(pendingBalance).add(reservedOfferBalance);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ public class XmrNodeSettings implements PersistableEnvelope {
|
|||||||
String bootstrapUrl;
|
String bootstrapUrl;
|
||||||
@Nullable
|
@Nullable
|
||||||
List<String> startupFlags;
|
List<String> startupFlags;
|
||||||
|
@Nullable
|
||||||
|
Boolean syncBlockchain;
|
||||||
|
|
||||||
public XmrNodeSettings() {
|
public XmrNodeSettings() {
|
||||||
}
|
}
|
||||||
@ -43,7 +45,8 @@ public class XmrNodeSettings implements PersistableEnvelope {
|
|||||||
return new XmrNodeSettings(
|
return new XmrNodeSettings(
|
||||||
proto.getBlockchainPath(),
|
proto.getBlockchainPath(),
|
||||||
proto.getBootstrapUrl(),
|
proto.getBootstrapUrl(),
|
||||||
proto.getStartupFlagsList());
|
proto.getStartupFlagsList(),
|
||||||
|
proto.getSyncBlockchain());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -52,6 +55,7 @@ public class XmrNodeSettings implements PersistableEnvelope {
|
|||||||
Optional.ofNullable(blockchainPath).ifPresent(e -> builder.setBlockchainPath(blockchainPath));
|
Optional.ofNullable(blockchainPath).ifPresent(e -> builder.setBlockchainPath(blockchainPath));
|
||||||
Optional.ofNullable(bootstrapUrl).ifPresent(e -> builder.setBootstrapUrl(bootstrapUrl));
|
Optional.ofNullable(bootstrapUrl).ifPresent(e -> builder.setBootstrapUrl(bootstrapUrl));
|
||||||
Optional.ofNullable(startupFlags).ifPresent(e -> builder.addAllStartupFlags(startupFlags));
|
Optional.ofNullable(startupFlags).ifPresent(e -> builder.addAllStartupFlags(startupFlags));
|
||||||
|
Optional.ofNullable(syncBlockchain).ifPresent(e -> builder.setSyncBlockchain(syncBlockchain));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
|
||||||
import haveno.common.Timer;
|
import haveno.common.Timer;
|
||||||
import haveno.common.UserThread;
|
import haveno.common.UserThread;
|
||||||
import haveno.core.api.XmrConnectionService;
|
import haveno.core.api.XmrConnectionService;
|
||||||
@ -106,7 +108,7 @@ public class XmrWalletBase {
|
|||||||
height = wallet.getHeight(); // can get read timeout while syncing
|
height = wallet.getHeight(); // can get read timeout while syncing
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error getting wallet height while syncing with progress: " + e.getMessage());
|
log.warn("Error getting wallet height while syncing with progress: " + e.getMessage());
|
||||||
if (wallet != null && !isShutDownStarted) e.printStackTrace();
|
if (wallet != null && !isShutDownStarted) log.warn(ExceptionUtils.getStackTrace(e));
|
||||||
|
|
||||||
// stop polling and release latch
|
// stop polling and release latch
|
||||||
syncProgressError = e;
|
syncProgressError = e;
|
||||||
|
@ -818,7 +818,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
MoneroFeeEstimate feeEstimates = getDaemon().getFeeEstimate();
|
MoneroFeeEstimate feeEstimates = getDaemon().getFeeEstimate();
|
||||||
BigInteger baseFeeEstimate = feeEstimates.getFees().get(2); // get elevated fee per kB
|
BigInteger baseFeeEstimate = feeEstimates.getFees().get(2); // get elevated fee per kB
|
||||||
BigInteger qmask = feeEstimates.getQuantizationMask();
|
BigInteger qmask = feeEstimates.getQuantizationMask();
|
||||||
log.info("Monero base fee estimate={}, qmask={}: " + baseFeeEstimate, qmask);
|
log.info("Monero base fee estimate={}, qmask={}", baseFeeEstimate, qmask);
|
||||||
|
|
||||||
// get tx base fee
|
// get tx base fee
|
||||||
BigInteger baseFee = baseFeeEstimate.multiply(BigInteger.valueOf(txWeight));
|
BigInteger baseFee = baseFeeEstimate.multiply(BigInteger.valueOf(txWeight));
|
||||||
@ -922,8 +922,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
try {
|
try {
|
||||||
ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS);
|
ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error shutting down {}: {}", getClass().getSimpleName(), e.getMessage());
|
log.warn("Error shutting down {}: {}\n", getClass().getSimpleName(), e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
// force close wallet
|
// force close wallet
|
||||||
forceCloseMainWallet();
|
forceCloseMainWallet();
|
||||||
@ -945,8 +944,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
List<XmrAddressEntry> unusedAddressEntries = getUnusedAddressEntries();
|
List<XmrAddressEntry> unusedAddressEntries = getUnusedAddressEntries();
|
||||||
if (!unusedAddressEntries.isEmpty()) return xmrAddressEntryList.swapAvailableToAddressEntryWithOfferId(unusedAddressEntries.get(0), context, offerId);
|
if (!unusedAddressEntries.isEmpty()) return xmrAddressEntryList.swapAvailableToAddressEntryWithOfferId(unusedAddressEntries.get(0), context, offerId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error getting new address entry based on incoming transactions");
|
log.warn("Error getting new address entry based on incoming transactions: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new entry
|
// create new entry
|
||||||
@ -1172,8 +1170,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
try {
|
try {
|
||||||
balanceListener.onBalanceChanged(balance);
|
balanceListener.onBalanceChanged(balance);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Failed to notify balance listener of change");
|
log.warn("Failed to notify balance listener of change: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1309,8 +1306,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
try {
|
try {
|
||||||
doMaybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
doMaybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error initializing main wallet: " + e.getMessage());
|
log.warn("Error initializing main wallet: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
HavenoUtils.setTopError(e.getMessage());
|
HavenoUtils.setTopError(e.getMessage());
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -1459,9 +1455,10 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
log.info("Done creating full wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms");
|
log.info("Done creating full wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms");
|
||||||
return walletFull;
|
return walletFull;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
String errorMsg = "Could not create wallet '" + config.getPath() + "': " + e.getMessage();
|
||||||
|
log.warn(errorMsg + "\n", e);
|
||||||
if (walletFull != null) forceCloseWallet(walletFull, config.getPath());
|
if (walletFull != null) forceCloseWallet(walletFull, config.getPath());
|
||||||
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'");
|
throw new IllegalStateException(errorMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,9 +1522,10 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
log.info("Done opening full wallet " + config.getPath());
|
log.info("Done opening full wallet " + config.getPath());
|
||||||
return walletFull;
|
return walletFull;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
String errorMsg = "Could not open full wallet '" + config.getPath() + "': " + e.getMessage();
|
||||||
|
log.warn(errorMsg + "\n", e);
|
||||||
if (walletFull != null) forceCloseWallet(walletFull, config.getPath());
|
if (walletFull != null) forceCloseWallet(walletFull, config.getPath());
|
||||||
throw new IllegalStateException("Could not open full wallet '" + config.getPath() + "'");
|
throw new IllegalStateException(errorMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1557,7 +1555,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
log.info("Done creating RPC wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms");
|
log.info("Done creating RPC wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms");
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Could not create wallet '" + config.getPath() + "': " + e.getMessage() + "\n", e);
|
||||||
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
|
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
|
||||||
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.");
|
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.");
|
||||||
}
|
}
|
||||||
@ -1629,7 +1627,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
log.info("Done opening RPC wallet " + config.getPath());
|
log.info("Done opening RPC wallet " + config.getPath());
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Could not open wallet '" + config.getPath() + "': " + e.getMessage() + "\n", e);
|
||||||
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
|
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
|
||||||
throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.\n\nError message: " + e.getMessage());
|
throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.\n\nError message: " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -1733,7 +1731,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
wallet.changePassword(oldPassword, newPassword);
|
wallet.changePassword(oldPassword, newPassword);
|
||||||
saveMainWallet();
|
saveMainWallet();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Error changing main wallet password: " + e.getMessage() + "\n", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1916,7 +1914,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||||||
cacheWalletInfo();
|
cacheWalletInfo();
|
||||||
requestSaveMainWallet();
|
requestSaveMainWallet();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Error caching wallet info: " + e.getMessage() + "\n", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
core/src/main/resources/cash_register.wav
Normal file
BIN
core/src/main/resources/cash_register.wav
Normal file
Binary file not shown.
BIN
core/src/main/resources/chime.wav
Normal file
BIN
core/src/main/resources/chime.wav
Normal file
Binary file not shown.
@ -1266,6 +1266,7 @@ setting.preferences.general=General preferences
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Max. deviation from market price
|
setting.preferences.deviation=Max. deviation from market price
|
||||||
setting.preferences.avoidStandbyMode=Avoid standby mode
|
setting.preferences.avoidStandbyMode=Avoid standby mode
|
||||||
|
setting.preferences.useSoundForNotifications=Play sounds for notifications
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -987,6 +987,7 @@ setting.preferences.general=Základní nastavení
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Max. odchylka od tržní ceny
|
setting.preferences.deviation=Max. odchylka od tržní ceny
|
||||||
setting.preferences.avoidStandbyMode=Vyhněte se pohotovostnímu režimu
|
setting.preferences.avoidStandbyMode=Vyhněte se pohotovostnímu režimu
|
||||||
|
setting.preferences.useSoundForNotifications=Přehrávat zvuky pro upozornění
|
||||||
setting.preferences.autoConfirmXMR=Automatické potvrzení XMR
|
setting.preferences.autoConfirmXMR=Automatické potvrzení XMR
|
||||||
setting.preferences.autoConfirmEnabled=Povoleno
|
setting.preferences.autoConfirmEnabled=Povoleno
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Požadovaná potvrzení
|
setting.preferences.autoConfirmRequiredConfirmations=Požadovaná potvrzení
|
||||||
|
@ -987,6 +987,7 @@ setting.preferences.general=Allgemeine Voreinstellungen
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Max. Abweichung vom Marktpreis
|
setting.preferences.deviation=Max. Abweichung vom Marktpreis
|
||||||
setting.preferences.avoidStandbyMode=Standby Modus verhindern
|
setting.preferences.avoidStandbyMode=Standby Modus verhindern
|
||||||
|
setting.preferences.useSoundForNotifications=Spiele Geräusche für Benachrichtigungen
|
||||||
setting.preferences.autoConfirmXMR=XMR automatische Bestätigung
|
setting.preferences.autoConfirmXMR=XMR automatische Bestätigung
|
||||||
setting.preferences.autoConfirmEnabled=Aktiviert
|
setting.preferences.autoConfirmEnabled=Aktiviert
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Benötigte Bestätigungen
|
setting.preferences.autoConfirmRequiredConfirmations=Benötigte Bestätigungen
|
||||||
|
@ -988,6 +988,7 @@ setting.preferences.general=Preferencias generales
|
|||||||
setting.preferences.explorer=Explorador Monero
|
setting.preferences.explorer=Explorador Monero
|
||||||
setting.preferences.deviation=Desviación máxima del precio de mercado
|
setting.preferences.deviation=Desviación máxima del precio de mercado
|
||||||
setting.preferences.setting.preferences.avoidStandbyMode=Evitar modo en espera
|
setting.preferences.setting.preferences.avoidStandbyMode=Evitar modo en espera
|
||||||
|
setting.preferences.useSoundForNotifications=Reproducir sonidos para notificaciones
|
||||||
setting.preferences.autoConfirmXMR=Autoconfirmación XMR
|
setting.preferences.autoConfirmXMR=Autoconfirmación XMR
|
||||||
setting.preferences.autoConfirmEnabled=Habilitado
|
setting.preferences.autoConfirmEnabled=Habilitado
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Confirmaciones requeridas
|
setting.preferences.autoConfirmRequiredConfirmations=Confirmaciones requeridas
|
||||||
|
@ -984,6 +984,7 @@ setting.preferences.general=اولویتهای عمومی
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=حداکثر تفاوت از قیمت روز بازار
|
setting.preferences.deviation=حداکثر تفاوت از قیمت روز بازار
|
||||||
setting.preferences.avoidStandbyMode=حالت «آماده باش» را نادیده بگیر
|
setting.preferences.avoidStandbyMode=حالت «آماده باش» را نادیده بگیر
|
||||||
|
setting.preferences.useSoundForNotifications=پخش صداها برای اعلانها
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -989,6 +989,7 @@ setting.preferences.general=Préférences générales
|
|||||||
setting.preferences.explorer=Exploreur Monero
|
setting.preferences.explorer=Exploreur Monero
|
||||||
setting.preferences.deviation=Ecart maximal par rapport au prix du marché
|
setting.preferences.deviation=Ecart maximal par rapport au prix du marché
|
||||||
setting.preferences.avoidStandbyMode=Éviter le mode veille
|
setting.preferences.avoidStandbyMode=Éviter le mode veille
|
||||||
|
setting.preferences.useSoundForNotifications=Jouer des sons pour les notifications
|
||||||
setting.preferences.autoConfirmXMR=Auto-confirmation XMR
|
setting.preferences.autoConfirmXMR=Auto-confirmation XMR
|
||||||
setting.preferences.autoConfirmEnabled=Activé
|
setting.preferences.autoConfirmEnabled=Activé
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Confirmations requises
|
setting.preferences.autoConfirmRequiredConfirmations=Confirmations requises
|
||||||
|
@ -986,6 +986,7 @@ setting.preferences.general=Preferenze generali
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Deviazione massima del prezzo di mercato
|
setting.preferences.deviation=Deviazione massima del prezzo di mercato
|
||||||
setting.preferences.avoidStandbyMode=Evita modalità standby
|
setting.preferences.avoidStandbyMode=Evita modalità standby
|
||||||
|
setting.preferences.useSoundForNotifications=Riproduci suoni per le notifiche
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -987,6 +987,7 @@ setting.preferences.general=一般設定
|
|||||||
setting.preferences.explorer=ビットコインのエクスプローラ
|
setting.preferences.explorer=ビットコインのエクスプローラ
|
||||||
setting.preferences.deviation=市場価格からの最大偏差
|
setting.preferences.deviation=市場価格からの最大偏差
|
||||||
setting.preferences.avoidStandbyMode=スタンバイモードを避ける
|
setting.preferences.avoidStandbyMode=スタンバイモードを避ける
|
||||||
|
setting.preferences.useSoundForNotifications=通知音の再生
|
||||||
setting.preferences.autoConfirmXMR=XMR自動確認
|
setting.preferences.autoConfirmXMR=XMR自動確認
|
||||||
setting.preferences.autoConfirmEnabled=有効されました
|
setting.preferences.autoConfirmEnabled=有効されました
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=必要承認
|
setting.preferences.autoConfirmRequiredConfirmations=必要承認
|
||||||
|
@ -988,6 +988,7 @@ setting.preferences.general=Preferências gerais
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Desvio máx. do preço do mercado
|
setting.preferences.deviation=Desvio máx. do preço do mercado
|
||||||
setting.preferences.avoidStandbyMode=Impedir modo de economia de energia
|
setting.preferences.avoidStandbyMode=Impedir modo de economia de energia
|
||||||
|
setting.preferences.useSoundForNotifications=Reproduzir sons para notificações
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -985,6 +985,7 @@ setting.preferences.general=Preferências gerais
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Máx. desvio do preço de mercado
|
setting.preferences.deviation=Máx. desvio do preço de mercado
|
||||||
setting.preferences.avoidStandbyMode=Evite o modo espera
|
setting.preferences.avoidStandbyMode=Evite o modo espera
|
||||||
|
setting.preferences.useSoundForNotifications=Reproduzir sons para notificações
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -984,6 +984,7 @@ setting.preferences.general=Основные настройки
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Макс. отклонение от рыночного курса
|
setting.preferences.deviation=Макс. отклонение от рыночного курса
|
||||||
setting.preferences.avoidStandbyMode=Избегать режима ожидания
|
setting.preferences.avoidStandbyMode=Избегать режима ожидания
|
||||||
|
setting.preferences.useSoundForNotifications=Воспроизводить звуки для уведомлений
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -984,6 +984,7 @@ setting.preferences.general=การตั้งค่าทั่วไป
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=สูงสุด ส่วนเบี่ยงเบนจากราคาตลาด
|
setting.preferences.deviation=สูงสุด ส่วนเบี่ยงเบนจากราคาตลาด
|
||||||
setting.preferences.avoidStandbyMode=หลีกเลี่ยงโหมดแสตนบายด์
|
setting.preferences.avoidStandbyMode=หลีกเลี่ยงโหมดแสตนบายด์
|
||||||
|
setting.preferences.useSoundForNotifications=เล่นเสียงสำหรับการแจ้งเตือน
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -1261,6 +1261,7 @@ setting.preferences.general=Genel tercihler
|
|||||||
setting.preferences.explorer=Monero Gezgini
|
setting.preferences.explorer=Monero Gezgini
|
||||||
setting.preferences.deviation=Piyasa fiyatından maksimum sapma
|
setting.preferences.deviation=Piyasa fiyatından maksimum sapma
|
||||||
setting.preferences.avoidStandbyMode=Bekleme modundan kaçın
|
setting.preferences.avoidStandbyMode=Bekleme modundan kaçın
|
||||||
|
setting.preferences.useSoundForNotifications=Bildirimler için sesleri çal
|
||||||
setting.preferences.autoConfirmXMR=XMR otomatik onay
|
setting.preferences.autoConfirmXMR=XMR otomatik onay
|
||||||
setting.preferences.autoConfirmEnabled=Etkin
|
setting.preferences.autoConfirmEnabled=Etkin
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Gerekli onaylar
|
setting.preferences.autoConfirmRequiredConfirmations=Gerekli onaylar
|
||||||
|
@ -986,6 +986,7 @@ setting.preferences.general=Tham khảo chung
|
|||||||
setting.preferences.explorer=Monero Explorer
|
setting.preferences.explorer=Monero Explorer
|
||||||
setting.preferences.deviation=Sai lệch tối đa so với giá thị trường
|
setting.preferences.deviation=Sai lệch tối đa so với giá thị trường
|
||||||
setting.preferences.avoidStandbyMode=Tránh để chế độ chờ
|
setting.preferences.avoidStandbyMode=Tránh để chế độ chờ
|
||||||
|
setting.preferences.useSoundForNotifications=Phát âm thanh cho thông báo
|
||||||
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
setting.preferences.autoConfirmXMR=XMR auto-confirm
|
||||||
setting.preferences.autoConfirmEnabled=Enabled
|
setting.preferences.autoConfirmEnabled=Enabled
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
|
||||||
|
@ -987,6 +987,7 @@ setting.preferences.general=通用偏好
|
|||||||
setting.preferences.explorer=比特币区块浏览器
|
setting.preferences.explorer=比特币区块浏览器
|
||||||
setting.preferences.deviation=与市场价格最大差价
|
setting.preferences.deviation=与市场价格最大差价
|
||||||
setting.preferences.avoidStandbyMode=避免待机模式
|
setting.preferences.avoidStandbyMode=避免待机模式
|
||||||
|
setting.preferences.useSoundForNotifications=播放通知声音
|
||||||
setting.preferences.autoConfirmXMR=XMR 自动确认
|
setting.preferences.autoConfirmXMR=XMR 自动确认
|
||||||
setting.preferences.autoConfirmEnabled=启用
|
setting.preferences.autoConfirmEnabled=启用
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=已要求确认
|
setting.preferences.autoConfirmRequiredConfirmations=已要求确认
|
||||||
|
@ -987,6 +987,7 @@ setting.preferences.general=通用偏好
|
|||||||
setting.preferences.explorer=比特幣區塊瀏覽器
|
setting.preferences.explorer=比特幣區塊瀏覽器
|
||||||
setting.preferences.deviation=與市場價格最大差價
|
setting.preferences.deviation=與市場價格最大差價
|
||||||
setting.preferences.avoidStandbyMode=避免待機模式
|
setting.preferences.avoidStandbyMode=避免待機模式
|
||||||
|
setting.preferences.useSoundForNotifications=播放通知音效
|
||||||
setting.preferences.autoConfirmXMR=XMR 自動確認
|
setting.preferences.autoConfirmXMR=XMR 自動確認
|
||||||
setting.preferences.autoConfirmEnabled=啟用
|
setting.preferences.autoConfirmEnabled=啟用
|
||||||
setting.preferences.autoConfirmRequiredConfirmations=已要求確認
|
setting.preferences.autoConfirmRequiredConfirmations=已要求確認
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
package haveno.desktop.main.account.content.cryptoaccounts;
|
package haveno.desktop.main.account.content.cryptoaccounts;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import haveno.common.crypto.KeyRing;
|
|
||||||
import haveno.common.file.CorruptedStorageFileHandler;
|
import haveno.common.file.CorruptedStorageFileHandler;
|
||||||
import haveno.common.proto.persistable.PersistenceProtoResolver;
|
import haveno.common.proto.persistable.PersistenceProtoResolver;
|
||||||
import haveno.core.account.witness.AccountAgeWitnessService;
|
import haveno.core.account.witness.AccountAgeWitnessService;
|
||||||
@ -55,7 +54,6 @@ class CryptoAccountsDataModel extends ActivatableDataModel {
|
|||||||
private final String accountsFileName = "CryptoPaymentAccounts";
|
private final String accountsFileName = "CryptoPaymentAccounts";
|
||||||
private final PersistenceProtoResolver persistenceProtoResolver;
|
private final PersistenceProtoResolver persistenceProtoResolver;
|
||||||
private final CorruptedStorageFileHandler corruptedStorageFileHandler;
|
private final CorruptedStorageFileHandler corruptedStorageFileHandler;
|
||||||
private final KeyRing keyRing;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CryptoAccountsDataModel(User user,
|
public CryptoAccountsDataModel(User user,
|
||||||
@ -64,8 +62,7 @@ class CryptoAccountsDataModel extends ActivatableDataModel {
|
|||||||
TradeManager tradeManager,
|
TradeManager tradeManager,
|
||||||
AccountAgeWitnessService accountAgeWitnessService,
|
AccountAgeWitnessService accountAgeWitnessService,
|
||||||
PersistenceProtoResolver persistenceProtoResolver,
|
PersistenceProtoResolver persistenceProtoResolver,
|
||||||
CorruptedStorageFileHandler corruptedStorageFileHandler,
|
CorruptedStorageFileHandler corruptedStorageFileHandler) {
|
||||||
KeyRing keyRing) {
|
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.openOfferManager = openOfferManager;
|
this.openOfferManager = openOfferManager;
|
||||||
@ -73,7 +70,6 @@ class CryptoAccountsDataModel extends ActivatableDataModel {
|
|||||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||||
this.persistenceProtoResolver = persistenceProtoResolver;
|
this.persistenceProtoResolver = persistenceProtoResolver;
|
||||||
this.corruptedStorageFileHandler = corruptedStorageFileHandler;
|
this.corruptedStorageFileHandler = corruptedStorageFileHandler;
|
||||||
this.keyRing = keyRing;
|
|
||||||
setChangeListener = change -> fillAndSortPaymentAccounts();
|
setChangeListener = change -> fillAndSortPaymentAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,12 +153,12 @@ class CryptoAccountsDataModel extends ActivatableDataModel {
|
|||||||
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
||||||
.filter(paymentAccount -> paymentAccount instanceof AssetAccount)
|
.filter(paymentAccount -> paymentAccount instanceof AssetAccount)
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importAccounts(Stage stage) {
|
public void importAccounts(Stage stage) {
|
||||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumPaymentAccounts() {
|
public int getNumPaymentAccounts() {
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
package haveno.desktop.main.account.content.traditionalaccounts;
|
package haveno.desktop.main.account.content.traditionalaccounts;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import haveno.common.crypto.KeyRing;
|
|
||||||
import haveno.common.file.CorruptedStorageFileHandler;
|
import haveno.common.file.CorruptedStorageFileHandler;
|
||||||
import haveno.common.proto.persistable.PersistenceProtoResolver;
|
import haveno.common.proto.persistable.PersistenceProtoResolver;
|
||||||
import haveno.core.account.witness.AccountAgeWitnessService;
|
import haveno.core.account.witness.AccountAgeWitnessService;
|
||||||
@ -56,7 +55,6 @@ class TraditionalAccountsDataModel extends ActivatableDataModel {
|
|||||||
private final String accountsFileName = "FiatPaymentAccounts";
|
private final String accountsFileName = "FiatPaymentAccounts";
|
||||||
private final PersistenceProtoResolver persistenceProtoResolver;
|
private final PersistenceProtoResolver persistenceProtoResolver;
|
||||||
private final CorruptedStorageFileHandler corruptedStorageFileHandler;
|
private final CorruptedStorageFileHandler corruptedStorageFileHandler;
|
||||||
private final KeyRing keyRing;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TraditionalAccountsDataModel(User user,
|
public TraditionalAccountsDataModel(User user,
|
||||||
@ -65,8 +63,7 @@ class TraditionalAccountsDataModel extends ActivatableDataModel {
|
|||||||
TradeManager tradeManager,
|
TradeManager tradeManager,
|
||||||
AccountAgeWitnessService accountAgeWitnessService,
|
AccountAgeWitnessService accountAgeWitnessService,
|
||||||
PersistenceProtoResolver persistenceProtoResolver,
|
PersistenceProtoResolver persistenceProtoResolver,
|
||||||
CorruptedStorageFileHandler corruptedStorageFileHandler,
|
CorruptedStorageFileHandler corruptedStorageFileHandler) {
|
||||||
KeyRing keyRing) {
|
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.openOfferManager = openOfferManager;
|
this.openOfferManager = openOfferManager;
|
||||||
@ -74,7 +71,6 @@ class TraditionalAccountsDataModel extends ActivatableDataModel {
|
|||||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||||
this.persistenceProtoResolver = persistenceProtoResolver;
|
this.persistenceProtoResolver = persistenceProtoResolver;
|
||||||
this.corruptedStorageFileHandler = corruptedStorageFileHandler;
|
this.corruptedStorageFileHandler = corruptedStorageFileHandler;
|
||||||
this.keyRing = keyRing;
|
|
||||||
setChangeListener = change -> fillAndSortPaymentAccounts();
|
setChangeListener = change -> fillAndSortPaymentAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,12 +155,12 @@ class TraditionalAccountsDataModel extends ActivatableDataModel {
|
|||||||
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
||||||
.filter(paymentAccount -> !(paymentAccount instanceof AssetAccount))
|
.filter(paymentAccount -> !(paymentAccount instanceof AssetAccount))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importAccounts(Stage stage) {
|
public void importAccounts(Stage stage) {
|
||||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumPaymentAccounts() {
|
public int getNumPaymentAccounts() {
|
||||||
|
@ -54,6 +54,7 @@ class TransactionsListItem {
|
|||||||
private boolean received;
|
private boolean received;
|
||||||
private boolean detailsAvailable;
|
private boolean detailsAvailable;
|
||||||
private BigInteger amount = BigInteger.ZERO;
|
private BigInteger amount = BigInteger.ZERO;
|
||||||
|
private BigInteger txFee = BigInteger.ZERO;
|
||||||
private String memo = "";
|
private String memo = "";
|
||||||
private long confirmations = 0;
|
private long confirmations = 0;
|
||||||
@Getter
|
@Getter
|
||||||
@ -107,6 +108,7 @@ class TransactionsListItem {
|
|||||||
amount = valueSentFromMe.multiply(BigInteger.valueOf(-1));
|
amount = valueSentFromMe.multiply(BigInteger.valueOf(-1));
|
||||||
received = false;
|
received = false;
|
||||||
direction = Res.get("funds.tx.direction.sentTo");
|
direction = Res.get("funds.tx.direction.sentTo");
|
||||||
|
txFee = tx.getFee().multiply(BigInteger.valueOf(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionalTradable.isPresent()) {
|
if (optionalTradable.isPresent()) {
|
||||||
@ -201,6 +203,14 @@ class TransactionsListItem {
|
|||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigInteger getTxFee() {
|
||||||
|
return txFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTxFeeStr() {
|
||||||
|
return txFee.equals(BigInteger.ZERO) ? "" : HavenoUtils.formatXmr(txFee);
|
||||||
|
}
|
||||||
|
|
||||||
public String getAddressString() {
|
public String getAddressString() {
|
||||||
return addressString;
|
return addressString;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
<TableColumn fx:id="detailsColumn" minWidth="220" maxWidth="220"/>
|
<TableColumn fx:id="detailsColumn" minWidth="220" maxWidth="220"/>
|
||||||
<TableColumn fx:id="addressColumn" minWidth="260"/>
|
<TableColumn fx:id="addressColumn" minWidth="260"/>
|
||||||
<TableColumn fx:id="transactionColumn" minWidth="180"/>
|
<TableColumn fx:id="transactionColumn" minWidth="180"/>
|
||||||
<TableColumn fx:id="amountColumn" minWidth="130" maxWidth="130"/>
|
<TableColumn fx:id="amountColumn" minWidth="110" maxWidth="110"/>
|
||||||
|
<TableColumn fx:id="txFeeColumn" minWidth="110" maxWidth="110"/>
|
||||||
<TableColumn fx:id="memoColumn" minWidth="40"/>
|
<TableColumn fx:id="memoColumn" minWidth="40"/>
|
||||||
<TableColumn fx:id="confidenceColumn" minWidth="120" maxWidth="130"/>
|
<TableColumn fx:id="confidenceColumn" minWidth="120" maxWidth="130"/>
|
||||||
<TableColumn fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110" visible="false"/>
|
<TableColumn fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110" visible="false"/>
|
||||||
|
@ -70,7 +70,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
@FXML
|
@FXML
|
||||||
TableView<TransactionsListItem> tableView;
|
TableView<TransactionsListItem> tableView;
|
||||||
@FXML
|
@FXML
|
||||||
TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, memoColumn, confidenceColumn, revertTxColumn;
|
TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, txFeeColumn, memoColumn, confidenceColumn, revertTxColumn;
|
||||||
@FXML
|
@FXML
|
||||||
Label numItems;
|
Label numItems;
|
||||||
@FXML
|
@FXML
|
||||||
@ -89,7 +89,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||||
private Scene scene;
|
private Scene scene;
|
||||||
|
|
||||||
private TransactionsUpdater transactionsUpdater = new TransactionsUpdater();
|
private final TransactionsUpdater transactionsUpdater = new TransactionsUpdater();
|
||||||
|
|
||||||
private class TransactionsUpdater extends MoneroWalletListener {
|
private class TransactionsUpdater extends MoneroWalletListener {
|
||||||
@Override
|
@Override
|
||||||
@ -129,11 +129,12 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
||||||
transactionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txId", Res.getBaseCurrencyCode())));
|
transactionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txId", Res.getBaseCurrencyCode())));
|
||||||
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
|
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
|
||||||
|
txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee", Res.getBaseCurrencyCode())));
|
||||||
memoColumn.setGraphic(new AutoTooltipLabel(Res.get("funds.tx.memo")));
|
memoColumn.setGraphic(new AutoTooltipLabel(Res.get("funds.tx.memo")));
|
||||||
confidenceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.confirmations", Res.getBaseCurrencyCode())));
|
confidenceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.confirmations", Res.getBaseCurrencyCode())));
|
||||||
revertTxColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.revert", Res.getBaseCurrencyCode())));
|
revertTxColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.revert", Res.getBaseCurrencyCode())));
|
||||||
|
|
||||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
|
||||||
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.tx.noTxAvailable")));
|
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.tx.noTxAvailable")));
|
||||||
|
|
||||||
setDateColumnCellFactory();
|
setDateColumnCellFactory();
|
||||||
@ -141,6 +142,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
setAddressColumnCellFactory();
|
setAddressColumnCellFactory();
|
||||||
setTransactionColumnCellFactory();
|
setTransactionColumnCellFactory();
|
||||||
setAmountColumnCellFactory();
|
setAmountColumnCellFactory();
|
||||||
|
setTxFeeColumnCellFactory();
|
||||||
setMemoColumnCellFactory();
|
setMemoColumnCellFactory();
|
||||||
setConfidenceColumnCellFactory();
|
setConfidenceColumnCellFactory();
|
||||||
setRevertTxColumnCellFactory();
|
setRevertTxColumnCellFactory();
|
||||||
@ -156,7 +158,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString()));
|
addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString()));
|
||||||
transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId));
|
transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId));
|
||||||
amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmount));
|
amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmount));
|
||||||
confidenceColumn.setComparator(Comparator.comparingLong(item -> item.getNumConfirmations()));
|
confidenceColumn.setComparator(Comparator.comparingLong(TransactionsListItem::getNumConfirmations));
|
||||||
memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo));
|
memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo));
|
||||||
|
|
||||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||||
@ -216,8 +218,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
columns[2] = item.getDirection() + " " + item.getAddressString();
|
columns[2] = item.getDirection() + " " + item.getAddressString();
|
||||||
columns[3] = item.getTxId();
|
columns[3] = item.getTxId();
|
||||||
columns[4] = item.getAmountStr();
|
columns[4] = item.getAmountStr();
|
||||||
columns[5] = item.getMemo() == null ? "" : item.getMemo();
|
columns[5] = item.getTxFeeStr();
|
||||||
columns[6] = String.valueOf(item.getNumConfirmations());
|
columns[6] = item.getMemo() == null ? "" : item.getMemo();
|
||||||
|
columns[7] = String.valueOf(item.getNumConfirmations());
|
||||||
return columns;
|
return columns;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -414,6 +417,33 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setTxFeeColumnCellFactory() {
|
||||||
|
txFeeColumn.setCellValueFactory((addressListItem) ->
|
||||||
|
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
||||||
|
txFeeColumn.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableCell<TransactionsListItem, TransactionsListItem> call(TableColumn<TransactionsListItem,
|
||||||
|
TransactionsListItem> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final TransactionsListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty) {
|
||||||
|
setGraphic(new AutoTooltipLabel(item.getTxFeeStr()));
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setMemoColumnCellFactory() {
|
private void setMemoColumnCellFactory() {
|
||||||
memoColumn.setCellValueFactory((addressListItem) ->
|
memoColumn.setCellValueFactory((addressListItem) ->
|
||||||
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
||||||
|
@ -678,8 +678,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||||||
closeTicketButton.disableProperty().unbind();
|
closeTicketButton.disableProperty().unbind();
|
||||||
hide();
|
hide();
|
||||||
}, (errMessage, err) -> {
|
}, (errMessage, err) -> {
|
||||||
log.error("Error closing dispute ticket: " + errMessage);
|
log.error("Error closing dispute ticket: " + errMessage + "\n", err);
|
||||||
err.printStackTrace();
|
|
||||||
new Popup().error(err.toString()).show();
|
new Popup().error(err.toString()).show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -153,8 +153,7 @@ public abstract class TradeSubView extends HBox {
|
|||||||
tradeStepView.setChatCallback(chatCallback);
|
tradeStepView.setChatCallback(chatCallback);
|
||||||
tradeStepView.activate();
|
tradeStepView.activate();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Creating viewClass {} caused an error {}", viewClass, e.getMessage());
|
log.error("Creating viewClass {} caused an error {}\n", viewClass, e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||||||
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
|
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
|
||||||
|
|
||||||
private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically,
|
private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically,
|
||||||
avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle,
|
avoidStandbyMode, useSoundForNotifications, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle,
|
||||||
notifyOnPreReleaseToggle;
|
notifyOnPreReleaseToggle;
|
||||||
private int gridRow = 0;
|
private int gridRow = 0;
|
||||||
private int displayCurrenciesGridRowIndex = 0;
|
private int displayCurrenciesGridRowIndex = 0;
|
||||||
@ -209,7 +209,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void initializeGeneralOptions() {
|
private void initializeGeneralOptions() {
|
||||||
int titledGroupBgRowSpan = displayStandbyModeFeature ? 7 : 6;
|
int titledGroupBgRowSpan = displayStandbyModeFeature ? 8 : 7;
|
||||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, titledGroupBgRowSpan, Res.get("setting.preferences.general"));
|
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, titledGroupBgRowSpan, Res.get("setting.preferences.general"));
|
||||||
GridPane.setColumnSpan(titledGroupBg, 1);
|
GridPane.setColumnSpan(titledGroupBg, 1);
|
||||||
|
|
||||||
@ -285,6 +285,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||||||
avoidStandbyMode = addSlideToggleButton(root, ++gridRow,
|
avoidStandbyMode = addSlideToggleButton(root, ++gridRow,
|
||||||
Res.get("setting.preferences.avoidStandbyMode"));
|
Res.get("setting.preferences.avoidStandbyMode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useSoundForNotifications = addSlideToggleButton(root, ++gridRow,
|
||||||
|
Res.get("setting.preferences.useSoundForNotifications"), Layout.GROUP_DISTANCE * -1); // TODO: why must negative value be used to place toggle consistently?
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSeparator() {
|
private void initializeSeparator() {
|
||||||
@ -518,6 +521,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||||||
GridPane.setHgrow(resetDontShowAgainButton, Priority.ALWAYS);
|
GridPane.setHgrow(resetDontShowAgainButton, Priority.ALWAYS);
|
||||||
GridPane.setColumnIndex(resetDontShowAgainButton, 0);
|
GridPane.setColumnIndex(resetDontShowAgainButton, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeAutoConfirmOptions() {
|
private void initializeAutoConfirmOptions() {
|
||||||
GridPane autoConfirmGridPane = new GridPane();
|
GridPane autoConfirmGridPane = new GridPane();
|
||||||
GridPane.setHgrow(autoConfirmGridPane, Priority.ALWAYS);
|
GridPane.setHgrow(autoConfirmGridPane, Priority.ALWAYS);
|
||||||
@ -790,6 +794,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||||||
} else {
|
} else {
|
||||||
preferences.setUseStandbyMode(false);
|
preferences.setUseStandbyMode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useSoundForNotifications.setSelected(preferences.isUseSoundForNotifications());
|
||||||
|
useSoundForNotifications.setOnAction(e -> preferences.setUseSoundForNotifications(useSoundForNotifications.isSelected()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activateAutoConfirmPreferences() {
|
private void activateAutoConfirmPreferences() {
|
||||||
|
@ -65,6 +65,7 @@ import javafx.scene.text.TextAlignment;
|
|||||||
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
@ -565,12 +566,10 @@ public class ChatView extends AnchorPane {
|
|||||||
inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + result.getName() + "]");
|
inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + result.getName() + "]");
|
||||||
}
|
}
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException e) {
|
||||||
e.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
}
|
||||||
} catch (MalformedURLException e2) {
|
} catch (MalformedURLException e2) {
|
||||||
e2.printStackTrace();
|
log.error(ExceptionUtils.getStackTrace(e2));
|
||||||
log.error(e2.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -593,8 +592,7 @@ public class ChatView extends AnchorPane {
|
|||||||
inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + name + "]");
|
inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + name + "]");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e.toString());
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,8 +627,7 @@ public class ChatView extends AnchorPane {
|
|||||||
try (FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath())) {
|
try (FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath())) {
|
||||||
fileOutputStream.write(attachment.getBytes());
|
fileOutputStream.write(attachment.getBytes());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
log.error("Error opening attachment: {}\n", e.getMessage(), e);
|
||||||
System.out.println(e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import com.googlecode.jcsv.writer.internal.CSVWriterBuilder;
|
|||||||
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
|
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
|
||||||
import haveno.common.UserThread;
|
import haveno.common.UserThread;
|
||||||
import haveno.common.config.Config;
|
import haveno.common.config.Config;
|
||||||
import haveno.common.crypto.KeyRing;
|
|
||||||
import haveno.common.file.CorruptedStorageFileHandler;
|
import haveno.common.file.CorruptedStorageFileHandler;
|
||||||
import haveno.common.persistence.PersistenceManager;
|
import haveno.common.persistence.PersistenceManager;
|
||||||
import haveno.common.proto.persistable.PersistableEnvelope;
|
import haveno.common.proto.persistable.PersistableEnvelope;
|
||||||
@ -168,12 +167,11 @@ public class GUIUtil {
|
|||||||
Preferences preferences,
|
Preferences preferences,
|
||||||
Stage stage,
|
Stage stage,
|
||||||
PersistenceProtoResolver persistenceProtoResolver,
|
PersistenceProtoResolver persistenceProtoResolver,
|
||||||
CorruptedStorageFileHandler corruptedStorageFileHandler,
|
CorruptedStorageFileHandler corruptedStorageFileHandler) {
|
||||||
KeyRing keyRing) {
|
|
||||||
if (!accounts.isEmpty()) {
|
if (!accounts.isEmpty()) {
|
||||||
String directory = getDirectoryFromChooser(preferences, stage);
|
String directory = getDirectoryFromChooser(preferences, stage);
|
||||||
if (!directory.isEmpty()) {
|
if (!directory.isEmpty()) {
|
||||||
PersistenceManager<PersistableEnvelope> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
PersistenceManager<PersistableEnvelope> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, null);
|
||||||
PaymentAccountList paymentAccounts = new PaymentAccountList(accounts);
|
PaymentAccountList paymentAccounts = new PaymentAccountList(accounts);
|
||||||
persistenceManager.initialize(paymentAccounts, fileName, PersistenceManager.Source.PRIVATE_LOW_PRIO);
|
persistenceManager.initialize(paymentAccounts, fileName, PersistenceManager.Source.PRIVATE_LOW_PRIO);
|
||||||
persistenceManager.persistNow(() -> {
|
persistenceManager.persistNow(() -> {
|
||||||
@ -193,8 +191,7 @@ public class GUIUtil {
|
|||||||
Preferences preferences,
|
Preferences preferences,
|
||||||
Stage stage,
|
Stage stage,
|
||||||
PersistenceProtoResolver persistenceProtoResolver,
|
PersistenceProtoResolver persistenceProtoResolver,
|
||||||
CorruptedStorageFileHandler corruptedStorageFileHandler,
|
CorruptedStorageFileHandler corruptedStorageFileHandler) {
|
||||||
KeyRing keyRing) {
|
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
File initDir = new File(preferences.getDirectoryChooserPath());
|
File initDir = new File(preferences.getDirectoryChooserPath());
|
||||||
if (initDir.isDirectory()) {
|
if (initDir.isDirectory()) {
|
||||||
@ -207,7 +204,7 @@ public class GUIUtil {
|
|||||||
if (Paths.get(path).getFileName().toString().equals(fileName)) {
|
if (Paths.get(path).getFileName().toString().equals(fileName)) {
|
||||||
String directory = Paths.get(path).getParent().toString();
|
String directory = Paths.get(path).getParent().toString();
|
||||||
preferences.setDirectoryChooserPath(directory);
|
preferences.setDirectoryChooserPath(directory);
|
||||||
PersistenceManager<PaymentAccountList> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, keyRing);
|
PersistenceManager<PaymentAccountList> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, null);
|
||||||
persistenceManager.readPersisted(fileName, persisted -> {
|
persistenceManager.readPersisted(fileName, persisted -> {
|
||||||
StringBuilder msg = new StringBuilder();
|
StringBuilder msg = new StringBuilder();
|
||||||
HashSet<PaymentAccount> paymentAccounts = new HashSet<>();
|
HashSet<PaymentAccount> paymentAccounts = new HashSet<>();
|
||||||
|
@ -878,9 +878,9 @@
|
|||||||
<sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/>
|
<sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="io.github.woodser" name="monero-java" version="0.8.31">
|
<component group="io.github.woodser" name="monero-java" version="0.8.33">
|
||||||
<artifact name="monero-java-0.8.31.jar">
|
<artifact name="monero-java-0.8.33.jar">
|
||||||
<sha256 value="46b81b98bc76f60a965bc7de429ff72cf6c443858987cbd51b9cacd2f8a8d28b" origin="Generated by Gradle"/>
|
<sha256 value="f9a02386ec0870b13a512bf5f72da464c9507e1a1ed6982716bff87641f94e81" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="io.grpc" name="grpc-api" version="1.42.1">
|
<component group="io.grpc" name="grpc-api" version="1.42.1">
|
||||||
|
@ -24,6 +24,7 @@ import haveno.common.config.Config;
|
|||||||
import haveno.network.p2p.network.NetworkNode;
|
import haveno.network.p2p.network.NetworkNode;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -96,8 +97,7 @@ public class Socks5ProxyProvider {
|
|||||||
try {
|
try {
|
||||||
return new Socks5Proxy(tokens[0], Integer.valueOf(tokens[1]));
|
return new Socks5Proxy(tokens[0], Integer.valueOf(tokens[1]));
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
log.error(e.getMessage());
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("Incorrect format for socks5ProxyAddress. Should be: host:port.\n" +
|
log.error("Incorrect format for socks5ProxyAddress. Should be: host:port.\n" +
|
||||||
|
@ -57,6 +57,8 @@ import javafx.beans.property.ReadOnlyIntegerProperty;
|
|||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||||
@ -433,15 +435,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NotNull Throwable throwable) {
|
public void onFailure(@NotNull Throwable throwable) {
|
||||||
log.error(throwable.toString());
|
log.error(ExceptionUtils.getStackTrace(throwable));
|
||||||
throwable.printStackTrace();
|
|
||||||
sendDirectMessageListener.onFault(throwable.toString());
|
sendDirectMessageListener.onFault(throwable.toString());
|
||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor());
|
}, MoreExecutors.directExecutor());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
e.printStackTrace();
|
log.error("Error sending encrypted direct message, message={}, error={}\n", message.toString(), e.getMessage(), e);
|
||||||
log.error(message.toString());
|
|
||||||
log.error(e.toString());
|
|
||||||
sendDirectMessageListener.onFault(e.toString());
|
sendDirectMessageListener.onFault(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,7 @@ public class MailboxMessageList extends PersistableList<MailboxItem> {
|
|||||||
try {
|
try {
|
||||||
return MailboxItem.fromProto(e, networkProtoResolver);
|
return MailboxItem.fromProto(e, networkProtoResolver);
|
||||||
} catch (ProtobufferException protobufferException) {
|
} catch (ProtobufferException protobufferException) {
|
||||||
protobufferException.printStackTrace();
|
log.error("Error at MailboxItem.fromProto: {}", protobufferException.toString(), protobufferException);
|
||||||
log.error("Error at MailboxItem.fromProto: {}", protobufferException.toString());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -335,8 +335,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD
|
|||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor());
|
}, MoreExecutors.directExecutor());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("sendEncryptedMessage failed");
|
log.error("sendEncryptedMessage failed: {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
sendMailboxMessageListener.onFault("sendEncryptedMailboxMessage failed " + e);
|
sendMailboxMessageListener.onFault("sendEncryptedMailboxMessage failed " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,8 +643,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD
|
|||||||
log.info("The mailboxEntry was already removed earlier.");
|
log.info("The mailboxEntry was already removed earlier.");
|
||||||
}
|
}
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
e.printStackTrace();
|
log.error("Could not remove ProtectedMailboxStorageEntry from network. Error: {}\n", e.toString(), e);
|
||||||
log.error("Could not remove ProtectedMailboxStorageEntry from network. Error: {}", e.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,8 @@ import javafx.beans.property.ObjectProperty;
|
|||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -511,8 +513,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
|||||||
|
|
||||||
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
|
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error(t.getMessage());
|
log.error(ExceptionUtils.getStackTrace(t));
|
||||||
t.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
ThreadUtils.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler), THREAD_ID);
|
ThreadUtils.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler), THREAD_ID);
|
||||||
@ -537,16 +538,14 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
|||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
log.trace("SocketException at shutdown might be expected {}", e.getMessage());
|
log.trace("SocketException at shutdown might be expected {}", e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Exception at shutdown. " + e.getMessage());
|
log.error("Exception at shutdown. {}\n", e.getMessage(), e);
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
capabilitiesListeners.clear();
|
capabilitiesListeners.clear();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
protoInputStream.close();
|
protoInputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e.getMessage());
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.shutdownAndAwaitTermination(executorService, SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS);
|
Utilities.shutdownAndAwaitTermination(executorService, SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||||
|
@ -76,8 +76,7 @@ public class LocalhostNetworkNode extends NetworkNode {
|
|||||||
try {
|
try {
|
||||||
startServer(new ServerSocket(servicePort));
|
startServer(new ServerSocket(servicePort));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
log.error("Exception at startServer: {}\n", e.getMessage(), e);
|
||||||
log.error("Exception at startServer: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
setupListeners.stream().forEach(SetupListener::onHiddenServicePublished);
|
setupListeners.stream().forEach(SetupListener::onHiddenServicePublished);
|
||||||
}, simulateTorDelayTorNode, TimeUnit.MILLISECONDS);
|
}, simulateTorDelayTorNode, TimeUnit.MILLISECONDS);
|
||||||
|
@ -97,11 +97,10 @@ class Server implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (isServerActive())
|
if (isServerActive())
|
||||||
e.printStackTrace();
|
log.error("Error executing server loop: {}\n", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error("Executing task failed. " + t.getMessage());
|
log.error("Executing task failed: {}\n", t.getMessage(), t);
|
||||||
t.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,8 +974,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
broadcaster.broadcast(refreshTTLMessage, sender);
|
broadcaster.broadcast(refreshTTLMessage, sender);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
log.error("refreshTTL failed, missing data: {}", e.toString());
|
log.error("refreshTTL failed, missing data: {}\n", e.toString(), e);
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -116,8 +116,7 @@ public abstract class StoreService<T extends PersistableEnvelope> {
|
|||||||
log.debug("Could not find resourceFile " + resourceFileName + ". That is expected if none is provided yet.");
|
log.debug("Could not find resourceFile " + resourceFileName + ". That is expected if none is provided yet.");
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error("Could not copy resourceFile " + resourceFileName + " to " +
|
log.error("Could not copy resourceFile " + resourceFileName + " to " +
|
||||||
destinationFile.getAbsolutePath() + ".\n" + e.getMessage());
|
destinationFile.getAbsolutePath() + ".\n", e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("No resource file was copied. {} exists already.", fileName);
|
log.debug("No resource file was copied. {} exists already.", fileName);
|
||||||
|
@ -1740,6 +1740,7 @@ message PreferencesPayload {
|
|||||||
string buy_screen_crypto_currency_code = 60;
|
string buy_screen_crypto_currency_code = 60;
|
||||||
string sell_screen_crypto_currency_code = 61;
|
string sell_screen_crypto_currency_code = 61;
|
||||||
bool split_offer_output = 62;
|
bool split_offer_output = 62;
|
||||||
|
bool use_sound_for_notifications = 63;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AutoConfirmSettings {
|
message AutoConfirmSettings {
|
||||||
@ -1754,6 +1755,7 @@ message XmrNodeSettings {
|
|||||||
string blockchain_path = 1;
|
string blockchain_path = 1;
|
||||||
string bootstrap_url = 2;
|
string bootstrap_url = 2;
|
||||||
repeated string startup_flags = 3;
|
repeated string startup_flags = 3;
|
||||||
|
bool sync_blockchain = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
11
scripts/install_tails/deprecated/README.md
Normal file
11
scripts/install_tails/deprecated/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Steps to use (This has serious security concerns to tails threat model only run when you need to access haveno)
|
||||||
|
|
||||||
|
## 1. Enable persistent storage and admin password before starting tails
|
||||||
|
|
||||||
|
## 2. Get your haveno deb file in persistent storage (amd64 version for tails)
|
||||||
|
|
||||||
|
## 3. Edit the path to the haveno deb file if necessary then run ```sudo ./haveno-install.sh```
|
||||||
|
## 4. As amnesia run ```source ~/.bashrc```
|
||||||
|
## 5. Start haveno using ```haveno-tails```
|
||||||
|
|
||||||
|
## You will need to run this script after each reset, but your data will be saved persistently in /home/amnesia/Persistence/Haveno
|
77
scripts/install_tails/deprecated/haveno-install.sh
Normal file
77
scripts/install_tails/deprecated/haveno-install.sh
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Written by BrandyJson, with heavy inspiration from bisq.wiki tails script #
|
||||||
|
#############################################################################
|
||||||
|
echo "Installing dpkg from persistent, (1.07-1, if this is out of date change the deb path in the script or manually install after running"
|
||||||
|
dpkg -i "/home/amnesia/Persistent/haveno_1.0.7-1_amd64.deb"
|
||||||
|
echo -e "Allowing amnesia to read tor control port cookie, only run this script when you actually want to use haveno\n\n!!! not secure !!!\n"
|
||||||
|
chmod o+r /var/run/tor/control.authcookie
|
||||||
|
echo "Updating apparmor-profile"
|
||||||
|
echo "---
|
||||||
|
- apparmor-profiles:
|
||||||
|
- '/opt/haveno/bin/Haveno'
|
||||||
|
users:
|
||||||
|
- 'amnesia'
|
||||||
|
commands:
|
||||||
|
AUTHCHALLENGE:
|
||||||
|
- 'SAFECOOKIE .*'
|
||||||
|
SETEVENTS:
|
||||||
|
- 'CIRC ORCONN INFO NOTICE WARN ERR HS_DESC HS_DESC_CONTENT'
|
||||||
|
GETINFO:
|
||||||
|
- pattern: 'status/bootstrap-phase'
|
||||||
|
response:
|
||||||
|
- pattern: '250-status/bootstrap-phase=*'
|
||||||
|
replacement: '250-status/bootstrap-phase=NOTICE BOOTSTRAP PROGRESS=100 TAG=done SUMMARY="Done"'
|
||||||
|
- 'net/listeners/socks'
|
||||||
|
ADD_ONION:
|
||||||
|
- pattern: 'NEW:(\S+) Port=9999,(\S+)'
|
||||||
|
replacement: 'NEW:{} Port=9999,{client-address}:{}'
|
||||||
|
- pattern: '(\S+):(\S+) Port=9999,(\S+)'
|
||||||
|
replacement: '{}:{} Port=9999,{client-address}:{}'
|
||||||
|
DEL_ONION:
|
||||||
|
- '.+'
|
||||||
|
HSFETCH:
|
||||||
|
- '.+'
|
||||||
|
events:
|
||||||
|
CIRC:
|
||||||
|
suppress: true
|
||||||
|
ORCONN:
|
||||||
|
suppress: true
|
||||||
|
INFO:
|
||||||
|
suppress: true
|
||||||
|
NOTICE:
|
||||||
|
suppress: true
|
||||||
|
WARN:
|
||||||
|
suppress: true
|
||||||
|
ERR:
|
||||||
|
suppress: true
|
||||||
|
HS_DESC:
|
||||||
|
response:
|
||||||
|
- pattern: '650 HS_DESC CREATED (\S+) (\S+) (\S+) \S+ (.+)'
|
||||||
|
replacement: '650 HS_DESC CREATED {} {} {} redacted {}'
|
||||||
|
- pattern: '650 HS_DESC UPLOAD (\S+) (\S+) .*'
|
||||||
|
replacement: '650 HS_DESC UPLOAD {} {} redacted redacted'
|
||||||
|
- pattern: '650 HS_DESC UPLOADED (\S+) (\S+) .+'
|
||||||
|
replacement: '650 HS_DESC UPLOADED {} {} redacted'
|
||||||
|
- pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH'
|
||||||
|
replacement: '650 HS_DESC REQUESTED {} NO_AUTH'
|
||||||
|
- pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH \S+ \S+'
|
||||||
|
replacement: '650 HS_DESC REQUESTED {} NO_AUTH redacted redacted'
|
||||||
|
- pattern: '650 HS_DESC RECEIVED (\S+) NO_AUTH \S+ \S+'
|
||||||
|
replacement: '650 HS_DESC RECEIVED {} NO_AUTH redacted redacted'
|
||||||
|
- pattern: '.*'
|
||||||
|
replacement: ''
|
||||||
|
HS_DESC_CONTENT:
|
||||||
|
suppress: true" > /etc/onion-grater.d/haveno.yml
|
||||||
|
echo "Adding rule to iptables to allow for monero-wallet-rpc to work"
|
||||||
|
iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 18081 -m owner --uid-owner 1855 -j ACCEPT
|
||||||
|
echo "Updating torsocks to allow for inbound connection"
|
||||||
|
sed -i 's/#AllowInbound/AllowInbound/g' /etc/tor/torsocks.conf
|
||||||
|
|
||||||
|
echo "Restarting onion-grater service"
|
||||||
|
|
||||||
|
systemctl restart onion-grater.service
|
||||||
|
|
||||||
|
echo "alias haveno-tails='torsocks /opt/haveno/bin/Haveno --torControlPort 951 --torControlCookieFile=/var/run/tor/control.authcookie --torControlUseSafeCookieAuth --useTorForXmr=ON --userDataDir=/home/amnesia/Persistent/'" >> /home/amnesia/.bashrc
|
||||||
|
echo -e "Everything is set up just run\n\nsource ~/.bashrc\n\nThen you can start haveno using haveno-tails"
|
@ -75,7 +75,7 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
|
|||||||
seedNode = new SeedNode();
|
seedNode = new SeedNode();
|
||||||
UserThread.execute(this::onApplicationLaunched);
|
UserThread.execute(this::onApplicationLaunched);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Error launching seed node: {}\n", e.toString(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user