Compare commits

...

82 Commits

Author SHA1 Message Date
onryo fe04ef3095 Merge branch 'dev' 2 months ago
onryo 23e3e3899a Add release name before merging 2 months ago
Duke 23813ae00e Update relnotes 3 months ago
Duke d8e528f696 Bump version to 1.4.2 3 months ago
Duke 5610d6c572 Update relnotes for 1.4.2 3 months ago
Duke 3a6f632b9b Try to prevent #155 3 months ago
Duke 2754629a95 Do not log sensitive data to STDOUT 3 months ago
Duke eea2a9a6bf Choose number of compile jobs in build.sh #156 4 months ago
duke e6195fd918 Merge pull request 'Replace old graphics with new' (#147) from onryo into dev 4 months ago
Duke b3f195432e Merge branch 'dev' 4 months ago
Duke 02325ad7ae relnotes 4 months ago
Duke 0c9a3f43ad linguist 4 months ago
Duke 00b143e04f Create relnotes for 1.4.1 4 months ago
Duke c442377473 bump version 4 months ago
duke 5659a2a725 Merge pull request 'Debug tab' (#148) from debuglog into dev 4 months ago
Duke 702619a8e0 Support dragonx debug log and custom number of lines 4 months ago
onryo ee5e94cfd0 fix build when removing old files 4 months ago
onryo 8119c5b6e3 fix 146 4 months ago
Duke da3fb9c8a4 Add refresh button for debug log 4 months ago
Duke 0f45b3fe5b Add tab for viewing the debug log 4 months ago
Duke 05790935ba Revert "change gif when sending" 4 months ago
duke 203c23dad2 Merge pull request 'Allow custom rescan height on privkey import' (#145) from import into dev 4 months ago
Duke 1b10aefbe8 Cleanup 4 months ago
Duke d35a601dcc verify that taddr privkeys are base58 4 months ago
Duke b52c7bc151 Remove isSproutAddress 4 months ago
Duke a0cc4184bc Trim leading and trailing whitespace from rescan height when importing a privkey 4 months ago
Duke 8b41a3b0f4 Disable rescanfrom input if rescan is unchecked 4 months ago
Duke 68bd0db44c Only import valid zaddr+taddr privkeys and only rescan if there was at least 1 valid privkey 4 months ago
Duke 2000377783 Too bad this code does not seem to work 4 months ago
Duke e042c1fb09 We do not support sprout privkeys that begin with SK 4 months ago
Duke 7db95fbf49 Support disabling rescan or a custom rescan height when importing privkeys 4 months ago
Duke 8bb0b3df5c Make import popup look nicer 4 months ago
Duke f689547a36 Add basic rescan options to import popup 4 months ago
onryo f50ccd78b5 change gif when sending 4 months ago
onryo 219e41ccb5 dialog text 4 months ago
Duke ec6327a6b0 Add function to validate taddr privkeys 4 months ago
Duke 227dcaddbb Slightly better zaddr privkey validation 4 months ago
onryo 868bf83155 add rescanfrom 4 months ago
onryo 4ef65d1a3f add chkrescan 4 months ago
Duke 17c44521be Use takeFirst() instead of first() and pop_front() 4 months ago
Duke c5ceac8443 View transparent spends and shielded outputs in txs; Allow double clicking on a tx in tx tab to view tx 5 months ago
Duke 8b8bca02ac Add View transaction as right menu option in tx tab 5 months ago
Duke 81702d25c1 Add view transaction ui file 5 months ago
Duke fb67b86d0d View Transaction 5 months ago
Duke f914f6d61a Just say Error, since we show this error for all errors, not just transaction errors 5 months ago
Duke a18014b6d4 Render valuePools json and each tx in their own property 5 months ago
Duke 1e4095651a Allow items to be selected 5 months ago
Duke 946ed661e9 Tor v3 has been supported for a while 5 months ago
Duke 9e4c26ccd2 Show transaction list in CSV format when viewing a block; allow viewing block 0 5 months ago
Duke 5dc1944084 More debugging about block properties 5 months ago
Duke 9187f3c620 Add getrawtransaction RPC method 5 months ago
Duke 4d28ac2969 Add z_viewtransaction RPC method 5 months ago
Duke d3846c7bdf Merge branch 'master' into dev 5 months ago
Duke 775581f942 Merge branch 'dev' 5 months ago
Duke 0c70550080 update relnotes 5 months ago
Duke e7d46d9a95 update translations 5 months ago
Duke 9bf04778bd bump version to 1.4.0 5 months ago
fekt 427c960546 Require int for block height 8 months ago
Duke b8955b176f Render integer values correctly in Get Block Info 8 months ago
fekt 25630d75df Merge branch 'dev' of https://git.hush.is/hush/SilentDragon into dev 9 months ago
fekt dee213dc5a Adding missing getblock.ui 9 months ago
fekt ed22b79957 Update 'doc/relnotes/README.md' 9 months ago
fekt ba2f322124 Initial commit for viewing getblock info 9 months ago
fekt 64f32cac57 Update 'doc/relnotes/README.md' 9 months ago
fekt d06cc5af81 Allow setting IP for tor proxy 9 months ago
fekt ffb12e0adf Update 'doc/relnotes/README.md' 10 months ago
fekt dbc34dde12 Specify count for listtransactions 10 months ago
fekt cf5c369de3 Update relnotes 10 months ago
fekt ed1fab8550 Use single set of translation resources 1 year ago
fekt 41f18d76ee Revert "Update 'application-sdx.qrc'" 1 year ago
fekt d96fa89e02 Update 'application-sdx.qrc' 1 year ago
fekt 2834abcbc6 derp fix 1 year ago
fekt 03fc69d001 Added DragonX file names 1 year ago
fekt 8cfb0b4ec6 Fix for saving on Windows 1 year ago
Duke 1d2e7007fb Fix compiler errors and warnings 1 year ago
Jonathan "Duke" Leto 403b29ec2e Remove websocket junk 1 year ago
onryo 7fe00b6b46 Fix Lack of Q_OBJECT macros for #120 1 year ago
fekt 5c9cc656f0 Update 'README.md' 1 year ago
fekt 4bb1d98ecd Fixing SDX .wxs file 1 year ago
fekt b4400e3ac8 Wixl files for .msi 1 year ago
fekt fb07f11fd2 Update application-sdx.qrc 1 year ago
fekt 8d3fce909d DragonX info tab logo 1 year ago
  1. 3
      README.md
  2. 71
      SilentDragon-1.3.1.wxs
  3. 87
      SilentDragonX-1.3.1.wxs
  4. 40
      application-sdx.qrc
  5. 3
      application.qrc
  6. 23
      build.sh
  7. 44
      doc/relnotes/README.md
  8. 0
      res-drgx/hushdlogo.png
  9. BIN
      res-drgx/silentdragon_be.qm
  10. 2690
      res-drgx/silentdragon_be.ts
  11. BIN
      res-drgx/silentdragon_bg.qm
  12. 2560
      res-drgx/silentdragon_bg.ts
  13. BIN
      res-drgx/silentdragon_de.qm
  14. 2917
      res-drgx/silentdragon_de.ts
  15. BIN
      res-drgx/silentdragon_es.qm
  16. 2898
      res-drgx/silentdragon_es.ts
  17. BIN
      res-drgx/silentdragon_fi.qm
  18. 2911
      res-drgx/silentdragon_fi.ts
  19. BIN
      res-drgx/silentdragon_fil.qm
  20. 2751
      res-drgx/silentdragon_fil.ts
  21. BIN
      res-drgx/silentdragon_fr.qm
  22. 2945
      res-drgx/silentdragon_fr.ts
  23. BIN
      res-drgx/silentdragon_hr.qm
  24. 2754
      res-drgx/silentdragon_hr.ts
  25. BIN
      res-drgx/silentdragon_id.qm
  26. 2464
      res-drgx/silentdragon_id.ts
  27. BIN
      res-drgx/silentdragon_it.qm
  28. 2897
      res-drgx/silentdragon_it.ts
  29. BIN
      res-drgx/silentdragon_nl.qm
  30. 2686
      res-drgx/silentdragon_nl.ts
  31. BIN
      res-drgx/silentdragon_pl.qm
  32. 2689
      res-drgx/silentdragon_pl.ts
  33. BIN
      res-drgx/silentdragon_pt.qm
  34. 2885
      res-drgx/silentdragon_pt.ts
  35. BIN
      res-drgx/silentdragon_ro.qm
  36. 2752
      res-drgx/silentdragon_ro.ts
  37. BIN
      res-drgx/silentdragon_ru.qm
  38. 2691
      res-drgx/silentdragon_ru.ts
  39. BIN
      res-drgx/silentdragon_sr.qm
  40. 2754
      res-drgx/silentdragon_sr.ts
  41. BIN
      res-drgx/silentdragon_tr.qm
  42. 2902
      res-drgx/silentdragon_tr.ts
  43. BIN
      res-drgx/silentdragon_uk.qm
  44. 3152
      res-drgx/silentdragon_uk.ts
  45. BIN
      res-drgx/silentdragon_zh.qm
  46. 3037
      res-drgx/silentdragon_zh.ts
  47. BIN
      res-drgx/tropical-hush.png
  48. BIN
      res/silentdragon-animated-dark.gif
  49. BIN
      res/silentdragon-animated-startup.gif
  50. BIN
      res/silentdragon-animated.gif
  51. BIN
      res/silentdragon_be.qm
  52. 942
      res/silentdragon_be.ts
  53. 942
      res/silentdragon_bg.ts
  54. BIN
      res/silentdragon_de.qm
  55. 944
      res/silentdragon_de.ts
  56. BIN
      res/silentdragon_es.qm
  57. 944
      res/silentdragon_es.ts
  58. BIN
      res/silentdragon_fi.qm
  59. 944
      res/silentdragon_fi.ts
  60. BIN
      res/silentdragon_fil.qm
  61. 944
      res/silentdragon_fil.ts
  62. BIN
      res/silentdragon_fr.qm
  63. 944
      res/silentdragon_fr.ts
  64. BIN
      res/silentdragon_hr.qm
  65. 944
      res/silentdragon_hr.ts
  66. BIN
      res/silentdragon_it.qm
  67. 944
      res/silentdragon_it.ts
  68. BIN
      res/silentdragon_nl.qm
  69. 942
      res/silentdragon_nl.ts
  70. BIN
      res/silentdragon_pl.qm
  71. 942
      res/silentdragon_pl.ts
  72. BIN
      res/silentdragon_pt.qm
  73. 944
      res/silentdragon_pt.ts
  74. BIN
      res/silentdragon_ro.qm
  75. 944
      res/silentdragon_ro.ts
  76. BIN
      res/silentdragon_ru.qm
  77. 942
      res/silentdragon_ru.ts
  78. BIN
      res/silentdragon_sr.qm
  79. 944
      res/silentdragon_sr.ts
  80. BIN
      res/silentdragon_tr.qm
  81. 944
      res/silentdragon_tr.ts
  82. BIN
      res/silentdragon_uk.qm
  83. 944
      res/silentdragon_uk.ts
  84. BIN
      res/silentdragon_zh.qm
  85. 946
      res/silentdragon_zh.ts
  86. 2
      silentdragon.pro
  87. 40
      silentdragonx.pro
  88. 2
      src/addressbook.h
  89. 6
      src/balancestablemodel.h
  90. 27
      src/connection.cpp
  91. 237
      src/createhushconfdialog.ui
  92. 85
      src/getblock.ui
  93. 1
      src/main.cpp
  94. 421
      src/mainwindow.cpp
  95. 5
      src/mainwindow.h
  96. 95
      src/mainwindow.ui
  97. 6
      src/memoedit.h
  98. 1
      src/precompiled.h
  99. 34
      src/privkey.ui
  100. 53
      src/rpc.cpp
  101. 3
      src/rpc.h
  102. 4
      src/sendtab.cpp
  103. 32
      src/settings.cpp
  104. 2
      src/settings.h
  105. 283
      src/settings.ui
  106. 3
      src/validateaddress.cpp
  107. 4
      src/validateaddress.h
  108. 2
      src/version.h
  109. 2
      src/viewalladdresses.h
  110. 85
      src/viewtransaction.ui

3
README.md

@ -37,7 +37,6 @@ bits of data.
This means your IP address is known to these servers. Enable Tor setting
in SilentDragon to prevent this, or better yet, use TAILS: https://tails.boum.org/
NOTE: Tor v3 is not yet supported.
# Installation
@ -172,6 +171,8 @@ Linux: `~/.hush/HUSH3`
Windows 10: `C:\Documents and Settings\%user\Application Data\Hush` or `C:\Users\%user\AppData\Roaming\Hush`
Mac : `~/Library/Application Support/Hush/HUSH3`
## Support
For support or other questions, join us on [Telegram](https://hush.is/telegram), or toot at our [Mastodon](https://fosstodon.org/@myhushteam) or join [Telegram Support](https://hush.is/telegram_support) or [file an issue](https://git.hush.is/hush/SilentDragon/issues).

71
SilentDragon-1.3.1.wxs

@ -0,0 +1,71 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='SilentDragon' Id='a2e4bc6c-5911-4a07-a05c-d2fec0a44a7f' UpgradeCode='a41d7a93-a6cb-41fb-89d2-706a8c22bc99'
Language='1033' Codepage='1252' Version='1.3.1' Manufacturer='HUSH'>
<Package Id='*' Keywords='Installer' Description="HUSH SilentDragon Installer"
Comments='' Manufacturer='HUSH'
InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />
<Media Id='1' Cabinet='SilentDragon.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="HUSH SilentDragon 1.3.1 Installation [1]" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='HUSH' Name='HUSH'>
<Directory Id='INSTALLDIR' Name='SilentDragon'>
<Component Id='MainExecutable' Guid='56443570-635d-48e4-8448-8ffd0d7c415a'>
<File Id='SilentDragonEXE' Name='silentdragon.exe' DiskId='1' Source='silentdragon.exe' KeyPath='yes'>
<Shortcut Id="startmenuSilentDragon" Directory="ProgramMenuDir" Name="SilentDragon" WorkingDirectory='INSTALLDIR' Icon="silentdragon.exe" IconIndex="0" Advertise="yes" />
<Shortcut Id="desktopSilentDragon" Directory="DesktopFolder" Name="SilentDragon" WorkingDirectory='INSTALLDIR' Icon="silentdragon.exe" IconIndex="0" Advertise="yes" />
</File>
</Component>
<Component Id="asmap" Guid="190ad39b-44fa-4b22-94ee-d42aca7acc7b">
<File Id="asmap.dat" DiskId='1' Source="asmap.dat" KeyPath="yes"/>
</Component>
<Component Id="hush-cli" Guid="e19e8fd8-aeb9-4dad-99bd-70da0a0aa92c2">
<File Id="hush-cli.exe" DiskId='1' Source="hush-cli.exe" KeyPath="yes"/>
</Component>
<Component Id="hush-tx" Guid="f96b2a39-4734-4a8d-abc3-895006052e97">
<File Id="hush-tx.exe" DiskId='1' Source="hush-tx.exe" KeyPath="yes"/>
</Component>
<Component Id="hushd" Guid="fa66588f-8788-4b29-b6d6-c4a903e49d79">
<File Id="hushd.exe" DiskId='1' Source="hushd.exe" KeyPath="yes"/>
</Component>
<Component Id="sapling-output" Guid="1ecc1590-ddf3-4f6d-94c5-6bf091aef77a">
<File Id="sapling-output.params" DiskId='1' Source="sapling-output.params" KeyPath="yes"/>
</Component>
<Component Id="sapling-spend" Guid="828d3827-5f2b-47c6-8717-8a664054a2af">
<File Id="sapling-spend.params" DiskId='1' Source="sapling-spend.params" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="SilentDragon">
<Component Id="ProgramMenuDir" Guid="7ac6af1f-1377-4158-915f-c410cc5cd2a9">
<RemoveFolder Id='ProgramMenuDir' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='ProgramMenuDir' />
<ComponentRef Id='asmap' />
<ComponentRef Id='hush-cli' />
<ComponentRef Id='hush-tx' />
<ComponentRef Id='hushd' />
<ComponentRef Id='sapling-output' />
<ComponentRef Id='sapling-spend' />
</Feature>
<Icon Id="silentdragon.exe" SourceFile="silentdragon.ico" />
</Product>
</Wix>

87
SilentDragonX-1.3.1.wxs

@ -0,0 +1,87 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='SilentDragonX' Id='c2083d6a-4511-4c37-b23c-6699badb781f' UpgradeCode='0877ea1a-0662-48a2-8512-b5868f0a40a6'
Language='1033' Codepage='1252' Version='1.3.1' Manufacturer='HUSH'>
<Package Id='*' Keywords='Installer' Description="HUSH SilentDragonX Installer"
Comments='' Manufacturer='HUSH'
InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />
<Media Id='1' Cabinet='SilentDragonX.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="HUSH SilentDragonX 1.3.1 Installation [1]" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='HUSH' Name='HUSH'>
<Directory Id='INSTALLDIR' Name='SilentDragonX'>
<Component Id='MainExecutable' Guid='e96fa770-8ac4-4e69-85b0-1d5b97d658f1'>
<File Id='SilentDragonXEXE' Name='silentdragonx.exe' DiskId='1' Source='silentdragonx.exe' KeyPath='yes'>
<Shortcut Id="startmenuSilentDragonX" Directory="ProgramMenuDir" Name="SilentDragonX" WorkingDirectory='INSTALLDIR' Icon="silentdragonx.exe" IconIndex="0" Advertise="yes" />
<Shortcut Id="desktopSilentDragonX" Directory="DesktopFolder" Name="SilentDragonX" WorkingDirectory='INSTALLDIR' Icon="silentdragonx.exe" IconIndex="0" Advertise="yes" />
</File>
</Component>
<Component Id="asmap" Guid="1e7a811c-6076-4046-b592-3aebf31961c4">
<File Id="asmap.dat" DiskId='1' Source="asmap.dat" KeyPath="yes"/>
</Component>
<Component Id="dragonx-cli" Guid="5b648615-b957-470e-9ec0-777b8896e913">
<File Id="dragonx-cli.bat" DiskId='1' Source="dragonx-cli.bat" KeyPath="yes"/>
</Component>
<Component Id="dragonxd" Guid="779810d3-b092-4349-940b-03ba73ec556d">
<File Id="dragonxd.bat" DiskId='1' Source="dragonxd.bat" KeyPath="yes"/>
</Component>
<Component Id="hush-cli" Guid="305d8117-5685-4d06-b0be-a7cd176f8111">
<File Id="hush-cli.exe" DiskId='1' Source="hush-cli.exe" KeyPath="yes"/>
</Component>
<Component Id="hushd" Guid="5024eceb-fba3-48d8-9ab5-e61ae5c1964d">
<File Id="hushd.exe" DiskId='1' Source="hushd.exe" KeyPath="yes"/>
</Component>
<Component Id="hush-smart-chain" Guid="c66ffa5c-02ae-42e0-bbca-8cc71a4e92e9">
<File Id="hush-smart-chain.bat" DiskId='1' Source="hush-smart-chain.bat" KeyPath="yes"/>
</Component>
<Component Id="hush-tx" Guid="7baac56a-8bf4-4bb2-b97d-a59da5c0edd6">
<File Id="hush-tx.exe" DiskId='1' Source="hush-tx.exe" KeyPath="yes"/>
</Component>
<Component Id="readme" Guid="5edea091-83d0-4f1c-a84f-298e4e8e61e9">
<File Id="README.txt" DiskId='1' Source="README.txt" KeyPath="yes"/>
</Component>
<Component Id="sapling-output" Guid="dddc6a47-8a26-49ec-b5a8-e38a06e11000">
<File Id="sapling-output.params" DiskId='1' Source="sapling-output.params" KeyPath="yes"/>
</Component>
<Component Id="sapling-spend" Guid="42edd54d-b480-4aaa-a976-ec305127dbbb">
<File Id="sapling-spend.params" DiskId='1' Source="sapling-spend.params" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="SilentDragonX">
<Component Id="ProgramMenuDir" Guid="2ac41712-9a5d-48d6-9ca9-fe31bad57153">
<RemoveFolder Id='ProgramMenuDir' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='ProgramMenuDir' />
<ComponentRef Id='asmap' />
<ComponentRef Id='dragonx-cli' />
<ComponentRef Id='dragonxd' />
<ComponentRef Id='hush-cli' />
<ComponentRef Id='hushd' />
<ComponentRef Id='hush-smart-chain' />
<ComponentRef Id='hush-tx' />
<ComponentRef Id='readme' />
<ComponentRef Id='sapling-output' />
<ComponentRef Id='sapling-spend' />
</Feature>
<Icon Id="silentdragonx.exe" SourceFile="silentdragonx.ico" />
</Product>
</Wix>

40
application-sdx.qrc

@ -24,7 +24,7 @@
<file alias="lock_closed.png">res-drgx/lock_closed.png</file>
</qresource>
<qresource prefix="/img">
<file alias="hushdlogo.png">res/hushdlogo.png</file>
<file alias="hushdlogo.png">res-drgx/hushdlogo.png</file>
<file alias="logobig.gif">res-drgx/logobig.gif</file>
<file alias="silentdragon-animated.gif">res-drgx/silentdragon-animated.gif</file>
<file alias="silentdragon-animated-dark.gif">res-drgx/silentdragon-animated-dark.gif</file>
@ -32,25 +32,25 @@
<file alias="silentdragon-animated-startup-dark.gif">res-drgx/silentdragon-animated-startup-dark.gif</file>
</qresource>
<qresource prefix="/translations">
<file alias="silentdragon_be.qm">res-drgx/silentdragon_be.qm</file>
<file alias="silentdragon_bg.qm">res-drgx/silentdragon_bg.qm</file>
<file alias="silentdragon_de.qm">res-drgx/silentdragon_de.qm</file>
<file alias="silentdragon_es.qm">res-drgx/silentdragon_es.qm</file>
<file alias="silentdragon_fi.qm">res-drgx/silentdragon_fi.qm</file>
<file alias="silentdragon_fil.qm">res-drgx/silentdragon_fil.qm</file>
<file alias="silentdragon_fr.qm">res-drgx/silentdragon_fr.qm</file>
<file alias="silentdragon_hr.qm">res-drgx/silentdragon_hr.qm</file>
<file alias="silentdragon_it.qm">res-drgx/silentdragon_it.qm</file>
<file alias="silentdragon_id.qm">res-drgx/silentdragon_id.qm</file>
<file alias="silentdragon_nl.qm">res-drgx/silentdragon_nl.qm</file>
<file alias="silentdragon_pl.qm">res-drgx/silentdragon_pl.qm</file>
<file alias="silentdragon_pt.qm">res-drgx/silentdragon_pt.qm</file>
<file alias="silentdragon_ro.qm">res-drgx/silentdragon_ro.qm</file>
<file alias="silentdragon_ru.qm">res-drgx/silentdragon_ru.qm</file>
<file alias="silentdragon_sr.qm">res-drgx/silentdragon_sr.qm</file>
<file alias="silentdragon_tr.qm">res-drgx/silentdragon_tr.qm</file>
<file alias="silentdragon_uk.qm">res-drgx/silentdragon_uk.qm</file>
<file alias="silentdragon_zh.qm">res-drgx/silentdragon_zh.qm</file>
<file alias="silentdragon_be.qm">res/silentdragon_be.qm</file>
<file alias="silentdragon_bg.qm">res/silentdragon_bg.qm</file>
<file alias="silentdragon_de.qm">res/silentdragon_de.qm</file>
<file alias="silentdragon_es.qm">res/silentdragon_es.qm</file>
<file alias="silentdragon_fi.qm">res/silentdragon_fi.qm</file>
<file alias="silentdragon_fil.qm">res/silentdragon_fil.qm</file>
<file alias="silentdragon_fr.qm">res/silentdragon_fr.qm</file>
<file alias="silentdragon_hr.qm">res/silentdragon_hr.qm</file>
<file alias="silentdragon_it.qm">res/silentdragon_it.qm</file>
<file alias="silentdragon_id.qm">res/silentdragon_id.qm</file>
<file alias="silentdragon_nl.qm">res/silentdragon_nl.qm</file>
<file alias="silentdragon_pl.qm">res/silentdragon_pl.qm</file>
<file alias="silentdragon_pt.qm">res/silentdragon_pt.qm</file>
<file alias="silentdragon_ro.qm">res/silentdragon_ro.qm</file>
<file alias="silentdragon_ru.qm">res/silentdragon_ru.qm</file>
<file alias="silentdragon_sr.qm">res/silentdragon_sr.qm</file>
<file alias="silentdragon_tr.qm">res/silentdragon_tr.qm</file>
<file alias="silentdragon_uk.qm">res/silentdragon_uk.qm</file>
<file alias="silentdragon_zh.qm">res/silentdragon_zh.qm</file>
</qresource>
<qresource prefix="/css">
<file alias="blue.css">res/css/blue.css</file>

3
application.qrc

@ -26,9 +26,6 @@
<qresource prefix="/img">
<file alias="hushdlogo.png">res/hushdlogo.png</file>
<file alias="logobig.gif">res/logobig.gif</file>
<file alias="silentdragon-animated.gif">res/silentdragon-animated.gif</file>
<file alias="silentdragon-animated-dark.gif">res/silentdragon-animated-dark.gif</file>
<file alias="silentdragon-animated-startup.gif">res/silentdragon-animated-startup.gif</file>
<file alias="silentdragon-animated-startup-dark.gif">res/silentdragon-animated-startup-dark.gif</file>
</qresource>
<qresource prefix="/translations">

23
build.sh

@ -4,18 +4,7 @@
set -e
UNAME=$(uname)
if [ "$UNAME" == "Linux" ] ; then
JOBS=$(nproc)
elif [ "$UNAME" == "FreeBSD" ] ; then
JOBS=$(nproc)
elif [ "$UNAME" == "Darwin" ] ; then
JOBS=$(sysctl -n hw.ncpu)
else
JOBS=1
fi
VERSION=$(cat src/version.h |cut -d\" -f2)
VERSION=$(grep APP_VERSION src/version.h |cut -d\" -f2)
CONF=${SDCONF:-silentdragon.pro}
WALLET="SilentDragon"
if [ "$CONF" == "silentdragonx.pro" ] ; then
@ -40,12 +29,12 @@ make --version
qbuild () {
qmake $CONF -spec linux-clang CONFIG+=debug
make -j$JOBS
make -j2 "$@"
}
qbuild_release () {
qmake $CONF -spec linux-clang CONFIG+=release
make -j$JOBS
make -j2 "$@"
}
if [ "$1" == "clean" ]; then
@ -55,9 +44,9 @@ elif [ "$1" == "linguist" ]; then
lrelease $CONF
elif [ "$1" == "cleanbuild" ]; then
make clean
qbuild
qbuild "$@"
elif [ "$1" == "release" ]; then
qbuild_release
qbuild_release "$@"
else
qbuild
qbuild "$@"
fi

44
doc/relnotes/README.md

@ -10,6 +10,50 @@ and no longer on Github, since they banned Duke Leto and
also because they censor many people around the world and work with
evil organizations.
# SilentDragon 1.4.2 "Waggish Weevil"
```
11 files changed, 35 insertions(+), 32 deletions(-)
```
* Fix a coredump that can happen after importing a private key https://git.hush.is/hush/SilentDragon/issues/155
* Prevent the logging of sensitive data to STDOUT, since it could be redirected to a file or shared in a bug report or screenshot https://git.hush.is/hush/SilentDragon/commit/2754629a95c1efe603b3c3245f90a26b3ed7f177
* Update startup animation graphic https://git.hush.is/hush/SilentDragon/pulls/147
* Allow compiling with a custom number of jobs in build.sh https://git.hush.is/hush/SilentDragon/issues/156
# SilentDragon 1.4.1 "Scintillating Sundew"
```
52 files changed, 7163 insertions(+), 5023 deletions(-)
```
* View details of a transaction #136
* If a tx has no memo, you can simply double click on it to view more details.
* Otherwise, right click and choose View Transaction
* Render more details in View Block #135
* Now all transactions are listed as well as valuePools key
* Greatly improved Private Key Importing
* A custom rescan height or disabling rescanning is now possible
* Invalid privkeys are now filtered out before being sent to the full node
* This prevents confusing popups #142
* Fixed bug where importing multiple taddrs would rescan multiple times
* New Tab "Debug Log" renders content of debug.log
* Allows showing the last X lines of debug.log, defaults to 50 lines
# SilentDragon 1.4.0 "Zany Zooid"
```
95 files changed, 8438 insertions(+), 60854 deletions(-)
```
* Ability to view block info for any height #103
* Support a proxy running on something other than 127.0.0.1 #127
* Bug fix for Windows file path when exporting #128
* Bug fix for `listtransactions` to display more than 10 mining reward txs in Transactions tab #126
* Now compiles on Ubuntu 20.04 thanks to jahway #125
* Translation fixes thanks to onryo #120
* Single set of translations for SD and SDX #122
# SilentDragon 1.3.1 "Omnicompetent Okapi"
```

0
res-drgx/tropical-hush-square.png → res-drgx/hushdlogo.png

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

BIN
res-drgx/silentdragon_be.qm

Binary file not shown.

2690
res-drgx/silentdragon_be.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_bg.qm

Binary file not shown.

2560
res-drgx/silentdragon_bg.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_de.qm

Binary file not shown.

2917
res-drgx/silentdragon_de.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_es.qm

Binary file not shown.

2898
res-drgx/silentdragon_es.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_fi.qm

Binary file not shown.

2911
res-drgx/silentdragon_fi.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_fil.qm

Binary file not shown.

2751
res-drgx/silentdragon_fil.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_fr.qm

Binary file not shown.

2945
res-drgx/silentdragon_fr.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_hr.qm

Binary file not shown.

2754
res-drgx/silentdragon_hr.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_id.qm

Binary file not shown.

2464
res-drgx/silentdragon_id.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_it.qm

Binary file not shown.

2897
res-drgx/silentdragon_it.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_nl.qm

Binary file not shown.

2686
res-drgx/silentdragon_nl.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_pl.qm

Binary file not shown.

2689
res-drgx/silentdragon_pl.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_pt.qm

Binary file not shown.

2885
res-drgx/silentdragon_pt.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_ro.qm

Binary file not shown.

2752
res-drgx/silentdragon_ro.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_ru.qm

Binary file not shown.

2691
res-drgx/silentdragon_ru.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_sr.qm

Binary file not shown.

2754
res-drgx/silentdragon_sr.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_tr.qm

Binary file not shown.

2902
res-drgx/silentdragon_tr.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_uk.qm

Binary file not shown.

3152
res-drgx/silentdragon_uk.ts

File diff suppressed because it is too large

BIN
res-drgx/silentdragon_zh.qm

Binary file not shown.

3037
res-drgx/silentdragon_zh.ts

File diff suppressed because it is too large

BIN
res-drgx/tropical-hush.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

BIN
res/silentdragon-animated-dark.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

BIN
res/silentdragon-animated-startup.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

BIN
res/silentdragon-animated.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

BIN
res/silentdragon_be.qm

Binary file not shown.

942
res/silentdragon_be.ts

File diff suppressed because it is too large

942
res/silentdragon_bg.ts

File diff suppressed because it is too large

BIN
res/silentdragon_de.qm

Binary file not shown.

944
res/silentdragon_de.ts

File diff suppressed because it is too large

BIN
res/silentdragon_es.qm

Binary file not shown.

944
res/silentdragon_es.ts

File diff suppressed because it is too large

BIN
res/silentdragon_fi.qm

Binary file not shown.

944
res/silentdragon_fi.ts

File diff suppressed because it is too large

BIN
res/silentdragon_fil.qm

Binary file not shown.

944
res/silentdragon_fil.ts

File diff suppressed because it is too large

BIN
res/silentdragon_fr.qm

Binary file not shown.

944
res/silentdragon_fr.ts

File diff suppressed because it is too large

BIN
res/silentdragon_hr.qm

Binary file not shown.

944
res/silentdragon_hr.ts

File diff suppressed because it is too large

BIN
res/silentdragon_it.qm

Binary file not shown.

944
res/silentdragon_it.ts

File diff suppressed because it is too large

BIN
res/silentdragon_nl.qm

Binary file not shown.

942
res/silentdragon_nl.ts

File diff suppressed because it is too large

BIN
res/silentdragon_pl.qm

Binary file not shown.

942
res/silentdragon_pl.ts

File diff suppressed because it is too large

BIN
res/silentdragon_pt.qm

Binary file not shown.

944
res/silentdragon_pt.ts

File diff suppressed because it is too large

BIN
res/silentdragon_ro.qm

Binary file not shown.

944
res/silentdragon_ro.ts

File diff suppressed because it is too large

BIN
res/silentdragon_ru.qm

Binary file not shown.

942
res/silentdragon_ru.ts

File diff suppressed because it is too large

BIN
res/silentdragon_sr.qm

Binary file not shown.

944
res/silentdragon_sr.ts

File diff suppressed because it is too large

BIN
res/silentdragon_tr.qm

Binary file not shown.

944
res/silentdragon_tr.ts

File diff suppressed because it is too large

BIN
res/silentdragon_uk.qm

Binary file not shown.

944
res/silentdragon_uk.ts

File diff suppressed because it is too large

BIN
res/silentdragon_zh.qm

Binary file not shown.

946
res/silentdragon_zh.ts

File diff suppressed because it is too large

2
silentdragon.pro

@ -89,6 +89,8 @@ HEADERS += \
src/viewalladdresses.h
FORMS += \
src/getblock.ui \
src/viewtransaction.ui \
src/mainwindow.ui \
src/qrcode.ui \
src/rescandialog.ui \

40
silentdragonx.pro

@ -88,6 +88,8 @@ HEADERS += \
src/viewalladdresses.h
FORMS += \
src/getblock.ui \
src/viewtransaction.ui \
src/mainwindow.ui \
src/qrcode.ui \
src/rescandialog.ui \
@ -109,25 +111,25 @@ FORMS += \
src/requestdialog.ui
TRANSLATIONS = res-drgx/silentdragon_be.ts \
res-drgx/silentdragon_bg.ts \
res-drgx/silentdragon_de.ts \
res-drgx/silentdragon_es.ts \
res-drgx/silentdragon_fi.ts \
res-drgx/silentdragon_fil.ts \
res-drgx/silentdragon_fr.ts \
res-drgx/silentdragon_hr.ts \
res-drgx/silentdragon_id.ts \
res-drgx/silentdragon_it.ts \
res-drgx/silentdragon_nl.ts \
res-drgx/silentdragon_pl.ts \
res-drgx/silentdragon_pt.ts \
res-drgx/silentdragon_ro.ts \
res-drgx/silentdragon_ru.ts \
res-drgx/silentdragon_sr.ts \
res-drgx/silentdragon_tr.ts \
res-drgx/silentdragon_uk.ts \
res-drgx/silentdragon_zh.ts
TRANSLATIONS = res/silentdragon_be.ts \
res/silentdragon_bg.ts \
res/silentdragon_de.ts \
res/silentdragon_es.ts \
res/silentdragon_fi.ts \
res/silentdragon_fil.ts \
res/silentdragon_fr.ts \
res/silentdragon_hr.ts \
res/silentdragon_id.ts \
res/silentdragon_it.ts \
res/silentdragon_nl.ts \
res/silentdragon_pl.ts \
res/silentdragon_pt.ts \
res/silentdragon_ro.ts \
res/silentdragon_ru.ts \
res/silentdragon_sr.ts \
res/silentdragon_tr.ts \
res/silentdragon_uk.ts \
res/silentdragon_zh.ts
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication _FORTIFY_SOURCE=2

2
src/addressbook.h

@ -9,6 +9,8 @@ class MainWindow;
class AddressBookModel : public QAbstractTableModel {
Q_OBJECT
public:
AddressBookModel(QTableView* parent);
~AddressBookModel();

6
src/balancestablemodel.h

@ -13,8 +13,10 @@ struct UnspentOutput {
bool spendable;
};
class BalancesTableModel : public QAbstractTableModel
{
class BalancesTableModel : public QAbstractTableModel {
Q_OBJECT
public:
BalancesTableModel(QObject* parent);
~BalancesTableModel();

27
src/connection.cpp

@ -8,6 +8,7 @@
#include "rpc.h"
#include "precompiled.h"
#include "version.h"
#include "sd.h"
extern bool isdragonx;
@ -211,11 +212,13 @@ void ConnectionLoader::createHushConf() {
// Show the dialog
QString datadir = "";
bool useTor = false;
QString torProxy = "127.0.0.1";
QString torPort = "9050";
if (d.exec() == QDialog::Accepted) {
datadir = ui.lblDirName->text();
useTor = ui.chkUseTor->isChecked();
torProxy = ui.torProxy->text();
torPort = ui.torPort->text();
}
@ -266,7 +269,7 @@ void ConnectionLoader::createHushConf() {
out << "datadir=" % datadir % "\n";
}
if (useTor) {
out << "proxy=127.0.0.1:" << torPort << "\n";
out << "proxy="<< torProxy << ":" << torPort << "\n";
}
file.close();
@ -887,15 +890,25 @@ Connection::~Connection() {
void Connection::doRPC(const QJsonValue& payload, const std::function<void(QJsonValue)>& cb,
const std::function<void(QNetworkReply*, const QJsonValue&)>& ne) {
if (shutdownInProgress) {
qDebug() << __func__ << ": Ignoring RPC because shutdown in progress";
DEBUG("Ignoring RPC because shutdown in progress");
return;
}
if(payload.isNull() || payload.isUndefined()) {
qDebug() << "no payload! ignoring";
DEBUG("no payload! ignoring");
return;
} else {
qDebug() << __func__ << ": " << payload["method"].toString() << payload;
// this will match importprivkey z_importkey z_importviewingkey importwallet z_importwallet
// and some other RPCs that have no GUI
// So this code ends up redacting payloads which contain private keys and filenames which contain private keys
QRegExp re("import");
//DEBUG("payload.toString==" << payload["method"].toString());
//DEBUG("payload.toString.indexIn==" << re.indexIn(payload["method"].toString()) );
if( re.indexIn(payload["method"].toString()) == -1 ) {
DEBUG( payload["method"].toString() << payload );
} else {
DEBUG( payload["method"].toString() << " PAYLOAD REDACTED " );
}
}
QJsonDocument jd_rpc_call(payload.toObject());
@ -906,7 +919,7 @@ void Connection::doRPC(const QJsonValue& payload, const std::function<void(QJson
QObject::connect(reply, &QNetworkReply::finished, [=] {
reply->deleteLater();
if (shutdownInProgress) {
// Ignoring callback because shutdown in progress
DEBUG("Ignoring callback because shutdown in progress");
return;
}
@ -934,8 +947,10 @@ void Connection::doRPC(const QJsonValue& payload, const std::function<void(QJson
void Connection::doRPCWithDefaultErrorHandling(const QJsonValue& payload, const std::function<void(QJsonValue)>& cb) {
doRPC(payload, cb, [=] (QNetworkReply* reply, const QJsonValue &parsed) {
if (!parsed.isUndefined() && !parsed["error"].toObject()["message"].isNull()) {
DEBUG("got a parse error");
this->showTxError(parsed["error"].toObject()["message"].toString());
} else {
DEBUG("got a reply error");
this->showTxError(reply->errorString());
}
});
@ -956,7 +971,7 @@ void Connection::showTxError(const QString& error) {
return;
shown = true;
QMessageBox::critical(main, QObject::tr("Transaction Error"), QObject::tr("There was an error! : ") + "\n\n"
QMessageBox::critical(main, QObject::tr("Error"), QObject::tr("There was an error! : ") + "\n\n"
+ error, QMessageBox::StandardButton::Ok);
shown = false;
}

237
src/createhushconfdialog.ui

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>508</width>
<height>352</height>
<height>369</height>
</rect>
</property>
<property name="windowTitle">
@ -95,93 +95,154 @@
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="chkCustomDatadir">
<property name="text">
<string>Use custom datadir</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Please choose a directory to store your wallet.dat and blockchain</string>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnPickDir">
<property name="text">
<string>Choose directory</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDirName">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="chkUseTor">
<property name="text">
<string>Connect over Tor</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Please note that you'll need to already have a Tor service configured</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_tor_port">
<property name="text">
<string>Tor Port</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="torPort">
<property name="text">
<string notr="true">9050</string>
</property>
</widget>
</item>
</layout>
<widget class="QCheckBox" name="chkCustomDatadir">
<property name="geometry">
<rect>
<x>8</x>
<y>8</y>
<width>148</width>
<height>22</height>
</rect>
</property>
<property name="text">
<string>Use custom datadir</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>8</x>
<y>36</y>
<width>395</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Please choose a directory to store your wallet.dat and blockchain</string>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>8</x>
<y>102</y>
<width>16</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
<widget class="QCheckBox" name="chkUseTor">
<property name="geometry">
<rect>
<x>8</x>
<y>126</y>
<width>133</width>
<height>22</height>
</rect>
</property>
<property name="text">
<string>Connect over Tor</string>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>8</x>
<y>154</y>
<width>415</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Please note that you'll need to already have a Tor service configured</string>
</property>
</widget>
<widget class="QLabel" name="label_tor_port">
<property name="geometry">
<rect>
<x>178</x>
<y>178</y>
<width>49</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Tor Port</string>
</property>
</widget>
<widget class="QLineEdit" name="torPort">
<property name="geometry">
<rect>
<x>230</x>
<y>178</y>
<width>59</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string notr="true">9050</string>
</property>
</widget>
<widget class="QLineEdit" name="torProxy">
<property name="geometry">
<rect>
<x>62</x>
<y>180</y>
<width>111</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string notr="true">127.0.0.1</string>
</property>
</widget>
<widget class="QLabel" name="label_tor_proxy">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<width>49</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Proxy IP</string>
</property>
</widget>
<widget class="QWidget" name="">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnPickDir">
<property name="text">
<string>Choose directory</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDirName">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

85
src/getblock.ui

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GetBlock</class>
<widget class="QDialog" name="GetBlock">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Get Block Info</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="lblHeight">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Block Height:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTableView" name="tblProps">
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GetBlock</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GetBlock</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

1
src/main.cpp

@ -6,6 +6,7 @@
#include "rpc.h"
#include "settings.h"
#include "version.h"
#include <QCommandLineParser>
bool isdragonx = 0;

421
src/mainwindow.cpp

@ -13,7 +13,9 @@
#include "ui_settings.h"
#include "ui_viewalladdresses.h"
#include "ui_validateaddress.h"
#include "ui_viewtransaction.h"
#include "ui_rescandialog.h"
#include "ui_getblock.h"
#include "rpc.h"
#include "balancestablemodel.h"
#include "settings.h"
@ -22,6 +24,7 @@
#include "connection.h"
#include "requestdialog.h"
#include <QLCDNumber>
#include <QThread>
#include "sd.h"
extern bool isdragonx;
@ -94,6 +97,12 @@ MainWindow::MainWindow(QWidget *parent) :
// Validate Address
QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress);
// Get Block
QObject::connect(ui->actionGet_Block, &QAction::triggered, this, &MainWindow::getBlock);
// View tx
QObject::connect(ui->actionView_Transaction, &QAction::triggered, this, &MainWindow::viewTransaction);
// Address Book
QObject::connect(ui->action_Address_Book, &QAction::triggered, this, &MainWindow::addressBook);
@ -127,6 +136,7 @@ MainWindow::MainWindow(QWidget *parent) :
qDebug() << "Created RPC";
setupMiningTab();
setupDebugLogTab();
restoreSavedStates();
}
@ -699,8 +709,9 @@ void MainWindow::setupSettingsModal() {
if (!isUsingTor && settings.chkTor->isChecked()) {
// If "use tor" was previously unchecked and now checked
QString torProxy= settings.torProxy->text();
QString torPort = settings.torPort->text();
QString proxyConfig = "proxy=127.0.0.1:" % torPort;
QString proxyConfig = "proxy="%torProxy%":"%torPort;
Settings::addToHushConf(hushConfLocation, proxyConfig);
rpc->getConnection()->config->proxy = proxyConfig;
@ -895,7 +906,225 @@ void MainWindow::validateAddress() {
d.exec();
});
}
// Ask user for txid to view
void MainWindow::viewTransaction() {
// Make sure everything is up and running
if (!getRPC() || !getRPC()->getConnection())
return;
// First thing is ask the user for a txid
bool ok;
QString txid = QInputDialog::getText(this, tr("View Transaction"),
tr("Enter Transaction ID (txid):"), QLineEdit::Normal, "", &ok);
if (!ok)
return;
viewTxid(txid);
}
// view a given txid
void MainWindow::viewTxid(QString txid) {
// ignore leading and trailing whitespace
txid = txid.trimmed();
QRegExp rx("^[0-9a-f]{64}$");
if(!rx.exactMatch(txid)) {
DEBUG("invalid txid " << txid );
return;
}
// we got a valid txid
getRPC()->getrawtransaction(txid, [=] (QJsonValue props) {
// TODO: only z_viewtransaction shows memo
// getRPC()->z_viewtransaction(txid, [=] (QJsonValue props) {
QDialog d(this);
Ui_ViewTransaction vt;
vt.setupUi(&d);
Settings::saveRestore(&d);
Settings::saveRestoreTableHeader(vt.tblProps, &d, "getblockprops");
vt.tblProps->horizontalHeader()->setStretchLastSection(true);
vt.lblHeight->setText(txid);
QList<QPair<QString, QString>> propsList;
for (QString property_name: props.toObject().keys()) {
QString property_value;
DEBUG("property " << property_name << "=" << props.toObject()[property_name] );
if (props.toObject()[property_name].isString()) {
property_value = props.toObject()[property_name].toString();
} else if (props.toObject()[property_name].isDouble()) {
property_value = QString::number( props.toObject()[property_name].toDouble(), 'f', 0);
} else if (props.toObject()[property_name].isBool()) {
property_value = props.toObject()[property_name].toBool() ? "true" : "false" ;
} else if (props.toObject()[property_name].isArray()) {
DEBUG( property_name << " is an array");
// vin is the Vector of INputs of transparent spends
if( property_name == "vin" ) {
int index = 0;
auto vins = props.toObject()[property_name].toArray();
for (const auto& vin : vins) {
QString this_vin = "vin " + QString::number(index);
auto vinObj = vin.toObject();
// Is this a normal input or coinbase input?
bool is_coinbase = vinObj["coinbase"].toString().length() > 0;
if (is_coinbase) {
propsList.append(
QPair<QString, QString>( this_vin + " coinbase", vinObj["coinbase"].toString() )
);
} else {
// the address of this spend
propsList.append(
QPair<QString, QString>( this_vin + " address", vinObj["address"].toString() )
);
// the value of this spend
propsList.append(
QPair<QString, QString>( this_vin + " value", QString::number(vinObj["value"].toDouble()) )
);
// the txid in which this UTXO was created
propsList.append(
QPair<QString, QString>( this_vin + " txid", vinObj["txid"].toString() )
);
// the index of vout in the txid it was created
propsList.append(
QPair<QString, QString>( this_vin + " vout", QString::number(vinObj["vout"].toInt()) )
);
}
// sequence number is part of both coinbase and non-coinbase vins
propsList.append(
QPair<QString, QString>( this_vin + " sequence", QString::number(vinObj["sequence"].toDouble()) )
);
index++;
}
} else if (property_name == "vout") {
// vout = Vector of OUTputs of transparent sends
auto vouts = props.toObject()[property_name].toArray();
if(vouts.size() == 0) {
propsList.append( QPair<QString, QString>( "vout", "Empty") );
} else {
//...
}
} else if (property_name == "vShieldedOutput") {
// the vector of shielded outputs
auto zouts = props.toObject()[property_name].toArray();
if(zouts.size() == 0) {
propsList.append( QPair<QString, QString>( property_name, "Empty"));
} else {
int index = 0;
QString property_value = "";
for (const auto& zout : zouts) {
auto zoutObj = zout.toObject();
auto properties = {"proof", "cv", "cmu", "encCiphertext", "outCiphertext", "ephemeralKey" };
for(const auto& prop : properties ) {
propsList.append(
QPair<QString, QString>( "vShieldedOutput " + QString::number(index) + " " + prop, zoutObj[prop].toString() )
);
}
index++;
}
}
} else if (property_name == "vShieldedSpend") {
// the vector of shielded spends
auto zins = props.toObject()[property_name].toArray();
if(zins.size() == 0) {
propsList.append( QPair<QString, QString>( property_name, "Empty"));
} else {
// TODO
}
}
} else if (props.toObject()[property_name].isObject()) {
DEBUG( property_name << " is an object");
}
if (property_name != "vin" && property_name != "vout" &&
property_name != "vShieldedOutput" && property_name != "vShieldedSpend" ) {
propsList.append( QPair<QString, QString>( property_name, property_value ));
}
}
ValidateAddressesModel model(vt.tblProps, propsList);
vt.tblProps->setModel(&model);
d.exec();
});
}
// Get block info
void MainWindow::getBlock() {
// Make sure everything is up and running
if (!getRPC() || !getRPC()->getConnection())
return;
// First thing is ask the user for a block height
bool ok;
int i = QInputDialog::getInt(this, tr("Get Block Info"),
tr("Enter Block Height:"), 12345, 0, 2147483647, 1, &ok);
if (!ok)
return;
auto blockheight = QString::number(i);
getRPC()->getBlock(blockheight, [=] (QJsonValue props) {
QDialog d(this);
Ui_GetBlock gb;
gb.setupUi(&d);
Settings::saveRestore(&d);
Settings::saveRestoreTableHeader(gb.tblProps, &d, "getblockprops");
gb.tblProps->horizontalHeader()->setStretchLastSection(true);
gb.lblHeight->setText(blockheight);
QList<QPair<QString, QString>> propsList;
for (QString property_name: props.toObject().keys()) {
QString property_value;
DEBUG("property " << property_name << "=" << props.toObject()[property_name] );
if (props.toObject()[property_name].isString()) {
property_value = props.toObject()[property_name].toString();
} else if (props.toObject()[property_name].isDouble()) {
property_value = QString::number( props.toObject()[property_name].toDouble(), 'f', 0);
} else if (props.toObject()[property_name].isBool()) {
property_value = props.toObject()[property_name].toBool() ? "true" : "false" ;
} else if (props.toObject()[property_name].isArray()) {
DEBUG( property_name << " is an array");
if( property_name == "tx") {
auto txs = props.toObject()[property_name].toArray();
int index = 0;
// create a property for each tx in the block so it renders in a more useful way
for (const auto& tx : txs) {
QString this_property_name = "tx " + QString::number(index);
propsList.append(
QPair<QString, QString>( this_property_name, tx.toString() )
);
index++;
}
} else if (property_name == "valuePools") {
auto stuff = props.toObject()[property_name].toArray();
property_value = QJsonDocument(stuff).toJson();
property_value.remove("\n");
property_value.remove(" ");
}
} else if (props.toObject()[property_name].isObject()) {
DEBUG( property_name << " is an object");
}
// tx properties are added in their own special way above
if (property_name != "tx") {
propsList.append(
QPair<QString, QString>( property_name, property_value )
);
}
}
ValidateAddressesModel model(gb.tblProps, propsList);
gb.tblProps->setModel(&model);
d.exec();
});
}
void MainWindow::doImport(QList<QString>* keys) {
@ -904,21 +1133,22 @@ void MainWindow::doImport(QList<QString>* keys) {
return;
}
DEBUG(" keys.size= " << keys->size() );
if (keys->isEmpty()) {
delete keys;
ui->statusBar->showMessage(tr("Private key import rescan finished"));
return;
}
// Pop the first key
QString key = keys->first();
keys->pop_front();
bool rescan = keys->isEmpty();
// Get the first key
QString key = keys->takeFirst();
if (key.startsWith("SK") ||
key.startsWith("secret")) { // Z key
bool rescan = false;
if (Settings::getInstance()->isValidSaplingPrivateKey(key) ) {
DEBUG("importing zaddr privkey with rescan=" << rescan);
rpc->importZPrivKey(key, rescan, [=] (auto) { this->doImport(keys); });
} else {
DEBUG("importing taddr privkey with rescan=" << rescan);
rpc->importTPrivKey(key, rescan, [=] (auto) { this->doImport(keys); });
}
}
@ -1019,7 +1249,6 @@ void MainWindow::payHushURI(QString uri, QString myAddr) {
}
}
void MainWindow::importPrivKey() {
QDialog d(this);
Ui_PrivKey pui;
@ -1031,20 +1260,27 @@ void MainWindow::importPrivKey() {
tr("Please paste your private keys here, one per line") % ".\n" %
tr("The keys will be imported into your connected Hush node"));
// if rescan is not checked, disable the rescan height input
QObject::connect(pui.chkrescan, &QCheckBox::stateChanged, [=](auto checked) {
pui.rescanfrom->setEnabled(checked);
});
if (d.exec() == QDialog::Accepted && !pui.privKeyTxt->toPlainText().trimmed().isEmpty()) {
auto rawkeys = pui.privKeyTxt->toPlainText().trimmed().split("\n");
QList<QString> keysTmp;
// Filter out all the empty keys.
// Filter out all the empty keys and comment lines
std::copy_if(rawkeys.begin(), rawkeys.end(), std::back_inserter(keysTmp), [=] (auto key) {
return !key.startsWith("#") && !key.trimmed().isEmpty();
});
auto keys = new QList<QString>();
// ignore anything after the first space of a line, such as if you paste a line from z_exportwallet output
std::transform(keysTmp.begin(), keysTmp.end(), std::back_inserter(*keys), [=](auto key) {
return key.trimmed().split(" ")[0];
});
// Special case.
// Sometimes, when importing from a paperwallet or such, the key is split by newlines, and might have
// been pasted like that. So check to see if the whole thing is one big private key
@ -1055,13 +1291,53 @@ void MainWindow::importPrivKey() {
delete multiline;
}
// Start the import. The function takes ownership of keys
QTimer::singleShot(1, [=]() {doImport(keys);});
// Finally, validate all keys, removing any which are invalid
auto keysValidated = new QList<QString>();
auto settings = Settings::getInstance();
std::copy_if(keys->begin(), keys->end(), std::back_inserter(*keysValidated), [=] (auto key) {
bool isValid = settings->isValidSaplingPrivateKey(key) || settings->isValidTransparentPrivateKey(key);
if (!isValid) { DEBUG("privkey " << key << " is not valid"); }
return isValid;
});
DEBUG("found " << keysValidated->size() << " valid privkeys");
bool rescan = pui.chkrescan->isChecked();
// avoid giving invalid data to RPCs and a rescan if there were no valid privkeys
if(keysValidated->size() == 0) {
QMessageBox::information(this, "No valid keys",
tr("No valid private keys were found, please make sure you copy and pasted correctly"),
QMessageBox::Ok);
return;
}
// Start the import. The function takes ownership of keysValidated
QTimer::singleShot(1, [=]() {
// we import all keys without rescanning and then finally decide if we will rescan once
doImport(keysValidated);
if (rescan) {
//TODO: verify rescanfrom is a valid integer
rpc->rescan(pui.rescanfrom->text().trimmed().toInt() , [=] (QJsonValue response){
//DEBUG("rescanning from height " << pui.rescanfrom->text().toInt() << " finished" << response);
DEBUG("rescanning finished" << response);
ui->statusBar->showMessage(tr("Rescanning finished"), 5000);
});
}
});
// Show the dialog that keys will be imported.
QMessageBox::information(this,
"Imported", tr("The keys were imported! It may take several minutes to rescan the blockchain. Until then, functionality may be limited"),
if(rescan) {
QMessageBox::information(this, "Imported",
tr("The keys were imported! It may take several hours to rescan the blockchain. Until then, functionality may be limited"),
QMessageBox::Ok);
} else {
QMessageBox::information(this, "Imported",
tr("The keys were imported! You chose to not rescan, so funds in that address will not show up in your wallet yet."),
QMessageBox::Ok);
}
}
}
@ -1070,10 +1346,16 @@ void MainWindow::importPrivKey() {
*/
void MainWindow::exportTransactions() {
// First, get the export file name
QString exportName = "hush-transactions-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".csv";
QString exportName;
if(isdragonx){
exportName = "drgx-transactions-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".csv";
}else{
exportName = "hush-transactions-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".csv";
}
QUrl csvName = QFileDialog::getSaveFileUrl(this,
tr("Export transactions"), exportName, "CSV file (*.csv)");
QDir docsDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
QUrl pName = QUrl::fromLocalFile(docsDir.filePath(exportName));
QUrl csvName = QFileDialog::getSaveFileUrl(this, tr("Export transactions"), pName, "CSV file (*.csv)");
if (csvName.isEmpty())
return;
@ -1093,7 +1375,12 @@ void MainWindow::backupWalletDat() {
return;
QDir hushdir(rpc->getConnection()->config->hushDir);
QString backupDefaultName = "hush-wallet-backup-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".dat";
QString backupDefaultName;
if(isdragonx){
backupDefaultName = "drgx-wallet-backup-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".dat";
}else{
backupDefaultName = "hush-wallet-backup-" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".dat";
}
if (Settings::getInstance()->isTestnet()) {
hushdir.cd("testnet3");
@ -1107,7 +1394,8 @@ void MainWindow::backupWalletDat() {
return;
}
QUrl backupName = QFileDialog::getSaveFileUrl(this, tr("Backup wallet.dat"), backupDefaultName, "Data file (*.dat)");
QUrl pName = QUrl::fromLocalFile(hushdir.filePath(backupDefaultName));
QUrl backupName = QFileDialog::getSaveFileUrl(this, tr("Backup wallet.dat"), pName, "Data file (*.dat)");
if (backupName.isEmpty())
return;
@ -1698,6 +1986,66 @@ void MainWindow::setupMiningTab() {
// Mining tab currently only enabled for DragonX
}
}
QString MainWindow::readDebugLines(uint32_t lines) {
QString coin = isdragonx ? "DRAGONX" : "HUSH3";
#ifdef Q_OS_LINUX
QFile file(QDir::homePath() + "/.hush/" + coin + "/debug.log");
#elif defined(Q_OS_DARWIN)
QFile file(QDir::homePath() + "/Library/Application Support/Hush/" + coin + "/debug.log");
#elif defined(Q_OS_WIN64)
QFile file(QDir::homePath() + "/AppData/Roaming/Hush/" + coin + "/debug.log");
#else
// Bless Your Heart, You Like Danger!
QFile file(QDir::homePath() + "/.hush/" + coin + "/debug.log");
#endif // Q_OS_LINUX
if(file.exists()) {
DEBUG(": Found debug.log at " << file);
} else {
DEBUG("No debug.log found!");
return "";
}
if(file.open(QIODevice::ReadOnly))
{
qint64 fileSize = file.size();
DEBUG("debug.log size=" << fileSize);
if(fileSize < 2) {
DEBUG("debug.log is too small");
return "";
}
file.seek(file.size()-1);
uint32_t count = 0;
while ( (count < lines) && (file.pos() > 0) )
{
QString ch = file.read(1);
file.seek(file.pos()-2);
if (ch == "\n")
count++;
}
file.seek(file.pos()+2);
QString debugText = file.readAll();
DEBUG("got " << debugText.size() << " bytes of debugText");
file.close();
return debugText;
}
return "";
}
void MainWindow::setupDebugLogTab() {
ui->debugLog->setReadOnly(true);
ui->debugLog->setPlainText("Loading debug log...");
QObject::connect(ui->refreshDebugButton, &QPushButton::clicked, [=] () {
uint32_t debugLines = ui->debugLines->text().trimmed().toInt();
if (debugLines == 0) { debugLines = 50; }
DEBUG("refresh debug log clicked with debugLines=" << debugLines);
ui->debugLog->setPlainText( readDebugLines(debugLines) );
});
ui->debugLog->setPlainText( readDebugLines() );
}
void MainWindow::setupPeersTab() {
qDebug() << __FUNCTION__;
// Set up context menu on peers tab
@ -1848,33 +2196,8 @@ void MainWindow::setupPeersTab() {
menu.exec(ui->peersTable->viewport()->mapToGlobal(pos));
});
/*
//grep 'BAN THRESHOLD EXCEEDED' ~/.hush/HUSH3/debug.log
//grep Disconnected ...
QFile debuglog = "";
#ifdef Q_OS_LINUX
debuglog = "~/.hush/HUSH3/debug.log";
#elif defined(Q_OS_DARWIN)
debuglog = "~/Library/Application Support/Hush/HUSH3/debug.log";
#elif defined(Q_OS_WIN64)
// "C:/Users/<USER>/AppData/Roaming/<APPNAME>",
// TODO: get current username
debuglog = "C:/Users/<USER>/AppData/Roaming/Hush/HUSH3/debug.log";
#else
// Bless Your Heart, You Like Danger!
// There are open bounties to port HUSH softtware to OpenBSD and friends:
// git.hush.is/hush/tasks
debuglog = "~/.hush/HUSH3/debug.log";
#endif // Q_OS_LINUX
if(debuglog.exists()) {
qDebug() << __func__ << ": Found debuglog at " << debuglog;
} else {
qDebug() << __func__ << ": No debug.log found";
}
*/
//ui->recentlyBannedPeers = "Could not open " + debuglog;
}
@ -1979,6 +2302,11 @@ void MainWindow::setupTransactionsTab() {
mb.exec();
}
}
} else {
// if no memo, show View Transaction
DEBUG("double clicked tx index=" << index);
QString txid = txModel->getTxId(index.row());
viewTxid(txid);
}
});
@ -2003,6 +2331,11 @@ void MainWindow::setupTransactionsTab() {
ui->statusBar->showMessage(tr("Copied to clipboard"), 3 * 1000);
});
menu.addAction(tr("View transaction"), [=] () {
ui->statusBar->showMessage(tr("Viewing transaction") + " " + txid, 3 * 1000);
viewTxid(txid);
});
if (!addr.isEmpty()) {
menu.addAction(tr("Copy address"), [=] () {
QGuiApplication::clipboard()->setText(addr);

5
src/mainwindow.h

@ -52,6 +52,9 @@ public:
void payHushURI(QString uri = "", QString myAddr = "");
void validateAddress();
void getBlock();
void viewTransaction();
void viewTxid(QString txid = "");
void updateLabels();
void updateTAddrCombo(bool checked);
@ -82,6 +85,7 @@ private:
void closeEvent(QCloseEvent* event);
QString readDebugLines(uint32_t lines = 50);
void setupSendTab();
void setupPeersTab();
void setupTransactionsTab();
@ -91,6 +95,7 @@ private:
void setupChatTab();
void setupMarketTab();
void setupMiningTab();
void setupDebugLogTab();
void slot_change_theme(QString& themeName);
void slot_change_currency(const QString& currencyName);

95
src/mainwindow.ui

@ -121,6 +121,7 @@
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -133,6 +134,7 @@
<widget class="QLabel" name="balTotal">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -158,6 +160,7 @@
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -170,6 +173,7 @@
<widget class="QLabel" name="balUSDTotal">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -384,8 +388,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1409</width>
<height>865</height>
<width>1447</width>
<height>860</height>
</rect>
</property>
<layout class="QVBoxLayout" name="sendToLayout">
@ -1126,6 +1130,68 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_debug">
<attribute name="title">
<string>Debug Log</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="refreshDebugButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
Click to see the latest debug log data
<string/>
</property>
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="debugLabel">
<property name="text">
<string>Number of lines to show</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="debugLines">
<property name="enabled">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>50</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QPlainTextEdit" name="debugLog">
<property name="plainText">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>Node info</string>
@ -1210,7 +1276,6 @@
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="clientnamespacer">
<property name="text">
@ -1245,7 +1310,6 @@
</property>
</widget>
</item>
<item row="16" column="2">
<widget class="QLabel" name="longestchain">
<property name="text">
@ -1273,7 +1337,6 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="numconnections">
<property name="text">
@ -1281,8 +1344,6 @@
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="chaintxcountlabel">
<property name="sizePolicy">
@ -1296,7 +1357,6 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
@ -1391,7 +1451,6 @@
</property>
</widget>
</item>
<item row="12" column="2">
<widget class="QLabel" name="rpcport">
<property name="text">
@ -1446,7 +1505,6 @@
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="p2pportspacer">
<property name="text">
@ -1488,7 +1546,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
@ -1549,7 +1606,6 @@
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="chaintxcountspacer">
<property name="text">
@ -1608,13 +1664,14 @@
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1487</width>
<height>24</height>
<height>30</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -1646,6 +1703,8 @@
<property name="title">
<string>&amp;Apps</string>
</property>
<addaction name="actionGet_Block"/>
<addaction name="actionView_Transaction"/>
<addaction name="actionValidate_Address"/>
<addaction name="separator"/>
</widget>
@ -1751,6 +1810,16 @@
<string>Validate Address</string>
</property>
</action>
<action name="actionGet_Block">
<property name="text">
<string>Get Block Info</string>
</property>
</action>
<action name="actionView_Transaction">
<property name="text">
<string>View Transaction Info</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

6
src/memoedit.h

@ -5,8 +5,10 @@
#include "precompiled.h"
class MemoEdit : public QPlainTextEdit
{
class MemoEdit : public QPlainTextEdit {
Q_OBJECT
public:
MemoEdit(QWidget* parent);

1
src/precompiled.h

@ -62,7 +62,6 @@
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtWebSockets/QtWebSockets>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>

34
src/privkey.ui

@ -14,7 +14,7 @@
<string>Private Keys</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<item row="1" column="0" colspan="3">
<widget class="QPlainTextEdit" name="privKeyTxt">
<property name="plainText">
<string/>
@ -22,6 +22,38 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="chkrescan">
<property name="text">
<string>Rescan</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="rescanlabel">
<property name="text">
<string>Rescan Height</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="rescanfrom">
<property name="text">
<string notr="true">1</string>
</property>
<property name="minimumSize">
<size>
<width>50</width>
</size>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>

53
src/rpc.cpp

@ -6,6 +6,7 @@
#include "settings.h"
#include "senttxstore.h"
#include "version.h"
#include <QThread>
#include "sd.h"
extern bool isdragonx;
@ -274,6 +275,28 @@ void RPC::getZUnspent(const std::function<void(QJsonValue)>& cb) {
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
void RPC::z_viewtransaction(QString txid, const std::function<void(QJsonValue)>& cb) {
QJsonObject payload = {
{"jsonrpc", "1.0"},
{"id", "42"},
{"method", "z_viewtransaction"},
{"params", QJsonArray {txid}}
};
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
void RPC::getrawtransaction(QString txid, const std::function<void(QJsonValue)>& cb) {
QJsonObject payload = {
{"jsonrpc", "1.0"},
{"id", "42"},
{"method", "getrawtransaction"},
{"params", QJsonArray {txid, 1}}
};
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
void RPC::newZaddr(const std::function<void(QJsonValue)>& cb) {
QJsonObject payload = {
{"jsonrpc", "1.0"},
@ -346,24 +369,24 @@ void RPC::importTPrivKey(QString privkey, bool rescan, const std::function<void(
// If privkey starts with 5, K or L, use old-style Hush params, same as BTC+ZEC
if( privkey.startsWith("5") || privkey.startsWith("K") || privkey.startsWith("L") ) {
qDebug() << "Detected old-style HUSH WIF";
DEBUG("Detected old-style taddr HUSH WIF");
payload = {
{"jsonrpc", "1.0"},
{"id", "42"},
{"method", "importprivkey"},
{"params", QJsonArray { privkey, "", "false", "0", "128" }},
{"params", QJsonArray { privkey, "", rescan , "0", "128" }},
};
} else {
qDebug() << "Detected new-style HUSH WIF";
DEBUG("Detected new-style taddr HUSH WIF");
payload = {
{"jsonrpc", "1.0"},
{"id", "42"},
{"method", "importprivkey"},
{"params", QJsonArray { privkey, (rescan? "yes" : "no") }},
{"params", QJsonArray { privkey, "", rescan }},
};
}
qDebug() << "Importing WIF with rescan=" << rescan;
DEBUG("Importing taddr WIF with rescan=" << rescan);
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
@ -373,6 +396,10 @@ void RPC::validateAddress(QString address, const std::function<void(QJsonValue)>
conn->doRPCWithDefaultErrorHandling(makePayload(method, address), cb);
}
void RPC::getBlock(QString height, const std::function<void(QJsonValue)>& cb) {
conn->doRPCWithDefaultErrorHandling(makePayload("getblock", height), cb);
}
void RPC::getBalance(const std::function<void(QJsonValue)>& cb) {
QJsonObject payload = {
{"jsonrpc", "1.0"},
@ -395,8 +422,14 @@ void RPC::listBanned(const std::function<void(QJsonValue)>& cb) {
}
void RPC::getTransactions(const std::function<void(QJsonValue)>& cb) {
QString method = "listtransactions";
conn->doRPCWithDefaultErrorHandling(makePayload(method), cb);
QJsonObject payload = {
{"jsonrpc", "1.0"},
{"id", "42"},
{"method", "listtransactions"},
{"params", QJsonArray { "*", 99999 }}
};
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
void RPC::mergeToAddress(QJsonArray &params, const std::function<void(QJsonValue)>& cb,
@ -757,9 +790,9 @@ void RPC::getInfoThenRefresh(bool force) {
int version = reply["version"].toInt();
int p2pport = reply["p2pport"].toInt();
int rpcport = reply["rpcport"].toInt();
int notarized = reply["notarized"].toInt();
int protocolversion = reply["protocolversion"].toInt();
int lag = curBlock - notarized;
// int notarized = reply["notarized"].toInt();
// int lag = curBlock - notarized;
// TODO: store all future halvings
int blocks_until_halving= 2020000 - curBlock;
char halving_days[8];
@ -1682,7 +1715,7 @@ void RPC::shutdownHushd() {
d.setWindowTitle("SilentDragonX");
}
QMovie *movie1 = new QMovie(":/img/silentdragon-animated-dark.gif");;
QMovie *movie1 = new QMovie(":/img/silentdragon-animated-startup-dark.gif");;
auto theme = Settings::getInstance()->get_theme_name();
movie1->setScaledSize(QSize(512,512));
connD.topIcon->setMovie(movie1);

3
src/rpc.h

@ -101,6 +101,8 @@ public:
void newZaddr(const std::function<void(QJsonValue)>& cb);
void newTaddr(const std::function<void(QJsonValue)>& cb);
void z_viewtransaction(QString txid, const std::function<void(QJsonValue)>& cb);
void getrawtransaction(QString txid, const std::function<void(QJsonValue)>& cb);
void setGenerate(int proclimit, const std::function<void(QJsonValue)>& cb);
void stopGenerate(int proclimit, const std::function<void(QJsonValue)>& cb);
@ -110,6 +112,7 @@ public:
void importZPrivKey(QString addr, bool rescan, const std::function<void(QJsonValue)>& cb);
void importTPrivKey(QString addr, bool rescan, const std::function<void(QJsonValue)>& cb);
void validateAddress(QString address, const std::function<void(QJsonValue)>& cb);
void getBlock(QString height, const std::function<void(QJsonValue)>& cb);
void shutdownHushd();
void noConnection();

4
src/sendtab.cpp

@ -693,7 +693,7 @@ bool MainWindow::confirmTx(Tx tx) {
return true;
} else {
return false;
}
}
}
// Send button clicked
@ -720,7 +720,7 @@ void MainWindow::sendButton() {
auto connD = new Ui_ConnectionDialog();
connD->setupUi(d);
QMovie *movie1 = new QMovie(":/img/silentdragon-animated-dark.gif");;
QMovie *movie1 = new QMovie(":/img/silentdragon-animated-startup-dark.gif");;
auto theme = Settings::getInstance()->get_theme_name();
movie1->setScaledSize(QSize(512,512));
connD->topIcon->setMovie(movie1);

32
src/settings.cpp

@ -3,6 +3,7 @@
#include "mainwindow.h"
#include "settings.h"
#include "sd.h"
#include <QUrlQuery>
extern bool isdragonx;
@ -133,13 +134,6 @@ bool Settings::isSaplingAddress(QString addr) {
(!isTestnet() && addr.startsWith("zs1"));
}
bool Settings::isSproutAddress(QString addr) {
if (!isValidAddress(addr))
return false;
return isZAddress(addr) && !isSaplingAddress(addr);
}
bool Settings::isZAddress(QString addr) {
if (!isValidAddress(addr))
return false;
@ -434,6 +428,30 @@ double Settings::getMinerFee() {
return 0.0001;
}
bool Settings::isValidTransparentPrivateKey(QString pk) {
if (pk.length() > 52) {
DEBUG("privkey invalid, too long");
return false;
}
if (pk.length() < 51) {
DEBUG("privkey invalid, too short");
return false;
}
// TODO: can a taddr privkey start with anything else?
if (pk.startsWith("U") || pk.startsWith("5") || pk.startsWith("L") || pk.startsWith("K") || pk.startsWith("7")) {
// verify only contains base58 characters
QRegExp exp("^[U5LK7][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51,52}$", Qt::CaseSensitive);
bool valid = exp.exactMatch(pk);
if(!valid) { DEBUG("privkey invalid, not base58"); }
return valid;
} else {
DEBUG("privkey invalid, wrong prefix");
return false;
}
}
bool Settings::isValidSaplingPrivateKey(QString pk) {
if (isTestnet()) {
QRegExp zspkey("^secret-extended-key-test[0-9a-z]{278}$", Qt::CaseInsensitive);

2
src/settings.h

@ -47,9 +47,9 @@ public:
void setTestnet(bool isTestnet);
bool isSaplingAddress(QString addr);
bool isSproutAddress(QString addr);
bool isValidSaplingPrivateKey(QString pk);
bool isValidTransparentPrivateKey(QString pk);
bool isSyncing();
void setSyncing(bool syncing);

283
src/settings.ui

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>623</width>
<height>653</height>
<height>622</height>
</rect>
</property>
<property name="minimumSize">
@ -145,228 +145,165 @@
<string>Options</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="chkSaveTxs">
<property name="text">
<string>Remember shielded transactions</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="chkAutoShield">
<item row="1" column="0" colspan="5">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Shield change from t-Addresses to your sapling address</string>
<string>Shielded transactions are saved locally and shown in the transactions tab. If you uncheck this, shielded transactions will not appear in the transactions tab.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="5">
<widget class="QPushButton" name="btnClearSaved">
<property name="text">
<string>Clear History</string>
</property>
</widget>
</item>
<item row="12" column="0" colspan="2">
<widget class="QLabel" name="label_10">
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="chkCustomFees">
<property name="text">
<string>Connect to the internet to fetch prices</string>
<string>Allow custom fees</string>
</property>
</widget>
</item>
<item row="14" column="0" colspan="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<item row="3" column="0" colspan="6">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Allow overriding the default fees when sending transactions. Enabling this option may compromise your privacy since fees are transparent. </string>
</property>
</spacer>
</item>
<item row="15" column="1">
<widget class="QComboBox" name="comboBoxTheme">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<property name="wordWrap">
<bool>true</bool>
</property>
<item>
<property name="text">
<string notr="true">default</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">blue</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">light</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">dark</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">midnight</string>
</property>
</item>
<item>
<property name="text">
<string>dragonx</string>
</property>
</item>
</widget>
</item>
<item row="18" column="1">
<widget class="QComboBox" name="comboBoxLanguage">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="4" column="0" colspan="5">
<widget class="QCheckBox" name="chkAutoShield">
<property name="text">
<string>Shield change from t-Addresses to your sapling address</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QLabel" name="lblTor">
<item row="5" column="0" colspan="6">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Connect to the Tor network via SOCKS proxy, which runs on 127.0.0.1:9050 by default or 127.0.0.1:9150 for Tor Browser. Please note that you'll have to install and run the Tor service externally.</string>
<string>Normally, change from t-Addresses goes to another t-Address. Checking this option will send the change to your shielded sapling address instead. Check this option to increase your privacy.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_tor_port">
<property name="text">
<string>Tor Port</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="torPort">
<property name="text">
<string notr="true">9050</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="chkTor">
<property name="text">
<string>Theme</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<string>Connect via Tor</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_6">
<item row="7" column="0" colspan="6">
<widget class="QLabel" name="lblTor">
<property name="text">
<string>Allow overriding the default fees when sending transactions. Enabling this option may compromise your privacy since fees are transparent. </string>
<string>Connect to the Tor network via SOCKS proxy, which runs on 127.0.0.1:9050 by default or 127.0.0.1:9150 for Tor Browser. Please note that you'll have to install and run the Tor service externally.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QCheckBox" name="chkCheckUpdates">
<item row="8" column="0">
<widget class="QLabel" name="label_tor_proxy">
<property name="text">
<string>Check git.hush.is for updates at startup</string>
<string>Proxy IP</string>
</property>
</widget>
</item>
<item row="12" column="0" colspan="2">
<widget class="QCheckBox" name="chkFetchPrices">
<item row="8" column="1" colspan="2">
<widget class="QLineEdit" name="torProxy">
<property name="text">
<string>Fetch prices</string>
<string notr="true">127.0.0.1</string>
</property>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QLabel" name="label_8">
<item row="8" column="3">
<widget class="QLabel" name="label_tor_port">
<property name="text">
<string>Connect to git.hush.is on startup to check for updates</string>
<string>Tor Port</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="chkCustomFees">
<item row="8" column="4">
<widget class="QLineEdit" name="torPort">
<property name="text">
<string>Allow custom fees</string>
<string notr="true">9050</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<item row="9" column="0" colspan="6">
<widget class="QCheckBox" name="chkCheckUpdates">
<property name="text">
<string>Shielded transactions are saved locally and shown in the transactions tab. If you uncheck this, shielded transactions will not appear in the transactions tab.</string>
<string>Connect to git.hush.is on startup to check for updates</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</widget>
</item>
<item row="10" column="0" colspan="6">
<widget class="QCheckBox" name="chkFetchPrices">
<property name="text">
<string>Connect to the internet to fetch prices</string>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_201">
<item row="11" column="2">
<widget class="QComboBox" name="comboBoxTheme">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Local Currency</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="chkTor">
<property name="text">
<string>Connect via Tor</string>
</property>
<item>
<property name="text">
<string notr="true">default</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">blue</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">light</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">dark</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">midnight</string>
</property>
</item>
<item>
<property name="text">
<string>dragonx</string>
</property>
</item>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="langlabel">
<item row="12" column="0" colspan="2">
<widget class="QLabel" name="label_201">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -374,14 +311,14 @@
</sizepolicy>
</property>
<property name="text">
<string>Language</string>
<string>Local Currency</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="16" column="1">
<item row="12" column="2">
<widget class="QComboBox" name="comboBoxCurrency">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@ -606,13 +543,45 @@
</item>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_7">
<item row="13" column="0" colspan="2">
<widget class="QLabel" name="langlabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Normally, change from t-Addresses goes to another t-Address. Checking this option will send the change to your shielded sapling address instead. Check this option to increase your privacy.</string>
<string>Language</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QComboBox" name="comboBoxLanguage">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QLabel" name="label_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Theme</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>

3
src/validateaddress.cpp

@ -29,6 +29,9 @@ QVariant ValidateAddressesModel::data(const QModelIndex &index, int role) const
return QVariant();
}
Qt::ItemFlags ValidateAddressesModel::flags(const QModelIndex &index) const {
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant ValidateAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {

4
src/validateaddress.h

@ -7,6 +7,8 @@
class ValidateAddressesModel : public QAbstractTableModel {
Q_OBJECT
public:
ValidateAddressesModel(QTableView* parent, QList<QPair<QString, QString>> props);
~ValidateAddressesModel() = default;
@ -16,6 +18,8 @@ public:
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
private:
QList<QPair<QString, QString>> props;
QStringList headers;

2
src/version.h

@ -1 +1 @@
#define APP_VERSION "1.3.1"
#define APP_VERSION "1.4.2"

2
src/viewalladdresses.h

@ -8,6 +8,8 @@
class ViewAllAddressesModel : public QAbstractTableModel {
Q_OBJECT
public:
ViewAllAddressesModel(QTableView* parent, QList<QString> taddrs, RPC* rpc);
~ViewAllAddressesModel() = default;

85
src/viewtransaction.ui

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ViewTransaction</class>
<widget class="QDialog" name="ViewTransaction">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>View Transaction</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="lblHeight">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Transaction ID (txid):</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTableView" name="tblProps">
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ViewTransaction</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ViewTransaction</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Loading…
Cancel
Save