UFRMWallet.pas 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713
  1. unit UFRMWallet;
  2. { Copyright (c) 2016 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. THIS LICENSE HEADER MUST NOT BE REMOVED.
  12. }
  13. {$IFDEF FPC}
  14. {$MODE Delphi}
  15. {$ENDIF}
  16. interface
  17. {$I ../config.inc}
  18. uses
  19. {$IFnDEF FPC}
  20. pngimage, Windows, AppEvnts, ShlObj,
  21. {$ELSE}
  22. LCLIntf, LCLType, LMessages,
  23. {$ENDIF}
  24. Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,
  25. ExtCtrls, ComCtrls, UWallet, StdCtrls, ULog, Grids, UAppParams, UBlockChain,
  26. UNode, UGridUtils, UJSONFunctions, UAccounts, Menus, ImgList, UNetProtocol,
  27. UCrypto, Buttons, UPoolMining, URPC, UFRMAccountSelect, UConst,
  28. UAccountKeyStorage, UBaseTypes, UPCDataTypes, UOrderedList,
  29. UFRMRPCCalls, UTxMultiOperation, USettings, UEPasa,
  30. {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
  31. Const
  32. CM_PC_WalletKeysChanged = WM_USER + 1;
  33. CM_PC_NetConnectionUpdated = WM_USER + 2;
  34. type
  35. { TFRMWallet }
  36. TFRMWallet = class(TForm)
  37. cbHashRateUnits: TComboBox;
  38. ebHashRateBackBlocks: TEdit;
  39. lblHashRateBackBlocks: TLabel;
  40. lblHashRateBackBlocks1: TLabel;
  41. MiRPCCalls: TMenuItem;
  42. pnlTop: TPanel;
  43. Image1: TImage;
  44. sbSearchAccount: TSpeedButton;
  45. StatusBar: TStatusBar;
  46. PageControl: TPageControl;
  47. tsMyAccounts: TTabSheet;
  48. tsOperations: TTabSheet;
  49. TimerUpdateStatus: TTimer;
  50. tsLogs: TTabSheet;
  51. pnlTopLogs: TPanel;
  52. cbShowDebugLogs: TCheckBox;
  53. memoLogs: TMemo;
  54. pnlMyAccountsTop: TPanel;
  55. dgAccounts: TDrawGrid;
  56. cbMyPrivateKeys: TComboBox;
  57. Splitter1: TSplitter;
  58. MainMenu: TMainMenu;
  59. miProject: TMenuItem;
  60. miOptions: TMenuItem;
  61. miPrivatekeys: TMenuItem;
  62. miN1: TMenuItem;
  63. miAbout: TMenuItem;
  64. miAboutPascalCoin: TMenuItem;
  65. miNewOperation: TMenuItem;
  66. Panel1: TPanel;
  67. Label2: TLabel;
  68. ebFilterOperationsStartBlock: TEdit;
  69. ebFilterOperationsEndBlock: TEdit;
  70. tsNodeStats: TTabSheet;
  71. memoNetConnections: TMemo;
  72. memoNetServers: TMemo;
  73. memoNetBlackLists: TMemo;
  74. Label3: TLabel;
  75. Label6: TLabel;
  76. Label7: TLabel;
  77. lblCurrentBlockCaption: TLabel;
  78. lblCurrentBlock: TLabel;
  79. lblCurrentBlockTimeCaption: TLabel;
  80. lblCurrentBlockTime: TLabel;
  81. lblOperationsPendingCaption: TLabel;
  82. lblOperationsPending: TLabel;
  83. lblMiningStatusCaption: TLabel;
  84. lblMinersClients: TLabel;
  85. lblCurrentDifficultyCaption: TLabel;
  86. lblCurrentDifficulty: TLabel;
  87. lblTimeAverage: TLabel;
  88. Label4: TLabel;
  89. tsBlockChain: TTabSheet;
  90. Panel2: TPanel;
  91. Label9: TLabel;
  92. ebBlockChainBlockStart: TEdit;
  93. ebBlockChainBlockEnd: TEdit;
  94. Label8: TLabel;
  95. lblNodeStatus: TLabel;
  96. tsPendingOperations: TTabSheet;
  97. dgPendingOperations: TDrawGrid;
  98. pnlPendingOperations: TPanel;
  99. Label10: TLabel;
  100. cbExploreMyAccounts: TCheckBox;
  101. N1: TMenuItem;
  102. MiClose: TMenuItem;
  103. MiDecodePayload: TMenuItem;
  104. Label5: TLabel;
  105. lblCurrentAccounts: TLabel;
  106. lblTimeAverageAux: TLabel;
  107. tsMessages: TTabSheet;
  108. lbNetConnections: TListBox;
  109. bbSendAMessage: TButton;
  110. Label11: TLabel;
  111. memoMessages: TMemo;
  112. memoMessageToSend: TMemo;
  113. Label12: TLabel;
  114. Label13: TLabel;
  115. Label14: TLabel;
  116. Label16: TLabel;
  117. lblBlocksFound: TLabel;
  118. pnlAccounts: TPanel;
  119. pnlAccountsInfo: TPanel;
  120. Label17: TLabel;
  121. Label19: TLabel;
  122. lblAccountsCount: TLabel;
  123. lblAccountsBalance: TLabel;
  124. lblReceivedMessages: TLabel;
  125. lblBuild: TLabel;
  126. ebFindAccountNumber: TEdit;
  127. Label18: TLabel;
  128. IPnodes1: TMenuItem;
  129. bbChangeKeyName: TBitBtn;
  130. pcAccountsOptions: TPageControl;
  131. tsAccountOperations: TTabSheet;
  132. dgAccountOperations: TDrawGrid;
  133. tsMultiSelectAccounts: TTabSheet;
  134. dgSelectedAccounts: TDrawGrid;
  135. pnlSelectedAccountsTop: TPanel;
  136. pnlSelectedAccountsBottom: TPanel;
  137. pnlSelectedAccountsLeft: TPanel;
  138. sbSelectedAccountsAdd: TSpeedButton;
  139. sbSelectedAccountsAddAll: TSpeedButton;
  140. sbSelectedAccountsDel: TSpeedButton;
  141. sbSelectedAccountsDelAll: TSpeedButton;
  142. Label20: TLabel;
  143. lblSelectedAccountsCount: TLabel;
  144. Label22: TLabel;
  145. lblSelectedAccountsBalance: TLabel;
  146. bbSelectedAccountsOperation: TBitBtn;
  147. Label15: TLabel;
  148. MiOperations: TMenuItem;
  149. MiAddaccounttoSelected: TMenuItem;
  150. MiRemoveaccountfromselected: TMenuItem;
  151. N2: TMenuItem;
  152. MiMultiaccountoperation: TMenuItem;
  153. N3: TMenuItem;
  154. MiFindnextaccountwithhighbalance: TMenuItem;
  155. MiFindpreviousaccountwithhighbalance: TMenuItem;
  156. MiFindaccount: TMenuItem;
  157. cbFilterAccounts: TCheckBox;
  158. ebFilterAccountByBalanceMin: TEdit;
  159. ebFilterAccountByBalanceMax: TEdit;
  160. bbAccountsRefresh: TBitBtn;
  161. dgBlockChainExplorer: TDrawGrid;
  162. dgOperationsExplorer: TDrawGrid;
  163. MiFindOperationbyOpHash: TMenuItem;
  164. MiAccountInformation: TMenuItem;
  165. MiOperationsExplorer: TMenuItem;
  166. procedure cbHashRateUnitsClick(Sender: TObject);
  167. procedure ebHashRateBackBlocksExit(Sender: TObject);
  168. procedure ebHashRateBackBlocksKeyPress(Sender: TObject; var Key: char);
  169. procedure FormCreate(Sender: TObject);
  170. procedure FormDestroy(Sender: TObject);
  171. procedure MiOperationsExplorerClick(Sender: TObject);
  172. procedure MiRPCCallsClick(Sender: TObject);
  173. procedure sbSearchAccountClick(Sender: TObject);
  174. procedure TimerUpdateStatusTimer(Sender: TObject);
  175. procedure cbMyPrivateKeysChange(Sender: TObject);
  176. procedure dgAccountsClick(Sender: TObject);
  177. procedure miOptionsClick(Sender: TObject);
  178. procedure miAboutPascalCoinClick(Sender: TObject);
  179. procedure miNewOperationClick(Sender: TObject);
  180. procedure miPrivatekeysClick(Sender: TObject);
  181. procedure dgAccountsColumnMoved(Sender: TObject; FromIndex,
  182. ToIndex: Integer);
  183. procedure dgAccountsFixedCellClick(Sender: TObject; ACol, ARow: Integer);
  184. procedure PageControlChange(Sender: TObject);
  185. procedure ebFilterOperationsAccountExit(Sender: TObject);
  186. procedure ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: Char);
  187. procedure ebBlockChainBlockStartExit(Sender: TObject);
  188. procedure ebBlockChainBlockStartKeyPress(Sender: TObject; var Key: Char);
  189. procedure cbExploreMyAccountsClick(Sender: TObject);
  190. procedure MiCloseClick(Sender: TObject);
  191. procedure MiDecodePayloadClick(Sender: TObject);
  192. procedure bbSendAMessageClick(Sender: TObject);
  193. procedure lblReceivedMessagesClick(Sender: TObject);
  194. procedure ebFindAccountNumberChange(Sender: TObject);
  195. procedure ebFindAccountNumberExit(Sender: TObject);
  196. procedure IPnodes1Click(Sender: TObject);
  197. procedure bbChangeKeyNameClick(Sender: TObject);
  198. procedure sbSelectedAccountsAddClick(Sender: TObject);
  199. procedure sbSelectedAccountsAddAllClick(Sender: TObject);
  200. procedure sbSelectedAccountsDelClick(Sender: TObject);
  201. procedure sbSelectedAccountsDelAllClick(Sender: TObject);
  202. procedure bbSelectedAccountsOperationClick(Sender: TObject);
  203. procedure MiAddaccounttoSelectedClick(Sender: TObject);
  204. procedure MiRemoveaccountfromselectedClick(Sender: TObject);
  205. procedure MiMultiaccountoperationClick(Sender: TObject);
  206. procedure MiFindnextaccountwithhighbalanceClick(Sender: TObject);
  207. procedure MiFindpreviousaccountwithhighbalanceClick(Sender: TObject);
  208. procedure MiFindaccountClick(Sender: TObject);
  209. procedure bbAccountsRefreshClick(Sender: TObject);
  210. procedure ebFilterAccountByBalanceMinExit(Sender: TObject);
  211. procedure ebFilterAccountByBalanceMinKeyPress(Sender: TObject;
  212. var Key: Char);
  213. procedure cbFilterAccountsClick(Sender: TObject);
  214. procedure MiFindOperationbyOpHashClick(Sender: TObject);
  215. procedure MiAccountInformationClick(Sender: TObject);
  216. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  217. procedure Test_ShowDiagnosticTool(Sender: TObject);
  218. private
  219. FLastNodesCacheUpdatedTS : TDateTime;
  220. FBackgroundPanel : TPanel;
  221. FBackgroundLabel : TLabel;
  222. FMinersBlocksFound: Integer;
  223. procedure SetMinersBlocksFound(const Value: Integer);
  224. Procedure CheckIsReady;
  225. Procedure FinishedLoadingApp;
  226. Procedure FillAccountInformation(Const Strings : TStrings; Const AccountNumber : Cardinal);
  227. Procedure FillOperationInformation(Const Strings : TStrings; Const OperationResume : TOperationResume);
  228. Procedure InitMacOSMenu;
  229. Procedure InitMenuForTesting;
  230. {$IFDEF TESTNET}
  231. Procedure Test_RandomOperations(Sender: TObject);
  232. Procedure Test_ConnectDisconnect(Sender: TObject);
  233. {$ENDIF}
  234. {$IFDEF TESTING_NO_POW_CHECK}
  235. Procedure Test_CreateABlock(Sender: TObject);
  236. {$ENDIF}
  237. Procedure Test_ShowPublicKeys(Sender: TObject);
  238. Procedure Test_ShowOperationsInMemory(Sender: TObject);
  239. Procedure Test_FindAccountsForPrivateBuyOrSwapToMe(Sender : TObject);
  240. procedure OnAccountsGridUpdatedData(Sender : TObject);
  241. protected
  242. { Private declarations }
  243. FNode : TNode;
  244. FIsActivated : Boolean;
  245. FWalletKeys : TWalletKeysExt;
  246. FLog : TLog;
  247. FNodeNotifyEvents : TNodeNotifyEvents;
  248. FAccountsGrid : TAccountsGrid;
  249. FSelectedAccountsGrid : TAccountsGrid;
  250. FOperationsAccountGrid : TOperationsGrid;
  251. FPendingOperationsGrid : TOperationsGrid;
  252. FOperationsExplorerGrid : TOperationsGrid;
  253. FBlockChainGrid : TBlockChainGrid;
  254. FMinerPrivateKeyType : TMinerPrivateKeyType;
  255. FUpdating : Boolean;
  256. FMessagesUnreadCount : Integer;
  257. FMinAccountBalance : Int64;
  258. FMaxAccountBalance : Int64;
  259. FPoolMiningServer : TPoolMiningServer;
  260. FRPCServer : TRPCServer;
  261. FMustProcessWalletChanged : Boolean;
  262. FMustProcessNetConnectionUpdated : Boolean;
  263. FThreadActivate : TObject;
  264. FLastAccountsGridInvalidateTC : TTickCount;
  265. Procedure OnNewAccount(Sender : TObject);
  266. Procedure OnReceivedHelloMessage(Sender : TObject);
  267. Procedure OnNetStatisticsChanged(Sender : TObject);
  268. procedure OnNewLog(logtype : TLogType; Time : TDateTime; ThreadID : TThreadID; Const sender, logtext : String);
  269. procedure OnWalletChanged(Sender : TObject);
  270. procedure OnNetConnectionsUpdated(Sender : TObject);
  271. procedure OnNetNodeServersUpdated(Sender : TObject);
  272. procedure OnNetBlackListUpdated(Sender : TObject);
  273. Procedure OnNodeMessageEvent(NetConnection : TNetConnection; MessageData : String);
  274. Procedure OnNodeKeysActivity(Sender : TObject);
  275. Procedure OnSelectedAccountsGridUpdated(Sender : TObject);
  276. Procedure OnMiningServerNewBlockFound(Sender : TObject);
  277. Procedure UpdateConnectionStatus;
  278. Procedure UpdateAccounts(RefreshData : Boolean);
  279. Procedure UpdateBlockChainState;
  280. Procedure UpdatePrivateKeys;
  281. Procedure UpdateOperations;
  282. Procedure UpdateConfigChanged(Sender:TObject);
  283. Procedure UpdateNodeStatus;
  284. Procedure UpdateAvailableConnections;
  285. procedure Activate; override;
  286. Function ForceMining : Boolean; virtual;
  287. Function GetAccountKeyForMiner : TAccountKey;
  288. Procedure DoUpdateAccounts;
  289. Function DoUpdateAccountsFilter : Boolean;
  290. procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
  291. procedure CM_NetConnectionUpdated(var Msg: TMessage); message CM_PC_NetConnectionUpdated;
  292. public
  293. { Public declarations }
  294. Property WalletKeys : TWalletKeysExt read FWalletKeys;
  295. Property MinersBlocksFound : Integer read FMinersBlocksFound write SetMinersBlocksFound;
  296. end;
  297. var
  298. FRMWallet: TFRMWallet;
  299. implementation
  300. {$IFnDEF FPC}
  301. {$R *.dfm}
  302. {$ELSE}
  303. {$R *.lfm}
  304. {$ENDIF}
  305. Uses UFolderHelper,{$IFDEF USE_GNUGETTEXT}gnugettext,{$ENDIF}
  306. {$IFDEF Use_OpenSSL}
  307. UOpenSSL,
  308. {$ENDIF}
  309. UTime, UFileStorage,
  310. {$IFDEF USE_ABSTRACTMEM_BLOCKCHAIN_STORAGE}
  311. UAbstractMemBlockchainStorage,
  312. {$ENDIF}
  313. UThread, UOpTransaction, UFRMPascalCoinWalletConfig,
  314. UFRMOperationsExplorer,
  315. {$IFDEF TESTNET}
  316. UFRMRandomOperations,
  317. UFRMDiagnosticTool,
  318. {$ENDIF}
  319. UPCTNetDataExtraMessages,
  320. UAbstractBTree, UEPasaDecoder,
  321. UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText,
  322. UCommon, UPCOrderedLists;
  323. Type
  324. { TThreadActivate }
  325. TThreadActivate = Class(TPCThread)
  326. private
  327. FLastTC : TTickCount;
  328. FLastMsg : String;
  329. procedure OnProgressNotify(sender : TObject; const mesage : String; curPos, totalCount : Int64);
  330. procedure ThreadSafeNotify;
  331. protected
  332. procedure BCExecute; override;
  333. End;
  334. { TThreadActivate }
  335. procedure TThreadActivate.OnProgressNotify(sender: TObject; const mesage: String; curPos, totalCount: Int64);
  336. var pct : String;
  337. begin
  338. If TPlatform.GetElapsedMilliseconds(FLastTC)>500 then begin
  339. FLastTC := TPlatform.GetTickCount;
  340. if (totalCount>0) then pct := Format('%.2f',[curPos*100/totalCount])+'%'
  341. else pct := '';
  342. FLastMsg:='Please wait until finished: '+mesage+' '+pct;
  343. Synchronize(ThreadSafeNotify);
  344. end;
  345. end;
  346. procedure TThreadActivate.ThreadSafeNotify;
  347. begin
  348. If (FLastMsg<>'') then begin
  349. if Assigned(FRMWallet.FBackgroundLabel) then begin
  350. FRMWallet.FBackgroundLabel.Caption:=FLastMsg;
  351. end;
  352. end else FRMWallet.UpdateNodeStatus;
  353. end;
  354. procedure TThreadActivate.BCExecute;
  355. Var currentProcess : String;
  356. LTC : TTickCount;
  357. LRaw : TRawBytes;
  358. begin
  359. FLastTC := 0;
  360. FLastMsg := '';
  361. //
  362. {$IFDEF PRODUCTION}
  363. OnProgressNotify(Self,'Reading Hardcoded RandomHash file',0,0);
  364. LRaw := TCrypto.HexaToRaw(CT_Hardcoded_RandomHash_Table_HASH);
  365. TPascalCoinProtocol.AllowUseHardcodedRandomHashTable(
  366. ExtractFileDir(Application.ExeName)+PathDelim+CT_Hardcoded_RandomHash_Table_Filename,
  367. LRaw );
  368. {$ENDIF}
  369. FLastTC := 0;
  370. OnProgressNotify(Self,'Initializing databases',0,0);
  371. // Read Operations saved from disk
  372. TAbstractMemBlockchainStorage( TNode.Node.Bank.Storage ).AutoFlushCache := False;
  373. TNode.Node.InitSafeboxAndOperations($FFFFFFFF,OnProgressNotify); // New Build 2.1.4 to load pending operations buffer
  374. TAbstractMemBlockchainStorage( TNode.Node.Bank.Storage ).AutoFlushCache := True;
  375. TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
  376. TNode.Node.NetServer.Active := true;
  377. FLastTC := 0;
  378. FLastMsg := '';
  379. LTC := TPlatform.GetTickCount;
  380. if (TNode.Node.Bank.BlocksCount<=1) then begin
  381. while (Not Terminated) And (Not TNode.Node.IsReady(currentProcess) Or (TNode.Node.Bank.BlocksCount<=1)) do begin
  382. Synchronize(ThreadSafeNotify);
  383. Sleep(200);
  384. {$IFDEF TESTNET}
  385. if (TPlatform.GetElapsedMilliseconds(LTC)>5000) then Break;
  386. {$ENDIF}
  387. end;
  388. end;
  389. if Not Terminated then begin
  390. Synchronize( FRMWallet.DoUpdateAccounts );
  391. Synchronize( FRMWallet.FinishedLoadingApp );
  392. end;
  393. FRMWallet.FThreadActivate := Nil;
  394. end;
  395. { TFRMWallet }
  396. procedure TFRMWallet.Activate;
  397. Var ips : AnsiString;
  398. nsarr : TNodeServerAddressArray;
  399. i : Integer;
  400. begin
  401. inherited;
  402. if FIsActivated then exit;
  403. FIsActivated := true;
  404. try
  405. TCrypto.InitCrypto;
  406. // Read Wallet
  407. Try
  408. FWalletKeys.WalletFileName := TNode.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
  409. Except
  410. On E:Exception do begin
  411. E.Message := 'Cannot open your wallet... Perhaps another instance of Pascal Coin is active!'+#10+#10+E.Message;
  412. Raise;
  413. end;
  414. End;
  415. UpdateConfigChanged(Self);
  416. ips := TSettings.TryConnectOnlyWithThisFixedServers;
  417. TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
  418. TNetData.NetData.DiscoverFixedServersOnly(nsarr);
  419. setlength(nsarr,0);
  420. // Creating Node:
  421. FNode := TNode.Node;
  422. FNode.NetServer.Port := TSettings.InternetServerPort;
  423. FNode.PeerCache := TSettings.PeerCache+';'+CT_Discover_IPs;
  424. FNode.MaxPayToKeyPurchasePrice := TSettings.MaxPayToKeyPurchasePrice;
  425. // Create RPC server
  426. FRPCServer := TRPCServer.Create;
  427. FRPCServer.WalletKeys := WalletKeys;
  428. FRPCServer.Active := TSettings.JsonRpcPortEnabled;
  429. FRPCServer.ValidIPs := TSettings.JsonRpcAllowedIPs;
  430. WalletKeys.SafeBox := FNode.Bank.SafeBox;
  431. // Check Database
  432. {$IFDEF USE_ABSTRACTMEM_BLOCKCHAIN_STORAGE}
  433. FNode.Bank.StorageClass := TAbstractMemBlockchainStorageSecondary;
  434. {$ELSE}
  435. FNode.Bank.StorageClass := TFileStorage;
  436. {$ENDIF}
  437. FNode.Bank.Storage.Initialize;
  438. // Init Grid
  439. FSelectedAccountsGrid.Node := FNode;
  440. FWalletKeys.OnChanged.Add( OnWalletChanged );
  441. FAccountsGrid.Node := FNode;
  442. FOperationsAccountGrid.Node := FNode;
  443. FBlockChainGrid.HashRateAverageBlocksCount := TSettings.HashRateAvgBlocksCount;
  444. i := Integer(TSettings.ShowHashRateAs);
  445. if (i<Integer(Low(TShowHashRateAs))) Or (i>Integer(High(TShowHashRateAs))) then i := Integer({$IFDEF TESTNET}hr_Mega{$ELSE}hr_Tera{$ENDIF});
  446. FBlockChainGrid.HashRateAs := TShowHashRateAs(i);
  447. // Reading database
  448. FThreadActivate := TThreadActivate.Create(true);
  449. TThreadActivate(FThreadActivate).FreeOnTerminate := true;
  450. TThreadActivate(FThreadActivate).Suspended := False;
  451. UpdateNodeStatus;
  452. TPCTNetDataExtraMessages.InitNetDataExtraMessages(FNode,TNetData.NetData,FWalletKeys);
  453. Except
  454. On E:Exception do begin
  455. E.Message := 'An error occurred during initialization. Application cannot continue:'+#10+#10+E.Message+#10+#10+'Application will close...';
  456. Application.MessageBox(PChar(E.Message),PChar(Application.Title),MB_ICONERROR+MB_OK);
  457. Halt;
  458. end;
  459. end;
  460. UpdatePrivateKeys;
  461. UpdateAccounts(false);
  462. if TSettings.FirstTime then begin
  463. TSettings.FirstTime := false;
  464. miAboutPascalCoinClick(Nil);
  465. end;
  466. PageControlChange(Nil);
  467. end;
  468. procedure TFRMWallet.bbAccountsRefreshClick(Sender: TObject);
  469. begin
  470. UpdateAccounts(true);
  471. end;
  472. procedure TFRMWallet.bbChangeKeyNameClick(Sender: TObject);
  473. var i : Integer;
  474. name : String;
  475. begin
  476. if (cbMyPrivateKeys.ItemIndex<0) then exit;
  477. i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
  478. if (i<0) Or (i>=FWalletKeys.Count) then raise Exception.Create('Must select a Key');
  479. name := FWalletKeys.Key[i].Name;
  480. if InputQuery('Change Key name','Input new name',name) then begin
  481. FWalletKeys.SetName(i,name);
  482. end;
  483. UpdatePrivateKeys;
  484. end;
  485. procedure TFRMWallet.bbSelectedAccountsOperationClick(Sender: TObject);
  486. var l : TOrderedCardinalList;
  487. begin
  488. CheckIsReady;
  489. if FSelectedAccountsGrid.AccountsCount<=0 then raise Exception.Create('Must select at least 1 account');
  490. With TFRMOperation.Create(Self) do
  491. Try
  492. l := FSelectedAccountsGrid.LockAccountsList;
  493. try
  494. SenderAccounts.CopyFrom(l);
  495. finally
  496. FSelectedAccountsGrid.UnlockAccountsList;
  497. end;
  498. DefaultFee := TSettings.DefaultFee;
  499. WalletKeys := FWalletKeys;
  500. ShowModal;
  501. Finally
  502. Free;
  503. End;
  504. end;
  505. procedure TFRMWallet.bbSendAMessageClick(Sender: TObject);
  506. Var basem,m : String;
  507. them, errors : String;
  508. i,n : Integer;
  509. nc : TNetConnection;
  510. begin
  511. CheckIsReady;
  512. if (lbNetConnections.SelCount<=0) Or (lbNetConnections.ItemIndex<0) then raise Exception.Create('Select at least one connection');
  513. if lbNetConnections.SelCount<=0 then n := 1
  514. else n := lbNetConnections.SelCount;
  515. basem := memoMessageToSend.Lines.Text;
  516. m := '';
  517. // Clear non valid characters:
  518. for i := Low(basem) to High(basem) do begin
  519. if basem[i] in [#32..#127] then m := m + basem[i]
  520. else m:=m+'.';
  521. end;
  522. if trim(m)='' then raise Exception.Create('No message');
  523. if Application.MessageBox(PChaR('Send this message to '+inttostr(n)+' nodes?'+#10+
  524. 'NOTE: Sending unauthorized messages will be considered spam and you will be banned'+#10+
  525. #10+
  526. 'Message: '+#10+
  527. m),PChar(Application.Title),MB_ICONQUESTION+MB_YESNO+MB_DEFBUTTON1)<>IdYes then exit;
  528. them := m;
  529. if n>1 then begin
  530. for i := 0 to lbNetConnections.Items.Count - 1 do begin
  531. if lbNetConnections.Selected[i] then begin
  532. nc := TNetConnection(lbNetconnections.Items.Objects[i]);
  533. if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
  534. FNode.SendNodeMessage(nc,m,errors);
  535. memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
  536. end;
  537. end;
  538. end;
  539. end else begin
  540. nc := TNetConnection(lbNetconnections.Items.Objects[lbNetconnections.ItemIndex]);
  541. if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
  542. FNode.SendNodeMessage(nc,m,errors);
  543. memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
  544. end;
  545. end;
  546. Application.MessageBox(PChaR('Message sent to '+inttostr(n)+' nodes'+#10+
  547. 'Message: '+#10+m),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
  548. end;
  549. procedure TFRMWallet.cbExploreMyAccountsClick(Sender: TObject);
  550. begin
  551. cbMyPrivateKeys.Enabled := cbExploreMyAccounts.Checked;
  552. UpdateAccounts(true);
  553. UpdateOperations;
  554. end;
  555. procedure TFRMWallet.cbFilterAccountsClick(Sender: TObject);
  556. begin
  557. If not DoUpdateAccountsFilter then UpdateAccounts(true);
  558. end;
  559. procedure TFRMWallet.cbMyPrivateKeysChange(Sender: TObject);
  560. begin
  561. UpdateAccounts(true);
  562. end;
  563. procedure TFRMWallet.CheckIsReady;
  564. Var isready : String;
  565. begin
  566. if Not Assigned(FNode) then Abort;
  567. if Not FNode.IsReady(isready) then begin
  568. Raise Exception.Create('You cannot do this operation now:'+#10+#10+isready);
  569. end;
  570. end;
  571. procedure TFRMWallet.CM_NetConnectionUpdated(var Msg: TMessage);
  572. Const CT_BooleanToString : Array[Boolean] of String = ('False','True');
  573. Var i : integer;
  574. NC : TNetConnection;
  575. l : TList<TNetConnection>;
  576. sClientApp, sLastConnTime : String;
  577. strings, sNSC, sRS, sDisc : TStrings;
  578. hh,nn,ss,ms : Word;
  579. begin
  580. Try
  581. if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
  582. try
  583. strings := memoNetConnections.Lines;
  584. sNSC := TStringList.Create;
  585. sRS := TStringList.Create;
  586. sDisc := TStringList.Create;
  587. strings.BeginUpdate;
  588. Try
  589. for i := 0 to l.Count - 1 do begin
  590. NC := l[i];
  591. If NC.Client.BytesReceived>0 then begin
  592. sClientApp := '['+IntToStr(NC.NetProtocolVersion.protocol_version)+'-'+IntToStr(NC.NetProtocolVersion.protocol_available)+'] '+NC.ClientAppVersion;
  593. end else begin
  594. sClientApp := '(no data)';
  595. end;
  596. if NC.Connected then begin
  597. if NC.Client.LastCommunicationTime>1000 then begin
  598. DecodeTime(now - NC.Client.LastCommunicationTime,hh,nn,ss,ms);
  599. if (hh=0) and (nn=0) And (ss<10) then begin
  600. sLastConnTime := ' - Last comunication <10 sec.';
  601. end else begin
  602. sLastConnTime := Format(' - Last comunication %.2dm%.2ds',[(hh*60)+nn,ss]);
  603. end;
  604. end else begin
  605. sLastConnTime := '';
  606. end;
  607. if NC is TNetServerClient then begin
  608. sNSC.Add(Format('Client: IP:%s Block:%d Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
  609. [NC.ClientRemoteAddr,NC.RemoteOperationBlock.block,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
  610. end else begin
  611. if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
  612. [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]))
  613. else begin
  614. sRS.Add(Format('Remote Server: IP:%s Block:%d Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
  615. [NC.ClientRemoteAddr,NC.RemoteOperationBlock.block,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
  616. end;
  617. end;
  618. end else begin
  619. if NC is TNetServerClient then begin
  620. sDisc.Add(Format('Disconnected client: IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
  621. end else if NC.IsMyselfServer then begin
  622. sDisc.Add(Format('Disconnected MySelf IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
  623. end else begin
  624. sDisc.Add(Format('Disconnected Remote Server: IP:%s %s - %s',[NC.ClientRemoteAddr,CT_BooleanToString[NC.Connected],sClientApp]));
  625. end;
  626. end;
  627. end;
  628. strings.Clear;
  629. strings.Add(Format('Connections Updated %s Clients:%d Servers:%d (valid servers:%d)',[DateTimeToStr(now),sNSC.Count,sRS.Count,TNetData.NetData.NetStatistics.ServersConnectionsWithResponse]));
  630. strings.AddStrings(sRS);
  631. strings.AddStrings(sNSC);
  632. if sDisc.Count>0 then begin
  633. strings.Add('');
  634. strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
  635. strings.AddStrings(sDisc);
  636. end;
  637. Finally
  638. strings.EndUpdate;
  639. sNSC.Free;
  640. sRS.Free;
  641. sDisc.Free;
  642. End;
  643. //CheckMining;
  644. finally
  645. TNetData.NetData.NetConnections.UnlockList;
  646. end;
  647. Finally
  648. FMustProcessNetConnectionUpdated := false;
  649. End;
  650. end;
  651. procedure TFRMWallet.CM_WalletChanged(var Msg: TMessage);
  652. begin
  653. UpdatePrivateKeys;
  654. FMustProcessWalletChanged := false;
  655. end;
  656. procedure TFRMWallet.dgAccountsClick(Sender: TObject);
  657. begin
  658. UpdateOperations;
  659. end;
  660. procedure TFRMWallet.dgAccountsColumnMoved(Sender: TObject; FromIndex, ToIndex: Integer);
  661. begin
  662. TSettings.Save;
  663. end;
  664. procedure TFRMWallet.dgAccountsFixedCellClick(Sender: TObject; ACol,
  665. ARow: Integer);
  666. begin
  667. TSettings.Save;
  668. end;
  669. procedure TFRMWallet.DoUpdateAccounts;
  670. begin
  671. UpdateAccounts(true);
  672. end;
  673. function TFRMWallet.DoUpdateAccountsFilter: Boolean;
  674. Var m,bmin,bmax:Int64;
  675. doupd : Boolean;
  676. begin
  677. if FUpdating then exit;
  678. FUpdating := true;
  679. Try
  680. If Not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMin.Text,bmin) then bmin := 0;
  681. If not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMax.Text,bmax) then bmax := CT_MaxWalletAmount;
  682. if (bmax<bmin) or (bmax=0) then bmax := CT_MaxWalletAmount;
  683. if bmin>bmax then bmin := 0;
  684. doupd := (bmin<>FMinAccountBalance) Or (bmax<>FMaxAccountBalance);
  685. if bmin>0 then
  686. ebFilterAccountByBalanceMin.Text:=TAccountComp.FormatMoney(bmin)
  687. else ebFilterAccountByBalanceMin.Text := '';
  688. if bmax<CT_MaxWalletAmount then
  689. ebFilterAccountByBalanceMax.Text := TAccountComp.FormatMoney(bmax)
  690. else ebFilterAccountByBalanceMax.Text := '';
  691. if cbFilterAccounts.Checked then begin
  692. FMinAccountBalance := bmin;
  693. FMaxAccountBalance := bmax;
  694. ebFilterAccountByBalanceMin.ParentFont := true;
  695. ebFilterAccountByBalanceMax.ParentFont := true;
  696. end else begin
  697. FMinAccountBalance := 0;
  698. FMaxAccountBalance := CT_MaxWalletAmount;
  699. ebFilterAccountByBalanceMin.font.Color := clDkGray;
  700. ebFilterAccountByBalanceMax.font.Color := clDkGray;
  701. end;
  702. Finally
  703. FUpdating := false;
  704. End;
  705. if doupd then UpdateAccounts(true);
  706. Result := doupd;
  707. end;
  708. procedure TFRMWallet.ebBlockChainBlockStartExit(Sender: TObject);
  709. var bstart,bend : Int64;
  710. begin
  711. If FUpdating then exit;
  712. FUpdating := True;
  713. Try
  714. bstart := StrToInt64Def(ebBlockChainBlockStart.Text,-1);
  715. bend := StrToInt64Def(ebBlockChainBlockEnd.Text,-1);
  716. FBlockChainGrid.SetBlocks(bstart,bend);
  717. if FBlockChainGrid.BlockStart>=0 then ebBlockChainBlockStart.Text := Inttostr(FBlockChainGrid.BlockStart) else ebBlockChainBlockStart.Text := '';
  718. if FBlockChainGrid.BlockEnd>=0 then ebBlockChainBlockEnd.Text := Inttostr(FBlockChainGrid.BlockEnd) else ebBlockChainBlockEnd.Text := '';
  719. Finally
  720. FUpdating := false;
  721. End;
  722. end;
  723. procedure TFRMWallet.ebBlockChainBlockStartKeyPress(Sender: TObject;
  724. var Key: Char);
  725. begin
  726. if key=#13 then ebBlockChainBlockStartExit(Nil);
  727. end;
  728. procedure TFRMWallet.ebFilterAccountByBalanceMinExit(Sender: TObject);
  729. begin
  730. DoUpdateAccountsFilter;
  731. end;
  732. procedure TFRMWallet.ebFilterAccountByBalanceMinKeyPress(Sender: TObject;
  733. var Key: Char);
  734. begin
  735. if key=#13 then DoUpdateAccountsFilter;
  736. end;
  737. procedure TFRMWallet.ebFilterOperationsAccountExit(Sender: TObject);
  738. Var bstart,bend : Int64;
  739. begin
  740. If FUpdating then exit;
  741. FUpdating := True;
  742. Try
  743. bstart := StrToInt64Def(ebFilterOperationsStartBlock.Text,-1);
  744. if bstart>=0 then ebFilterOperationsStartBlock.Text := Inttostr(bstart) else ebFilterOperationsStartBlock.Text := '';
  745. bend := StrToInt64Def(ebFilterOperationsEndBlock.Text,-1);
  746. if bend>=0 then ebFilterOperationsEndBlock.Text := Inttostr(bend) else ebFilterOperationsEndBlock.Text := '';
  747. FOperationsExplorerGrid.SetBlocks(bstart,bend);
  748. Finally
  749. FUpdating := false;
  750. End;
  751. end;
  752. procedure TFRMWallet.ebFilterOperationsAccountKeyPress(Sender: TObject;
  753. var Key: Char);
  754. begin
  755. if key=#13 then ebFilterOperationsAccountExit(Nil);
  756. end;
  757. procedure TFRMWallet.ebFindAccountNumberChange(Sender: TObject);
  758. Var an : Cardinal;
  759. LAccountNameRawValue : TRawBytes;
  760. LErrors : String;
  761. LAccNames : TOrderedRawList;
  762. begin
  763. if Trim(ebFindAccountNumber.Text)='' then begin
  764. ebFindAccountNumber.Color := clWindow;
  765. ebFindAccountNumber.Font.Color := clDkGray;
  766. end else if TAccountComp.AccountTxtNumberToAccountNumber(ebFindAccountNumber.Text,an) then begin
  767. ebFindAccountNumber.Color := clWindow;
  768. if FAccountsGrid.MoveRowToAccount(an) then begin
  769. ebFindAccountNumber.Font.Color := clWindowText;
  770. end else begin
  771. ebFindAccountNumber.Font.Color := clRed;
  772. end;
  773. end else begin
  774. LAccountNameRawValue.FromString(ebFindAccountNumber.Text);
  775. LAccNames := TOrderedRawList.Create;
  776. Try
  777. if FNode.Bank.SafeBox.FindAccountsStartingByName(LAccountNameRawValue,LAccNames,1)>0 then begin
  778. an := LAccNames.GetTag(0);
  779. ebFindAccountNumber.Color := clWindow;
  780. if FAccountsGrid.MoveRowToAccount(an) then begin
  781. ebFindAccountNumber.Font.Color := clWindowText;
  782. end else begin
  783. ebFindAccountNumber.Font.Color := clRed;
  784. end;
  785. end else begin
  786. // Invalid value
  787. ebFindAccountNumber.Color := clRed;
  788. ebFindAccountNumber.Font.Color := clWindowText;
  789. end;
  790. Finally
  791. LAccNames.Free;
  792. End;
  793. end;
  794. end;
  795. procedure TFRMWallet.ebFindAccountNumberExit(Sender: TObject);
  796. begin
  797. ebFindAccountNumber.Text := '';
  798. end;
  799. procedure TFRMWallet.FinishedLoadingApp;
  800. var LLockedMempool : TPCOperationsComp;
  801. LFoundAccounts, i, LOnSafebox,LOnMempool : Integer;
  802. Lpubkeys : TList<TAccountKey>;
  803. begin
  804. FNodeNotifyEvents.Node := FNode;
  805. // Init
  806. TNetData.NetData.OnReceivedHelloMessage := OnReceivedHelloMessage;
  807. TNetData.NetData.OnStatisticsChanged := OnNetStatisticsChanged;
  808. TNetData.NetData.OnNetConnectionsUpdated := onNetConnectionsUpdated;
  809. TNetData.NetData.OnNodeServersUpdated := OnNetNodeServersUpdated;
  810. TNetData.NetData.OnBlackListUpdated := OnNetBlackListUpdated;
  811. //
  812. TimerUpdateStatus.Interval := 1000;
  813. TimerUpdateStatus.Enabled := true;
  814. //
  815. FPoolMiningServer := TPoolMiningServer.Create;
  816. FPoolMiningServer.Port := TSettings.JsonRpcMinerServerPort;
  817. FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
  818. FPoolMiningServer.MinerPayload := TEncoding.ANSI.GetBytes(TSettings.MinerName);
  819. LLockedMempool := FNode.LockMempoolWrite;
  820. try
  821. LLockedMempool.AccountKey := GetAccountKeyForMiner;
  822. finally
  823. FNode.UnlockMempoolWrite;
  824. end;
  825. FPoolMiningServer.Active := TSettings.JsonRpcMinerServerActive;
  826. FPoolMiningServer.OnMiningServerNewBlockFound := OnMiningServerNewBlockFound;
  827. FreeAndNil(FBackgroundLabel);
  828. FreeAndNil(FBackgroundPanel);
  829. PageControl.Visible:=True;
  830. PageControl.Enabled:=True;
  831. UpdatePrivateKeys;
  832. //
  833. LFoundAccounts := 0;
  834. FNode.Bank.SafeBox.StartThreadSafe;
  835. try
  836. Lpubkeys := TList<TAccountKey>.Create;
  837. Try
  838. for i := 0 to FWalletKeys.Count-1 do begin
  839. if (FWalletKeys.Key[i].HasPrivateKey) then begin
  840. Lpubkeys.Add(FWalletKeys.Key[i].AccountKey);
  841. end;
  842. end;
  843. if (Lpubkeys.Count>0) then begin
  844. LFoundAccounts := FNode.GetAccountsAvailableByPublicKey(Lpubkeys,LOnSafebox,LOnMempool);
  845. end else LFoundAccounts := 0;
  846. Finally
  847. Lpubkeys.Free;
  848. End;
  849. finally
  850. FNode.Bank.SafeBox.EndThreadSave;
  851. end;
  852. if LFoundAccounts<1 then begin
  853. // TODO: Wallet has no PASA ...
  854. end;
  855. end;
  856. procedure TFRMWallet.FillAccountInformation(const Strings: TStrings;
  857. const AccountNumber: Cardinal);
  858. Var account : TAccount;
  859. s : String;
  860. LjsonObj : TPCJSONObject;
  861. begin
  862. if AccountNumber<0 then exit;
  863. account := FNode.GetMempoolAccount(AccountNumber);
  864. if Length(account.name)>0 then s:='Name: '+TEncoding.ANSI.GetString(account.name)
  865. else s:='';
  866. Strings.Add(Format('Account: %s %s Type:%d',[TAccountComp.AccountNumberToAccountTxtNumber(AccountNumber),s,account.account_type]));
  867. Strings.Add('');
  868. Strings.Add(Format('Current balance: %s',[TAccountComp.FormatMoney(account.balance)]));
  869. Strings.Add('');
  870. Strings.Add(Format('Updated on block: %d (%d blocks ago)',[account.GetLastUpdatedBlock,FNode.Bank.BlocksCount-account.GetLastUpdatedBlock]));
  871. Strings.Add(Format('Updated on block as active mode: %d (%d blocks ago)',[account.updated_on_block_active_mode,FNode.Bank.BlocksCount-account.updated_on_block_active_mode]));
  872. Strings.Add(Format('Public key type: %s',[TAccountComp.GetECInfoTxt(account.accountInfo.accountKey.EC_OpenSSL_NID)]));
  873. Strings.Add(Format('Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(account.accountInfo.accountKey)]));
  874. if Length(account.account_data)>0 then
  875. Strings.Add(Format('Account Data: %s',[account.account_data.ToHexaString]))
  876. else Strings.Add(Format('Account Data: (No data)',[]));
  877. Strings.Add(Format('Account Seal: %s',[account.account_seal.ToHexaString]));
  878. if TAccountComp.IsAccountForSale(account.accountInfo) then begin
  879. Strings.Add('');
  880. Strings.Add('** Account is for sale: **');
  881. Strings.Add(Format('Price: %s',[TAccountComp.FormatMoney(account.accountInfo.price)]));
  882. Strings.Add(Format('Seller account (where to pay): %s',[TAccountComp.AccountNumberToAccountTxtNumber(account.accountInfo.account_to_pay)]));
  883. if TAccountComp.IsAccountForPrivateSale(account.accountInfo) then begin
  884. Strings.Add('');
  885. Strings.Add('** Private sale **');
  886. Strings.Add(Format('New Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(account.accountInfo.new_publicKey)]));
  887. Strings.Add('');
  888. if TAccountComp.IsAccountLocked(account.accountInfo,FNode.Bank.BlocksCount) then begin
  889. Strings.Add(Format('PURCHASE IS SECURE UNTIL BLOCK %d (current %d, remains %d)',
  890. [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount,account.accountInfo.locked_until_block-FNode.Bank.BlocksCount]));
  891. end else begin
  892. Strings.Add(Format('PURCHASE IS NOT SECURE (Expired on block %d, current %d)',
  893. [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount]));
  894. end;
  895. end;
  896. end else if TAccountComp.IsAccountForSwap(account.accountInfo) then begin
  897. Strings.Add('');
  898. if TAccountComp.IsAccountForAccountSwap(account.accountInfo) then begin
  899. Strings.Add('** Account is for Atomic Account Swap: **');
  900. Strings.Add(Format('New Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(account.accountInfo.new_publicKey)]));
  901. end else if TAccountComp.IsAccountForCoinSwap(account.accountInfo) then begin
  902. Strings.Add('** Account is for Atomic Coin Swap: **');
  903. Strings.Add(Format('Amount to swap: %s',[TAccountComp.FormatMoney(account.accountInfo.price)]));
  904. Strings.Add(Format('Counterparty account: %s',[TAccountComp.AccountNumberToAccountTxtNumber(account.accountInfo.account_to_pay)]));
  905. end;
  906. Strings.Add(Format('Public secret to find: %s',[account.accountInfo.hashed_secret.ToHexaString]));
  907. Strings.Add('');
  908. if TAccountComp.IsAccountLocked(account.accountInfo,FNode.Bank.BlocksCount) then begin
  909. Strings.Add(Format('SWAP IS SECURE UNTIL BLOCK %d (current %d, remains %d)',
  910. [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount,account.accountInfo.locked_until_block-FNode.Bank.BlocksCount]));
  911. end else begin
  912. Strings.Add(Format('SWAP IS NOT SECURE (Expired on block %d, current %d)',
  913. [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount]));
  914. end;
  915. end;
  916. LjsonObj := TPCJSONObject.Create;
  917. Try
  918. TPascalCoinJSONComp.FillAccountObject(account,LjsonObj);
  919. Strings.Add('ACCOUNT JSON:');
  920. Strings.Add(LjsonObj.ToJSON(False));
  921. Finally
  922. LjsonObj.Free;
  923. end;
  924. end;
  925. procedure TFRMWallet.FillOperationInformation(const Strings: TStrings;
  926. const OperationResume: TOperationResume);
  927. var i : Integer;
  928. jsonObj : TPCJSONObject;
  929. LEPASA : TEPasa;
  930. begin
  931. If (not OperationResume.valid) then exit;
  932. If OperationResume.Block<FNode.Bank.BlocksCount then
  933. if (OperationResume.NOpInsideBlock>=0) then begin
  934. Strings.Add(Format('Block: %d/%d',[OperationResume.Block,OperationResume.NOpInsideBlock]))
  935. end else begin
  936. Strings.Add(Format('Block: %d',[OperationResume.Block]))
  937. end
  938. else Strings.Add('** Pending operation not included on blockchain **');
  939. Strings.Add(Format('%s',[OperationResume.OperationTxt]));
  940. If (OperationResume.isMultiOperation) then begin
  941. Strings.Add('Multioperation:');
  942. For i := 0 to High(OperationResume.Senders) do begin
  943. Strings.Add(Format(' Sender (%d/%d): %s %s PASC Payload(%d):%s',[i+1,length(OperationResume.Senders),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Senders[i].Account),TAccountComp.FormatMoney(OperationResume.Senders[i].Amount),OperationResume.Senders[i].Payload.payload_type,OperationResume.Senders[i].Payload.payload_raw.ToHexaString]));
  944. end;
  945. For i := 0 to High(OperationResume.Receivers) do begin
  946. Strings.Add(Format(' Receiver (%d/%d): %s %s PASC Payload(%d):%s',[i+1,length(OperationResume.Receivers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Receivers[i].Account),TAccountComp.FormatMoney(OperationResume.Receivers[i].Amount),OperationResume.Receivers[i].Payload.payload_type,OperationResume.Receivers[i].Payload.payload_raw.ToHexaString]));
  947. end;
  948. For i := 0 to High(OperationResume.Changers) do begin
  949. Strings.Add(Format(' Change info (%d/%d): %s [%s]',[i+1,length(OperationResume.Changers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Changers[i].Account),TOpMultiOperation.OpChangeAccountInfoTypesToText(OperationResume.Changers[i].Changes_type)]));
  950. end;
  951. end;
  952. Strings.Add(Format('OpType:%d Subtype:%d',[OperationResume.OpType,OperationResume.OpSubtype]));
  953. Strings.Add(Format('Operation Hash (ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash)]));
  954. If (Length(OperationResume.OperationHash_OLD)>0) then begin
  955. Strings.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash_OLD)]));
  956. end;
  957. if TEPasaDecoder.TryDecodeEPASA(OperationResume.DestAccount,OperationResume.OriginalPayload,FNode,FWalletKeys,Nil,LEPASA) then begin
  958. Strings.Add('EPASA: '+LEPASA.ToString);
  959. end else Strings.Add('No EPASA format');
  960. Strings.Add(Format('Payload type:%s length:%d',['0x'+IntToHex(OperationResume.OriginalPayload.payload_type,2), length(OperationResume.OriginalPayload.payload_raw)]));
  961. if (Length(OperationResume.OriginalPayload.payload_raw)>0) then begin
  962. If OperationResume.PrintablePayload<>'' then begin
  963. Strings.Add(Format('Payload (human): %s',[OperationResume.PrintablePayload]));
  964. end;
  965. Strings.Add(Format('Payload (Hexadecimal): %s',[TCrypto.ToHexaString(OperationResume.OriginalPayload.payload_raw)]));
  966. end;
  967. If OperationResume.Balance>=0 then begin
  968. Strings.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(OperationResume.Balance)]));
  969. end;
  970. jsonObj := TPCJSONObject.Create;
  971. Try
  972. TPascalCoinJSONComp.FillOperationObject(OperationResume,FNode.Bank.BlocksCount,
  973. FNode,FWalletKeys,Nil,
  974. jsonObj);
  975. Strings.Add('OPERATION JSON:');
  976. Strings.Add(jsonObj.ToJSON(False));
  977. Finally
  978. jsonObj.Free;
  979. end;
  980. end;
  981. Procedure TFRMWallet.InitMacOSMenu;
  982. {$IFDEF FPC}
  983. var
  984. mi : TMenuItem;
  985. app : TMenuItem;
  986. {$ENDIF}
  987. begin
  988. {$IFDEF FPC}
  989. {$IFNDEF DARWIN}
  990. Exit;
  991. {$ENDIF}
  992. app := TMenuItem.Create(MainMenu);
  993. app := TMenuItem.Create(MainMenu);
  994. app.Caption:=#$EF#$A3#$BF;
  995. miAboutPascalCoin.Parent.Remove(miAboutPascalCoin);
  996. app.Add(miAboutPascalCoin);
  997. {$IFDEF TESTNET}
  998. // Things for testing purposes only
  999. miAbout.caption := 'Testing';
  1000. {$ELSE}
  1001. miAbout.Visible:=false;
  1002. {$ENDIF}
  1003. // Move "Options" to "Prefernces"
  1004. mi := TMenuItem.Create(MainMenu);
  1005. mi.Caption:='-';
  1006. app.Add(mi);
  1007. miOptions.Parent.Remove(miOptions);
  1008. miOptions.Caption:='Preferences...';
  1009. miOptions.ShortCut:=Menus.ShortCut(VK_OEM_COMMA, [ssMeta]);
  1010. app.Add(miOptions);
  1011. MiFindaccount.ShortCut:=Menus.ShortCut(VK_F, [ssMeta]);
  1012. MiOperationsExplorer.ShortCut:=Menus.ShortCut(VK_E, [ssMeta]);
  1013. MiFindpreviousaccountwithhighbalance.ShortCut:=Menus.Shortcut(VK_F3, [ssMeta]);
  1014. miOptions.ShortCut:=Menus.ShortCut(VK_OEM_COMMA, [ssMeta]); // match preferences
  1015. miPrivatekeys.ShortCut:=Menus.Shortcut(VK_P, [ssMeta]);
  1016. N1.Visible:=false;
  1017. MiClose.Visible:=false;
  1018. MainMenu.Items.Insert(0, app);
  1019. {$endif}
  1020. end;
  1021. procedure TFRMWallet.InitMenuForTesting;
  1022. var mi : TMenuItem;
  1023. begin
  1024. {$IFDEF TESTNET}
  1025. mi := TMenuItem.Create(MainMenu);
  1026. mi.Caption:='-';
  1027. miAbout.Add(mi);
  1028. {$IFDEF TESTING_NO_POW_CHECK}
  1029. mi := TMenuItem.Create(MainMenu);
  1030. mi.Caption:='Create a block';
  1031. mi.OnClick:=Test_CreateABlock;
  1032. {$IFnDEF FPC}
  1033. mi.ShortCut := TextToShortCut('CTRL+B');
  1034. {$ENDIF}
  1035. miAbout.Add(mi);
  1036. {$ENDIF}
  1037. mi := TMenuItem.Create(MainMenu);
  1038. mi.Caption:='Connect/Disconnect';
  1039. mi.OnClick:=Test_ConnectDisconnect;
  1040. {$IFnDEF FPC}
  1041. mi.ShortCut := TextToShortCut('CTRL+D');
  1042. {$ENDIF}
  1043. miAbout.Add(mi);
  1044. mi := TMenuItem.Create(MainMenu);
  1045. mi.Caption:='Create Random operations';
  1046. mi.OnClick:=Test_RandomOperations;
  1047. miAbout.Add(mi);
  1048. mi := TMenuItem.Create(MainMenu);
  1049. mi.Caption:='Diagnostic Tool';
  1050. mi.OnClick:=Test_ShowDiagnosticTool;
  1051. miAbout.Add(mi);
  1052. mi := TMenuItem.Create(MainMenu);
  1053. mi.Caption:='Show public keys state';
  1054. mi.OnClick:=Test_ShowPublicKeys;
  1055. miAbout.Add(mi);
  1056. mi := TMenuItem.Create(MainMenu);
  1057. mi.Caption:='Show operations in memory';
  1058. mi.OnClick:=Test_ShowOperationsInMemory;
  1059. miAbout.Add(mi);
  1060. mi := TMenuItem.Create(MainMenu);
  1061. mi.Caption:='Search accounts for private or swap to me';
  1062. mi.OnClick:=Test_FindAccountsForPrivateBuyOrSwapToMe;
  1063. miAbout.Add(mi);
  1064. {$ELSE}
  1065. {$ENDIF}
  1066. end;
  1067. {$IFDEF TESTING_NO_POW_CHECK}
  1068. procedure TFRMWallet.Test_CreateABlock(Sender: TObject);
  1069. var ops, mempoolOps : TPCOperationsComp;
  1070. nba : TBlockAccount;
  1071. errors : String;
  1072. begin
  1073. {$IFDEF TESTNET}
  1074. ops := TPCOperationsComp.Create(Nil);
  1075. Try
  1076. ops.bank := FNode.Bank;
  1077. mempoolOps := FNode.LockMempoolRead;
  1078. try
  1079. ops.CopyFrom(mempoolOps);
  1080. finally
  1081. FNode.UnlockMempoolRead;
  1082. end;
  1083. ops.BlockPayload.FromString(IntToStr(FNode.Bank.BlocksCount));
  1084. ops.nonce := FNode.Bank.BlocksCount;
  1085. ops.UpdateTimestamp;
  1086. FNode.AddNewBlockChain(Nil,ops,errors);
  1087. finally
  1088. ops.Free;
  1089. end;
  1090. {$ELSE}
  1091. Raise Exception.Create('NOT ALLOWED!');
  1092. {$ENDIF}
  1093. end;
  1094. {$ENDIF}
  1095. {$IFDEF TESTNET}
  1096. procedure TFRMWallet.Test_ConnectDisconnect(Sender: TObject);
  1097. begin
  1098. TNetData.NetData.NetConnectionsActive := Not TNetData.NetData.NetConnectionsActive;
  1099. Exit;
  1100. if FNode.NetServer.Active then begin
  1101. FNode.NetServer.Active := False;
  1102. end else begin
  1103. FNode.NetServer.Active := True;
  1104. end;
  1105. end;
  1106. procedure TFRMWallet.Test_RandomOperations(Sender: TObject);
  1107. Var FRM : TFRMRandomOperations;
  1108. begin
  1109. FRM := TFRMRandomOperations.Create(Self);
  1110. Try
  1111. FRM.SourceNode := FNode;
  1112. FRM.SourceWalletKeys := FWalletKeys;
  1113. FRM.ShowModal;
  1114. finally
  1115. FRM.Free;
  1116. end;
  1117. end;
  1118. {$ENDIF}
  1119. procedure TFRMWallet.Test_ShowOperationsInMemory(Sender: TObject);
  1120. var LFRM : TFRMMemoText;
  1121. i, nOps : Integer;
  1122. Lslist : TStrings;
  1123. begin
  1124. Lslist := TStringList.Create;
  1125. try
  1126. TPCOperationsStorage.PCOperationsStorage.GetStats(Lslist);
  1127. nOps := TPCOperationsStorage.PCOperationsStorage.Count;
  1128. LFRM := TFRMMemoText.Create(Self);
  1129. try
  1130. LFRM.InitData('Operations in Memory '+IntToStr(nOps),Lslist.Text);
  1131. LFRM.ShowModal;
  1132. finally
  1133. LFRM.Free;
  1134. end;
  1135. finally
  1136. Lslist.Free;
  1137. end;
  1138. end;
  1139. procedure TFRMWallet.Test_ShowPublicKeys(Sender: TObject);
  1140. var F : TFRMMemoText;
  1141. i : Integer;
  1142. sl : TStrings;
  1143. ak : TAccountKey;
  1144. nmin,nmax : Integer;
  1145. l : TList<Pointer>;
  1146. Pacsd : PAccountKeyStorageData;
  1147. acc : TAccount;
  1148. begin
  1149. sl := TStringList.Create;
  1150. try
  1151. for i:=0 to FNode.Bank.SafeBox.AccountsCount-1 do begin
  1152. acc := FNode.Bank.SafeBox.Account(i);
  1153. if acc.accountInfo.new_publicKey.EC_OpenSSL_NID<>0 then begin
  1154. sl.Add(Format('Account %d new public key %d %s',[acc.account,
  1155. acc.accountInfo.new_publicKey.EC_OpenSSL_NID,
  1156. TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(acc.accountInfo.new_publicKey))]));
  1157. end;
  1158. end;
  1159. {$IFnDEF USE_ABSTRACTMEM}
  1160. l := TAccountKeyStorage.KS.LockList;
  1161. try
  1162. sl.Add(Format('%d public keys in TAccountKeyStorage data',[l.count]));
  1163. for i:=0 to l.count-1 do begin
  1164. Pacsd := l[i];
  1165. if (Pacsd^.counter<=0) then begin
  1166. sl.Add(Format('%d/%d public keys counter %d',[i+1,l.count,Pacsd^.counter]));
  1167. end;
  1168. if FNode.Bank.SafeBox.OrderedAccountKeysList.IndexOfAccountKey(Pacsd^.ptrAccountKey^)<0 then begin
  1169. sl.Add(Format('%d/%d public keys counter %d Type %d NOT FOUND %s',[i+1,l.count,Pacsd^.counter,
  1170. Pacsd^.ptrAccountKey^.EC_OpenSSL_NID,
  1171. TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(Pacsd^.ptrAccountKey^))]));
  1172. end;
  1173. end;
  1174. finally
  1175. TAccountKeyStorage.KS.UnlockList;
  1176. end;
  1177. sl.Add(Format('%d public keys in %d accounts',[FNode.Bank.SafeBox.OrderedAccountKeysList.Count,FNode.Bank.Safebox.AccountsCount]));
  1178. for i:=0 to FNode.Bank.SafeBox.OrderedAccountKeysList.Count-1 do begin
  1179. ak := FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKey[i];
  1180. if ( FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[i].Count > 0) then begin
  1181. nmin := FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[i].Get(0);
  1182. nmax := FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[i].Get( FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[i].Count-1 );
  1183. end else begin
  1184. nmin := -1; nmax := -1;
  1185. end;
  1186. sl.Add(Format('%d/%d %d accounts (%d to %d) for key type %d %s',[
  1187. i+1,FNode.Bank.SafeBox.OrderedAccountKeysList.Count,
  1188. FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[i].Count,
  1189. nmin,nmax,
  1190. ak.EC_OpenSSL_NID,
  1191. TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ak)) ]));
  1192. end;
  1193. {$ENDIF}
  1194. F := TFRMMemoText.Create(Self);
  1195. try
  1196. F.InitData('Keys in safebox',sl.Text);
  1197. F.ShowModal;
  1198. finally
  1199. F.Free;
  1200. end;
  1201. finally
  1202. sl.Free;
  1203. end;
  1204. end;
  1205. function TFRMWallet.ForceMining: Boolean;
  1206. begin
  1207. Result := false;
  1208. end;
  1209. procedure TFRMWallet.FormClose(Sender: TObject; var Action: TCloseAction);
  1210. begin
  1211. if Assigned(FThreadActivate) then begin
  1212. TThreadActivate(FThreadActivate).Terminate;
  1213. FThreadActivate := Nil;
  1214. end;
  1215. end;
  1216. procedure TFRMWallet.FormCreate(Sender: TObject);
  1217. Var i : Integer;
  1218. begin
  1219. {$IFDEF USE_GNUGETTEXT}TranslateComponent(self);{$ENDIF}
  1220. //
  1221. {$IFNDEF FPC}
  1222. {$IFDEF TESTNET}
  1223. System.ReportMemoryLeaksOnShutdown := True; // Delphi memory leaks testing
  1224. {$ENDIF}
  1225. {$ENDIF}
  1226. FLastAccountsGridInvalidateTC := TPlatform.GetTickCount;
  1227. FLastNodesCacheUpdatedTS := Now;
  1228. FBackgroundPanel := Nil;
  1229. FBackgroundLabel := Nil;
  1230. FThreadActivate := Nil;
  1231. FMustProcessWalletChanged := false;
  1232. FMustProcessNetConnectionUpdated := false;
  1233. FRPCServer := Nil;
  1234. FNode := Nil;
  1235. FPoolMiningServer := Nil;
  1236. FMinAccountBalance := 0;
  1237. FMaxAccountBalance := CT_MaxWalletAmount;
  1238. FMessagesUnreadCount := 0;
  1239. lblReceivedMessages.Visible := false;
  1240. memoNetConnections.Lines.Clear;
  1241. memoNetServers.Lines.Clear;
  1242. memoNetBlackLists.Lines.Clear;
  1243. memoMessages.Lines.Clear;
  1244. memoMessageToSend.Lines.Clear;
  1245. FUpdating := false;
  1246. TimerUpdateStatus.Enabled := false;
  1247. FIsActivated := false;
  1248. FWalletKeys := TWalletKeysExt.Create(Self);
  1249. for i := 0 to StatusBar.Panels.Count - 1 do begin
  1250. StatusBar.Panels[i].Text := '';
  1251. end;
  1252. FLog := TLog.Create(Self);
  1253. FLog.OnNewLog := OnNewLog;
  1254. FLog.SaveTypes := [];
  1255. If Not ForceDirectories(TNode.GetPascalCoinDataFolder) then raise Exception.Create('Cannot create dir: '+TNode.GetPascalCoinDataFolder);
  1256. TSettings.Load;
  1257. TSettings.OnChanged.Add(UpdateConfigChanged);
  1258. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  1259. FNodeNotifyEvents.OnBlocksChanged := OnNewAccount;
  1260. FNodeNotifyEvents.OnNodeMessageEvent := OnNodeMessageEvent;
  1261. FNodeNotifyEvents.OnKeyActivity := OnNodeKeysActivity;
  1262. FAccountsGrid := TAccountsGrid.Create(Self);
  1263. FAccountsGrid.DrawGrid := dgAccounts;
  1264. FAccountsGrid.AllowMultiSelect := True;
  1265. FAccountsGrid.OnAccountsGridUpdatedData := OnAccountsGridUpdatedData;
  1266. FAccountsGrid.AccountsGridDatasource := acds_Node;
  1267. FSelectedAccountsGrid := TAccountsGrid.Create(Self);
  1268. FSelectedAccountsGrid.AccountsGridDatasource := acds_InternalList;
  1269. FSelectedAccountsGrid.DrawGrid := dgSelectedAccounts;
  1270. FSelectedAccountsGrid.OnUpdated := OnSelectedAccountsGridUpdated;
  1271. FOperationsAccountGrid := TOperationsGrid.Create(Self);
  1272. FOperationsAccountGrid.DrawGrid := dgAccountOperations;
  1273. FOperationsAccountGrid.MustShowAlwaysAnAccount := true;
  1274. FOperationsAccountGrid.WalletKeys := FWalletKeys;
  1275. FPendingOperationsGrid := TOperationsGrid.Create(Self);
  1276. FPendingOperationsGrid.DrawGrid := dgPendingOperations;
  1277. FPendingOperationsGrid.AccountNumber := -1; // all
  1278. FPendingOperationsGrid.PendingOperations := true;
  1279. FPendingOperationsGrid.WalletKeys := FWalletKeys;
  1280. FOperationsExplorerGrid := TOperationsGrid.Create(Self);
  1281. FOperationsExplorerGrid.DrawGrid := dgOperationsExplorer;
  1282. FOperationsExplorerGrid.AccountNumber := -1;
  1283. FOperationsExplorerGrid.PendingOperations := False;
  1284. FOperationsExplorerGrid.WalletKeys := FWalletKeys;
  1285. FBlockChainGrid := TBlockChainGrid.Create(Self);
  1286. FBlockChainGrid.DrawGrid := dgBlockChainExplorer;
  1287. FBlockChainGrid.ShowTimeAverageColumns:={$IFDEF SHOW_AVERAGE_TIME_STATS}True;{$ELSE}False;{$ENDIF}
  1288. // FWalletKeys.OnChanged.Add( OnWalletChanged );
  1289. {$IFDEF USE_GNUGETTEXT}
  1290. // use language from the params and retranslate if needed
  1291. // might be better to move this a bit earlier in the formcreate routine
  1292. UseLanguage(TSettings.AppParams.ParamByName[CT_PARAM_UILanguage].GetAsString(GetCurrentLanguage));
  1293. RetranslateComponent(self);
  1294. {$ENDIF}
  1295. //
  1296. UpdatePrivateKeys;
  1297. UpdateBlockChainState;
  1298. UpdateConnectionStatus;
  1299. PageControl.ActivePage := tsOperations;
  1300. pcAccountsOptions.ActivePage := tsAccountOperations;
  1301. ebFilterOperationsStartBlock.Text := '';
  1302. ebFilterOperationsEndBlock.Text := '';
  1303. cbExploreMyAccounts.Checked:=True; // By default
  1304. cbExploreMyAccountsClick(nil);
  1305. MinersBlocksFound := 0;
  1306. lblBuild.Caption := 'Build: '+CT_ClientAppVersion;
  1307. {$IFDEF TESTNET}
  1308. lblBuild.Font.Color := clRed;
  1309. {$ENDIF}
  1310. PageControl.Enabled := False;
  1311. PageControl.Visible := False;
  1312. FBackgroundPanel := TPanel.Create(Self);
  1313. FBackgroundPanel.Parent:=Self;
  1314. FBackgroundPanel.Align:=alClient;
  1315. FBackgroundPanel.Font.Size:=15;
  1316. FBackgroundPanel.BevelWidth := 10;
  1317. FBackgroundLabel := TLabel.Create(Self);
  1318. FBackgroundLabel.Parent := FBackgroundPanel;
  1319. FBackgroundLabel.Align := alClient;
  1320. FBackgroundLabel.Layout := tlCenter;
  1321. FBackgroundLabel.Font.Size := 18;
  1322. FBackgroundLabel.Alignment := taCenter;
  1323. FBackgroundLabel.WordWrap := True;
  1324. cbHashRateUnits.Items.Clear;
  1325. cbHashRateUnits.Items.Add('h/s');
  1326. cbHashRateUnits.Items.Add('Kh/s');
  1327. cbHashRateUnits.Items.Add('Mh/s');
  1328. cbHashRateUnits.Items.Add('Gh/s');
  1329. cbHashRateUnits.Items.Add('Th/s');
  1330. cbHashRateUnits.Items.Add('Ph/s');
  1331. cbHashRateUnits.Items.Add('Eh/s');
  1332. // Things for testing purposes only
  1333. InitMenuForTesting;
  1334. {$ifdef DARWIN}
  1335. // this is macOS specific menu layout
  1336. InitMacOSMenu;
  1337. {$endif}
  1338. PageControl.ActivePageIndex := 0;
  1339. {$IFDEF DEBUG}
  1340. System.ReportMemoryLeaksOnShutdown := True; // Delphi memory leaks testing
  1341. {$ENDIF}
  1342. end;
  1343. procedure TFRMWallet.ebHashRateBackBlocksKeyPress(Sender: TObject; var Key: char);
  1344. begin
  1345. if Key=#13 then ebHashRateBackBlocksExit(Nil);
  1346. end;
  1347. procedure TFRMWallet.ebHashRateBackBlocksExit(Sender: TObject);
  1348. var i : Integer;
  1349. begin
  1350. If FUpdating then exit;
  1351. FUpdating := True;
  1352. Try
  1353. i := StrToIntDef(ebHashRateBackBlocks.Text,-1);
  1354. FBlockChainGrid.HashRateAverageBlocksCount:=i;
  1355. TSettings.HashRateAvgBlocksCount := FBlockChainGrid.HashRateAverageBlocksCount;
  1356. Finally
  1357. ebHashRateBackBlocks.Text := IntToStr(FBlockChainGrid.HashRateAverageBlocksCount);
  1358. FUpdating := false;
  1359. End;
  1360. end;
  1361. procedure TFRMWallet.cbHashRateUnitsClick(Sender: TObject);
  1362. begin
  1363. If FUpdating then Exit;
  1364. FUpdating := True;
  1365. Try
  1366. case cbHashRateUnits.ItemIndex of
  1367. 0 : FBlockChainGrid.HashRateAs := hr_Unit;
  1368. 1 : FBlockChainGrid.HashRateAs := hr_Kilo;
  1369. 2 : FBlockChainGrid.HashRateAs := hr_Mega;
  1370. 3 : FBlockChainGrid.HashRateAs := hr_Giga;
  1371. 4 : FBlockChainGrid.HashRateAs := hr_Tera;
  1372. 5 : FBlockChainGrid.HashRateAs := hr_Peta;
  1373. 6 : FBlockChainGrid.HashRateAs := hr_Exa;
  1374. else FBlockChainGrid.HashRateAs := hr_Mega;
  1375. end;
  1376. TSettings.ShowHashRateAs := FBlockChainGrid.HashRateAs;
  1377. Finally
  1378. FUpdating := false;
  1379. End;
  1380. end;
  1381. procedure TFRMWallet.FormDestroy(Sender: TObject);
  1382. Var i : Integer;
  1383. step : String;
  1384. begin
  1385. TLog.NewLog(ltinfo,Classname,'Destroying form - START');
  1386. Try
  1387. if Assigned(FThreadActivate) then begin
  1388. TThreadActivate(FThreadActivate).Terminate;
  1389. FThreadActivate := Nil;
  1390. end;
  1391. FreeAndNil(FRPCServer);
  1392. FreeAndNil(FPoolMiningServer);
  1393. step := 'Saving params';
  1394. TSettings.Save;
  1395. //
  1396. step := 'Assigning nil events';
  1397. FLog.OnNewLog :=Nil;
  1398. FNodeNotifyEvents.Node := Nil;
  1399. FOperationsAccountGrid.Node := Nil;
  1400. FOperationsExplorerGrid.Node := Nil;
  1401. FPendingOperationsGrid.Node := Nil;
  1402. FAccountsGrid.Node := Nil;
  1403. FSelectedAccountsGrid.Node := Nil;
  1404. TNetData.NetData.OnReceivedHelloMessage := Nil;
  1405. TNetData.NetData.OnStatisticsChanged := Nil;
  1406. TNetData.NetData.OnNetConnectionsUpdated := Nil;
  1407. TNetData.NetData.OnNodeServersUpdated := Nil;
  1408. TNetData.NetData.OnBlackListUpdated := Nil;
  1409. //
  1410. step := 'Destroying NodeNotifyEvents';
  1411. FreeAndNil(FNodeNotifyEvents);
  1412. //
  1413. step := 'Assigning Nil to TNetData';
  1414. TNetData.NetData.OnReceivedHelloMessage := Nil;
  1415. TNetData.NetData.OnStatisticsChanged := Nil;
  1416. step := 'Destroying grids operators';
  1417. FreeAndNil(FOperationsAccountGrid);
  1418. FreeAndNil(FOperationsExplorerGrid);
  1419. FreeAndNil(FBlockChainGrid);
  1420. step := 'Desactivating Node';
  1421. TNode.Node.NetServer.Active := false;
  1422. FNode := Nil;
  1423. TNetData.NetData.Free;
  1424. step := 'Processing messages 1';
  1425. Application.ProcessMessages;
  1426. step := 'Destroying Node';
  1427. TNode.Node.Free;
  1428. step := 'Destroying Wallet';
  1429. FreeAndNil(FWalletKeys);
  1430. step := 'Processing messages 2';
  1431. Application.ProcessMessages;
  1432. step := 'Destroying stringslist';
  1433. Except
  1434. On E:Exception do begin
  1435. TLog.NewLog(lterror,Classname,'Error destroying Form step: '+step+' Errors ('+E.ClassName+'): ' +E.Message);
  1436. end;
  1437. End;
  1438. TLog.NewLog(ltinfo,Classname,'Destroying form - END');
  1439. FreeAndNil(FLog);
  1440. Sleep(100);
  1441. end;
  1442. procedure TFRMWallet.MiOperationsExplorerClick(Sender: TObject);
  1443. begin
  1444. With TFRMOperationsExplorer.Create(Self) do
  1445. try
  1446. SourceNode := FNode;
  1447. SourceWalletKeys := FWalletKeys;
  1448. ShowModal;
  1449. finally
  1450. Free;
  1451. end;
  1452. end;
  1453. procedure TFRMWallet.MiRPCCallsClick(Sender: TObject);
  1454. Var FRM : TFRMRPCCalls;
  1455. begin
  1456. FRM := TFRMRPCCalls.Create(Self);
  1457. Try
  1458. FRM.ServerURL:='127.0.0.1:'+IntToStr(FRPCServer.Port);
  1459. FRM.ShowModal;
  1460. finally
  1461. FRM.Free;
  1462. end;
  1463. end;
  1464. procedure TFRMWallet.sbSearchAccountClick(Sender: TObject);
  1465. Var F : TFRMAccountSelect;
  1466. begin
  1467. F := TFRMAccountSelect.Create(Self);
  1468. try
  1469. F.Node := FNode;
  1470. F.WalletKeys := FWalletKeys;
  1471. F.ShowModal;
  1472. finally
  1473. F.Free;
  1474. end;
  1475. end;
  1476. function TFRMWallet.GetAccountKeyForMiner: TAccountKey;
  1477. Var PK : TECPrivateKey;
  1478. i : Integer;
  1479. PublicK : TECDSA_Public;
  1480. begin
  1481. Result := CT_TECDSA_Public_Nul;
  1482. if Not Assigned(FWalletKeys) then exit;
  1483. case FMinerPrivateKeyType of
  1484. mpk_NewEachTime: PublicK := CT_TECDSA_Public_Nul;
  1485. mpk_Selected: begin
  1486. PublicK := TAccountComp.RawString2Accountkey(TSettings.MinerSelectedPublicKey);
  1487. end;
  1488. else
  1489. // Random
  1490. PublicK := CT_TECDSA_Public_Nul;
  1491. if FWalletKeys.Count>0 then begin
  1492. i := Random(FWalletKeys.Count);
  1493. if (Length(FWalletKeys.Key[i].CryptedKey)=0) then begin
  1494. // Not valid, search for first valid:
  1495. i:=0;
  1496. while (i<FWalletKeys.Count) And (Length(FWalletKeys.Key[i].CryptedKey)=0) do inc(i);
  1497. if i<FWalletKeys.Count then PublicK := FWalletKeys.Key[i].AccountKey;
  1498. end else PublicK := FWalletKeys.Key[i].AccountKey;
  1499. end;
  1500. end;
  1501. i := FWalletKeys.IndexOfAccountKey(PublicK);
  1502. if i>=0 then begin
  1503. if (Length(FWalletKeys.Key[i].CryptedKey)=0) then i:=-1;
  1504. end;
  1505. if i<0 then begin
  1506. PK := TECPrivateKey.Create;
  1507. try
  1508. PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
  1509. FWalletKeys.AddPrivateKey('New for miner '+DateTimeToStr(Now), PK);
  1510. PublicK := PK.PublicKey;
  1511. // Set to AppParams if not mpk_NewEachTime
  1512. if (FMinerPrivateKeyType<>mpk_NewEachTime) then begin
  1513. TSettings.MinerSelectedPublicKey := TAccountComp.AccountKey2RawString(PublicK);
  1514. FMinerPrivateKeyType:=mpk_Selected;
  1515. TSettings.MinerPrivateKeyType := mpk_Selected;
  1516. end;
  1517. finally
  1518. PK.Free;
  1519. end;
  1520. end;
  1521. Result := PublicK;
  1522. end;
  1523. procedure TFRMWallet.IPnodes1Click(Sender: TObject);
  1524. Var FRM : TFRMNodesIp;
  1525. begin
  1526. FRM := TFRMNodesIp.Create(Self);
  1527. Try
  1528. FRM.AppParams := TSettings.AppParams;
  1529. FRM.ShowModal;
  1530. Finally
  1531. FRM.Free;
  1532. End;
  1533. end;
  1534. procedure TFRMWallet.lblReceivedMessagesClick(Sender: TObject);
  1535. begin
  1536. PageControl.ActivePage := tsMessages;
  1537. end;
  1538. procedure TFRMWallet.miAboutPascalCoinClick(Sender: TObject);
  1539. begin
  1540. With TFRMAbout.Create(Self) do
  1541. try
  1542. showmodal;
  1543. finally
  1544. free;
  1545. end;
  1546. end;
  1547. procedure TFRMWallet.MiAccountInformationClick(Sender: TObject);
  1548. Var F : TFRMMemoText;
  1549. accn : Int64;
  1550. s,title : String;
  1551. account : TAccount;
  1552. strings : TStrings;
  1553. i : Integer;
  1554. opr : TOperationResume;
  1555. begin
  1556. accn := -1;
  1557. title := '';
  1558. strings := TStringList.Create;
  1559. try
  1560. opr := CT_TOperationResume_NUL;
  1561. if PageControl.ActivePage=tsOperations then begin
  1562. i := FOperationsExplorerGrid.DrawGrid.Row;
  1563. if (i>0) and (i<=FOperationsExplorerGrid.OperationsResume.Count) then begin
  1564. opr := FOperationsExplorerGrid.OperationsResume.Items[i-1];
  1565. end;
  1566. end else if PageControl.ActivePage=tsPendingOperations then begin
  1567. i := FPendingOperationsGrid.DrawGrid.Row;
  1568. if (i>0) and (i<=FPendingOperationsGrid.OperationsResume.Count) then begin
  1569. opr := FPendingOperationsGrid.OperationsResume.Items[i-1];
  1570. end;
  1571. end else if PageControl.ActivePage=tsMyAccounts then begin
  1572. accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
  1573. if accn<0 then raise Exception.Create('Select an account');
  1574. FillAccountInformation(strings,accn);
  1575. title := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(accn)+' info';
  1576. i := FOperationsAccountGrid.DrawGrid.Row;
  1577. if (i>0) and (i<=FOperationsAccountGrid.OperationsResume.Count) then begin
  1578. opr := FOperationsAccountGrid.OperationsResume.Items[i-1];
  1579. end;
  1580. end;
  1581. If (opr.valid) then begin
  1582. if accn>=0 then strings.Add('')
  1583. else title := 'Operation info';
  1584. strings.Add('Operation info:');
  1585. FillOperationInformation(strings,opr);
  1586. end else if accn<0 then Raise Exception.Create('No info available');
  1587. F := TFRMMemoText.Create(Self);
  1588. Try
  1589. F.Caption := title;
  1590. strings.add(Format('Agg Hashrate: %s',[FNode.Bank.SafeBox.AggregatedHashrate.ToDecimal]));
  1591. strings.add(Format('Agg Hashrate: %s',[FNode.Bank.SafeBox.AggregatedHashrate.HexaValue]));
  1592. F.Memo.Lines.Assign(strings);
  1593. F.ShowModal;
  1594. Finally
  1595. F.Free;
  1596. End;
  1597. finally
  1598. strings.free;
  1599. end;
  1600. end;
  1601. procedure TFRMWallet.MiAddaccounttoSelectedClick(Sender: TObject);
  1602. begin
  1603. PageControl.ActivePage := tsMyAccounts;
  1604. PageControlChange(Nil);
  1605. pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
  1606. sbSelectedAccountsAddClick(Sender);
  1607. end;
  1608. procedure TFRMWallet.MiCloseClick(Sender: TObject);
  1609. begin
  1610. Close;
  1611. end;
  1612. procedure TFRMWallet.MiDecodePayloadClick(Sender: TObject);
  1613. begin
  1614. if PageControl.ActivePage=tsOperations then begin
  1615. FOperationsExplorerGrid.ShowModalDecoder(FWalletKeys, TSettings.AppParams);
  1616. end else if PageControl.ActivePage=tsPendingOperations then begin
  1617. FPendingOperationsGrid.ShowModalDecoder(FWalletKeys,TSettings.AppParams);
  1618. end else if PageControl.ActivePage=tsMyAccounts then begin
  1619. FOperationsAccountGrid.ShowModalDecoder(FWalletKeys,TSettings.AppParams);
  1620. end;
  1621. end;
  1622. procedure TFRMWallet.Test_FindAccountsForPrivateBuyOrSwapToMe(Sender: TObject);
  1623. { This procedure will search in Safebox all accounts in "for_private_sale" state
  1624. or in "for_account_swap" that can be self-signed using one of my private keys
  1625. }
  1626. function CaptureSender0Coins(var AAccountSender0Coins : TAccount; var ANeededWalletKey : TWalletKey) : Boolean;
  1627. var ii : Integer;
  1628. begin
  1629. //
  1630. Result := False;
  1631. for ii := 0 to WalletKeys.AccountsKeyList.Count-1 do begin
  1632. if WalletKeys.AccountsKeyList.AccountKeyList[ii].Count>0 then begin
  1633. if WalletKeys.TryGetKey(WalletKeys.AccountsKeyList.AccountKey[ii],ANeededWalletKey) then begin
  1634. AAccountSender0Coins := FNode.Bank.SafeBox.Account( WalletKeys.AccountsKeyList.AccountKeyList[ii].Get(0) );
  1635. Result := True;
  1636. end;
  1637. end;
  1638. end;
  1639. end;
  1640. var i : Integer;
  1641. LLines : TStrings;
  1642. LAccount, LAccountSender0Coins : TAccount;
  1643. LAccountOpDesc : String;
  1644. LCountAccountsFound_total, LCountAccountsFound_Operation : Integer;
  1645. LNeededWalletKey : TWalletKey;
  1646. s : String;
  1647. LOpTransaction : TOpTransaction;
  1648. LOperationsHashTree, LGlobalOperationsHashTree : TOperationsHashTree;
  1649. LStream : TStream;
  1650. LRaw : TRawBytes;
  1651. LFRM : TFRMMemoText;
  1652. LOpPayload : TOperationPayload;
  1653. begin
  1654. if Not WalletKeys.IsValidPassword then raise Exception.Create('Your wallet keys are locked');
  1655. LOpPayload := CT_TOperationPayload_NUL;
  1656. if InputQuery('Search ATOMIC SWAP by SECRET','Insert SECRET value (use 0x... for Hexadecimal, otherwise will be a String)',s) then begin
  1657. if s.StartsWith('0x') then begin
  1658. if not UCommon.TryHex2Bytes(s,LOpPayload.payload_raw) then raise Exception.Create('SECRET value is not an Hexadecimal'+#10+s);
  1659. end else begin
  1660. LOpPayload.payload_raw.FromString(s);
  1661. end;
  1662. end;
  1663. LCountAccountsFound_total := 0;
  1664. LCountAccountsFound_Operation := 0;
  1665. LLines := TStringList.Create;
  1666. LGlobalOperationsHashTree := TOperationsHashTree.Create;
  1667. try
  1668. for i:=0 to FNode.Bank.SafeBox.AccountsCount-1 do begin
  1669. LAccountOpDesc := '';
  1670. LAccount := FNode.Bank.SafeBox.Account(i);
  1671. LOpTransaction := Nil;
  1672. Try
  1673. Case LAccount.accountInfo.state of
  1674. as_ForSale : begin
  1675. if Not TAccountComp.IsNullAccountKey( LAccount.accountInfo.new_publicKey ) then begin
  1676. if Not WalletKeys.TryGetKey(LAccount.accountInfo.new_publicKey,LNeededWalletKey) then Continue;
  1677. if Not Assigned(LNeededWalletKey.PrivateKey) then Continue; // Key not available!
  1678. end else Continue;
  1679. // Private sale to me
  1680. // Is in time?
  1681. if TAccountComp.IsAccountLocked(LAccount.accountInfo,FNode.Bank.BlocksCount) then begin
  1682. //
  1683. if LAccount.balance>=LAccount.accountInfo.price then begin
  1684. LAccountOpDesc := Format('Account %s is for private sale to me and with enough balance to pay %s (balance %s)',[
  1685. TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),
  1686. TAccountComp.FormatMoney(LAccount.accountInfo.price),
  1687. TAccountComp.FormatMoney(LAccount.balance)]);
  1688. // No key needed... just a transaction SELF SIGNED
  1689. LOpTransaction := TOpBuyAccount.CreateBuy(FNode.Bank.SafeBox.CurrentProtocol,
  1690. LAccount.account, LAccount.n_operation+1,
  1691. LAccount.account, LAccount.accountInfo.account_to_pay, LAccount.accountInfo.price,
  1692. 0,0,
  1693. LAccount.accountInfo.new_publicKey,
  1694. LNeededWalletKey.PrivateKey,
  1695. LOpPayload);
  1696. end else begin
  1697. LAccountOpDesc := Format('Account %s is for private sale to me but needs a Buy operation paying %s PASC (%s pending)',[
  1698. TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),
  1699. TAccountComp.FormatMoney(LAccount.accountInfo.price),
  1700. TAccountComp.FormatMoney(LAccount.accountInfo.price - LAccount.balance)]);
  1701. end;
  1702. end else begin
  1703. LAccountOpDesc := Format('Account %s is for private sale to me but is out-of-lock period',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account)]);
  1704. end;
  1705. end;
  1706. as_ForAtomicAccountSwap : begin
  1707. if Not WalletKeys.TryGetKey(LAccount.accountInfo.new_publicKey,LNeededWalletKey) then Continue;
  1708. if TAccountComp.IsAccountLocked(LAccount.accountInfo,FNode.Bank.BlocksCount) then begin
  1709. if TAccountComp.IsValidAccountInfoHashLockKey(LAccount.accountInfo,LOpPayload.payload_raw) then begin
  1710. // Atomic Account swap using provided SECRET
  1711. LAccountOpDesc := Format('Account %s is for Atomic Account Swap to me using SECRET %s',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),UCommon.Bytes2Hex(LOpPayload.payload_raw,True)]);
  1712. //
  1713. // No key needed... just a Buy Operation SELF SIGNED
  1714. LOpTransaction := TOpBuyAccount.CreateBuy(FNode.Bank.SafeBox.CurrentProtocol,
  1715. LAccount.account, LAccount.n_operation+1,
  1716. LAccount.account, LAccount.accountInfo.account_to_pay, LAccount.accountInfo.price,
  1717. 0,0,
  1718. LAccount.accountInfo.new_publicKey,
  1719. LNeededWalletKey.PrivateKey,
  1720. LOpPayload);
  1721. end else begin
  1722. LAccountOpDesc := Format('Account %s is for Atomic Account Swap to me but SECRET %s is not valid',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),UCommon.Bytes2Hex(LOpPayload.payload_raw,True)]);
  1723. end;
  1724. end else begin
  1725. LAccountOpDesc := Format('Account %s is for Atomic Account Swap to me but is out-of-lock period',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account)]);
  1726. end;
  1727. end;
  1728. as_ForAtomicCoinSwap : begin
  1729. if Not TAccountComp.IsValidAccountInfoHashLockKey(LAccount.accountInfo,LOpPayload.payload_raw) then Continue;
  1730. // Atomic Coin swap using provided SECRET
  1731. if TAccountComp.IsAccountLocked(LAccount.accountInfo,FNode.Bank.BlocksCount) then begin
  1732. // Single transaction using amount 0 from ANY sender
  1733. if CaptureSender0Coins(LAccountSender0Coins,LNeededWalletKey) then begin
  1734. // Atomic Account swap using provided SECRET
  1735. LAccountOpDesc := Format('Account %s is for Atomic Coin Swap to me using SECRET %s',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),UCommon.Bytes2Hex(LOpPayload.payload_raw,True)]);
  1736. //
  1737. // No key needed... just a transaction SELF SIGNED
  1738. LOpTransaction := TOpTransaction.CreateTransaction(FNode.Bank.SafeBox.CurrentProtocol,
  1739. LAccountSender0Coins.account, LAccountSender0Coins.n_operation+1,
  1740. LAccount.account,
  1741. LNeededWalletKey.PrivateKey,
  1742. 0,0, // No Amount no Fee
  1743. LOpPayload);
  1744. end else begin
  1745. LAccountOpDesc := Format('Account %s is for Atomic Coin Swap using SECRET %s but I have no key to sign',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),UCommon.Bytes2Hex(LOpPayload.payload_raw,True)]);
  1746. end;
  1747. end else begin
  1748. LAccountOpDesc := Format('Account %s is for Atomic Coin Swap using SECRET %s but is out-of-lock period',[TAccountComp.AccountNumberToAccountTxtNumber(LAccount.account),UCommon.Bytes2Hex(LOpPayload.payload_raw,True)]);
  1749. end;
  1750. end;
  1751. else Continue;
  1752. End;
  1753. // Do
  1754. Inc(LCountAccountsFound_total);
  1755. LLines.Add(Format('%s',[LAccountOpDesc]));
  1756. if Assigned(LOpTransaction) then begin
  1757. Inc(LCountAccountsFound_Operation);
  1758. LOperationsHashTree := TOperationsHashTree.Create;
  1759. LStream := TMemoryStream.Create;
  1760. try
  1761. LOperationsHashTree.AddOperationToHashTree(LOpTransaction);
  1762. LGlobalOperationsHashTree.AddOperationToHashTree(LOpTransaction);
  1763. LLines.Add(Format('Operation: %s',[LOpTransaction.ToString]));
  1764. LOperationsHashTree.SaveOperationsHashTreeToStream(LStream,False);
  1765. LRaw.FromStream(LStream);
  1766. LLines.Add(Format('rawoperations (for JSON-RPC call): %s',[LRaw.ToHexaString]));
  1767. finally
  1768. LOperationsHashTree.Free;
  1769. LStream.Free;
  1770. end;
  1771. end;
  1772. Finally
  1773. FreeAndNil(LOpTransaction);
  1774. End;
  1775. end; // For
  1776. LLines.Add('');
  1777. LLines.Add(Format('Found %d of %d available account from a Safebox with %d accounts',[
  1778. LCountAccountsFound_Operation,
  1779. LCountAccountsFound_total,
  1780. FNode.Bank.SafeBox.AccountsCount]));
  1781. LStream := TMemoryStream.Create;
  1782. try
  1783. LGlobalOperationsHashTree.SaveOperationsHashTreeToStream(LStream,False);
  1784. LRaw.FromStream(LStream);
  1785. LLines.Add(Format('rawoperations (for JSON-RPC call) of %d operations: %s',[LGlobalOperationsHashTree.OperationsCount, LRaw.ToHexaString]));
  1786. finally
  1787. LStream.Free;
  1788. end;
  1789. //
  1790. LFRM := TFRMMemoText.Create(Self);
  1791. try
  1792. LFRM.InitData('',LLines.Text);
  1793. LFRM.ShowModal;
  1794. finally
  1795. LFRM.Free;
  1796. end;
  1797. finally
  1798. LLines.Free;
  1799. LGlobalOperationsHashTree.Free;
  1800. end;
  1801. end;
  1802. procedure TFRMWallet.Test_ShowDiagnosticTool(Sender: TObject);
  1803. {$IFDEF TESTNET}
  1804. var
  1805. LDialog : TFRMDiagnosticTool;
  1806. {$ENDIF}
  1807. begin
  1808. {$IFDEF TESTNET}
  1809. LDialog := TFRMDiagnosticTool.Create(Nil);
  1810. try
  1811. LDialog.ShowModal;
  1812. finally
  1813. LDialog.Free;
  1814. end;
  1815. {$ENDIF}
  1816. end;
  1817. procedure TFRMWallet.MiFindaccountClick(Sender: TObject);
  1818. begin
  1819. PageControl.ActivePage := tsMyAccounts;
  1820. PageControlChange(Nil);
  1821. ebFindAccountNumber.SetFocus;
  1822. end;
  1823. procedure TFRMWallet.MiFindnextaccountwithhighbalanceClick(Sender: TObject);
  1824. Var an : Cardinal;
  1825. an64 : Int64;
  1826. start : TAccount;
  1827. begin
  1828. PageControl.ActivePage := tsMyAccounts;
  1829. PageControlChange(Nil);
  1830. an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
  1831. if an64<0 then an := 0
  1832. else an := an64;
  1833. If an>=FNode.Bank.SafeBox.AccountsCount then exit;
  1834. start := FNode.Bank.SafeBox.Account(an);
  1835. while (an<FNode.Bank.SafeBox.AccountsCount) do begin
  1836. if FNode.Bank.SafeBox.Account(an).balance>start.balance then break
  1837. else inc(an);
  1838. end;
  1839. if (an<FNode.Bank.SafeBox.AccountsCount) then FAccountsGrid.MoveRowToAccount(an)
  1840. else raise Exception.Create('Not found any account higher than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
  1841. TAccountComp.FormatMoney(start.balance));
  1842. end;
  1843. procedure TFRMWallet.MiFindOperationbyOpHashClick(Sender: TObject);
  1844. Var FRM : TFRMPayloadDecoder;
  1845. oph : String;
  1846. begin
  1847. oph := '';
  1848. if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
  1849. //
  1850. FRM := TFRMPayloadDecoder.Create(Self);
  1851. try
  1852. FRM.Init(CT_TOperationResume_NUL,WalletKeys,TSettings.AppParams);
  1853. FRM.DoFind(oph);
  1854. FRM.ShowModal;
  1855. finally
  1856. FRM.Free;
  1857. end;
  1858. end;
  1859. procedure TFRMWallet.MiFindpreviousaccountwithhighbalanceClick(Sender: TObject);
  1860. Var an : Cardinal;
  1861. an64 : Int64;
  1862. start : TAccount;
  1863. begin
  1864. PageControl.ActivePage := tsMyAccounts;
  1865. PageControlChange(Nil);
  1866. an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
  1867. if an64<0 then an := FNode.Bank.SafeBox.AccountsCount-1
  1868. else an := an64;
  1869. If an>=FNode.Bank.SafeBox.AccountsCount then exit;
  1870. start := FNode.Bank.SafeBox.Account(an);
  1871. while (an>0) do begin
  1872. if FNode.Bank.SafeBox.Account(an).balance>start.balance then break
  1873. else dec(an);
  1874. end;
  1875. if (FNode.Bank.SafeBox.Account(an).balance>start.balance) then FAccountsGrid.MoveRowToAccount(an)
  1876. else raise Exception.Create('Not found any account lower than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
  1877. TAccountComp.FormatMoney(start.balance));
  1878. end;
  1879. procedure TFRMWallet.MiMultiaccountoperationClick(Sender: TObject);
  1880. begin
  1881. PageControl.ActivePage := tsMyAccounts;
  1882. pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
  1883. bbSelectedAccountsOperationClick(Sender);
  1884. end;
  1885. procedure TFRMWallet.miNewOperationClick(Sender: TObject);
  1886. var l : TOrderedCardinalList;
  1887. begin
  1888. CheckIsReady;
  1889. With TFRMOperation.Create(Self) do
  1890. Try
  1891. l := TOrderedCardinalList.Create;
  1892. try
  1893. If FAccountsGrid.SelectedAccounts(l)<1 then raise Exception.Create('No row selected');
  1894. SenderAccounts.CopyFrom(l);
  1895. finally
  1896. l.Free;
  1897. end;
  1898. DefaultFee := TSettings.DefaultFee;
  1899. WalletKeys := FWalletKeys;
  1900. ShowModal;
  1901. Finally
  1902. Free;
  1903. End;
  1904. end;
  1905. procedure TFRMWallet.miOptionsClick(Sender: TObject);
  1906. begin
  1907. With TFRMPascalCoinWalletConfig.Create(Self) do
  1908. try
  1909. AppParams := TSettings.AppParams;
  1910. WalletKeys := Self.FWalletKeys;
  1911. if ShowModal=MrOk then begin
  1912. TSettings.Save;
  1913. UpdateConfigChanged(Self);
  1914. {$IFDEF USE_GNUGETTEXT}RetranslateComponent(self);{$ENDIF}
  1915. end;
  1916. finally
  1917. free;
  1918. end;
  1919. end;
  1920. procedure TFRMWallet.miPrivatekeysClick(Sender: TObject);
  1921. Var FRM : TFRMWalletKeys;
  1922. begin
  1923. FRM := TFRMWalletKeys.Create(Self);
  1924. Try
  1925. FRM.WalletKeys := FWalletKeys;
  1926. FRM.ShowModal;
  1927. UpdatePrivateKeys;
  1928. Finally
  1929. FRM.Free;
  1930. End;
  1931. end;
  1932. procedure TFRMWallet.MiRemoveaccountfromselectedClick(Sender: TObject);
  1933. begin
  1934. PageControl.ActivePage := tsMyAccounts;
  1935. PageControlChange(Nil);
  1936. pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
  1937. sbSelectedAccountsDelClick(Sender);
  1938. end;
  1939. procedure TFRMWallet.OnAccountsGridUpdatedData(Sender: TObject);
  1940. begin
  1941. if FAccountsGrid.IsUpdatingData then begin
  1942. lblAccountsCount.Caption := '(Calculating)';
  1943. lblAccountsBalance.Caption := '(Calculating)';
  1944. end else begin
  1945. lblAccountsCount.Caption := IntToStr(FAccountsGrid.AccountsCount);
  1946. lblAccountsBalance.Caption := TAccountComp.FormatMoney(FAccountsGrid.AccountsBalance);
  1947. end;
  1948. end;
  1949. procedure TFRMWallet.OnMiningServerNewBlockFound(Sender: TObject);
  1950. begin
  1951. FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
  1952. end;
  1953. procedure TFRMWallet.OnNetBlackListUpdated(Sender: TObject);
  1954. Const CT_TRUE_FALSE : Array[Boolean] Of AnsiString = ('FALSE','TRUE');
  1955. Var i,j,n : integer;
  1956. P : PNodeServerAddress;
  1957. l : TList<Pointer>;
  1958. strings : TStrings;
  1959. begin
  1960. l := TNetData.NetData.NodeServersAddresses.LockList;
  1961. try
  1962. strings := memoNetBlackLists.Lines;
  1963. strings.BeginUpdate;
  1964. Try
  1965. strings.Clear;
  1966. strings.Add('BlackList Updated: '+DateTimeToStr(now)+' by TID:'+IntToHex(PtrInt(TThread.CurrentThread.ThreadID),8));
  1967. j := 0; n:=0;
  1968. for i := 0 to l.Count - 1 do begin
  1969. P := l[i];
  1970. if (P^.is_blacklisted) then begin
  1971. inc(n);
  1972. if Not P^.its_myself then begin
  1973. inc(j);
  1974. strings.Add(Format('Blacklist IP:%s:%d LastConnection:%s Reason: %s',
  1975. [
  1976. P^.ip,P^.port,
  1977. DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection))),P^.BlackListText]));
  1978. end;
  1979. end;
  1980. end;
  1981. Strings.Add(Format('Total Blacklisted IPs: %d (Total %d)',[j,n]));
  1982. Finally
  1983. strings.EndUpdate;
  1984. End;
  1985. finally
  1986. TNetData.NetData.NodeServersAddresses.UnlockList;
  1987. end;
  1988. end;
  1989. procedure TFRMWallet.OnNetConnectionsUpdated(Sender: TObject);
  1990. begin
  1991. if FMustProcessNetConnectionUpdated then exit;
  1992. FMustProcessNetConnectionUpdated := true;
  1993. PostMessage(Self.Handle,CM_PC_NetConnectionUpdated,0,0);
  1994. end;
  1995. procedure TFRMWallet.OnNetNodeServersUpdated(Sender: TObject);
  1996. Var i : integer;
  1997. P : PNodeServerAddress;
  1998. l : TList<Pointer>;
  1999. strings : TStrings;
  2000. s : String;
  2001. begin
  2002. l := TNetData.NetData.NodeServersAddresses.LockList;
  2003. try
  2004. strings := memoNetServers.Lines;
  2005. strings.BeginUpdate;
  2006. Try
  2007. strings.Clear;
  2008. strings.Add('NodeServers Updated: '+DateTimeToStr(now) +' Count: '+inttostr(l.Count));
  2009. for i := 0 to l.Count - 1 do begin
  2010. P := l[i];
  2011. if Not (P^.is_blacklisted) then begin
  2012. s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
  2013. if (P^.last_connection_by_me>0) then begin
  2014. s := s + ' [Server] ';
  2015. end;
  2016. if Assigned(P.netConnection) then begin
  2017. If P.last_connection>0 then s := s+ ' ** ACTIVE **'
  2018. else s := s+' ** TRYING TO CONNECT **';
  2019. end;
  2020. if P.its_myself then begin
  2021. s := s+' ** NOT VALID ** '+P.BlackListText;
  2022. end;
  2023. if P.last_connection>0 then begin
  2024. s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
  2025. end;
  2026. if P.last_connection_by_server>0 then begin
  2027. s := s + ' Last server connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection_by_server)));
  2028. end;
  2029. if (P.last_attempt_to_connect>0) then begin
  2030. s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect);
  2031. end;
  2032. if (P.total_failed_attemps_to_connect>0) then begin
  2033. s := s + ' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
  2034. end;
  2035. strings.Add(s);
  2036. end;
  2037. end;
  2038. Finally
  2039. strings.EndUpdate;
  2040. End;
  2041. finally
  2042. TNetData.NetData.NodeServersAddresses.UnlockList;
  2043. end;
  2044. end;
  2045. procedure TFRMWallet.OnNetStatisticsChanged(Sender: TObject);
  2046. Var NS : TNetStatistics;
  2047. begin
  2048. //CheckMining;
  2049. if Assigned(FNode) then begin
  2050. If FNode.NetServer.Active then begin
  2051. StatusBar.Panels[0].Text := 'Active (Port '+Inttostr(FNode.NetServer.Port)+')';
  2052. end else StatusBar.Panels[0].Text := 'Server stopped';
  2053. NS := TNetData.NetData.NetStatistics;
  2054. StatusBar.Panels[1].Text := Format('Connections:%d Clients:%d Servers:%d - Rcvd:%d Kb Send:%d Kb',
  2055. [NS.ActiveConnections,NS.ClientsConnections,NS.ServersConnections,NS.BytesReceived DIV 1024,NS.BytesSend DIV 1024]);
  2056. end else begin
  2057. StatusBar.Panels[0].Text := '';
  2058. StatusBar.Panels[1].Text := '';
  2059. end;
  2060. end;
  2061. procedure TFRMWallet.OnNewAccount(Sender: TObject);
  2062. begin
  2063. Try
  2064. UpdateAccounts(false);
  2065. UpdateBlockChainState;
  2066. Except
  2067. On E:Exception do begin
  2068. E.Message := 'Exception at OnNewAccount '+E.ClassName+': '+E.Message;
  2069. TLog.NewLog(lterror,ClassName,E.Message);
  2070. Raise;
  2071. end;
  2072. end;
  2073. end;
  2074. procedure TFRMWallet.OnNewLog(logtype: TLogType; Time : TDateTime; ThreadID : TThreadID; const sender,logtext: String);
  2075. Var s : AnsiString;
  2076. begin
  2077. if (logtype=ltdebug) And (Not cbShowDebugLogs.Checked) then exit;
  2078. if ThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
  2079. if MemoLogs.Lines.Count>300 then begin
  2080. // Limit max lines in logs...
  2081. memoLogs.Lines.BeginUpdate;
  2082. try
  2083. while memoLogs.Lines.Count>250 do memoLogs.Lines.Delete(0);
  2084. finally
  2085. memoLogs.Lines.EndUpdate;
  2086. end;
  2087. end;
  2088. memoLogs.Lines.Add(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',Time)+s+IntToHex(PtrInt(ThreadID),8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
  2089. //
  2090. end;
  2091. procedure TFRMWallet.OnNodeMessageEvent(NetConnection: TNetConnection; MessageData: String);
  2092. Var s : String;
  2093. begin
  2094. inc(FMessagesUnreadCount);
  2095. if Assigned(NetConnection) then begin
  2096. s := DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr;
  2097. memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr+' Length '+inttostr(Length(MessageData))+' bytes');
  2098. memoMessages.Lines.Add('RECEIVED> '+MessageData);
  2099. if TSettings.ShowModalMessages then begin
  2100. s := DateTimeToStr(now)+' Message from '+NetConnection.ClientRemoteAddr+#10+
  2101. 'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
  2102. if TCrypto.IsHumanReadable(TEncoding.ANSI.GetBytes(MessageData)) then begin
  2103. s := s + MessageData;
  2104. end else begin
  2105. s := s +'Value in hexadecimal:'+#10+
  2106. TCrypto.ToHexaString(TEncoding.ANSI.GetBytes(MessageData));
  2107. end;
  2108. Application.MessageBox(PChar(s),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
  2109. end;
  2110. end else begin
  2111. memoMessages.Lines.Add(DateTimeToStr(now)+' Internal message: '+MessageData);
  2112. end;
  2113. if FMessagesUnreadCount>1 then lblReceivedMessages.Caption := Format('You have received %d messages',[FMessagesUnreadCount])
  2114. else lblReceivedMessages.Caption := 'You have received 1 message';
  2115. lblReceivedMessages.Visible := true;
  2116. end;
  2117. procedure TFRMWallet.OnNodeKeysActivity(Sender: TObject);
  2118. begin
  2119. DoUpdateAccounts;
  2120. end;
  2121. procedure TFRMWallet.OnReceivedHelloMessage(Sender: TObject);
  2122. Var nsarr : TNodeServerAddressArray;
  2123. i : Integer;
  2124. s : AnsiString;
  2125. begin
  2126. If (FLastNodesCacheUpdatedTS + EncodeTime(0,5,0,0) > Now) then exit; // Prevent continuous saving
  2127. FLastNodesCacheUpdatedTS := Now;
  2128. // Update node servers Peer Cache
  2129. nsarr := TNetData.NetData.NodeServersAddresses.GetValidNodeServers(true,0);
  2130. s := '';
  2131. for i := low(nsarr) to High(nsarr) do begin
  2132. if (s<>'') then s := s+';';
  2133. s := s + nsarr[i].ip+':'+IntToStr( nsarr[i].port );
  2134. end;
  2135. TSettings.PeerCache := s;
  2136. TNode.Node.PeerCache := s;
  2137. end;
  2138. procedure TFRMWallet.OnSelectedAccountsGridUpdated(Sender: TObject);
  2139. begin
  2140. lblSelectedAccountsCount.Caption := Inttostr(FSelectedAccountsGrid.AccountsCount);
  2141. lblSelectedAccountsBalance.Caption := TAccountComp.FormatMoney( FSelectedAccountsGrid.AccountsBalance );
  2142. end;
  2143. procedure TFRMWallet.OnWalletChanged(Sender: TObject);
  2144. begin
  2145. if FMustProcessWalletChanged then exit;
  2146. FMustProcessWalletChanged := true;
  2147. PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
  2148. end;
  2149. procedure TFRMWallet.PageControlChange(Sender: TObject);
  2150. begin
  2151. MiDecodePayload.Enabled := false;
  2152. if PageControl.ActivePage=tsMyAccounts then begin
  2153. FAccountsGrid.Node := FNode;
  2154. MiDecodePayload.Enabled := true;
  2155. FSelectedAccountsGrid.Node := FNode;
  2156. end else begin
  2157. FAccountsGrid.Node := Nil;
  2158. FSelectedAccountsGrid.Node := Nil;
  2159. end;
  2160. if PageControl.ActivePage=tsPendingOperations then begin
  2161. FPendingOperationsGrid.Node := FNode;
  2162. MiDecodePayload.Enabled := true;
  2163. end else FPendingOperationsGrid.Node := Nil;
  2164. if PageControl.ActivePage=tsBlockChain then FBlockChainGrid.Node := FNode
  2165. else FBlockChainGrid.Node := Nil;
  2166. if PageControl.ActivePage=tsOperations then begin
  2167. FOperationsExplorerGrid.Node := FNode;
  2168. MiDecodePayload.Enabled := true;
  2169. end else FOperationsExplorerGrid.Node := Nil;
  2170. if PageControl.ActivePage=tsMessages then begin
  2171. UpdateAvailableConnections;
  2172. FMessagesUnreadCount := 0;
  2173. lblReceivedMessages.Visible := false;
  2174. end;
  2175. end;
  2176. procedure TFRMWallet.sbSelectedAccountsAddAllClick(Sender: TObject);
  2177. Var lsource,ltarget : TOrderedCardinalList;
  2178. i : Integer;
  2179. begin
  2180. lsource := FAccountsGrid.LockAccountsList;
  2181. Try
  2182. ltarget := FSelectedAccountsGrid.LockAccountsList;
  2183. Try
  2184. for i := 0 to lsource.Count-1 do begin
  2185. if FWalletKeys.IndexOfAccountKey(FNode.Bank.SafeBox.Account(lsource.Get(i)).accountInfo.accountKey)<0 then raise Exception.Create(Format('You cannot operate with account %d because private key not found in your wallet',[lsource.Get(i)]));
  2186. ltarget.Add(lsource.Get(i));
  2187. end;
  2188. Finally
  2189. FSelectedAccountsGrid.UnlockAccountsList;
  2190. End;
  2191. Finally
  2192. FAccountsGrid.UnlockAccountsList;
  2193. End;
  2194. end;
  2195. procedure TFRMWallet.sbSelectedAccountsAddClick(Sender: TObject);
  2196. Var l, selected : TOrderedCardinalList;
  2197. an : Int64;
  2198. i : Integer;
  2199. begin
  2200. an := FAccountsGrid.AccountNumber(dgAccounts.Row);
  2201. if (an<0) then raise Exception.Create('No account selected');
  2202. if FWalletKeys.IndexOfAccountKey(FNode.Bank.SafeBox.Account(an).accountInfo.accountkey)<0 then
  2203. raise Exception.Create(Format('You cannot add %s account because private key not found in your wallet.'#10+#10+'You''re not the owner!',
  2204. [TAccountComp.AccountNumberToAccountTxtNumber(an)]));
  2205. // Add
  2206. l := FSelectedAccountsGrid.LockAccountsList;
  2207. selected := TOrderedCardinalList.Create;
  2208. Try
  2209. FAccountsGrid.SelectedAccounts(selected);
  2210. for i := 0 to selected.Count-1 do begin
  2211. l.Add(selected.Get(i));
  2212. end;
  2213. Finally
  2214. selected.Free;
  2215. FSelectedAccountsGrid.UnlockAccountsList;
  2216. End;
  2217. end;
  2218. procedure TFRMWallet.sbSelectedAccountsDelAllClick(Sender: TObject);
  2219. Var l : TOrderedCardinalList;
  2220. begin
  2221. l := FSelectedAccountsGrid.LockAccountsList;
  2222. try
  2223. l.Clear;
  2224. finally
  2225. FSelectedAccountsGrid.UnlockAccountsList;
  2226. end;
  2227. end;
  2228. procedure TFRMWallet.sbSelectedAccountsDelClick(Sender: TObject);
  2229. Var an : Int64;
  2230. l : TOrderedCardinalList;
  2231. begin
  2232. l := FSelectedAccountsGrid.LockAccountsList;
  2233. try
  2234. an := FSelectedAccountsGrid.AccountNumber(dgSelectedAccounts.Row);
  2235. if an>=0 then l.Remove(an);
  2236. finally
  2237. FSelectedAccountsGrid.UnlockAccountsList;
  2238. end;
  2239. end;
  2240. procedure TFRMWallet.SetMinersBlocksFound(const Value: Integer);
  2241. begin
  2242. FMinersBlocksFound := Value;
  2243. lblBlocksFound.Caption := Inttostr(Value);
  2244. if Value>0 then lblBlocksFound.Font.Color := clGreen
  2245. else lblBlocksFound.Font.Color := clDkGray;
  2246. end;
  2247. procedure TFRMWallet.TimerUpdateStatusTimer(Sender: TObject);
  2248. begin
  2249. Try
  2250. UpdateConnectionStatus;
  2251. UpdateBlockChainState;
  2252. UpdateNodeStatus;
  2253. Except
  2254. On E:Exception do begin
  2255. E.Message := 'Exception at TimerUpdate '+E.ClassName+': '+E.Message;
  2256. TLog.NewLog(lterror,ClassName,E.Message);
  2257. end;
  2258. End;
  2259. end;
  2260. procedure TFRMWallet.UpdateAccounts(RefreshData : Boolean);
  2261. Var accl : TOrderedCardinalList;
  2262. l : TOrderedCardinalList;
  2263. i,j,k : Integer;
  2264. c : Cardinal;
  2265. LApplyfilter : Boolean;
  2266. acc : TAccount;
  2267. LFilters : TAccountsGridFilter;
  2268. begin
  2269. If Not Assigned(FWalletKeys) Then exit;
  2270. if Not Assigned(FNode) then Exit;
  2271. if Not RefreshData then begin
  2272. if TPlatform.GetElapsedMilliseconds(FLastAccountsGridInvalidateTC)>1000 then begin
  2273. FLastAccountsGridInvalidateTC := TPlatform.GetTickCount;
  2274. dgAccounts.Invalidate;
  2275. end;
  2276. exit;
  2277. end;
  2278. LApplyfilter := (cbFilterAccounts.Checked) and ((FMinAccountBalance>0) Or ((FMaxAccountBalance<CT_MaxWalletAmount) and (FMaxAccountBalance>=0)));
  2279. if (Not cbExploreMyAccounts.Checked) And (not LApplyfilter) then begin
  2280. FAccountsGrid.AccountsGridDatasource := acds_Node;
  2281. FAccountsGrid.UpdateData;
  2282. end else begin
  2283. LFilters := FAccountsGrid.AccountsGridFilter;
  2284. LFilters.MinBalance := FMinAccountBalance;
  2285. LFilters.MaxBalance := FMaxAccountBalance;
  2286. if cbExploreMyAccounts.Checked then begin
  2287. //FNode.Bank.SafeBox.StartThreadSafe;
  2288. try
  2289. LFilters.OrderedAccountsKeyList := FWalletKeys.AccountsKeyList;
  2290. if cbMyPrivateKeys.ItemIndex>0 then begin
  2291. i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
  2292. if (i>=0) And (i<FWalletKeys.Count) then begin
  2293. LFilters.indexAccountsKeyList := FWalletKeys.AccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
  2294. end;
  2295. end else LFilters.indexAccountsKeyList := -1;
  2296. finally
  2297. //FNode.Bank.SafeBox.EndThreadSave;
  2298. end;
  2299. end else begin
  2300. LFilters.OrderedAccountsKeyList := Nil;
  2301. LFilters.indexAccountsKeyList := -1;
  2302. end;
  2303. FAccountsGrid.AccountsGridFilter := LFilters;
  2304. FAccountsGrid.AccountsGridDatasource := acds_NodeFiltered;
  2305. end;
  2306. bbChangeKeyName.Enabled := cbExploreMyAccounts.Checked;
  2307. OnAccountsGridUpdatedData(Nil);
  2308. UpdateOperations;
  2309. end;
  2310. procedure TFRMWallet.UpdateAvailableConnections;
  2311. Var i : integer;
  2312. NC : TNetConnection;
  2313. l : TList<TNetConnection>;
  2314. begin
  2315. if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
  2316. try
  2317. lbNetConnections.Items.BeginUpdate;
  2318. Try
  2319. lbNetConnections.Items.Clear;
  2320. for i := 0 to l.Count - 1 do begin
  2321. NC := l[i];
  2322. if NC.Connected then begin
  2323. if NC is TNetServerClient then begin
  2324. if Not NC.IsMyselfServer then begin
  2325. lbNetConnections.Items.AddObject(Format('Client: IP:%s',[NC.ClientRemoteAddr]),NC);
  2326. end;
  2327. end else begin
  2328. if Not NC.IsMyselfServer then begin
  2329. lbNetConnections.Items.AddObject(Format('Server: IP:%s',[NC.ClientRemoteAddr]),NC);
  2330. end;
  2331. end;
  2332. end;
  2333. end;
  2334. Finally
  2335. lbNetConnections.Items.EndUpdate;
  2336. End;
  2337. finally
  2338. TNetData.NetData.NetConnections.UnlockList;
  2339. end;
  2340. end;
  2341. procedure TFRMWallet.UpdateBlockChainState;
  2342. Var isMining : boolean;
  2343. i,mc : Integer;
  2344. s : String;
  2345. f, favg : real;
  2346. LLockedMempool : TPCOperationsComp;
  2347. begin
  2348. UpdateNodeStatus;
  2349. mc := 0;
  2350. if Assigned(FNode) then begin
  2351. if FNode.Bank.BlocksCount>0 then begin
  2352. lblCurrentBlock.Caption := Inttostr(FNode.Bank.BlocksCount)+' (0..'+Inttostr(FNode.Bank.BlocksCount-1)+')'; ;
  2353. end else lblCurrentBlock.Caption := '(none)';
  2354. lblCurrentAccounts.Caption := Inttostr(FNode.Bank.AccountsCount);
  2355. lblCurrentBlockTime.Caption := UnixTimeToLocalElapsedTime(FNode.Bank.LastOperationBlock.timestamp);
  2356. LLockedMempool := FNode.LockMempoolRead;
  2357. try
  2358. lblOperationsPending.Caption := Inttostr(LLockedMempool.Count);
  2359. lblCurrentDifficulty.Caption := InttoHex(LLockedMempool.OperationBlock.compact_target,8);
  2360. finally
  2361. FNode.UnlockMempoolRead;
  2362. end;
  2363. favg := FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage);
  2364. f := (CT_NewLineSecondsAvg - favg) / CT_NewLineSecondsAvg;
  2365. lblTimeAverage.Caption := 'Last '+Inttostr(CT_CalcNewTargetBlocksAverage)+': '+FormatFloat('0.0',favg)+' sec. (Optimal '+Inttostr(CT_NewLineSecondsAvg)+'s) Deviation '+FormatFloat('0.00%',f*100);
  2366. if favg>=CT_NewLineSecondsAvg then begin
  2367. lblTimeAverage.Font.Color := clNavy;
  2368. end else begin
  2369. lblTimeAverage.Font.Color := clOlive;
  2370. end;
  2371. lblTimeAverageAux.Caption := Format('Last %d: %s sec. - %d: %s sec. - %d: %s sec. - %d: %s sec. - %d: %s sec.',[
  2372. CT_CalcNewTargetBlocksAverage * 2 ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage * 2)),
  2373. ((CT_CalcNewTargetBlocksAverage * 3) DIV 2) ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage((CT_CalcNewTargetBlocksAverage * 3) DIV 2)),
  2374. ((CT_CalcNewTargetBlocksAverage DIV 4)*3),FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(((CT_CalcNewTargetBlocksAverage DIV 4)*3))),
  2375. CT_CalcNewTargetBlocksAverage DIV 2,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 2)),
  2376. CT_CalcNewTargetBlocksAverage DIV 4,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 4))]);
  2377. end else begin
  2378. isMining := false;
  2379. lblCurrentBlock.Caption := '';
  2380. lblCurrentAccounts.Caption := '';
  2381. lblCurrentBlockTime.Caption := '';
  2382. lblOperationsPending.Caption := '';
  2383. lblCurrentDifficulty.Caption := '';
  2384. lblTimeAverage.Caption := '';
  2385. lblTimeAverageAux.Caption := '';
  2386. end;
  2387. if (Assigned(FPoolMiningServer)) And (FPoolMiningServer.Active) then begin
  2388. If FPoolMiningServer.ClientsCount>0 then begin
  2389. lblMinersClients.Caption := IntToStr(FPoolMiningServer.ClientsCount)+' connected JSON-RPC clients';
  2390. lblMinersClients.Font.Color := clNavy;
  2391. end else begin
  2392. lblMinersClients.Caption := 'No JSON-RPC clients';
  2393. lblMinersClients.Font.Color := clDkGray;
  2394. end;
  2395. MinersBlocksFound := FPoolMiningServer.ClientsWins;
  2396. end else begin
  2397. MinersBlocksFound := 0;
  2398. lblMinersClients.Caption := 'JSON-RPC server not active';
  2399. lblMinersClients.Font.Color := clRed;
  2400. end;
  2401. end;
  2402. procedure TFRMWallet.UpdateConfigChanged(Sender:TObject);
  2403. Var wa : Boolean;
  2404. i : Integer;
  2405. LLockedMempool : TPCOperationsComp;
  2406. begin
  2407. tsLogs.TabVisible := TSettings.ShowLogs;
  2408. if (Not tsLogs.TabVisible) then begin
  2409. FLog.OnNewLog := Nil;
  2410. if PageControl.ActivePage = tsLogs then PageControl.ActivePage := tsMyAccounts;
  2411. end else FLog.OnNewLog := OnNewLog;
  2412. if TSettings.SaveLogFiles then begin
  2413. if TSettings.SaveDebugLogs then FLog.SaveTypes := CT_TLogTypes_ALL
  2414. else FLog.SaveTypes := CT_TLogTypes_DEFAULT;
  2415. FLog.FileName := TNode.GetPascalCoinDataFolder+PathDelim+'PascalCointWallet.log';
  2416. end else begin
  2417. FLog.SaveTypes := [];
  2418. FLog.FileName := '';
  2419. end;
  2420. if Assigned(FNode) then begin
  2421. wa := FNode.NetServer.Active;
  2422. FNode.NetServer.Port := TSettings.InternetServerPort;
  2423. FNode.NetServer.Active := wa;
  2424. LLockedMempool := FNode.LockMempoolWrite;
  2425. try
  2426. LLockedMempool.BlockPayload := TEncoding.ANSI.GetBytes(TSettings.MinerName);
  2427. finally
  2428. FNode.UnlockMempoolWrite;
  2429. end;
  2430. FNode.NodeLogFilename := TNode.GetPascalCoinDataFolder+PathDelim+'blocks.log';
  2431. end;
  2432. if Assigned(FPoolMiningServer) then begin
  2433. if FPoolMiningServer.Port<>TSettings.JsonRpcMinerServerPort then begin
  2434. FPoolMiningServer.Active := false;
  2435. FPoolMiningServer.Port := TSettings.JsonRpcMinerServerPort;
  2436. end;
  2437. FPoolMiningServer.Active := TSettings.JsonRpcMinerServerActive;
  2438. FPoolMiningServer.UpdateAccountAndPayload(GetAccountKeyForMiner,TEncoding.ANSI.GetBytes(TSettings.MinerName));
  2439. end;
  2440. if Assigned(FRPCServer) then begin
  2441. FRPCServer.Active := TSettings.JsonRpcPortEnabled;
  2442. FRPCServer.ValidIPs := TSettings.JsonRpcAllowedIPs;
  2443. end;
  2444. i := Integer(TSettings.MinerPrivateKeyType);
  2445. if (i>=Integer(Low(TMinerPrivateKeyType))) And (i<=Integer(High(TMinerPrivateKeyType))) then FMinerPrivateKeyType := TMinerPrivateKeyType(i)
  2446. else FMinerPrivateKeyType := mpk_Random;
  2447. ebHashRateBackBlocks.Text := IntToStr(FBlockChainGrid.HashRateAverageBlocksCount);
  2448. Case FBlockChainGrid.HashRateAs of
  2449. hr_Unit : cbHashRateUnits.ItemIndex:=0;
  2450. hr_Kilo : cbHashRateUnits.ItemIndex:=1;
  2451. hr_Mega : cbHashRateUnits.ItemIndex:=2;
  2452. hr_Giga : cbHashRateUnits.ItemIndex:=3;
  2453. hr_Tera : cbHashRateUnits.ItemIndex:=4;
  2454. hr_Peta : cbHashRateUnits.ItemIndex:=5;
  2455. hr_Exa : cbHashRateUnits.ItemIndex:=6;
  2456. else cbHashRateUnits.ItemIndex:=-1;
  2457. end;
  2458. if TNetData.NetDataExists then begin
  2459. if TSettings.AppParams.ParamByName[CT_PARAM_AllowDownloadNewCheckpointIfOlderThan].GetAsBoolean(TNetData.NetData.MinFutureBlocksToDownloadNewSafebox>200) then begin
  2460. TNetData.NetData.MinFutureBlocksToDownloadNewSafebox:=TSettings.AppParams.ParamByName[CT_PARAM_MinFutureBlocksToDownloadNewSafebox].GetAsInteger(TNetData.NetData.MinFutureBlocksToDownloadNewSafebox);
  2461. end else TNetData.NetData.MinFutureBlocksToDownloadNewSafebox:=0;
  2462. end;
  2463. end;
  2464. procedure TFRMWallet.UpdateConnectionStatus;
  2465. var errors : String;
  2466. begin
  2467. UpdateNodeStatus;
  2468. OnNetStatisticsChanged(Nil);
  2469. if Assigned(FNode) then begin
  2470. if FNode.IsBlockChainValid(errors) then begin
  2471. StatusBar.Panels[2].Text := Format('Last account time:%s',
  2472. [FormatDateTime('dd/mm/yyyy hh:nn:ss',UnivDateTime2LocalDateTime(UnixToUnivDateTime( FNode.Bank.LastOperationBlock.timestamp )))]);
  2473. end else begin
  2474. StatusBar.Panels[2].Text := 'NO BLOCKCHAIN: '+errors;
  2475. end;
  2476. end else begin
  2477. StatusBar.Panels[2].Text := '';
  2478. end;
  2479. end;
  2480. procedure TFRMWallet.UpdateNodeStatus;
  2481. Var status : String;
  2482. begin
  2483. If Not Assigned(FNode) then begin
  2484. lblNodeStatus.Font.Color := clRed;
  2485. lblNodeStatus.Caption := 'Initializing...';
  2486. end else begin
  2487. If FNode.IsReady(status) then begin
  2488. if TNetData.NetData.NetStatistics.ActiveConnections>0 then begin
  2489. lblNodeStatus.Font.Color := clGreen;
  2490. if TNetData.NetData.IsDiscoveringServers then begin
  2491. lblNodeStatus.Caption := 'Discovering servers';
  2492. end else if TNetData.NetData.IsGettingNewBlockChainFromClient(status) then begin
  2493. lblNodeStatus.Caption := 'Obtaining new blockchain '+status;
  2494. end else begin
  2495. lblNodeStatus.Caption := 'Running';
  2496. end;
  2497. end else begin
  2498. lblNodeStatus.Font.Color := clRed;
  2499. lblNodeStatus.Caption := 'Alone in the world...';
  2500. end;
  2501. end else begin
  2502. lblNodeStatus.Font.Color := clRed;
  2503. lblNodeStatus.Caption := status;
  2504. end;
  2505. end;
  2506. If Assigned(FBackgroundLabel) then begin
  2507. FBackgroundLabel.Font.Color:=lblNodeStatus.Font.Color;
  2508. FBackgroundLabel.Caption:='Please wait until finished: '+lblNodeStatus.Caption;
  2509. end;
  2510. end;
  2511. procedure TFRMWallet.UpdateOperations;
  2512. Var accn : Int64;
  2513. begin
  2514. accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
  2515. FOperationsAccountGrid.AccountNumber := accn;
  2516. end;
  2517. procedure TFRMWallet.UpdatePrivateKeys;
  2518. Var i,last_i : Integer;
  2519. wk : TWalletKey;
  2520. s : AnsiString;
  2521. begin
  2522. FNodeNotifyEvents.WatchKeys := FWalletKeys.AccountsKeyList;
  2523. if (cbMyPrivateKeys.ItemIndex>=0) then last_i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex])
  2524. else last_i := -1;
  2525. cbMyPrivateKeys.items.BeginUpdate;
  2526. Try
  2527. cbMyPrivateKeys.Items.Clear;
  2528. For i:=0 to FWalletKeys.Count-1 do begin
  2529. wk := FWalletKeys.Key[i];
  2530. if (wk.Name='') then begin
  2531. s := 'Sha256='+TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString(wk.AccountKey) ) );
  2532. end else begin
  2533. s := wk.Name;
  2534. end;
  2535. if Not Assigned(wk.PrivateKey) then begin
  2536. if Length(wk.CryptedKey)>0 then s:=s+' (**NEED PASSWORD**)'
  2537. else s:=s+' (**PUBLIC KEY ONLY**)';
  2538. end;
  2539. cbMyPrivateKeys.Items.AddObject(s,TObject(i));
  2540. end;
  2541. cbMyPrivateKeys.Sorted := true;
  2542. cbMyPrivateKeys.Sorted := false;
  2543. cbMyPrivateKeys.Items.InsertObject(0,'(All my private keys)',TObject(-1));
  2544. Finally
  2545. cbMyPrivateKeys.Items.EndUpdate;
  2546. End;
  2547. last_i := cbMyPrivateKeys.Items.IndexOfObject(TObject(last_i));
  2548. if last_i<0 then last_i := 0;
  2549. if cbMyPrivateKeys.Items.Count>last_i then cbMyPrivateKeys.ItemIndex := last_i
  2550. else if cbMyPrivateKeys.Items.Count>=0 then cbMyPrivateKeys.ItemIndex := 0;
  2551. end;
  2552. initialization
  2553. FRMWallet := Nil;
  2554. end.