Compare commits

...

31 Commits

Author SHA1 Message Date
jw
0ffda21600 Merge pull request #126 from wowario/master
update checkpoints
2018-12-05 16:55:15 -08:00
wowario
41494095eb update version 2018-12-05 01:12:55 +03:00
wowario
c33e7f7bbb update checkpoints 2018-12-05 01:08:41 +03:00
jw
1fa62a2a25 Merge pull request #125 from 0x000090/cli-win-installer
Add scripts & resources for wownero cli installer.
2018-12-01 14:05:35 -08:00
0x000090
8894ff9381 Add scripts & resources for wownero cli installer. 2018-12-01 14:41:50 -06:00
jw
59ac413283 Merge pull request #123 from wownero/dev-v0.4
Dev v0.4
2018-11-09 08:18:36 -08:00
jw
db77810cd4 Merge pull request #122 from wowario/v0.4
Add LWMA-4, ASCII art, 10v fork height
2018-11-09 08:17:29 -08:00
wowario
fc9d0deb38 update difficulty minimum and guess 2018-11-09 19:09:29 +03:00
wowario
698d041e64 update checkpoints 2018-11-09 18:34:07 +03:00
wowario
7f28f73bd6 Difficulty: temper long solvetime 2018-11-09 13:02:08 +03:00
wowario
003f0b3af3 v0.4 ASCII art 2018-11-09 12:49:51 +03:00
wowario
47bd60ba50 Replace LWMA-3 with LWMA-4, add v10 fork height 2018-11-08 22:42:45 +03:00
wowario
6e6cb4fdaf Merge pull request #120 from wownero/release-v0.3.0.0
Merge release-v0.3.0.0 branch
2018-11-08 20:49:05 +03:00
wowario
de5e3660d9 Merge pull request #119 from wowario/checkpoints
update checkpoints
2018-11-08 18:32:08 +03:00
wowario
7bc2142590 correct cumulative difficulty count 2018-11-08 18:21:52 +03:00
wowario
8adea0a034 update checkpoints 2018-11-08 17:52:47 +03:00
wowario
58d006566b Merge pull request #118 from wowario/checkpoints
Update checkpoints
2018-11-07 22:26:54 +03:00
wowario
3263067b97 update checkpoint 2018-11-07 22:04:23 +03:00
wowario
6cf896f8ab update checkpoints 2018-11-07 20:51:19 +03:00
wowario
caae62e2ce update checkpoints 2018-11-07 20:51:10 +03:00
wowario
4865345889 Merge pull request #117 from wowario/checkpoints
update checkpoints
2018-11-07 19:21:20 +03:00
wowario
8b56a44adc counter attack 2018-11-07 19:19:07 +03:00
wowario
d1623175b2 update checkpoints 2018-11-07 09:13:13 +03:00
jw
0edab6407f Merge pull request #116 from wowario/checkpoints
update checkpoints
2018-10-29 08:19:07 -07:00
jw
7008314cb0 Merge pull request #115 from wowario/version
up version to 0.3.1.1
2018-10-29 08:18:56 -07:00
jw
35d15f2626 Merge pull request #114 from rbrunner7/mms-for-wow2
MMS for Wownero
2018-10-29 08:18:45 -07:00
wowario
47b543b591 update checkpoints 2018-10-29 01:20:17 +03:00
wowario
398a21019c up version 2018-10-29 01:05:00 +03:00
rbrunner7
fc915d3e0f MMS: Some Wownero-specific changes in 'simplewallet.cpp' 2018-10-28 20:00:33 +01:00
rbrunner7
b1e005b3c8 MMS: Initial version for Wownero, merged in from Monero
Wownero-specific changes still missing, see following second commit
2018-10-28 17:06:06 +01:00
jw
c299569449 Merge pull request #99 from wownero/release-v0.3.0.0
Release v0.3.0.0
2018-10-05 21:52:15 -07:00
24 changed files with 3481 additions and 80 deletions

View File

@@ -95,7 +95,8 @@ Dates are provided in the format YYYY-MM-DD.
| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| 1 | 2018-04-01 | v7 | v0.1.0.0 | v0.1.0.0 | Cryptonight variant 1, ringsize >= 8, sorted inputs
| 6969 | 2018-04-24 | v8 | v0.2.0.0 | v0.2.0.0 | Bulletproofs, LWMA difficulty algorithm, ringsize >= 10, reduce unlock to 4
| 53666 | 2018-10-06 | v9 | v0.3.0.0 | v0.3.1.0 | Cryptonight variant 2, LWMA v2, ringsize = 22, XXX
| 53666 | 2018-10-06 | v9 | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS
| 63469 | 2018-11-11 | v10 | v0.4.0.0 | v0.4.0.0 | LWMA v4
X's indicate that these details have not been determined as of commit date.

View File

@@ -0,0 +1,88 @@
#
# This is a script for easily building the wownero cli installer in an automated build. Note
# that it is also possible to build the installer by dropping the .nsi file on the NSIS GUI,
# but that this will not work, as the script requires some defines, parsed from the wownero
# version file, to be passed on the command line.
#
import sys
sys.dont_write_bytecode = True
import os
import os.path
import subprocess
#
# Grab the dir of this .py
#
basedir = os.path.dirname(os.path.abspath(__file__))
#
# Try to find version.cpp.in.
#
version_file = os.path.join('..', 'src', 'version.cpp.in')
if not os.path.isfile(version_file):
print('Version file not found: %s' % version_file)
sys.exit(-1)
#
# Try to parse version.cpp.in.
#
version_string = None
release_name = None
with open(version_file, 'r') as fp:
version_prefix = '#define DEF_MONERO_VERSION "'
release_prefix = '#define DEF_MONERO_RELEASE_NAME "'
for line in fp:
if line.startswith(version_prefix):
version_string = line.replace(version_prefix, '')[:-2]
elif line.startswith(release_prefix):
release_name = line.replace(release_prefix, '')[:-2]
if not version_string:
print('Failed to parse version from: %s' % version_file)
sys.exit(-1)
if not release_name:
print('Failed to parse release name from: %s' % version_file)
sys.exit(-1)
#
# Check that we got an expected version format.
#
version_parts = version_string.split('.')
if len(version_parts) != 4:
print('Invalid version string: %s' % version_string)
sys.exit(-1)
#
# Try to find makensis.
#
makensis = 'makensis.exe'
if not os.path.isfile(makensis):
for dir in os.environ['PATH'].split(';'):
test = os.path.join(dir, makensis)
if os.path.isfile(test):
makensis = test
break
if not os.path.isfile(makensis):
print('Failed to find makensis.exe')
sys.exit(-1)
#
# Build & run makensis command line.
#
cmd = '"%s"' % makensis
cmd += ' /V4'
cmd += ' /DVERSION_MAJOR=%s' % version_parts[0]
cmd += ' /DVERSION_MINOR=%s' % version_parts[1]
cmd += ' /DVERSION_BUILD=%s' % version_parts[2]
cmd += ' /DVERSION_REVISION=%s' % version_parts[3]
cmd += ' /DRELEASE_NAME="%s"' % release_name
cmd += ' "%s"' % os.path.join(basedir, 'cli-win', 'installer.nsi')
print("Calling makensis: %s" % cmd)
subprocess.call(cmd)

BIN
installers/cli-win/app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,262 @@
;-----------------------------------------------------------------------------------------
; File: Wownero CLI NSIS installer
; Author: 0x000090
; Date: 1 Dec 2018
; License: WTFPL
;-----------------------------------------------------------------------------------------
;
; DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
; Version 2, December 2004
;
; Copyright (C) 2018 Wownero Inc., a Monero Enterprise Alliance partner company
;
; DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
; TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
;
; 0. You just DO WHAT THE FUCK YOU WANT TO.
;
;-----------------------------------------------------------------------------------------
!include 'MUI2.nsh'
!include 'TextFunc.nsh'
!include 'WordFunc.nsh'
!include 'Sections.nsh'
;-----------------------------------------------------------------------------------------
!ifndef VERSION_MAJOR
!warning 'VERSION_MAJOR not defined!'
Quit
!endif
!ifndef VERSION_MINOR
!warning 'VERSION_MINOR not defined!'
Quit
!endif
!ifndef VERSION_BUILD
!warning 'VERSION_BUILD not defined!'
Quit
!endif
!ifndef VERSION_REVISION
!warning 'VERSION_REVISION not defined!'
Quit
!endif
!ifndef RELEASE_NAME
!warning 'RELEASE_NAME not defined!'
Quit
!endif
!define VERSION_SHORT '${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}'
!define VERSION_LONG '${VERSION_SHORT}.${VERSION_REVISION}'
;-----------------------------------------------------------------------------------------
!define PROJECT_NAME 'Wownero'
!define PRODUCT_NAME 'Wownero CLI'
!define COMPANY_NAME 'Wownero Inc.'
!define EXE_BASENAME 'wownero'
!define HELP_URL 'http://wownero.org/#community'
!define ABOUT_URL 'http://wownero.org/#about'
!define SOURCE_DIR '..\..\build\release\bin'
!define TARGET_DIR '..\..\build\installers'
!define TARGET_PATH '${TARGET_DIR}\Wownero-CLI-${VERSION_LONG}-win.exe'
!define INSTALL_SUBDIR 'cli'
!define INSTALL_SIZE 181000
!define UNINSTALLER_NAME 'uninstall.exe'
!define REG_BASE 'Software\Microsoft\Windows\CurrentVersion\Uninstall'
!define REG_KEY '${REG_BASE}\{E114584F-4E1B-4B2D-8B1C-69A188025E98}'
!define /date CURRENT_YEAR '%Y'
;-----------------------------------------------------------------------------------------
!system 'if not exist "${TARGET_DIR}" md "${TARGET_DIR}"'
;-----------------------------------------------------------------------------------------
Name '${PRODUCT_NAME}'
OutFile '${TARGET_PATH}'
BrandingText '${PRODUCT_NAME} ${VERSION_LONG} "${RELEASE_NAME}"'
CRCCheck force
RequestExecutionLevel admin
InstallDir "$PROGRAMFILES64\${PROJECT_NAME}\${INSTALL_SUBDIR}"
ShowInstDetails show
ShowUninstDetails show
;-----------------------------------------------------------------------------------------
VIAddVersionKey 'CompanyName' '${COMPANY_NAME}'
VIAddVersionKey 'ProductName' '${PRODUCT_NAME}'
VIAddVersionKey 'FileDescription' '${PRODUCT_NAME}'
VIAddVersionKey 'LegalCopyright' 'Copyright (c) ${CURRENT_YEAR}, ${COMPANY_NAME}'
VIAddVersionKey 'FileVersion' '${VERSION_SHORT}'
VIProductVersion '${VERSION_LONG}'
;-----------------------------------------------------------------------------------------
!define MUI_ABORTWARNING
!define MUI_UNABORTWARNING
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
!define MUI_ICON "app.ico"
!define MUI_UNICON "app.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP "header.bmp"
!define MUI_HEADERIMAGE_UNBITMAP "header.bmp"
!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH
!define MUI_HEADERIMAGE_UNBITMAP_NOSTRETCH
!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "welcome.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH
!define MUI_UNWELCOMEFINISHPAGE_UNBITMAP_NOSTRETCH
;-----------------------------------------------------------------------------------------
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
;-----------------------------------------------------------------------------------------
!insertmacro MUI_LANGUAGE "English"
;-----------------------------------------------------------------------------------------
Function VerifyUserIsAdmin
UserInfo::GetAccountType
Pop $0
${If} $0 != "admin"
MessageBox MB_ICONSTOP "Admin permissions required, please use right-click > Run as Administrator."
SetErrorLevel 740 ; ERROR_ELEVATION_REQUIRED
Quit
${EndIf}
FunctionEnd
Function .onInit
Call VerifyUserIsAdmin
FunctionEnd
Function un.onInit
FunctionEnd
;-----------------------------------------------------------------------------------------
!macro RemoveFile file
Push $0
${TrimNewLines} '${file}' $0
SetDetailsPrint both
${If} ${FileExists} '$0'
DetailPrint 'Deleting file $0'
SetDetailsPrint textonly
Delete "$0"
${Else}
DetailPrint 'File not found: $0'
${Endif}
SetDetailsPrint lastused
Pop $0
!macroend
!macro RemoveDir dir
Push $0
${TrimNewLines} '${dir}' $0
SetDetailsPrint both
${If} ${FileExists} '$0'
DetailPrint 'Deleting directory $0'
SetDetailsPrint textonly
RmDir /r "$0"
${Else}
DetailPrint 'Directory not found: $0'
${Endif}
SetDetailsPrint lastused
Pop $0
!macroend
;-----------------------------------------------------------------------------------------
Function WriteFiles
DetailPrint 'Installing application files...'
SetDetailsPrint both
SetOutPath '$INSTDIR'
File 'app.ico'
;
; Add here whatever else you want to be included:
;
File '${SOURCE_DIR}\${EXE_BASENAME}d.exe'
File '${SOURCE_DIR}\${EXE_BASENAME}-wallet-cli.exe'
File '${SOURCE_DIR}\${EXE_BASENAME}-wallet-rpc.exe'
File '${SOURCE_DIR}\${EXE_BASENAME}-gen-trusted-multisig.exe'
;
; NOTE: you can also add all files in a dir, like this:
;
;File /r '${SOURCE_DIR}\*.*'
SetDetailsPrint lastused
DetailPrint 'Writing uninstaller...'
WriteUninstaller '$INSTDIR\${UNINSTALLER_NAME}'
FunctionEnd
Function un.WriteFiles
DetailPrint 'Removing application files...'
!insertmacro RemoveDir '$INSTDIR'
FunctionEnd
;-----------------------------------------------------------------------------------------
Function WriteShortcuts
DetailPrint 'Creating Desktop shortcuts...'
CreateShortCut '$DESKTOP\${PRODUCT_NAME} Wallet.lnk' '$INSTDIR\${EXE_BASENAME}-wallet-cli.exe' '' '$INSTDIR\app.ico'
CreateShortCut '$DESKTOP\${PRODUCT_NAME} Daemon.lnk' '$INSTDIR\${EXE_BASENAME}d.exe' '' '$INSTDIR\app.ico'
DetailPrint 'Creating Start Menu shortcuts...'
CreateDirectory '$SMPROGRAMS\${COMPANY_NAME}\${PRODUCT_NAME}'
CreateShortCut '$SMPROGRAMS\${COMPANY_NAME}\${PRODUCT_NAME}\${PRODUCT_NAME} Wallet.lnk' '$INSTDIR\${EXE_BASENAME}-wallet-cli.exe' '' '$INSTDIR\app.ico'
CreateShortCut '$SMPROGRAMS\${COMPANY_NAME}\${PRODUCT_NAME}\${PRODUCT_NAME} Daemon.lnk' '$INSTDIR\${EXE_BASENAME}d.exe' '' '$INSTDIR\app.ico'
CreateShortCut '$SMPROGRAMS\${COMPANY_NAME}\${PRODUCT_NAME}\Uninstall ${PRODUCT_NAME}.lnk' '$INSTDIR\${UNINSTALLER_NAME}' '' '$INSTDIR\app.ico'
FunctionEnd
Function un.WriteShortcuts
DetailPrint 'Removing Desktop shortcuts...'
!insertmacro RemoveFile '$DESKTOP\${PRODUCT_NAME} Daemon.lnk'
!insertmacro RemoveFile '$DESKTOP\${PRODUCT_NAME} Wallet.lnk'
DetailPrint 'Removing Start Menu shortcuts...'
!insertmacro RemoveDir '$SMPROGRAMS\${COMPANY_NAME}\${PRODUCT_NAME}'
FunctionEnd
;-----------------------------------------------------------------------------------------
Function WriteUninstaller
DetailPrint 'Registering ${PRODUCT_NAME} ${VERSION_SHORT}'
WriteRegDWORD HKLM '${REG_KEY}' 'VersionMajor' ${VERSION_MAJOR}
WriteRegDWORD HKLM '${REG_KEY}' 'VersionMinor' ${VERSION_MINOR}
WriteRegDWORD HKLM '${REG_KEY}' 'EstimatedSize' ${INSTALL_SIZE}
WriteRegDWORD HKLM '${REG_KEY}' 'NoModify' 1
WriteRegDWORD HKLM '${REG_KEY}' 'NoRepair' 1
WriteRegStr HKLM '${REG_KEY}' 'Contact' '${COMPANY_NAME}'
WriteRegStr HKLM '${REG_KEY}' 'Publisher' '${COMPANY_NAME}'
WriteRegStr HKLM '${REG_KEY}' 'HelpLink' '${HELP_URL}'
WriteRegStr HKLM '${REG_KEY}' 'URLInfoAbout' '${ABOUT_URL}'
WriteRegStr HKLM '${REG_KEY}' 'DisplayVersion' '${VERSION_SHORT}'
WriteRegStr HKLM '${REG_KEY}' 'Comments' '${PRODUCT_NAME}'
WriteRegStr HKLM '${REG_KEY}' 'DisplayName' '${PRODUCT_NAME} ${VERSION_SHORT}'
WriteRegStr HKLM '${REG_KEY}' 'InstallLocation' '"$INSTDIR"'
WriteRegStr HKLM '${REG_KEY}' 'DisplayIcon' '"$INSTDIR\app.ico"'
WriteRegStr HKLM '${REG_KEY}' 'UninstallString' '"$INSTDIR\${UNINSTALLER_NAME}"'
WriteRegStr HKLM '${REG_KEY}' 'QuietUninstallString' '"$INSTDIR\${UNINSTALLER_NAME}" /S'
FunctionEnd
Function un.WriteUninstaller
DetailPrint 'Unregistering ${PRODUCT_NAME} ${VERSION_SHORT}...'
DeleteRegKey HKLM '${REG_KEY}'
FunctionEnd
;-----------------------------------------------------------------------------------------
Section "${PRODUCT_NAME} ${VERSION_SHORT}"
Call WriteFiles
Call WriteShortcuts
Call WriteUninstaller
SectionEnd
;-----------------------------------------------------------------------------------------
Section "Uninstall"
Call un.WriteFiles
Call un.WriteShortcuts
Call un.WriteUninstaller
SectionEnd

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

31
installers/readme.txt Normal file
View File

@@ -0,0 +1,31 @@
Installer notes
So, at this point I just have one installer, for the cli, on windows. What do you need
to know ..
1. It uses NSIS, and expects to find makensis.exe on your PATH.
2. It expects built products to be found at:
wownero/build/release/bin
3. It currently includes the daemon, wallet, rpc, and gen-trusted-multisig. I note that
releases on the wownero github have had different files (static libs, pthreads dll)
than I end up with in my /bin dir when I build, so you may or may not need to change
which files you include. At any rate, it is easy to do, in the WriteFiles function
in installer.nsi.
4. Provided everything is ok, it should be as simple as executing build-cli-win.py; built
installer, versioned according to src/version.cpp.in, will be depostied here:
wownero/build/installers/Wownero-CLI-<version>-win.exe
5. The installer includes an uninstaller, shortcuts on desktop & start menu, and it
registers itself with windows, so it shows up as expected in programs & features.
6. I have tried to keep the installer script pretty generic, so it can be reused later,
for gui, or whatever. It installs to a <program files>/Wownero/cli subdirectory, so
that other applications can eventually be installed alongside. NOTE: if you copy the
installer.nsi file to use for another project, you will need to make a new GUID for
it, and put it in the REG_KEY define.

Binary file not shown.

View File

@@ -191,6 +191,25 @@ namespace cryptonote
ADD_CHECKPOINT(55000, "4b662ceccefc3247edb4d654dd610b8fb496e85b88a5de43cc2bdd28171b15ff");
ADD_CHECKPOINT(57000, "08a79f09f12bb5d230b63963356a760d51618e526cfc636047a6f3798217c177");
ADD_CHECKPOINT(59000, "180b51ee2c5fbcd4362eb7a29df9422481310dd77d10bccdf8930724c31e007e");
ADD_CHECKPOINT(59900, "18cc0653ef39cb304c68045dba5eb6b885f936281cd939dea04d0e6c9cd4ae2e");
ADD_CHECKPOINT(60000, "0f02aa57a63f79f63dafed9063abe228a37cb19f00430dc3168b8a8f4ae8016c");
ADD_CHECKPOINT(61000, "509aca8c54eb5fe44623768757b6e890ae39d512478c75f614cbff3d91809350");
ADD_CHECKPOINT(62000, "7fe91ad256c08dbd961e04738968be22fb481093fbfa7959bde7796ccceba0e2");
ADD_CHECKPOINT(62150, "1a7c75f8ebeda0e20eb5877181eafd7db0fc887e3fed43e0b27ab2e7bccafd10");
ADD_CHECKPOINT(62269, "4969555d60742afb93925fd96d83ac28f45e6e3c0e583c9fb3c92d9b2100d38f");
ADD_CHECKPOINT(62405, "4d0ae890cf9f875f231c7069508ad28dc429d14814b52db114dfab7519a27584");
ADD_CHECKPOINT(62419, "bd8bf5ac4c4fb07ab4d0d492bd1699def5c095ab6943ad3b63a89d1d8b1ce748");
ADD_CHECKPOINT(62425, "41a922dba6f3906871b2ccaf31ec9c91033470c503959093dae796deda8940ea");
ADD_CHECKPOINT(62479, "a2e8ff4205ba2980eb70921b0b21b5fc656ee273664ea94b860c68ca069b60dd");
ADD_CHECKPOINT(62503, "25fa115962988b4b8f8cfd22744a3e653b22ead8c8468e64caf334fc75a97d08");
ADD_CHECKPOINT(62550, "bde522a8a81c392c98c979434aa1dd9d20b4ca52230ba6ae0362872757808a48");
ADD_CHECKPOINT(62629, "8368e1ce1d421f1fc969364558433e2b2363d0ffcb5f2d946633095e3e6734f5");
ADD_CHECKPOINT(62720, "f871cddd75951e2fe24c282d2bd28396fc922ea519b354ace992a0162cb333ff");
ADD_CHECKPOINT(62733, "8331dbeeaf23173d2235a062373a437befadb6492cceb7640127bf18653a9e61");
ADD_CHECKPOINT(62877, "62d44adc05d7d4fd9d15239c5575612207beab0bcf2da49158bf89e365441ca1");
ADD_CHECKPOINT(63469, "4e33a9343fc5b86661ec0affaeb5b5a065290602c02d817337e4a979fe5747d8"); //Hard fork to v10
ADD_CHECKPOINT(63950, "155b61475985ac3f48fda10091d732bdc8087a55554504959e88d29962c91b72");
ADD_CHECKPOINT(67500, "84acb8fa140d8c7eb49bcbcf662cbe7570496f463c637a67980613dbd70dbbc3");
return true;
}

View File

@@ -256,9 +256,9 @@ namespace cryptonote {
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= static_cast<uint64_t>(N+1) );
if ( height <= DIFFICULTY_HEIGHT ){
/*if ( height <= DIFFICULTY_HEIGHT ){
return static_cast<uint64_t>(DIFFICULTY_GUESS);
}
}*/
for ( int64_t i = 1; i <= N; i++ ) {
ST = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i-1]);
@@ -285,42 +285,71 @@ namespace cryptonote {
}
}
// LWMA-3 difficulty algorithm
// LWMA-4 difficulty algorithm
// Copyright (c) 2017-2018 Zawy, MIT License
// https://github.com/zawy12/difficulty-algorithms/issues/3
difficulty_type next_difficulty_v4(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height) {
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V2;
uint64_t L(0), ST, sum_3_ST(0), next_D, prev_D, this_timestamp, previous_timestamp;
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V2; // N=45, 60, and 90 for T=600, 120, 60.
uint64_t L(0), ST(0), next_D, prev_D, avg_D, i;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if ( height == DIFFICULTY_HEIGHT_V2 ){
return static_cast<uint64_t>(DIFFICULTY_GUESS);
}
if ( height <= DIFFICULTY_HEIGHT + 1 ) { return DIFFICULTY_GUESS; }
// Safely convert out-of-sequence timestamps into > 0 solvetimes.
std::vector<uint64_t>TS(N+1);
TS[0] = timestamps[0];
for ( i = 1; i <= N; i++) {
if ( timestamps[i] > TS[i-1] ) { TS[i] = timestamps[i]; }
else { TS[i] = TS[i-1]; }
}
previous_timestamp = timestamps[0];
for ( uint64_t i = 1; i <= N; i++) {
if ( timestamps[i] > previous_timestamp ) {
this_timestamp = timestamps[i];
} else { this_timestamp = previous_timestamp+1; }
ST = std::min(6*T ,this_timestamp - previous_timestamp);
previous_timestamp = this_timestamp;
L += ST * i ;
if ( i > N-3 ) { sum_3_ST += ST; }
}
for ( i = 1; i <= N; i++) {
// Temper long solvetime drops if they were preceded by 3 or 6 fast solves.
if ( i > 4 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-4] < (14*T)/10 ) { ST = 2*T; }
else if ( i > 7 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-7] < 4*T ) { ST = 2*T; }
else { // Assume normal conditions, so get ST.
// LWMA drops too much from long ST, so limit drops with a 5*T limit
ST = std::min(5*T ,TS[i] - TS[i-1]);
}
L += ST * i ;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = ( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N;
// Prevent round off error for small D and overflow for large D.
if (avg_D > 2000000*N*N*T) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*97);
}
else { next_D = (avg_D*N*(N+1)*T*97)/(200*L); }
next_D = ((cumulative_difficulties[N] - cumulative_difficulties[0])*T*(N+1)*99)/(100*2*L);
prev_D = cumulative_difficulties[N] - cumulative_difficulties[N-1];
next_D = std::max((prev_D*67)/100, std::min(next_D, (prev_D*150)/100));
prev_D = cumulative_difficulties[N] - cumulative_difficulties[N-1] ;
if ( sum_3_ST < (8*T)/10) { next_D = std::max(next_D,(prev_D*108)/100); }
// Apply 10% jump rule.
if ( ( TS[N] - TS[N-1] < (2*T)/10 ) ||
( TS[N] - TS[N-2] < (5*T)/10 ) ||
( TS[N] - TS[N-3] < (8*T)/10 ) )
{
next_D = std::max( next_D, std::min( (prev_D*110)/100, (105*avg_D)/100 ) );
}
// Make all insignificant digits zero for easy reading.
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
// Make least 3 digits equal avg of past 10 solvetimes.
if ( next_D > 100000 ) {
next_D = ((next_D+500)/1000)*1000 + std::min(static_cast<uint64_t>(999), (TS[N]-TS[N-10])/10);
}
if ( next_D < DIFFICULTY_MINIMUM ) {
return static_cast<uint64_t>(DIFFICULTY_MINIMUM);
}
else {
return static_cast<uint64_t>(next_D);
}
if ( next_D < DIFFICULTY_MINIMUM ) {
return static_cast<uint64_t>(DIFFICULTY_MINIMUM);
}
else {
return static_cast<uint64_t>(next_D);
}
}
}

View File

@@ -82,10 +82,9 @@
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1 // added +1 to make N=N
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
#define DIFFICULTY_HEIGHT 53666 // v9 fork height
#define DIFFICULTY_HEIGHT_V2 777777 // v10 fork height
#define DIFFICULTY_GUESS 40000000 // difficulty at fork 40m
#define DIFFICULTY_MINIMUM 25000000 // minimum difficulty set to 25m
#define DIFFICULTY_HEIGHT 63469 // v10 fork height
#define DIFFICULTY_GUESS 100000069 // difficulty at fork 100m
#define DIFFICULTY_MINIMUM 40000069 // minimum difficulty set to 40m
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 DIFFICULTY_TARGET_V1 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS

View File

@@ -93,6 +93,7 @@ static const struct {
{ 7, 1, 0, 1519605000 },
{ 8, 6969, 0, 1524214739 },
{ 9, 53666, 0, 1538689773 },
{ 10, 63469, 0, 1541700352 },
};
static const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)(0));
@@ -1061,7 +1062,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
return next_difficulty_v2(timestamps, cumulative_difficulties, target);
}
else if (version == 9) {
return next_difficulty_v2(timestamps, cumulative_difficulties, height);
return next_difficulty_v3(timestamps, cumulative_difficulties, height);
}
else {
return next_difficulty_v4(timestamps, cumulative_difficulties, height);
@@ -4452,7 +4453,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "897d3ae0f3aef8ef8362b0bb3535925738414fa78d9146f8a04c60555fa5a95f";
static const char expected_block_hashes_hash[] = "5aaafa48eb50fc5d8fa95b3a94da504170082245dd1f2d32ec7b72eb60877711";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;

View File

@@ -1344,16 +1344,24 @@ namespace cryptonote
main_message = "The daemon is running offline and will not attempt to sync to the Monero network.";
else
main_message = "The daemon will start synchronizing with the network. This may take a long time to complete.";
MGINFO_BLUE(ENDL <<
MGINFO_GREEN(ENDL <<
"\n \n"
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n"
"░░░░░░░░░░░░░▄█▄░░░░████▄░████▄░█░░░░░░░░▄█▄░░░░██░░░░▄▀░░▄███▄░░░░░░░░░░░░\n"
"░░░░░░░░░░░░░█▀ ▀▄░░█░░░█░█░░░█░█░░░░░░░░█▀ ▀▄░░█ █░░▄▀░░░█▀░░░▀░░░░░░░░░░░\n"
"░░░░░░░░░░░░░█░░░░░░█░░░█░█░░░█░█░░░░░░░░█░░░░░░█▄▄█ █░▀▄░██▄▄░░░░░░░░░░░░░\n"
"░░░░░░░░░░░░░█▄░░▄▀ ▀████░▀████░███▄░░░░░█▄░░▄▀ █░░█ █░░░█░█▄░░░▄▀░░░░░░░░░\n"
"░░░░░░░░░░░░░▀███▀░░░░░░░░░░░░░░░░░░▀░░░░▀███▀░░░░░█░░███░░▀███▀░░░░░░░░░░░\n"
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█░░░░░░░░░░░░░░░░░░░░░░░░\n"
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▀░░░░░░░░░░░░░░░░░░░░░░░░░" << ENDL);
" \n"
" | __/| \n"
" | @ @ WoW! \n"
" | <> _ \n"
" | _/|------____ ((| |)) \n"
" | `--' | \n"
" ____|_ ___| |___.' \n"
" /_/_____/____/_______| \n"
"########################################################\n"
"### ____ ############ _ #### ____ ######################\n"
"###| _ | __ _ _ __ | | __ | _ | ___ __ _ ___ ###\n"
"###| | | |/ _` | '_ || |/ / | | | |/ _ | / _` |/ _ | ###\n"
"###| |_| | (_| | | | | < | |_| | (_) | (_| | __/ ###\n"
"###|____/ |__,_|_| |_|_||_| |____/ |___/ __, ||___| ###\n"
"#########################################|___/##########\n"
"########################################################"<< ENDL);
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< main_message << ENDL
<< ENDL

File diff suppressed because it is too large Load Diff

View File

@@ -210,6 +210,7 @@ namespace cryptonote
bool sign_multisig(const std::vector<std::string>& args);
bool submit_multisig(const std::vector<std::string>& args);
bool export_raw_multisig(const std::vector<std::string>& args);
bool mms(const std::vector<std::string>& args);
bool print_ring(const std::vector<std::string>& args);
bool set_ring(const std::vector<std::string>& args);
bool save_known_rings(const std::vector<std::string>& args);
@@ -351,5 +352,38 @@ namespace cryptonote
bool m_auto_refresh_refreshing;
std::atomic<bool> m_in_manual_refresh;
uint32_t m_current_subaddress_account;
// MMS
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
mms::multisig_wallet_state get_multisig_wallet_state() const { return m_wallet->get_multisig_wallet_state(); };
bool mms_active() const { return get_message_store().get_active(); };
bool choose_mms_processing(const std::vector<mms::processing_data> &data_list, uint32_t &choice);
void list_mms_messages(const std::vector<mms::message> &messages);
void show_message(const mms::message &m);
void ask_send_all_ready_messages();
void check_for_messages();
bool user_confirms(const std::string &question);
bool get_message_from_arg(const std::string &arg, mms::message &m);
bool get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound);
void mms_init(const std::vector<std::string> &args);
void mms_info(const std::vector<std::string> &args);
void mms_member(const std::vector<std::string> &args);
void mms_list(const std::vector<std::string> &args);
void mms_next(const std::vector<std::string> &args);
void mms_sync(const std::vector<std::string> &args);
void mms_transfer(const std::vector<std::string> &args);
void mms_delete(const std::vector<std::string> &args);
void mms_send(const std::vector<std::string> &args);
void mms_receive(const std::vector<std::string> &args);
void mms_note(const std::vector<std::string> &args);
void mms_show(const std::vector<std::string> &args);
void mms_set(const std::vector<std::string> &args);
void mms_help(const std::vector<std::string> &args);
void mms_debug(const std::vector<std::string> &args);
bool m_called_by_mms = false;
bool called_by_mms();
bool m_command_successful;
};
}

View File

@@ -1,6 +1,6 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.3.1.0"
#define DEF_MONERO_RELEASE_NAME "Cool Cage"
#define DEF_MONERO_VERSION "0.4.0.1"
#define DEF_MONERO_RELEASE_NAME "Dank Doge"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#include "version.h"

View File

@@ -34,7 +34,10 @@ set(wallet_sources
wallet2.cpp
wallet_args.cpp
ringdb.cpp
node_rpc_proxy.cpp)
node_rpc_proxy.cpp
message_store.cpp
message_transporter.cpp
)
set(wallet_private_headers
wallet2.h
@@ -44,7 +47,9 @@ set(wallet_private_headers
wallet_rpc_server_commands_defs.h
wallet_rpc_server_error_codes.h
ringdb.h
node_rpc_proxy.h)
node_rpc_proxy.h
message_store.h
message_transporter.h)
monero_private_headers(wallet
${wallet_private_headers})
@@ -102,7 +107,6 @@ set_property(TARGET wallet_rpc_server
OUTPUT_NAME "wownero-wallet-rpc")
install(TARGETS wallet_rpc_server DESTINATION bin)
# build and install libwallet_merged only if we building for GUI
if (BUILD_GUI_DEPS)
set(libs_to_merge

1003
src/wallet/message_store.cpp Normal file

File diff suppressed because it is too large Load Diff

357
src/wallet/message_store.h Normal file
View File

@@ -0,0 +1,357 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <cstdlib>
#include <string>
#include <vector>
#include "crypto/hash.h"
#include <boost/serialization/vector.hpp>
#include "serialization/serialization.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_basic/account_boost_serialization.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "common/i18n.h"
#include "message_transporter.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.mms"
namespace mms
{
enum class message_type
{
key_set,
finalizing_key_set,
multisig_sync_data,
partially_signed_tx,
fully_signed_tx,
note
};
enum class message_direction
{
in,
out
};
enum class message_state
{
ready_to_send,
sent,
waiting,
processed,
cancelled
};
enum class message_processing
{
prepare_multisig,
make_multisig,
finalize_multisig,
create_sync_data,
process_sync_data,
sign_tx,
send_tx,
submit_tx
};
struct message
{
uint32_t id;
message_type type;
message_direction direction;
std::string content;
uint64_t created;
uint64_t modified;
uint64_t sent;
uint32_t member_index;
crypto::hash hash;
message_state state;
uint32_t wallet_height;
uint32_t round;
uint32_t signature_count;
std::string transport_id;
};
// "wallet_height" (for lack of a short name that would describe what it is about)
// is the number of transfers present in the wallet at the time of message
// construction; used to coordinate generation of sync info (which depends
// on the content of the wallet at time of generation)
struct coalition_member
{
std::string label;
std::string transport_address;
bool monero_address_known;
cryptonote::account_public_address monero_address;
bool me;
uint32_t index;
};
struct processing_data
{
message_processing processing;
std::vector<uint32_t> message_ids;
uint32_t receiving_member_index = 0;
};
struct file_transport_message
{
cryptonote::account_public_address sender_address;
crypto::chacha_iv iv;
crypto::public_key encryption_public_key;
message internal_message;
};
// Overal .mms file structure, with the "message_store" object serialized to and
// encrypted in "encrypted_data"
struct file_data
{
std::string magic_string;
uint32_t file_version;
crypto::chacha_iv iv;
std::string encrypted_data;
};
// The following struct provides info about the current state of a "wallet2" object
// at the time of a "message_store" method call that those methods need. See on the
// one hand a first parameter of this type for several of those methods, and on the
// other hand the method "wallet2::get_multisig_wallet_state" which clients like the
// CLI wallet can use to get that info.
//
// Note that in the case of a wallet that is already multisig "address" is NOT the
// multisig address, but the "original" wallet address at creation time. Likewise
// "view_secret_key" is the original view secret key then.
//
// This struct definition is here and not in "wallet2.h" to avoid circular imports.
struct multisig_wallet_state
{
cryptonote::account_public_address address;
cryptonote::network_type nettype;
crypto::secret_key view_secret_key;
bool multisig;
bool multisig_is_ready;
bool has_multisig_partial_key_images;
size_t num_transfer_details;
std::string mms_file;
~multisig_wallet_state()
{
view_secret_key = crypto::null_skey;
}
};
class message_store
{
public:
message_store();
// Initialize and start to use the MMS, set the first member, this wallet itself
// Filename, if not null and not empty, is used to create the ".mms" file
// reset it if already used, with deletion of all members and messages
void init(const multisig_wallet_state &state, const std::string &own_label,
const std::string &own_transport_address, uint32_t coalition_size, uint32_t threshold);
void set_active(bool active) { m_active = active; };
void set_auto_send(bool auto_send) { m_auto_send = auto_send; };
void set_options(const boost::program_options::variables_map& vm);
void set_options(const std::string &bitmessage_address, const std::string &bitmessage_login);
bool get_active() const { return m_active; };
bool get_auto_send() const { return m_auto_send; };
uint32_t get_threshold() const { return m_threshold; };
uint32_t get_coalition_size() const { return m_coalition_size; };
void set_member(const multisig_wallet_state &state,
uint32_t index,
const boost::optional<std::string> &label,
const boost::optional<std::string> &transport_address,
const boost::optional<cryptonote::account_public_address> monero_address);
const coalition_member &get_member(uint32_t index) const;
bool get_member_index_by_monero_address(const cryptonote::account_public_address &monero_address, uint32_t &index) const;
bool get_member_index_by_label(const std::string label, uint32_t &index) const;
const std::vector<coalition_member> &get_all_members() const { return m_members; };
bool member_info_complete() const;
// Process data just created by "me" i.e. the own local wallet, e.g. as the result of a "prepare_multisig" command
// Creates the resulting messages to the right members
void process_wallet_created_data(const multisig_wallet_state &state, message_type type, const std::string &content);
// Go through all the messages, look at the "ready to process" ones, and check whether any single one
// or any group of them can be processed, because they are processable as single messages (like a tx
// that is fully signed and thus ready for submit to the net) or because they form a complete group
// (e.g. key sets from all coalition members to make the wallet multisig). If there are multiple
// candidates, e.g. in 2/3 multisig sending to one OR the other member to sign, there will be more
// than 1 element in 'data' for the user to choose. If nothing is ready "false" is returned.
// The method mostly ignores the order in which the messages were received because messages may be delayed
// (e.g. sync data from a member arrives AFTER a transaction to submit) or because message time stamps
// may be wrong so it's not possible to order them reliably.
// Messages also may be ready by themselves but the wallet not yet ready for them (e.g. sync data already
// arriving when the wallet is not yet multisig because key sets were delayed or were lost altogether.)
// If nothing is ready 'wait_reason' may contain further info about the reason why.
bool get_processable_messages(const multisig_wallet_state &state,
bool force_sync,
std::vector<processing_data> &data_list,
std::string &wait_reason);
void set_messages_processed(const processing_data &data);
uint32_t add_message(const multisig_wallet_state &state,
uint32_t member_index, message_type type, message_direction direction,
const std::string &content);
const std::vector<message> &get_all_messages() const { return m_messages; };
bool get_message_by_id(uint32_t id, message &m) const;
message get_message_by_id(uint32_t id) const;
void set_message_processed_or_sent(uint32_t id);
void delete_message(uint32_t id);
void delete_all_messages();
void send_message(const multisig_wallet_state &state, uint32_t id);
bool check_for_messages(const multisig_wallet_state &state, std::vector<message> &messages);
void stop() { m_run.store(false, std::memory_order_relaxed); m_transporter.stop(); }
void write_to_file(const multisig_wallet_state &state, const std::string &filename);
void read_from_file(const multisig_wallet_state &state, const std::string &filename);
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver)
{
a & m_active;
a & m_coalition_size;
a & m_nettype;
a & m_threshold;
a & m_members;
a & m_messages;
a & m_next_message_id;
a & m_auto_send;
}
const char* message_type_to_string(message_type type);
const char* message_direction_to_string(message_direction direction);
const char* message_state_to_string(message_state state);
std::string member_to_string(const coalition_member &member, uint32_t max_width);
static const char *tr(const char *str) { return i18n_translate(str, "tools::mms"); }
static void init_options(boost::program_options::options_description& desc_params);
private:
bool m_active;
uint32_t m_coalition_size;
uint32_t m_threshold;
bool m_auto_send;
cryptonote::network_type m_nettype;
std::vector<coalition_member> m_members;
std::vector<message> m_messages;
uint32_t m_next_message_id;
std::string m_filename;
message_transporter m_transporter;
std::atomic<bool> m_run;
bool get_message_index_by_id(uint32_t id, uint32_t &index) const;
uint32_t get_message_index_by_id(uint32_t id) const;
bool any_message_of_type(message_type type, message_direction direction) const;
bool any_message_with_hash(const crypto::hash &hash) const;
bool message_ids_complete(const std::vector<uint32_t> ids) const;
void encrypt(uint32_t member_index, const std::string &plaintext,
std::string &ciphertext, crypto::public_key &encryption_public_key, crypto::chacha_iv &iv);
void decrypt(const std::string &ciphertext, const crypto::public_key &encryption_public_key, const crypto::chacha_iv &iv,
const crypto::secret_key &view_secret_key, std::string &plaintext);
void delete_transport_message(uint32_t id);
std::string account_address_to_string(const cryptonote::account_public_address &account_address) const;
void save(const multisig_wallet_state &state);
};
}
BOOST_CLASS_VERSION(mms::file_data, 0)
BOOST_CLASS_VERSION(mms::message_store, 0)
BOOST_CLASS_VERSION(mms::message, 0)
BOOST_CLASS_VERSION(mms::file_transport_message, 0)
BOOST_CLASS_VERSION(mms::coalition_member, 0)
namespace boost
{
namespace serialization
{
template <class Archive>
inline void serialize(Archive &a, mms::file_data &x, const boost::serialization::version_type ver)
{
a & x.magic_string;
a & x.file_version;
a & x.iv;
a & x.encrypted_data;
}
template <class Archive>
inline void serialize(Archive &a, mms::message &x, const boost::serialization::version_type ver)
{
a & x.id;
a & x.type;
a & x.direction;
a & x.content;
a & x.created;
a & x.modified;
a & x.sent;
a & x.member_index;
a & x.hash;
a & x.state;
a & x.wallet_height;
a & x.round;
a & x.signature_count;
a & x.transport_id;
}
template <class Archive>
inline void serialize(Archive &a, mms::coalition_member &x, const boost::serialization::version_type ver)
{
a & x.label;
a & x.transport_address;
a & x.monero_address_known;
a & x.monero_address;
a & x.me;
a & x.index;
}
template <class Archive>
inline void serialize(Archive &a, mms::file_transport_message &x, const boost::serialization::version_type ver)
{
a & x.sender_address;
a & x.iv;
a & x.encryption_public_key;
a & x.internal_message;
}
template <class Archive>
inline void serialize(Archive &a, crypto::chacha_iv &x, const boost::serialization::version_type ver)
{
a & x.data;
}
}
}

View File

@@ -0,0 +1,287 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include "message_transporter.h"
#include "string_coding.h"
#include <boost/format.hpp>
#include "wallet_errors.h"
#include "net/http_client.h"
#include "net/net_parse_helpers.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.mms"
#define PYBITMESSAGE_DEFAULT_API_PORT 8442
namespace mms
{
namespace bitmessage_rpc
{
struct message_info
{
uint32_t encodingType;
std::string toAddress;
uint32_t read;
std::string msgid;
std::string message;
std::string fromAddress;
std::string receivedTime;
std::string subject;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(encodingType)
KV_SERIALIZE(toAddress)
KV_SERIALIZE(read)
KV_SERIALIZE(msgid)
KV_SERIALIZE(message);
KV_SERIALIZE(fromAddress)
KV_SERIALIZE(receivedTime)
KV_SERIALIZE(subject)
END_KV_SERIALIZE_MAP()
};
struct inbox_messages_response
{
std::vector<message_info> inboxMessages;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(inboxMessages)
END_KV_SERIALIZE_MAP()
};
}
message_transporter::message_transporter()
{
m_run = true;
}
void message_transporter::set_options(const std::string &bitmessage_address, const std::string &bitmessage_login) {
m_bitmessage_url = bitmessage_address;
epee::net_utils::http::url_content address_parts{};
epee::net_utils::parse_url(m_bitmessage_url, address_parts);
if (address_parts.port == 0)
{
address_parts.port = PYBITMESSAGE_DEFAULT_API_PORT;
}
auto pos = bitmessage_login.find(":");
if (pos == std::string::npos)
{
m_bitmessage_user = bitmessage_login;
m_bitmessage_password.clear();
}
else
{
m_bitmessage_user = bitmessage_login.substr(0, pos);
m_bitmessage_password = bitmessage_login.substr(pos + 1);
}
boost::optional<epee::net_utils::http::login> login{};
login.emplace(m_bitmessage_user, m_bitmessage_password);
m_http_client.set_server(address_parts.host, std::to_string(address_parts.port), login);
}
bool message_transporter::receive_messages(const cryptonote::account_public_address &destination_monero_address,
const std::string &destination_transport_address,
std::vector<transport_message> &messages)
{
// The message body of the Bitmessage message is basically the transport message, as JSON (and nothing more).
// Weeding out other, non-MMS messages is done in a simple way: If it deserializes without error, it's an MMS message
// That JSON is Base64-encoded by the MMS because the Monero epee JSON serializer does not escape anything and happily
// includes even 0 (NUL) in strings, which might confuse Bitmessage or at least display confusingly in the client.
// There is yet another Base64-encoding of course as part of the Bitmessage API for the message body parameter
// The Bitmessage API call "getAllInboxMessages" gives back a JSON array with all the messages (despite using
// XML-RPC for the calls, and not JSON-RPC ...)
m_run.store(true, std::memory_order_relaxed);
std::string request;
start_xml_rpc_cmd(request, "getAllInboxMessages");
end_xml_rpc_cmd(request);
std::string answer;
post_request(request, answer);
std::string json = get_str_between_tags(answer, "<string>", "</string>");
bitmessage_rpc::inbox_messages_response bitmessage_res;
epee::serialization::load_t_from_json(bitmessage_res, json);
size_t size = bitmessage_res.inboxMessages.size();
messages.clear();
for (size_t i = 0; i < size; ++i)
{
if (!m_run.load(std::memory_order_relaxed))
{
// Stop was called, don't waste time processing any more messages
return false;
}
bitmessage_rpc::message_info message_info = bitmessage_res.inboxMessages[i];
transport_message message;
bool is_mms_message = false;
try
{
// First Base64-decoding: The message body is Base64 in the Bitmessage API
std::string message_body = epee::string_encoding::base64_decode(message_info.message);
// Second Base64-decoding: The MMS uses Base64 to hide non-textual data in its JSON from Bitmessage
json = epee::string_encoding::base64_decode(message_body);
epee::serialization::load_t_from_json(message, json);
is_mms_message = true;
}
catch(const std::exception& e)
{
}
if (is_mms_message)
{
if (message.destination_monero_address == destination_monero_address)
{
message.transport_id = message_info.msgid;
messages.push_back(message);
}
}
}
return true;
}
bool message_transporter::send_message(const transport_message &message)
{
// <toAddress> <fromAddress> <subject> <message> [encodingType [TTL]]
std::string request;
start_xml_rpc_cmd(request, "sendMessage");
add_xml_rpc_string_param(request, message.destination_transport_address);
add_xml_rpc_string_param(request, message.source_transport_address);
add_xml_rpc_base64_param(request, message.subject);
std::string json = epee::serialization::store_t_to_json(message);
std::string message_body = epee::string_encoding::base64_encode(json); // See comment in "receive_message" about reason for (double-)Base64 encoding
add_xml_rpc_base64_param(request, message_body);
add_xml_rpc_integer_param(request, 2);
end_xml_rpc_cmd(request);
std::string answer;
post_request(request, answer);
return true;
}
bool message_transporter::delete_message(const std::string &transport_id)
{
std::string request;
start_xml_rpc_cmd(request, "trashMessage");
add_xml_rpc_string_param(request, transport_id);
end_xml_rpc_cmd(request);
std::string answer;
post_request(request, answer);
return true;
}
bool message_transporter::post_request(const std::string &request, std::string &answer)
{
// Somehow things do not work out if one tries to connect "m_http_client" to Bitmessage
// and keep it connected over the course of several calls. But with a new connection per
// call and disconnecting after the call there is no problem (despite perhaps a small
// slowdown)
epee::net_utils::http::fields_list additional_params;
// Basic access authentication according to RFC 7617 (which the epee HTTP classes do not seem to support?)
std::string user_password(m_bitmessage_user + ":" + m_bitmessage_password);
std::string auth_string = epee::string_encoding::base64_encode(user_password);
auth_string.insert(0, "Basic ");
additional_params.push_back(std::make_pair("Authorization", auth_string));
additional_params.push_back(std::make_pair("Content-Type", "application/xml; charset=utf-8"));
const epee::net_utils::http::http_response_info* response = NULL;
std::chrono::milliseconds timeout = std::chrono::seconds(15);
bool r = m_http_client.invoke("/", "POST", request, timeout, std::addressof(response), std::move(additional_params));
if (r)
{
answer = response->m_body;
}
else
{
LOG_ERROR("POST request to Bitmessage failed: " << request.substr(0, 300));
THROW_WALLET_EXCEPTION(tools::error::no_connection_to_bitmessage, m_bitmessage_url);
}
m_http_client.disconnect(); // see comment above
std::string string_value = get_str_between_tags(answer, "<string>", "</string>");
if ((string_value.find("API Error") == 0) || (string_value.find("RPC ") == 0))
{
THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value);
}
return r;
}
// Pick some string between two delimiters
// When parsing the XML returned by PyBitmessage, don't bother to fully parse it but as a little hack rely on the
// fact that e.g. a single string returned will be, however deeply nested in "<params><param><value>...", delivered
// between the very first "<string>" and "</string>" tags to be found in the XML
std::string message_transporter::get_str_between_tags(const std::string &s, const std::string &start_delim, const std::string &stop_delim)
{
size_t first_delim_pos = s.find(start_delim);
if (first_delim_pos != std::string::npos)
{
size_t end_pos_of_first_delim = first_delim_pos + start_delim.length();
size_t last_delim_pos = s.find(stop_delim);
if (last_delim_pos != std::string::npos)
{
return s.substr(end_pos_of_first_delim, last_delim_pos - end_pos_of_first_delim);
}
}
return std::string();
}
void message_transporter::start_xml_rpc_cmd(std::string &xml, const std::string &method_name)
{
xml = (boost::format("<?xml version=\"1.0\"?><methodCall><methodName>%s</methodName><params>") % method_name).str();
}
void message_transporter::add_xml_rpc_string_param(std::string &xml, const std::string &param)
{
xml += (boost::format("<param><value><string>%s</string></value></param>") % param).str();
}
void message_transporter::add_xml_rpc_base64_param(std::string &xml, const std::string &param)
{
// Bitmessage expects some arguments Base64-encoded, but it wants them as parameters of type "string", not "base64" that is also part of XML-RPC
std::string encoded_param = epee::string_encoding::base64_encode(param);
xml += (boost::format("<param><value><string>%s</string></value></param>") % encoded_param).str();
}
void message_transporter::add_xml_rpc_integer_param(std::string &xml, const int32_t &param)
{
xml += (boost::format("<param><value><int>%i</int></value></param>") % param).str();
}
void message_transporter::end_xml_rpc_cmd(std::string &xml)
{
xml += "</params></methodCall>";
}
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include "serialization/keyvalue_serialization.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_basic/account_boost_serialization.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "net/http_server_impl_base.h"
#include "net/http_client.h"
#include "common/util.h"
#include "serialization/keyvalue_serialization.h"
#define PYBITMESSAGE_API_PORT 8442
namespace mms
{
struct transport_message
{
cryptonote::account_public_address source_monero_address;
std::string source_transport_address;
cryptonote::account_public_address destination_monero_address;
std::string destination_transport_address;
crypto::chacha_iv iv;
crypto::public_key encryption_public_key;
uint64_t timestamp;
uint32_t type;
std::string subject;
std::string content;
crypto::hash hash;
crypto::signature signature;
uint32_t round;
uint32_t signature_count;
std::string transport_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(source_monero_address)
KV_SERIALIZE(source_transport_address)
KV_SERIALIZE(destination_monero_address)
KV_SERIALIZE(destination_transport_address)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(iv)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(encryption_public_key)
KV_SERIALIZE(timestamp)
KV_SERIALIZE(type)
KV_SERIALIZE(subject)
KV_SERIALIZE(content)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(hash)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(signature)
KV_SERIALIZE(round)
KV_SERIALIZE(signature_count)
KV_SERIALIZE(transport_id)
END_KV_SERIALIZE_MAP()
};
class message_transporter {
public:
message_transporter();
void set_options(const std::string &bitmessage_address, const std::string &bitmessage_login);
bool send_message(const transport_message &message);
bool receive_messages(const cryptonote::account_public_address &destination_monero_address,
const std::string &destination_transport_address,
std::vector<transport_message> &messages);
bool delete_message(const std::string &transport_id);
void stop() { m_run.store(false, std::memory_order_relaxed); }
private:
epee::net_utils::http::http_simple_client m_http_client;
std::string m_bitmessage_url;
std::string m_bitmessage_user;
std::string m_bitmessage_password;
std::atomic<bool> m_run;
bool post_request(const std::string &request, std::string &answer);
std::string get_str_between_tags(const std::string &s, const std::string &start_delim, const std::string &stop_delim);
void start_xml_rpc_cmd(std::string &xml, const std::string &method_name);
void add_xml_rpc_string_param(std::string &xml, const std::string &param);
void add_xml_rpc_base64_param(std::string &xml, const std::string &param);
void add_xml_rpc_integer_param(std::string &xml, const int32_t &param);
void end_xml_rpc_cmd(std::string &xml);
};
}

View File

@@ -153,7 +153,7 @@ struct options {
};
};
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file)
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
{
keys_file = file_path;
wallet_file = file_path;
@@ -165,6 +165,7 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file,
{//provided wallet file name
keys_file += ".keys";
}
mms_file = file_path + ".mms";
}
uint64_t calculate_fee(uint64_t fee_per_kb, size_t bytes, uint64_t fee_multiplier)
@@ -230,6 +231,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
wallet->init(std::move(daemon_address), std::move(login));
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string());
wallet->get_message_store().set_options(vm);
return wallet;
}
@@ -676,6 +678,8 @@ wallet2::wallet2(network_type nettype, bool restricted):
m_light_wallet_connected(false),
m_light_wallet_balance(0),
m_light_wallet_unlocked_balance(0),
m_original_keys_available(false),
m_message_store(),
m_key_on_device(false),
m_ring_history_saved(false),
m_ringdb()
@@ -709,6 +713,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.stagenet);
command_line::add_arg(desc_params, opts.restricted);
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
mms::message_store::init_options(desc_params);
}
std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -2581,6 +2586,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
rapidjson::Document json;
json.SetObject();
rapidjson::Value value(rapidjson::kStringType);
value.SetString(account_data.c_str(), account_data.length());
json.AddMember("key_data", value, json.GetAllocator());
if (!seed_language.empty())
@@ -2683,6 +2689,22 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetUint(m_subaddress_lookahead_minor);
json.AddMember("subaddress_lookahead_minor", value2, json.GetAllocator());
value2.SetInt(m_original_keys_available ? 1 : 0);
json.AddMember("original_keys_available", value2, json.GetAllocator());
std::string original_address;
std::string original_view_secret_key;
if (m_original_keys_available)
{
original_address = get_account_address_as_str(m_nettype, false, m_original_address);
value.SetString(original_address.c_str(), original_address.length());
json.AddMember("original_address", value, json.GetAllocator());
original_view_secret_key = epee::string_tools::pod_to_hex(m_original_view_secret_key);
value.SetString(original_view_secret_key.c_str(), original_view_secret_key.length());
json.AddMember("original_view_secret_key", value, json.GetAllocator());
}
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2758,6 +2780,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = 0;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
m_key_on_device = false;
}
else if(json.IsObject())
@@ -2884,6 +2907,44 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
m_subaddress_lookahead_minor = field_subaddress_lookahead_minor;
if (json.HasMember("original_keys_available"))
{
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_keys_available, int, Int, false, false);
m_original_keys_available = field_original_keys_available;
if (m_original_keys_available)
{
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_address, std::string, String, false, std::string());
if (!field_original_address_found)
{
LOG_ERROR("Field original_address not found in JSON");
return false;
}
address_parse_info info;
bool ok = get_account_address_from_str(info, m_nettype, field_original_address);
if (!ok)
{
LOG_ERROR("Failed to parse original_address from JSON");
return false;
}
m_original_address = info.address;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_view_secret_key, std::string, String, false, std::string());
if (!field_original_view_secret_key_found)
{
LOG_ERROR("Field original_view_secret_key not found in JSON");
return false;
}
ok = epee::string_tools::hex_to_pod(field_original_view_secret_key, m_original_view_secret_key);
if (!ok)
{
LOG_ERROR("Failed to parse original_view_secret_key from JSON");
}
}
}
else
{
m_original_keys_available = false;
}
}
else
{
@@ -3051,6 +3112,10 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig_signers = multisig_signers;
m_key_on_device = false;
// Not possible to restore a multisig wallet that is able to activate the MMS
// (because the original keys are not (yet) part of the restore info)
m_original_keys_available = false;
if (!wallet_.empty())
{
bool r = store_keys(m_keys_file, password, false);
@@ -3101,6 +3166,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
m_original_keys_available = false;
m_key_on_device = false;
// calculate a starting refresh height
@@ -3199,6 +3265,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
m_original_keys_available = false;
m_key_on_device = false;
if (!wallet_.empty())
@@ -3249,6 +3316,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
m_original_keys_available = false;
m_key_on_device = false;
if (!wallet_.empty())
@@ -3295,6 +3363,7 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
m_original_keys_available = false;
if (!wallet_.empty()) {
bool r = store_keys(m_keys_file, password, false);
@@ -3369,6 +3438,15 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
CHECK_AND_ASSERT_THROW_MES(false, "Unsupported threshold case");
}
if (!m_original_keys_available)
{
// Save the original i.e. non-multisig keys so the MMS can continue to use them to encrypt and decrypt messages
// (making a wallet multisig overwrites those keys, see account_base::make_multisig)
m_original_address = m_account.get_keys().m_account_address;
m_original_view_secret_key = m_account.get_keys().m_view_secret_key;
m_original_keys_available = true;
}
// the multisig view key is shared by all, make one all can derive
MINFO("Creating view key...");
crypto::secret_key view_skey = cryptonote::generate_multisig_view_secret_key(get_account().get_keys().m_view_secret_key, view_keys);
@@ -3696,8 +3774,8 @@ void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee
//----------------------------------------------------------------------------------------------------
void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists)
{
std::string keys_file, wallet_file;
do_prepare_file_names(file_path, keys_file, wallet_file);
std::string keys_file, wallet_file, mms_file;
do_prepare_file_names(file_path, keys_file, wallet_file, mms_file);
boost::system::error_code ignore;
keys_file_exists = boost::filesystem::exists(keys_file, ignore);
@@ -3751,7 +3829,7 @@ bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash&
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_file_names(const std::string& file_path)
{
do_prepare_file_names(file_path, m_keys_file, m_wallet_file);
do_prepare_file_names(file_path, m_keys_file, m_wallet_file, m_mms_file);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -3922,6 +4000,8 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
MERROR("Failed to save rings, will try again next time");
}
m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
}
//----------------------------------------------------------------------------------------------------
void wallet2::trim_hashchain()
@@ -4029,6 +4109,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
const std::string old_file = m_wallet_file;
const std::string old_keys_file = m_keys_file;
const std::string old_address_file = m_wallet_file + ".address.txt";
const std::string old_mms_file = m_mms_file;
// save keys to the new file
// if we here, main wallet file is saved and we only need to save keys and address files
@@ -4058,6 +4139,14 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
if (!r) {
LOG_ERROR("error removing file: " << old_address_file);
}
// remove old message store file
if (boost::filesystem::exists(old_mms_file))
{
r = boost::filesystem::remove(old_mms_file);
if (!r) {
LOG_ERROR("error removing file: " << old_mms_file);
}
}
} else {
// save to new file
#ifdef WIN32
@@ -4083,6 +4172,14 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
std::error_code e = tools::replace_file(new_file, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
}
if (m_message_store.get_active())
{
// While the "m_message_store" object of course always exist, a file for the message
// store should only exist if the MMS is really active
m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
}
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(uint32_t index_major) const
@@ -10561,4 +10658,28 @@ void wallet2::generate_genesis(cryptonote::block& b) const {
cryptonote::generate_genesis_block(b, config::GENESIS_TX, config::GENESIS_NONCE);
}
}
//----------------------------------------------------------------------------------------------------
mms::multisig_wallet_state wallet2::get_multisig_wallet_state()
{
mms::multisig_wallet_state state;
state.nettype = m_nettype;
state.multisig = multisig(&state.multisig_is_ready);
state.has_multisig_partial_key_images = has_multisig_partial_key_images();
state.num_transfer_details = m_transfers.size();
if (state.multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_original_keys_available, error::wallet_internal_error, "MMS use not possible because own original Monero address not available");
state.address = m_original_address;
state.view_secret_key = m_original_view_secret_key;
}
else
{
state.address = m_account.get_keys().m_account_address;
state.view_secret_key = m_account.get_keys().m_view_secret_key;
}
state.mms_file=m_mms_file;
return state;
}
}

View File

@@ -58,6 +58,7 @@
#include "wallet_errors.h"
#include "common/password.h"
#include "node_rpc_proxy.h"
#include "message_store.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2"
@@ -454,6 +455,7 @@ namespace tools
typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry;
/*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
@@ -593,7 +595,7 @@ namespace tools
bool init(std::string daemon_address = "http://localhost:8080",
boost::optional<epee::net_utils::http::login> daemon_login = boost::none, uint64_t upper_transaction_size_limit = 0, bool ssl = false);
void stop() { m_run.store(false, std::memory_order_relaxed); }
void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }
i_wallet2_callback* callback() const { return m_callback; }
void callback(i_wallet2_callback* callback) { m_callback = callback; }
@@ -1077,6 +1079,10 @@ namespace tools
bool unblackball_output(const crypto::public_key &output);
bool is_output_blackballed(const crypto::public_key &output) const;
// MMS -------------------------------------------------------------------------------------------------
mms::message_store& get_message_store() { return m_message_store; };
mms::multisig_wallet_state get_multisig_wallet_state();
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -1148,6 +1154,7 @@ namespace tools
std::string m_daemon_address;
std::string m_wallet_file;
std::string m_keys_file;
std::string m_mms_file;
epee::net_utils::http::http_simple_client m_http_client;
hashchain m_blockchain;
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
@@ -1232,6 +1239,11 @@ namespace tools
std::string m_ring_database;
bool m_ring_history_saved;
std::unique_ptr<ringdb> m_ringdb;
mms::message_store m_message_store;
bool m_original_keys_available;
cryptonote::account_public_address m_original_address;
crypto::secret_key m_original_view_secret_key;
};
}
BOOST_CLASS_VERSION(tools::wallet2, 24)

View File

@@ -784,6 +784,31 @@ namespace tools
std::string m_wallet_file;
};
//----------------------------------------------------------------------------------------------------
struct mms_error : public wallet_logic_error
{
protected:
explicit mms_error(std::string&& loc, const std::string& message)
: wallet_logic_error(std::move(loc), message)
{
}
};
//----------------------------------------------------------------------------------------------------
struct no_connection_to_bitmessage : public mms_error
{
explicit no_connection_to_bitmessage(std::string&& loc, const std::string& address)
: mms_error(std::move(loc), "no connection to PyBitmessage at address " + address)
{
}
};
//----------------------------------------------------------------------------------------------------
struct bitmessage_api_error : public mms_error
{
explicit bitmessage_api_error(std::string&& loc, const std::string& error_string)
: mms_error(std::move(loc), "PyBitmessage returned " + error_string)
{
}
};
//----------------------------------------------------------------------------------------------------
#if !defined(_MSC_VER)