UGridUtils.pas 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840
  1. unit UGridUtils;
  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. Windows,
  21. {$ELSE}
  22. LCLIntf, LCLType, LMessages,
  23. {$ENDIF}
  24. Classes, Grids, UNode, UAccounts, UBlockChain, UAppParams, UThread, UPCDataTypes,
  25. UWallet, UCrypto, UPoolMining, URPC, UBaseTypes, UPCOrderedLists, USettings,
  26. {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
  27. Type
  28. // TAccountsGrid implements a visual integration of TDrawGrid
  29. // to show accounts information
  30. TAccountColumnType = (act_account_number,act_account_key,act_balance,act_updated,act_n_operation,act_updated_state,act_name,act_type,act_saleprice);
  31. TAccountColumn = Record
  32. ColumnType : TAccountColumnType;
  33. width : Integer;
  34. End;
  35. TAccountColumnArray = Array of TAccountColumn;
  36. TAccountsGrid = Class;
  37. TAccountsGridFilter = Record
  38. MinBalance,
  39. MaxBalance : Int64;
  40. OrderedAccountsKeyList : TOrderedAccountKeysList;
  41. indexAccountsKeyList : Integer;
  42. end;
  43. TAccountsGridUpdateThread = Class(TPCThread)
  44. FAccountsGrid : TAccountsGrid;
  45. FAccountsGridFilter : TAccountsGridFilter;
  46. FBalance : Int64;
  47. FIsProcessing : Boolean;
  48. FProcessedList : TOrderedCardinalList;
  49. protected
  50. procedure SynchronizedOnTerminated;
  51. procedure BCExecute; override;
  52. public
  53. constructor Create(AAccountsGrid : TAccountsGrid; AAccountsGridFilter : TAccountsGridFilter);
  54. destructor Destroy; override;
  55. property IsProcessing : Boolean read FisProcessing;
  56. End;
  57. TAccountsGridDatasource = (acds_Node, acds_InternalList, acds_NodeFiltered);
  58. TAccountsGrid = Class(TComponent)
  59. private
  60. FAccountsBalance : Int64;
  61. FAccountsList : TOrderedCardinalList;
  62. FColumns : TAccountColumnArray;
  63. FDrawGrid : TDrawGrid;
  64. FNodeNotifyEvents : TNodeNotifyEvents;
  65. FOnUpdated: TNotifyEvent;
  66. FAllowMultiSelect: Boolean;
  67. FAccountsGridUpdateThread : TAccountsGridUpdateThread;
  68. FAccountsGridFilter: TAccountsGridFilter;
  69. FOnAccountsGridUpdatedData: TNotifyEvent;
  70. FAccountsGridDatasource: TAccountsGridDatasource;
  71. //
  72. FBufferLastAccountNumber : Integer;
  73. FBufferLastAccount : TAccount;
  74. FBufferNodeAccountsCount : Integer;
  75. FBufferNodeBlocksCount : Integer;
  76. //
  77. procedure SetDrawGrid(const Value: TDrawGrid);
  78. Procedure InitGrid;
  79. Procedure InitGridRowCount;
  80. Procedure OnNodeNewOperation(Sender : TObject);
  81. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  82. procedure SetNode(const Value: TNode);
  83. function GetNode: TNode;
  84. procedure SetAllowMultiSelect(const Value: Boolean);
  85. procedure TerminateAccountGridUpdateThread(AWaitUntilTerminated : Boolean);
  86. procedure SetAccountsGridFilter(const Value: TAccountsGridFilter);
  87. function GetAccountsCount: Integer;
  88. procedure SetAccountsGridDatasource(const Value: TAccountsGridDatasource);
  89. procedure UpdateAccountsBalance;
  90. protected
  91. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  92. procedure BufferGetAccount(AAccountNumber : Integer; var AAccount : TAccount; var ANodeBlocksCount, ANodeAccountsCount : Integer);
  93. public
  94. Constructor Create(AOwner : TComponent); override;
  95. Destructor Destroy; override;
  96. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  97. Function LockAccountsList : TOrderedCardinalList;
  98. Procedure UnlockAccountsList;
  99. Property Node : TNode read GetNode write SetNode;
  100. Function AccountNumber(GridRow : Integer) : Int64;
  101. Procedure SaveToStream(Stream : TStream);
  102. Procedure LoadFromStream(Stream : TStream);
  103. Property AccountsBalance : Int64 read FAccountsBalance;
  104. Property AccountsCount : Integer read GetAccountsCount;
  105. Function MoveRowToAccount(nAccount : Cardinal) : Boolean;
  106. Property OnUpdated : TNotifyEvent read FOnUpdated write FOnUpdated;
  107. Property AllowMultiSelect : Boolean read FAllowMultiSelect write SetAllowMultiSelect;
  108. Function SelectedAccounts(accounts : TOrderedCardinalList) : Integer;
  109. property AccountsGridFilter : TAccountsGridFilter read FAccountsGridFilter write SetAccountsGridFilter;
  110. procedure UpdateData;
  111. function IsUpdatingData : Boolean;
  112. property OnAccountsGridUpdatedData : TNotifyEvent read FOnAccountsGridUpdatedData write FOnAccountsGridUpdatedData;
  113. property AccountsGridDatasource : TAccountsGridDatasource read FAccountsGridDatasource write SetAccountsGridDatasource;
  114. function GetColumns : TAccountColumnArray;
  115. procedure SetColumns(const AColumns : TAccountColumnArray);
  116. End;
  117. TOperationsGrid = Class;
  118. TOperationsGridUpdateThread = Class(TPCThread)
  119. FOperationsGrid : TOperationsGrid;
  120. procedure DoUpdateOperationsGrid(const ANode : TNode; const AWalleTKeys : TWalletKeys; const APasswords : TList<String>; var AList : TList<TOperationResume>);
  121. protected
  122. procedure BCExecute; override;
  123. public
  124. constructor Create(AOperationsGrid : TOperationsGrid);
  125. End;
  126. TOperationsGrid = Class(TComponent)
  127. private
  128. FDrawGrid: TDrawGrid;
  129. FAccountNumber: Int64;
  130. FOperationsResume : TOperationsResumeList;
  131. FNodeNotifyEvents : TNodeNotifyEvents;
  132. FPendingOperations: Boolean;
  133. FBlockStart: Int64;
  134. FBlockEnd: Int64;
  135. FMustShowAlwaysAnAccount: Boolean;
  136. FOperationsGridUpdateThread : TOperationsGridUpdateThread;
  137. FWalletKeys: TWalletKeys;
  138. FPasswords: TList<String>;
  139. Procedure OnNodeNewOperation(Sender : TObject);
  140. Procedure OnNodeNewAccount(Sender : TObject);
  141. Procedure InitGrid;
  142. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  143. procedure SetDrawGrid(const Value: TDrawGrid);
  144. procedure SetAccountNumber(const Value: Int64);
  145. procedure SetNode(const Value: TNode);
  146. function GetNode: TNode;
  147. procedure SetPendingOperations(const Value: Boolean);
  148. procedure SetBlockEnd(const Value: Int64);
  149. procedure SetBlockStart(const Value: Int64);
  150. procedure SetMustShowAlwaysAnAccount(const Value: Boolean);
  151. function GetSelectedOperation : TOperationResume;
  152. protected
  153. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  154. public
  155. property SelectedOperation : TOperationResume read GetSelectedOperation;
  156. Constructor Create(AOwner : TComponent); override;
  157. Destructor Destroy; override;
  158. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  159. Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
  160. Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
  161. Property MustShowAlwaysAnAccount : Boolean read FMustShowAlwaysAnAccount write SetMustShowAlwaysAnAccount;
  162. Property Node : TNode read GetNode write SetNode;
  163. property WalletKeys : TWalletKeys read FWalletKeys write FWalletKeys;
  164. property Passwords : TList<String> read FPasswords;
  165. Procedure UpdateAccountOperations; virtual;
  166. Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
  167. Property BlockStart : Int64 read FBlockStart write SetBlockStart;
  168. Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
  169. Procedure SetBlocks(bstart,bend : Int64);
  170. Property OperationsResume : TOperationsResumeList read FOperationsResume;
  171. End;
  172. TBlockChainData = Record
  173. Block : Cardinal;
  174. Timestamp : Cardinal;
  175. BlockProtocolVersion,
  176. BlockProtocolAvailable : Word;
  177. OperationsCount : Integer;
  178. Volume : Int64;
  179. Reward, Fee : Int64;
  180. Target : Cardinal;
  181. HashRateTargetHs : Double;
  182. HashRateHs : Double;
  183. HashRateTargetKhs : Int64;
  184. HashRateKhs : Int64;
  185. MinerPayload : TRawBytes;
  186. PoW : TRawBytes;
  187. SafeBoxHash : TRawBytes;
  188. TimeAverage200 : Real;
  189. TimeAverage150 : Real;
  190. TimeAverage100 : Real;
  191. TimeAverage75 : Real;
  192. TimeAverage50 : Real;
  193. TimeAverage25 : Real;
  194. TimeAverage10 : Real;
  195. TimeAverage5 : Real;
  196. End;
  197. TBlockChainGrid = Class;
  198. { TBlockChainGridUpdateThread }
  199. TBlockChainGridUpdateThread = Class(TPCThread)
  200. FBlockChainGrid : TBlockChainGrid;
  201. FBlockStart, FBlockEnd : Int64;
  202. procedure DoUpdateBlockChainGrid(ANode : TNode; var AList : TList<TBlockChainData>; ABlockStart, ABlockEnd : Int64);
  203. protected
  204. FGridUpdateCount: Integer;
  205. procedure BCExecute; override;
  206. procedure RefreshGrid;
  207. public
  208. constructor Create(ABlockChainGrid : TBlockChainGrid);
  209. End;
  210. { TBlockChainGrid }
  211. TBlockChainGrid = Class(TComponent)
  212. private
  213. FBlockChainDataList : TList<TBlockChainData>;
  214. FBlockStart: Int64;
  215. FHashRateAs: TShowHashRateAs;
  216. FMaxBlocks: Integer;
  217. FBlockEnd: Int64;
  218. FDrawGrid: TDrawGrid;
  219. FNodeNotifyEvents : TNodeNotifyEvents;
  220. FHashRateAverageBlocksCount: Integer;
  221. FShowTimeAverageColumns: Boolean;
  222. FBlockChainGridUpdateThread : TBlockChainGridUpdateThread;
  223. Procedure OnNodeNewAccount(Sender : TObject);
  224. Procedure InitGrid;
  225. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  226. function GetNode: TNode;
  227. procedure SetBlockEnd(const Value: Int64);
  228. procedure SetBlockStart(const Value: Int64);
  229. procedure SetDrawGrid(const Value: TDrawGrid);
  230. procedure SetHashRateAs(AValue: TShowHashRateAs);
  231. procedure SetMaxBlocks(const Value: Integer);
  232. procedure SetNode(const Value: TNode);
  233. procedure SetHashRateAverageBlocksCount(const Value: Integer);
  234. procedure SetShowTimeAverageColumns(AValue: Boolean);
  235. public
  236. protected
  237. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  238. public
  239. Constructor Create(AOwner : TComponent); override;
  240. Destructor Destroy; override;
  241. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  242. Property Node : TNode read GetNode write SetNode;
  243. Procedure UpdateBlockChainGrid; virtual;
  244. Property BlockStart : Int64 read FBlockStart write SetBlockStart;
  245. Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
  246. Procedure SetBlocks(bstart,bend : Int64);
  247. Property MaxBlocks : Integer read FMaxBlocks write SetMaxBlocks;
  248. Property HashRateAverageBlocksCount : Integer read FHashRateAverageBlocksCount write SetHashRateAverageBlocksCount;
  249. Property ShowTimeAverageColumns : Boolean read FShowTimeAverageColumns write SetShowTimeAverageColumns;
  250. Property HashRateAs : TShowHashRateAs read FHashRateAs write SetHashRateAs;
  251. End;
  252. Const
  253. CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateTargetHs:0;HashRateHs:0;HashRateTargetKhs:0;HashRateKhs:0;MinerPayload:Nil;PoW:Nil;SafeBoxHash:Nil;
  254. TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0;TimeAverage5:0);
  255. CT_TAccountsGridFilter_NUL : TAccountsGridFilter = (MinBalance:-1;MaxBalance:-1;OrderedAccountsKeyList:Nil;indexAccountsKeyList:-1);
  256. implementation
  257. uses
  258. Graphics, SysUtils, UTime, UOpTransaction, UConst,
  259. UEPasa, UEPasaDecoder,
  260. UFRMPayloadDecoder, ULog;
  261. { TAccountsGridUpdateThread }
  262. procedure TAccountsGridUpdateThread.BCExecute;
  263. Var
  264. LAccountsNumbersList : TAccountsNumbersList;
  265. i,j, j_min : Integer;
  266. c : Cardinal;
  267. LApplyfilter : Boolean;
  268. LAccount : TAccount;
  269. LNode : TNode;
  270. LAccountsList : TList<Int64>;
  271. begin
  272. LApplyfilter := ((FAccountsGridFilter.MinBalance>0) Or ((FAccountsGridFilter.MaxBalance>=0) And (FAccountsGridFilter.MaxBalance<CT_MaxWalletAmount)));
  273. FBalance := 0;
  274. LNode := FAccountsGrid.Node;
  275. try
  276. if (Assigned(FAccountsGridFilter.OrderedAccountsKeyList)) then begin
  277. if (FAccountsGridFilter.indexAccountsKeyList<0) then i := 0
  278. else i := FAccountsGridFilter.indexAccountsKeyList;
  279. while (Not Terminated) and (i<FAccountsGridFilter.OrderedAccountsKeyList.Count)
  280. and ((FAccountsGridFilter.indexAccountsKeyList<0) or (FAccountsGridFilter.indexAccountsKeyList=i)) do begin
  281. j_min := 0;
  282. while (j_min>=0) do begin
  283. LNode.bank.SafeBox.StartThreadSafe;
  284. FAccountsGridFilter.OrderedAccountsKeyList.Lock; // Protection v4
  285. Try
  286. LAccountsNumbersList := FAccountsGridFilter.OrderedAccountsKeyList.AccountKeyList[i];
  287. if Assigned(LAccountsNumbersList) then begin
  288. LAccountsList := TList<Int64>.Create;
  289. Try
  290. LAccountsNumbersList.FillList(j_min,50000,LAccountsList);
  291. for j := 0 to LAccountsList.Count - 1 do begin
  292. LAccount := LNode.Bank.SafeBox.Account(LAccountsList[j]);
  293. if LApplyfilter then begin
  294. if (LAccount.balance>=FAccountsGridFilter.MinBalance) And ((FAccountsGridFilter.MaxBalance<0) Or (LAccount.balance<=FAccountsGridFilter.MaxBalance)) then begin
  295. FProcessedList.Add(LAccount.account);
  296. FBalance := FBalance + LAccount.balance;
  297. end;
  298. end else begin
  299. FProcessedList.Add(LAccount.account);
  300. FBalance := FBalance + LAccount.balance;
  301. end;
  302. if Terminated then Exit;
  303. end;
  304. if LAccountsList.Count>0 then inc(j_min,LAccountsList.Count)
  305. else break;
  306. Finally
  307. LAccountsList.Free;
  308. End;
  309. end;
  310. finally
  311. FAccountsGridFilter.OrderedAccountsKeyList.Unlock;
  312. LNode.Bank.SafeBox.EndThreadSave;
  313. end;
  314. end;
  315. inc(i);
  316. end;
  317. end else begin
  318. c := 0;
  319. while (c<LNode.Bank.SafeBox.AccountsCount) and (Not Terminated) do begin
  320. LAccount := LNode.Bank.SafeBox.Account(c);
  321. if (LAccount.balance>=FAccountsGridFilter.MinBalance) And ((FAccountsGridFilter.MaxBalance<0) Or (LAccount.balance<=FAccountsGridFilter.MaxBalance)) then begin
  322. FProcessedList.Add(LAccount.account);
  323. FBalance := FBalance + LAccount.balance;
  324. end;
  325. inc(c);
  326. end;
  327. end;
  328. Finally
  329. if Not Terminated then begin
  330. Synchronize(SynchronizedOnTerminated);
  331. end;
  332. FisProcessing := False;
  333. End;
  334. end;
  335. constructor TAccountsGridUpdateThread.Create(AAccountsGrid: TAccountsGrid; AAccountsGridFilter: TAccountsGridFilter);
  336. begin
  337. inherited Create(True);
  338. FreeOnTerminate := False;
  339. FAccountsGrid := AAccountsGrid;
  340. FAccountsGridFilter := AAccountsGridFilter;
  341. FisProcessing := True;
  342. FProcessedList := TOrderedCardinalList.Create;
  343. Suspended := False;
  344. end;
  345. destructor TAccountsGridUpdateThread.Destroy;
  346. begin
  347. FreeAndNil(FProcessedList);
  348. inherited;
  349. end;
  350. procedure TAccountsGridUpdateThread.SynchronizedOnTerminated;
  351. var LacclTemp : TOrderedCardinalList;
  352. begin
  353. if Not Terminated then begin
  354. FAccountsGrid.FAccountsBalance := FBalance;
  355. LacclTemp := FAccountsGrid.LockAccountsList;
  356. try
  357. LacclTemp.CopyFrom( FProcessedList );
  358. finally
  359. FAccountsGrid.UnlockAccountsList;
  360. end;
  361. FisProcessing := False;
  362. if Assigned(FAccountsGrid.FOnAccountsGridUpdatedData) then FAccountsGrid.FOnAccountsGridUpdatedData(FAccountsGrid);
  363. end;
  364. end;
  365. { TAccountsGrid }
  366. Const CT_ColumnHeader : Array[TAccountColumnType] Of String =
  367. ('Account No','Key','Balance','Updated','N Op.','S','Name','Type','Price');
  368. function TAccountsGrid.AccountNumber(GridRow: Integer): Int64;
  369. begin
  370. if GridRow<1 then Result := -1
  371. else if (FAccountsGridDatasource=acds_Node) then begin
  372. if Assigned(Node) then begin
  373. Result := GridRow-1;
  374. end else Result := -1;
  375. end else if GridRow<=FAccountsList.Count then begin
  376. Result := (FAccountsList.Get(GridRow-1));
  377. end else Result := -1;
  378. end;
  379. procedure TAccountsGrid.BufferGetAccount(AAccountNumber: Integer;
  380. var AAccount: TAccount; var ANodeBlocksCount, ANodeAccountsCount: Integer);
  381. begin
  382. if FBufferLastAccountNumber<>AAccountNumber then begin
  383. FBufferNodeAccountsCount := Node.Bank.AccountsCount;
  384. if (AAccountNumber>=FBufferNodeAccountsCount) then FBufferLastAccount := CT_Account_NUL
  385. else FBufferLastAccount := Node.GetMempoolAccount(AAccountNumber);
  386. FBufferNodeBlocksCount := Node.Bank.BlocksCount;
  387. FBufferLastAccountNumber := AAccountNumber;
  388. end;
  389. AAccount := FBufferLastAccount;
  390. ANodeBlocksCount := FBufferNodeBlocksCount;
  391. ANodeAccountsCount := FBufferNodeAccountsCount;
  392. end;
  393. constructor TAccountsGrid.Create(AOwner: TComponent);
  394. Var i : Integer;
  395. begin
  396. inherited;
  397. FAllowMultiSelect := false;
  398. FOnUpdated := Nil;
  399. FAccountsBalance := 0;
  400. FAccountsList := TOrderedCardinalList.Create;
  401. FDrawGrid := Nil;
  402. SetLength(FColumns,7);
  403. FColumns[0].ColumnType := act_account_number;
  404. FColumns[0].width := 75;
  405. FColumns[1].ColumnType := act_name;
  406. FColumns[1].width := 80;
  407. FColumns[2].ColumnType := act_balance;
  408. FColumns[2].width := 80;
  409. FColumns[3].ColumnType := act_n_operation;
  410. FColumns[3].width := 35;
  411. FColumns[4].ColumnType := act_type;
  412. FColumns[4].width := 35;
  413. FColumns[5].ColumnType := act_saleprice;
  414. FColumns[5].width := 45;
  415. FColumns[6].ColumnType := act_updated_state;
  416. FColumns[6].width := 20;
  417. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  418. FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
  419. FAccountsGridUpdateThread := Nil;
  420. FOnAccountsGridUpdatedData := Nil;
  421. FAccountsGridFilter := CT_TAccountsGridFilter_NUL;
  422. FAccountsGridDatasource := acds_Node;
  423. FBufferLastAccountNumber := -1;
  424. end;
  425. destructor TAccountsGrid.Destroy;
  426. begin
  427. TerminateAccountGridUpdateThread(True);
  428. FNodeNotifyEvents.Free;
  429. FAccountsList.Free;
  430. inherited;
  431. end;
  432. function TAccountsGrid.GetAccountsCount: Integer;
  433. begin
  434. if Not Assigned(Node) then Exit(0);
  435. case FAccountsGridDatasource of
  436. acds_Node: Result := Node.Bank.AccountsCount;
  437. else
  438. Result := FAccountsList.Count;
  439. end;
  440. end;
  441. function TAccountsGrid.GetColumns: TAccountColumnArray;
  442. begin
  443. Result := FColumns;
  444. end;
  445. function TAccountsGrid.GetNode: TNode;
  446. begin
  447. Result := FNodeNotifyEvents.Node;
  448. end;
  449. procedure TAccountsGrid.InitGrid;
  450. Var i : Integer;
  451. begin
  452. if Not assigned(DrawGrid) then exit;
  453. InitGridRowCount;
  454. DrawGrid.FixedRows := 1;
  455. if Length(FColumns)=0 then DrawGrid.ColCount := 1
  456. else DrawGrid.ColCount := Length(FColumns);
  457. DrawGrid.FixedCols := 0;
  458. for i := low(FColumns) to high(FColumns) do begin
  459. DrawGrid.ColWidths[i] := FColumns[i].width;
  460. end;
  461. FDrawGrid.DefaultRowHeight := 18;
  462. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  463. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  464. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  465. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  466. if FAllowMultiSelect then DrawGrid.Options := DrawGrid.Options + [goRangeSelect];
  467. FBufferLastAccountNumber := -1;
  468. FDrawGrid.Invalidate;
  469. if Assigned(FOnUpdated) then FOnUpdated(Self);
  470. end;
  471. procedure TAccountsGrid.InitGridRowCount;
  472. var LRowCount : Integer;
  473. begin
  474. if Not assigned(DrawGrid) then exit;
  475. if FAccountsGridDatasource=acds_Node then begin
  476. if Assigned(Node) then begin
  477. if Node.Bank.AccountsCount<1 then LRowCount := 2
  478. else LRowCount := Node.Bank.AccountsCount+1;
  479. end else LRowCount := 2;
  480. end else begin
  481. if FAccountsList.Count<1 then LRowCount := 2
  482. else LRowCount := FAccountsList.Count+1;
  483. end;
  484. if DrawGrid.RowCount<>LRowCount then DrawGrid.RowCount:=LRowCount;
  485. FBufferLastAccountNumber := -1;
  486. FDrawGrid.Invalidate;
  487. end;
  488. function TAccountsGrid.IsUpdatingData: Boolean;
  489. begin
  490. if Assigned(FAccountsGridUpdateThread) then Result := FAccountsGridUpdateThread.IsProcessing
  491. else Result := False;
  492. end;
  493. procedure TAccountsGrid.LoadFromStream(Stream: TStream);
  494. Var c,i,j : Integer;
  495. begin
  496. if Stream.Read(c,sizeof(c))<sizeof(c) then exit;
  497. if c<=0 then exit;
  498. SetLength(FColumns,c);
  499. for i := 0 to c - 1 do begin
  500. Stream.Read(j,sizeof(j));
  501. if (j>=Integer(Low(TAccountColumnType))) And (j<=Integer(High(TAccountColumnType))) then begin
  502. FColumns[i].ColumnType := TAccountColumnType(j);
  503. end else FColumns[i].ColumnType := act_account_number;
  504. Stream.Read(FColumns[i].width,sizeof(FColumns[i].width));
  505. end;
  506. Stream.Read(j,sizeof(j));
  507. If Assigned(FDrawGrid) then FDrawGrid.Width := j;
  508. Stream.Read(j,sizeof(j));
  509. If Assigned(FDrawGrid) then FDrawGrid.Height := j;
  510. end;
  511. function TAccountsGrid.LockAccountsList: TOrderedCardinalList;
  512. begin
  513. Result := FAccountsList;
  514. end;
  515. function TAccountsGrid.MoveRowToAccount(nAccount: Cardinal): Boolean;
  516. Var oal : TOrderedCardinalList;
  517. idx : Integer;
  518. begin
  519. Result := false;
  520. if Not Assigned(FDrawGrid) then exit;
  521. if Not Assigned(Node) then exit;
  522. if FDrawGrid.RowCount<=1 then exit;
  523. if FAccountsGridDatasource=acds_Node then begin
  524. If (FDrawGrid.RowCount>nAccount+1) And (nAccount>=0) And (nAccount<Node.Bank.AccountsCount) then begin
  525. FDrawGrid.Row := nAccount+1;
  526. Result := true;
  527. end else begin
  528. FDrawGrid.Row := FDrawGrid.RowCount-1;
  529. end;
  530. end else begin
  531. oal := LockAccountsList;
  532. try
  533. If oal.Find(nAccount,idx) then begin
  534. If FDrawGrid.RowCount>idx+1 then begin
  535. FDrawGrid.Row := idx+1;
  536. Result := true;
  537. end else begin
  538. FDrawGrid.Row := FDrawGrid.RowCount-1;
  539. end;
  540. end else begin
  541. If FDrawGrid.RowCount>idx+1 then begin
  542. FDrawGrid.Row := idx+1;
  543. end else begin
  544. FDrawGrid.Row := FDrawGrid.RowCount-1;
  545. end;
  546. end;
  547. finally
  548. UnlockAccountsList;
  549. end;
  550. end;
  551. end;
  552. procedure TAccountsGrid.Notification(AComponent: TComponent;
  553. Operation: TOperation);
  554. begin
  555. inherited;
  556. if Operation=opRemove then begin
  557. if (AComponent=FDrawGrid) then begin
  558. SetDrawGrid(Nil);
  559. end;
  560. end;
  561. end;
  562. {$IFDEF FPC}
  563. Type
  564. TTextFormats = (tfBottom, tfCalcRect, tfCenter, tfEditControl, tfEndEllipsis,
  565. tfPathEllipsis, tfExpandTabs, tfExternalLeading, tfLeft, tfModifyString,
  566. tfNoClip, tfNoPrefix, tfRight, tfRtlReading, tfSingleLine, tfTop,
  567. tfVerticalCenter, tfWordBreak);
  568. TTextFormat = set of TTextFormats;
  569. Procedure Canvas_TextRect(Canvas : TCanvas; var Rect: TRect; var Text: string; State: TGridDrawState; TextFormat: TTextFormat = []);
  570. Var ts : TTextStyle;
  571. Begin
  572. if (tfRight in TextFormat) then ts.Alignment:=taRightJustify
  573. else if (tfCenter in TextFormat) then ts.Alignment:=taCenter
  574. else ts.Alignment:=taLeftJustify;
  575. if (tfWordBreak in TextFormat) then ts.Wordbreak:=true
  576. else ts.Wordbreak:=false;
  577. if (tfVerticalCenter in TextFormat) then ts.Layout:=tlCenter
  578. else if (tfBottom in TextFormat) then ts.Layout:=tlBottom
  579. else ts.Layout:=tlTop;
  580. ts.Clipping:=Not (tfNoClip in TextFormat);
  581. ts.SingleLine := (tfSingleLine in TextFormat);
  582. ts.Wordbreak:= (tfWordBreak in TextFormat);
  583. ts.EndEllipsis:= (tfEndEllipsis in TextFormat);
  584. ts.ExpandTabs:=false;
  585. ts.Opaque:=false;
  586. ts.ShowPrefix:= not (tfNoPrefix in TextFormat);
  587. ts.SystemFont:=false;
  588. Canvas.TextRect(Rect,Rect.Left,Rect.Top,Text,ts);
  589. end;
  590. {$ELSE}
  591. Procedure Canvas_TextRect(Canvas : TCanvas; var Rect: TRect; var Text: string; State: TGridDrawState; TextFormat: TTextFormat = []);
  592. Begin
  593. Canvas.TextRect(Rect,Text,TextFormat);
  594. end;
  595. {$ENDIF}
  596. procedure TAccountsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Longint;
  597. Rect: TRect; State: TGridDrawState);
  598. Function FromColorToColor(colorstart,colordest : Integer; step,totalsteps : Integer) : Integer;
  599. var sr,sg,sb,dr,dg,db : Byte;
  600. i : Integer;
  601. begin
  602. i := colorstart;
  603. sr := GetRValue(i);
  604. sg := GetGValue(i);
  605. sb := GetBValue(i);
  606. i := colordest;
  607. dr := GetRValue(i);
  608. dg := GetGValue(i);
  609. db := GetBValue(i);
  610. sr := sr + (((dr-sr) DIV totalsteps)*step);
  611. sg := sg + (((dg-sg) DIV totalsteps)*step);
  612. sb := sb + (((db-sb) DIV totalsteps)*step);
  613. Result :=RGB(sr,sg,sb);
  614. end;
  615. Var C : TAccountColumn;
  616. s : String;
  617. n_acc : Int64;
  618. account : TAccount;
  619. ndiff : Cardinal;
  620. LNodeBlocksCount,LNodeAccountsCount : Integer;
  621. begin
  622. if Not Assigned(Node) then exit;
  623. if (ACol>=0) AND (ACol<length(FColumns)) then begin
  624. C := FColumns[ACol];
  625. end else begin
  626. C.ColumnType := act_account_number;
  627. C.width := -1;
  628. end;
  629. DrawGrid.Canvas.Font.Color:=clWindowText;
  630. if (ARow=0) then begin
  631. // Header
  632. s := CT_ColumnHeader[C.ColumnType];
  633. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  634. end else begin
  635. n_acc := AccountNumber(ARow);
  636. if (n_acc>=0) then begin
  637. BufferGetAccount(n_acc,account,LNodeBlocksCount,LNodeAccountsCount);
  638. ndiff := LNodeBlocksCount - account.GetLastUpdatedBlock;
  639. if (gdSelected in State) then
  640. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  641. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  642. else DrawGrid.Canvas.Brush.Color := clWindow;
  643. DrawGrid.Canvas.FillRect(Rect);
  644. InflateRect(Rect,-2,-1);
  645. case C.ColumnType of
  646. act_account_number : Begin
  647. s := TAccountComp.AccountNumberToAccountTxtNumber(n_acc);
  648. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  649. End;
  650. act_account_key : Begin
  651. s := Tcrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.accountKey));
  652. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  653. End;
  654. act_balance : Begin
  655. if ndiff=0 then begin
  656. // Pending operation... showing final balance
  657. DrawGrid.Canvas.Font.Color := clBlue;
  658. s := '('+TAccountComp.FormatMoney(account.balance)+')';
  659. end else begin
  660. s := TAccountComp.FormatMoney(account.balance);
  661. if account.balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
  662. else if account.balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
  663. else DrawGrid.Canvas.Font.Color := clRed;
  664. end;
  665. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  666. End;
  667. act_updated : Begin
  668. s := Inttostr(account.GetLastUpdatedBlock);
  669. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  670. End;
  671. act_n_operation : Begin
  672. s := InttoStr(account.n_operation);
  673. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  674. End;
  675. act_updated_state : Begin
  676. if TAccountComp.IsAccountBlockedByProtocol(account.account,LNodeBlocksCount) then begin
  677. DrawGrid.Canvas.Brush.Color := clRed;
  678. end else if ndiff=0 then begin
  679. DrawGrid.Canvas.Brush.Color := RGB(255,128,0);
  680. end else if ndiff<=8 then begin
  681. DrawGrid.Canvas.Brush.Color := FromColorToColor(RGB(253,250,115),ColorToRGB(clGreen),ndiff-1,8-1);
  682. end else begin
  683. DrawGrid.Canvas.Brush.Color := clGreen;
  684. end;
  685. DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
  686. End;
  687. act_name : Begin
  688. s := account.name.ToPrintable;
  689. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  690. end;
  691. act_type : Begin
  692. s := IntToStr(account.account_type);
  693. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  694. end;
  695. act_saleprice : Begin
  696. if TAccountComp.IsAccountForSale(account.accountInfo) then begin
  697. // Show price for sale
  698. s := TAccountComp.FormatMoney(account.accountInfo.price);
  699. if TAccountComp.IsAccountForPrivateSale(account.accountInfo) then begin
  700. if TAccountComp.IsAccountLocked(account.accountInfo,LNodeBlocksCount) then begin
  701. DrawGrid.Canvas.Font.Color := clNavy;
  702. end else begin
  703. DrawGrid.Canvas.Font.Color := clRed;
  704. end;
  705. end else begin
  706. DrawGrid.Canvas.Font.Color := clGrayText
  707. end;
  708. end else if TAccountComp.IsAccountForSwap(account.accountInfo) then begin
  709. if TAccountComp.IsAccountForAccountSwap(account.accountInfo) then begin
  710. s := 'Account SWAP';
  711. end else if TAccountComp.IsAccountForCoinSwap(account.accountInfo) then begin
  712. s := 'SWAP '+TAccountComp.FormatMoney(account.accountInfo.price);
  713. end else s := 'SWAP';
  714. if TAccountComp.IsAccountLocked(account.accountInfo,LNodeBlocksCount) then begin
  715. DrawGrid.Canvas.Font.Color := clNavy;
  716. end else begin
  717. DrawGrid.Canvas.Font.Color := clRed;
  718. end;
  719. end else s := '';
  720. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  721. end;
  722. else
  723. s := '(???)';
  724. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  725. end;
  726. end;
  727. end;
  728. end;
  729. procedure TAccountsGrid.OnNodeNewOperation(Sender: TObject);
  730. begin
  731. FBufferLastAccountNumber := -1;
  732. If Assigned(FDrawGrid) then FDrawGrid.Invalidate;
  733. end;
  734. procedure TAccountsGrid.SaveToStream(Stream: TStream);
  735. Var c,i,j : Integer;
  736. begin
  737. c := Length(FColumns);
  738. Stream.Write(c,sizeof(c));
  739. for i := 0 to c - 1 do begin
  740. j := Integer(FColumns[i].ColumnType);
  741. Stream.Write(j,sizeof(j));
  742. if Assigned(FDrawGrid) then begin
  743. FColumns[i].width := FDrawGrid.ColWidths[i];
  744. end;
  745. Stream.Write(FColumns[i].width,sizeof(FColumns[i].width));
  746. end;
  747. j := FDrawGrid.Width;
  748. Stream.Write(j,sizeof(j));
  749. j := FDrawGrid.Height;
  750. Stream.Write(j,sizeof(j));
  751. end;
  752. function TAccountsGrid.SelectedAccounts(accounts: TOrderedCardinalList): Integer;
  753. var i64 : Int64;
  754. i : Integer;
  755. begin
  756. accounts.Clear;
  757. Result := 0;
  758. if not assigned(FDrawGrid) then exit;
  759. if FAllowMultiSelect then begin
  760. for i := FDrawGrid.Selection.Top to FDrawGrid.Selection.Bottom do begin
  761. i64 := AccountNumber(i);
  762. if i64>=0 then accounts.Add(i64);
  763. end;
  764. end;
  765. If accounts.Count=0 then begin
  766. i64 := AccountNumber(DrawGrid.Row);
  767. if i64>=0 then accounts.Add(i64);
  768. end;
  769. Result := accounts.Count;
  770. end;
  771. procedure TAccountsGrid.SetAccountsGridDatasource(const Value: TAccountsGridDatasource);
  772. begin
  773. if FAccountsGridDatasource=Value then Exit;
  774. FAccountsGridDatasource := Value;
  775. UpdateData;
  776. end;
  777. procedure TAccountsGrid.SetAccountsGridFilter(const Value: TAccountsGridFilter);
  778. begin
  779. FAccountsGridFilter := Value;
  780. UpdateData;
  781. end;
  782. procedure TAccountsGrid.SetAllowMultiSelect(const Value: Boolean);
  783. begin
  784. FAllowMultiSelect := Value;
  785. InitGrid;
  786. end;
  787. procedure TAccountsGrid.SetColumns(const AColumns: TAccountColumnArray);
  788. begin
  789. FColumns := AColumns;
  790. InitGrid;
  791. end;
  792. procedure TAccountsGrid.SetDrawGrid(const Value: TDrawGrid);
  793. begin
  794. if FDrawGrid=Value then exit;
  795. FDrawGrid := Value;
  796. if Assigned(Value) then begin
  797. Value.FreeNotification(self);
  798. FDrawGrid.OnDrawCell := OnGridDrawCell;
  799. UpdateData;
  800. end;
  801. end;
  802. procedure TAccountsGrid.SetNode(const Value: TNode);
  803. begin
  804. if GetNode=Value then exit;
  805. FNodeNotifyEvents.Node := Value;
  806. UpdateData;
  807. end;
  808. procedure TAccountsGrid.TerminateAccountGridUpdateThread(AWaitUntilTerminated : Boolean);
  809. var LTmp : TAccountsGridUpdateThread;
  810. begin
  811. LTmp := FAccountsGridUpdateThread;
  812. FAccountsGridUpdateThread := Nil;
  813. if Assigned(Ltmp) then begin
  814. if Not LTmp.IsProcessing then AWaitUntilTerminated := True;
  815. if Not AWaitUntilTerminated then begin
  816. LTmp.FreeOnTerminate := True;
  817. end;
  818. LTmp.Terminate;
  819. if AWaitUntilTerminated then begin
  820. LTmp.WaitFor;
  821. FreeAndNil(LTmp);
  822. end;
  823. end;
  824. end;
  825. procedure TAccountsGrid.UnlockAccountsList;
  826. begin
  827. UpdateAccountsBalance;
  828. InitGridRowCount;
  829. if Assigned(FOnUpdated) then FOnUpdated(Self);
  830. end;
  831. procedure TAccountsGrid.UpdateAccountsBalance;
  832. var i : Integer;
  833. LAcc : TAccount;
  834. begin
  835. if Assigned(Node) then begin
  836. case FAccountsGridDatasource of
  837. acds_Node: FAccountsBalance := Node.Bank.SafeBox.TotalBalance;
  838. acds_InternalList: begin
  839. FAccountsBalance := 0;
  840. for i := 0 to FAccountsList.Count - 1 do begin
  841. LAcc := Node.Bank.SafeBox.Account( FAccountsList.Get(i) );
  842. inc(FAccountsBalance, LAcc.balance);
  843. end;
  844. end;
  845. end;
  846. end;
  847. end;
  848. procedure TAccountsGrid.UpdateData;
  849. begin
  850. UpdateAccountsBalance;
  851. TerminateAccountGridUpdateThread(False);
  852. if Assigned(Node) then begin
  853. case FAccountsGridDatasource of
  854. acds_NodeFiltered: begin
  855. FAccountsBalance := 0;
  856. FAccountsGridUpdateThread := TAccountsGridUpdateThread.Create(Self,AccountsGridFilter);
  857. end;
  858. end;
  859. end;
  860. InitGridRowCount;
  861. if Assigned(FOnAccountsGridUpdatedData) then FOnAccountsGridUpdatedData(Self);
  862. end;
  863. { TOperationsGridUpdateThread }
  864. procedure TOperationsGridUpdateThread.BCExecute;
  865. var list : TList<TOperationResume>;
  866. i : Integer;
  867. begin
  868. list := TList<TOperationResume>.Create;
  869. try
  870. DoUpdateOperationsGrid(FOperationsGrid.Node,FOperationsGrid.WalletKeys,FOperationsGrid.Passwords,list);
  871. if (Not Terminated) then begin
  872. FOperationsGrid.FOperationsResume.Clear;
  873. for i := 0 to list.Count-1 do begin
  874. FOperationsGrid.FOperationsResume.Add(list[i]);
  875. end;
  876. Queue(FOperationsGrid.InitGrid);
  877. end;
  878. finally
  879. list.Free;
  880. end;
  881. end;
  882. constructor TOperationsGridUpdateThread.Create(AOperationsGrid: TOperationsGrid);
  883. begin
  884. FOperationsGrid := AOperationsGrid;
  885. inherited Create(True);
  886. FreeOnTerminate := False;
  887. Suspended := False;
  888. end;
  889. procedure TOperationsGridUpdateThread.DoUpdateOperationsGrid(const ANode : TNode; const AWalleTKeys : TWalletKeys;
  890. const APasswords : TList<String>; var AList: TList<TOperationResume>);
  891. Var list : TList<Cardinal>;
  892. i,j : Integer;
  893. OPR : TOperationResume;
  894. Op : TPCOperation;
  895. opc : TPCOperationsComp;
  896. bstart,bend : int64;
  897. LOperationsResume : TOperationsResumeList;
  898. LLockedMempool : TPCOperationsComp;
  899. LEPasa : TEPasa;
  900. begin
  901. if Not Assigned(ANode) then exit;
  902. AList.Clear;
  903. Try
  904. if (FOperationsGrid.MustShowAlwaysAnAccount) And (FOperationsGrid.AccountNumber<0) then exit;
  905. if FOperationsGrid.FPendingOperations then begin
  906. LLockedMempool := ANode.LockMempoolRead;
  907. try
  908. for i := LLockedMempool.Count - 1 downto 0 do begin
  909. Op := LLockedMempool.OperationsHashTree.GetOperation(i);
  910. If TPCOperation.OperationToOperationResume(0,Op,True,Op.SignerAccount,OPR) then begin
  911. OPR.NOpInsideBlock := i;
  912. OPR.Block := ANode.Bank.BlocksCount;
  913. OPR.Balance := LLockedMempool.SafeBoxTransaction.Account(Op.SignerAccount).balance;
  914. AList.Add(OPR);
  915. end;
  916. end;
  917. finally
  918. ANode.UnlockMempoolRead;
  919. end;
  920. end else begin
  921. if FOperationsGrid.AccountNumber<0 then begin
  922. opc := TPCOperationsComp.Create(Nil);
  923. try
  924. opc.bank := ANode.Bank;
  925. If FOperationsGrid.FBlockEnd<0 then begin
  926. If ANode.Bank.BlocksCount>0 then bend := ANode.Bank.BlocksCount-1
  927. else bend := 0;
  928. end else bend := FOperationsGrid.FBlockEnd;
  929. if FOperationsGrid.FBlockStart<0 then begin
  930. if (bend > 300) then bstart := bend - 300
  931. else bstart := 0;
  932. end else bstart:= FOperationsGrid.FBlockStart;
  933. If bstart<0 then bstart := 0;
  934. if bend>=ANode.Bank.BlocksCount then bend:=ANode.Bank.BlocksCount;
  935. while (bstart<=bend) and (Not Terminated) do begin
  936. opr := CT_TOperationResume_NUL;
  937. if (ANode.Bank.Storage.LoadBlockChainBlock(opc,bend)) then begin
  938. // Reward operation
  939. OPR := CT_TOperationResume_NUL;
  940. OPR.valid := true;
  941. OPR.Block := bend;
  942. OPR.time := opc.OperationBlock.timestamp;
  943. OPR.AffectedAccount := bend * CT_AccountsPerBlock;
  944. OPR.Amount := opc.OperationBlock.reward;
  945. OPR.Fee := opc.OperationBlock.fee;
  946. OPR.Balance := OPR.Amount+OPR.Fee;
  947. OPR.OperationTxt := 'Blockchain reward';
  948. AList.Add(OPR);
  949. // Reverse operations inside a block
  950. for i := opc.Count - 1 downto 0 do begin
  951. if TPCOperation.OperationToOperationResume(bend,opc.Operation[i],True,opc.Operation[i].SignerAccount,opr) then begin
  952. opr.NOpInsideBlock := i;
  953. opr.Block := bend;
  954. opr.time := opc.OperationBlock.timestamp;
  955. AList.Add(opr);
  956. end;
  957. end;
  958. end else break;
  959. dec(bend);
  960. end;
  961. finally
  962. opc.Free;
  963. end;
  964. end else begin
  965. list := TList<Cardinal>.Create;
  966. Try
  967. LLockedMempool := ANode.LockMempoolRead;
  968. try
  969. LLockedMempool.OperationsHashTree.GetOperationsAffectingAccount(FOperationsGrid.AccountNumber,list);
  970. for i := list.Count - 1 downto 0 do begin
  971. Op := LLockedMempool.OperationsHashTree.GetOperation((list[i]));
  972. If TPCOperation.OperationToOperationResume(0,Op,False,FOperationsGrid.AccountNumber,OPR) then begin
  973. OPR.NOpInsideBlock := i;
  974. OPR.Block := LLockedMempool.OperationBlock.block;
  975. OPR.Balance := LLockedMempool.SafeBoxTransaction.Account(FOperationsGrid.AccountNumber).balance;
  976. AList.Add(OPR);
  977. end;
  978. end;
  979. finally
  980. ANode.UnlockMempoolRead;
  981. end;
  982. Finally
  983. list.Free;
  984. End;
  985. ANode.GetStoredOperationsFromAccount(Self,AList,FOperationsGrid.AccountNumber,100,0,5000);
  986. end;
  987. end;
  988. Finally
  989. for i := 0 to AList.Count-1 do begin
  990. OPR := AList[i];
  991. if TEPasaDecoder.TryDecodeEPASA(OPR.DestAccount,OPR.OriginalPayload,ANode,AWalleTKeys,APasswords,LEPasa) then begin
  992. OPR.DecodedEPasaPayload := LEPasa.ToString(True);
  993. AList[i] := OPR;
  994. end;
  995. end;
  996. End;
  997. end;
  998. { TOperationsGrid }
  999. constructor TOperationsGrid.Create(AOwner: TComponent);
  1000. begin
  1001. FPasswords := TList<String>.Create;
  1002. FWalletKeys := Nil;
  1003. FAccountNumber := 0;
  1004. FDrawGrid := Nil;
  1005. MustShowAlwaysAnAccount := false;
  1006. FOperationsResume := TOperationsResumeList.Create;
  1007. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  1008. FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
  1009. FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
  1010. FBlockStart := -1;
  1011. FBlockEnd := -1;
  1012. FPendingOperations := false;
  1013. FOperationsGridUpdateThread := Nil;
  1014. inherited;
  1015. end;
  1016. destructor TOperationsGrid.Destroy;
  1017. begin
  1018. If Assigned(FOperationsGridUpdateThread) then begin
  1019. FOperationsGridUpdateThread.Terminate;
  1020. FOperationsGridUpdateThread.WaitFor;
  1021. FreeAndNil(FOperationsGridUpdateThread);
  1022. end;
  1023. FOperationsResume.Free;
  1024. FNodeNotifyEvents.Free;
  1025. FPasswords.Free;
  1026. inherited;
  1027. end;
  1028. function TOperationsGrid.GetNode: TNode;
  1029. begin
  1030. Result := FNodeNotifyEvents.Node;
  1031. end;
  1032. procedure TOperationsGrid.InitGrid;
  1033. begin
  1034. if Not Assigned(FDrawGrid) then exit;
  1035. if FOperationsResume.Count>0 then FDrawGrid.RowCount := FOperationsResume.Count+1
  1036. else FDrawGrid.RowCount := 2;
  1037. DrawGrid.FixedRows := 1;
  1038. DrawGrid.DefaultDrawing := true;
  1039. DrawGrid.FixedCols := 0;
  1040. DrawGrid.ColCount := 8;
  1041. DrawGrid.ColWidths[0] := 110; // Time
  1042. DrawGrid.ColWidths[1] := 70; // Block/Op
  1043. DrawGrid.ColWidths[2] := 60; // Account
  1044. DrawGrid.ColWidths[3] := 180; // OpType
  1045. DrawGrid.ColWidths[4] := 70; // Amount
  1046. DrawGrid.ColWidths[5] := 60; // Operation Fee
  1047. DrawGrid.ColWidths[6] := 80; // Balance
  1048. DrawGrid.ColWidths[7] := 500; // Payload
  1049. FDrawGrid.DefaultRowHeight := 18;
  1050. FDrawGrid.Invalidate;
  1051. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  1052. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  1053. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  1054. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  1055. end;
  1056. procedure TOperationsGrid.Notification(AComponent: TComponent; Operation: TOperation);
  1057. begin
  1058. inherited;
  1059. if Operation=opRemove then begin
  1060. if (AComponent=FDrawGrid) then begin
  1061. SetDrawGrid(Nil);
  1062. end;
  1063. end;
  1064. end;
  1065. procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
  1066. Var s, saux : String;
  1067. opr : TOperationResume;
  1068. LRectLeft, LRectRight : TRect;
  1069. begin
  1070. DrawGrid.Canvas.Font.Color:=clWindowText;
  1071. opr := CT_TOperationResume_NUL;
  1072. Try
  1073. if (ARow=0) then begin
  1074. // Header
  1075. case ACol of
  1076. 0 : s := 'Time';
  1077. 1 : s := 'Block/Op';
  1078. 2 : s := 'Account';
  1079. 3 : s := 'Operation';
  1080. 4 : s := 'Amount';
  1081. 5 : s := 'Fee';
  1082. 6 : s := 'Balance';
  1083. 7 : s := 'Payload';
  1084. else s:= '';
  1085. end;
  1086. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  1087. end else begin
  1088. if (gdSelected in State) then
  1089. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  1090. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  1091. else DrawGrid.Canvas.Brush.Color := clWindow;
  1092. DrawGrid.Canvas.FillRect(Rect);
  1093. InflateRect(Rect,-2,-1);
  1094. if (ARow<=FOperationsResume.Count) then begin
  1095. opr := FOperationsResume.OperationResume[ARow-1];
  1096. If (opr.AffectedAccount=opr.SignerAccount) then begin
  1097. end else begin
  1098. if (gdSelected in State) or (gdFocused in State) then begin
  1099. end else DrawGrid.Canvas.font.Color := clGrayText;
  1100. end;
  1101. if ACol=0 then begin
  1102. if opr.time=0 then s := '(Pending)'
  1103. else s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(opr.time)));
  1104. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1105. end else if ACol=1 then begin
  1106. s := Inttostr(opr.Block);
  1107. if opr.NOpInsideBlock>=0 then s := s + '/'+Inttostr(opr.NOpInsideBlock+1);
  1108. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1109. end else if ACol=2 then begin
  1110. s := TAccountComp.AccountNumberToAccountTxtNumber(opr.AffectedAccount);
  1111. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1112. end else if ACol=3 then begin
  1113. s := opr.OperationTxt;
  1114. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1115. end else if ACol=4 then begin
  1116. s := TAccountComp.FormatMoney(opr.Amount);
  1117. if opr.Amount>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1118. else if opr.Amount=0 then DrawGrid.Canvas.Font.Color := clGrayText
  1119. else DrawGrid.Canvas.Font.Color := clRed;
  1120. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1121. end else if ACol=5 then begin
  1122. s := TAccountComp.FormatMoney(opr.Fee);
  1123. if opr.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1124. else if opr.Fee=0 then DrawGrid.Canvas.Font.Color := clGrayText
  1125. else DrawGrid.Canvas.Font.Color := clRed;
  1126. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1127. end else if ACol=6 then begin
  1128. if opr.time=0 then begin
  1129. // Pending operation... showing final balance
  1130. DrawGrid.Canvas.Font.Color := clBlue;
  1131. s := '('+TAccountComp.FormatMoney(opr.Balance)+')';
  1132. end else begin
  1133. s := TAccountComp.FormatMoney(opr.Balance);
  1134. if opr.Balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1135. else if opr.Balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
  1136. else DrawGrid.Canvas.Font.Color := clRed;
  1137. end;
  1138. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1139. end else if ACol=7 then begin
  1140. s := opr.PrintablePayload;
  1141. LRectRight := Rect;
  1142. if opr.OriginalPayload.payload_type>0 then begin
  1143. saux := '0x'+IntToHex(opr.OriginalPayload.payload_type,2);
  1144. LRectLeft := Rect;
  1145. LRectLeft.Width := 30;
  1146. Rect.Inflate(-32,0,0,0);
  1147. DrawGrid.Canvas.Font.Color := clBlue;
  1148. DrawGrid.Canvas.Font.Style := [fsBold];
  1149. Canvas_TextRect(DrawGrid.Canvas,LRectLeft,saux,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  1150. if opr.DecodedEPasaPayload<>'' then begin
  1151. DrawGrid.Canvas.Font.Style := [fsBold];
  1152. s := opr.DecodedEPasaPayload
  1153. end else DrawGrid.Canvas.Font.Style := [];
  1154. end else if opr.OriginalPayload.payload_raw.ToString=s then begin
  1155. DrawGrid.Canvas.Font.Style := [fsBold];
  1156. end;
  1157. DrawGrid.Canvas.Font.Color := clBlack;
  1158. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine])
  1159. end else begin
  1160. s := '(???)';
  1161. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1162. end;
  1163. end;
  1164. end;
  1165. Except
  1166. On E:Exception do begin
  1167. TLog.NewLog(lterror,Classname,Format('Error at OnGridDrawCell row %d col %d Block %d - %s',[ARow,ACol,opr.Block,E.Message]));
  1168. end;
  1169. End;
  1170. end;
  1171. procedure TOperationsGrid.OnNodeNewAccount(Sender: TObject);
  1172. begin
  1173. If (AccountNumber<0) And (FBlockEnd<0) And (Not FPendingOperations) then UpdateAccountOperations;
  1174. end;
  1175. procedure TOperationsGrid.OnNodeNewOperation(Sender: TObject);
  1176. Var l : TList<Cardinal>;
  1177. LLockedMempool : TPCOperationsComp;
  1178. begin
  1179. Try
  1180. if (AccountNumber<0) then begin
  1181. If (FPendingOperations) then UpdateAccountOperations;
  1182. end else begin
  1183. l := TList<Cardinal>.Create;
  1184. Try
  1185. LLockedMempool := Node.LockMempoolRead;
  1186. try
  1187. If LLockedMempool.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,l)>0 then begin
  1188. if l.IndexOf(AccountNumber)>=0 then UpdateAccountOperations;
  1189. end;
  1190. finally
  1191. Node.UnlockMempoolRead;
  1192. end;
  1193. Finally
  1194. l.Free;
  1195. End;
  1196. end;
  1197. Except
  1198. On E:Exception do begin
  1199. E.message := 'Exception on updating OperationsGrid '+inttostr(AccountNumber)+': '+E.Message;
  1200. Raise;
  1201. end;
  1202. end;
  1203. end;
  1204. procedure TOperationsGrid.SetAccountNumber(const Value: Int64);
  1205. begin
  1206. if FAccountNumber=Value then exit;
  1207. FAccountNumber := Value;
  1208. if FAccountNumber>=0 then FPendingOperations := false;
  1209. UpdateAccountOperations;
  1210. end;
  1211. procedure TOperationsGrid.SetBlockEnd(const Value: Int64);
  1212. begin
  1213. FBlockEnd := Value;
  1214. end;
  1215. procedure TOperationsGrid.SetBlocks(bstart, bend: Int64);
  1216. begin
  1217. if (bstart=FBlockStart) And (bend=FBlockEnd) then exit;
  1218. FBlockStart := bstart;
  1219. FBlockEnd := bend;
  1220. if (FBlockEnd>0) And (FBlockStart>FBlockEnd) then FBlockStart := -1;
  1221. FAccountNumber := -1;
  1222. FPendingOperations := false;
  1223. UpdateAccountOperations;
  1224. end;
  1225. procedure TOperationsGrid.SetBlockStart(const Value: Int64);
  1226. begin
  1227. FBlockStart := Value;
  1228. end;
  1229. procedure TOperationsGrid.SetDrawGrid(const Value: TDrawGrid);
  1230. begin
  1231. if FDrawGrid=Value then exit;
  1232. FDrawGrid := Value;
  1233. if Assigned(Value) then begin
  1234. Value.FreeNotification(self);
  1235. FDrawGrid.OnDrawCell := OnGridDrawCell;
  1236. InitGrid;
  1237. end;
  1238. end;
  1239. procedure TOperationsGrid.SetMustShowAlwaysAnAccount(const Value: Boolean);
  1240. begin
  1241. if FMustShowAlwaysAnAccount=Value then exit;
  1242. FMustShowAlwaysAnAccount := Value;
  1243. UpdateAccountOperations;
  1244. end;
  1245. procedure TOperationsGrid.SetNode(const Value: TNode);
  1246. begin
  1247. if GetNode=Value then exit;
  1248. If Assigned(FOperationsGridUpdateThread) then begin
  1249. FOperationsGridUpdateThread.Terminate;
  1250. FOperationsGridUpdateThread.WaitFor;
  1251. FreeAndNil(FOperationsGridUpdateThread);
  1252. end;
  1253. FNodeNotifyEvents.Node := Value;
  1254. UpdateAccountOperations; // New Build 1.0.3
  1255. end;
  1256. procedure TOperationsGrid.SetPendingOperations(const Value: Boolean);
  1257. begin
  1258. FPendingOperations := Value;
  1259. if FPendingOperations then FAccountNumber := -1;
  1260. UpdateAccountOperations;
  1261. end;
  1262. function TOperationsGrid.GetSelectedOperation : TOperationResume;
  1263. Var i : Integer;
  1264. opr : TOperationResume;
  1265. FRM : TFRMPayloadDecoder;
  1266. begin
  1267. if Not Assigned(FDrawGrid) then exit;
  1268. if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then begin
  1269. Result := CT_TOperationResume_NUL;
  1270. exit;
  1271. end;
  1272. Result := FOperationsResume.OperationResume[FDrawGrid.Row-1];
  1273. end;
  1274. procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
  1275. Var i : Integer;
  1276. opr : TOperationResume;
  1277. FRM : TFRMPayloadDecoder;
  1278. begin
  1279. if Not Assigned(FDrawGrid) then exit;
  1280. if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then exit;
  1281. opr := FOperationsResume.OperationResume[FDrawGrid.Row-1];
  1282. FRM := TFRMPayloadDecoder.Create(FDrawGrid.Owner);
  1283. try
  1284. FRM.Init(opr,WalletKeys,AppParams);
  1285. FRM.ShowModal;
  1286. finally
  1287. FRM.Free;
  1288. end;
  1289. end;
  1290. procedure TOperationsGrid.UpdateAccountOperations;
  1291. begin
  1292. if Not Assigned(Node) then exit;
  1293. If Assigned(FOperationsGridUpdateThread) then begin
  1294. FOperationsGridUpdateThread.Terminate;
  1295. FOperationsGridUpdateThread.WaitFor;
  1296. FreeAndNil(FOperationsGridUpdateThread);
  1297. end;
  1298. FOperationsGridUpdateThread := TOperationsGridUpdateThread.Create(Self);
  1299. end;
  1300. { TBlockChainGridUpdateThread }
  1301. procedure TBlockChainGridUpdateThread.BCExecute;
  1302. var Llist : TList<TBlockChainData>;
  1303. i : Integer;
  1304. LBlockStart, LBlockEnd : Integer;
  1305. begin
  1306. if (Not Assigned(FBlockChainGrid.Node)) Or (Terminated) then Exit;
  1307. if (FBlockChainGrid.FBlockStart>FBlockChainGrid.FBlockEnd) And (FBlockChainGrid.FBlockStart>=0) then FBlockChainGrid.FBlockEnd := -1;
  1308. if (FBlockChainGrid.FBlockEnd>=0) And (FBlockChainGrid.FBlockEnd<FBlockChainGrid.FBlockStart) then FBlockChainGrid.FBlockStart:=-1;
  1309. if FBlockChainGrid.FBlockStart>(FBlockChainGrid.FNodeNotifyEvents.Node.Bank.BlocksCount-1) then FBlockChainGrid.FBlockStart := -1;
  1310. if (FBlockChainGrid.FBlockEnd>=0) And (FBlockChainGrid.FBlockEnd<FBlockChainGrid.Node.Bank.BlocksCount) then begin
  1311. LBlockEnd := FBlockChainGrid.FBlockEnd
  1312. end else begin
  1313. if (FBlockChainGrid.FBlockStart>=0) And (FBlockChainGrid.FBlockStart+FBlockChainGrid.MaxBlocks<=FBlockChainGrid.Node.Bank.BlocksCount) then LBlockEnd := FBlockChainGrid.FBlockStart + FBlockChainGrid.MaxBlocks - 1
  1314. else LBlockEnd := FBlockChainGrid.Node.Bank.BlocksCount-1;
  1315. end;
  1316. if (FBlockChainGrid.FBlockStart>=0) And (FBlockChainGrid.FBlockStart<FBlockChainGrid.Node.Bank.BlocksCount) then LBlockStart := FBlockChainGrid.FBlockStart
  1317. else begin
  1318. if LBlockEnd>FBlockChainGrid.MaxBlocks then LBlockStart := LBlockEnd - FBlockChainGrid.MaxBlocks + 1
  1319. else LBlockStart := 0;
  1320. end;
  1321. Llist := TList<TBlockChainData>.Create;
  1322. try
  1323. DoUpdateBlockChainGrid(FBlockChainGrid.Node,Llist,LBlockStart,LBlockEnd);
  1324. if (Not Terminated) then begin
  1325. FBlockChainGrid.FBlockChainDataList.clear;
  1326. for i := 0 to Llist.Count-1 do begin
  1327. FBlockChainGrid.FBlockChainDataList.Add(Llist[i]);
  1328. end;
  1329. if Assigned(FBlockChainGrid.DrawGrid) then begin
  1330. if Llist.Count>0 then FGridUpdateCount := Llist.Count+1
  1331. else FGridUpdateCount := 2;
  1332. Queue(RefreshGrid);
  1333. end;
  1334. end;
  1335. finally
  1336. Llist.Free;
  1337. end;
  1338. end;
  1339. procedure TBlockChainGridUpdateThread.RefreshGrid;
  1340. begin
  1341. if not Assigned(FBlockChainGrid) or not Assigned(FBlockChainGrid.DrawGrid)
  1342. then Exit;
  1343. FBlockChainGrid.DrawGrid.RowCount := FGridUpdateCount;
  1344. FBlockChainGrid.FDrawGrid.Invalidate;
  1345. end;
  1346. constructor TBlockChainGridUpdateThread.Create(ABlockChainGrid : TBlockChainGrid);
  1347. begin
  1348. FBlockChainGrid := ABlockChainGrid;
  1349. inherited Create(True);
  1350. FreeOnTerminate := False;
  1351. Suspended := False;
  1352. end;
  1353. procedure TBlockChainGridUpdateThread.DoUpdateBlockChainGrid(ANode: TNode; var AList: TList<TBlockChainData>; ABlockStart, ABlockEnd : Int64);
  1354. Var opc : TPCOperationsComp;
  1355. bcd : TBlockChainData;
  1356. opb : TOperationBlock;
  1357. bn : TBigNum;
  1358. begin
  1359. opc := TPCOperationsComp.Create(Nil);
  1360. try
  1361. opc.bank := ANode.Bank;
  1362. while (ABlockStart<=ABlockEnd) and (Not Terminated) do begin
  1363. bcd := CT_TBlockChainData_NUL;
  1364. opb := ANode.Bank.SafeBox.GetBlockInfo(ABlockEnd);
  1365. bcd.Block:=opb.block;
  1366. bcd.Timestamp := opb.timestamp;
  1367. bcd.BlockProtocolVersion := opb.protocol_version;
  1368. bcd.BlockProtocolAvailable := opb.protocol_available;
  1369. bcd.Reward := opb.reward;
  1370. bcd.Fee := opb.fee;
  1371. bcd.Target := opb.compact_target;
  1372. bn := ANode.Bank.SafeBox.CalcBlockHashRateInHs(bcd.Block,FBlockChainGrid.HashRateAverageBlocksCount);
  1373. try
  1374. bcd.HashRateHs := bn.Value;
  1375. bcd.HashRateKhs := bn.Divide(1000).Value;
  1376. finally
  1377. bn.Free;
  1378. end;
  1379. bn := TBigNum.TargetToHashRate(opb.compact_target);
  1380. Try
  1381. bcd.HashRateTargetHs := bn.Value / (CT_NewLineSecondsAvg);
  1382. bcd.HashRateTargetKhs := bn.Divide(1000).Divide(CT_NewLineSecondsAvg).Value;
  1383. finally
  1384. bn.Free;
  1385. end;
  1386. bcd.MinerPayload := opb.block_payload;
  1387. bcd.PoW := opb.proof_of_work;
  1388. bcd.SafeBoxHash := opb.initial_safe_box_hash;
  1389. if (Not Terminated) then begin
  1390. If (ANode.Bank.LoadOperations(opc,ABlockEnd)) then begin
  1391. bcd.OperationsCount := opc.Count;
  1392. bcd.Volume := opc.OperationsHashTree.TotalAmount + opc.OperationsHashTree.TotalFee;
  1393. end;
  1394. bcd.TimeAverage200:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,200);
  1395. bcd.TimeAverage150:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,150);
  1396. bcd.TimeAverage100:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,100);
  1397. bcd.TimeAverage75:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,75);
  1398. bcd.TimeAverage50:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,50);
  1399. bcd.TimeAverage25:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,25);
  1400. bcd.TimeAverage10:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,10);
  1401. bcd.TimeAverage5:=ANode.Bank.GetTargetSecondsAverage(bcd.Block,5);
  1402. AList.Add(bcd);
  1403. if (ABlockEnd>0) then dec(ABlockEnd) else Break;
  1404. end;
  1405. end;
  1406. finally
  1407. opc.Free;
  1408. end;
  1409. end;
  1410. { TBlockChainGrid }
  1411. constructor TBlockChainGrid.Create(AOwner: TComponent);
  1412. begin
  1413. inherited;
  1414. FBlockStart:=-1;
  1415. FBlockEnd:=-1;
  1416. FMaxBlocks := 300;
  1417. FDrawGrid := Nil;
  1418. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  1419. FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
  1420. FHashRateAverageBlocksCount := 50;
  1421. FBlockChainDataList := TList<TBlockChainData>.Create;
  1422. FShowTimeAverageColumns:=False;
  1423. FHashRateAs:={$IFDEF PRODUCTION}hr_Giga{$ELSE}hr_Mega{$ENDIF};
  1424. FBlockChainGridUpdateThread := Nil;
  1425. end;
  1426. destructor TBlockChainGrid.Destroy;
  1427. begin
  1428. If Assigned(FBlockChainGridUpdateThread) then begin
  1429. FBlockChainGridUpdateThread.Terminate;
  1430. FBlockChainGridUpdateThread.WaitFor;
  1431. FreeAndNil(FBlockChainGridUpdateThread);
  1432. end;
  1433. FNodeNotifyEvents.OnBlocksChanged := Nil;
  1434. FNodeNotifyEvents.Node := Nil;
  1435. FreeAndNil(FNodeNotifyEvents);
  1436. FreeAndNil(FBlockChainDataList);
  1437. inherited;
  1438. end;
  1439. function TBlockChainGrid.GetNode: TNode;
  1440. begin
  1441. Result := FNodeNotifyEvents.Node;
  1442. end;
  1443. procedure TBlockChainGrid.InitGrid;
  1444. begin
  1445. if Not Assigned(FDrawGrid) then exit;
  1446. FDrawGrid.RowCount := 2;
  1447. DrawGrid.FixedRows := 1;
  1448. DrawGrid.DefaultDrawing := true;
  1449. DrawGrid.FixedCols := 0;
  1450. If ShowTimeAverageColumns then DrawGrid.ColCount:=14
  1451. else DrawGrid.ColCount:=12;
  1452. DrawGrid.ColWidths[0] := 50; // Block
  1453. DrawGrid.ColWidths[1] := 110; // Time
  1454. DrawGrid.ColWidths[2] := 30; // Ops
  1455. DrawGrid.ColWidths[3] := 80; // Volume
  1456. DrawGrid.ColWidths[4] := 50; // Reward
  1457. DrawGrid.ColWidths[5] := 50; // Fee
  1458. DrawGrid.ColWidths[6] := 60; // Target
  1459. DrawGrid.ColWidths[7] := 80; // Hash Rate
  1460. DrawGrid.ColWidths[8] := 190; // Miner Payload
  1461. DrawGrid.ColWidths[9] := 190; // PoW
  1462. DrawGrid.ColWidths[10] := 190; // SafeBox Hash
  1463. DrawGrid.ColWidths[11] := 50; // Protocol
  1464. If ShowTimeAverageColumns then begin
  1465. DrawGrid.ColWidths[12] := 55; // Deviation
  1466. DrawGrid.ColWidths[13] := 350; // Time average
  1467. end;
  1468. FDrawGrid.DefaultRowHeight := 18;
  1469. FDrawGrid.Invalidate;
  1470. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  1471. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  1472. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  1473. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  1474. UpdateBlockChainGrid;
  1475. end;
  1476. procedure TBlockChainGrid.Notification(AComponent: TComponent;
  1477. Operation: TOperation);
  1478. begin
  1479. inherited;
  1480. if Operation=opRemove then begin
  1481. if (AComponent=FDrawGrid) then begin
  1482. SetDrawGrid(Nil);
  1483. end;
  1484. end;
  1485. end;
  1486. procedure TBlockChainGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Longint;
  1487. Rect: TRect; State: TGridDrawState);
  1488. Var s : String;
  1489. bcd : TBlockChainData;
  1490. deviation : Real;
  1491. hr_base : Int64;
  1492. begin
  1493. DrawGrid.Canvas.Font.Color:=clWindowText;
  1494. if (ARow=0) then begin
  1495. // Header
  1496. case ACol of
  1497. 0 : s := 'Block';
  1498. 1 : s := 'Time';
  1499. 2 : s := 'Ops';
  1500. 3 : s := 'Volume';
  1501. 4 : s := 'Reward';
  1502. 5 : s := 'Fee';
  1503. 6 : s := 'Target';
  1504. 7 : begin
  1505. case HashRateAs of
  1506. hr_Unit : s := 'h/s';
  1507. hr_Kilo : s := 'Kh/s';
  1508. hr_Mega : s := 'Mh/s';
  1509. hr_Giga : s := 'Gh/s';
  1510. hr_Tera : s := 'Th/s';
  1511. hr_Peta : s := 'Ph/s';
  1512. hr_Exa : s := 'Eh/s';
  1513. else s := '?h/s';
  1514. end;
  1515. end;
  1516. 8 : s := 'Miner Payload';
  1517. 9 : s := 'Proof of Work';
  1518. 10 : s := 'SafeBox Hash';
  1519. 11 : s := 'Protocol';
  1520. 12 : s := 'Deviation';
  1521. 13 : s := 'Time average';
  1522. else s:= '';
  1523. end;
  1524. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  1525. end else begin
  1526. if (gdSelected in State) then
  1527. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  1528. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  1529. else DrawGrid.Canvas.Brush.Color := clWindow;
  1530. DrawGrid.Canvas.FillRect(Rect);
  1531. InflateRect(Rect,-2,-1);
  1532. if ((ARow-1)<FBlockChainDataList.Count) then begin
  1533. bcd := FBlockChainDataList[ARow-1];
  1534. if ACol=0 then begin
  1535. s := IntToStr(bcd.Block);
  1536. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1537. end else if ACol=1 then begin
  1538. s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime((bcd.Timestamp))));
  1539. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1540. end else if ACol=2 then begin
  1541. if bcd.OperationsCount>=0 then begin
  1542. s := IntToStr(bcd.OperationsCount);
  1543. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1544. end else begin
  1545. DrawGrid.Canvas.Font.Color := clGrayText;
  1546. s := '(no data)';
  1547. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1548. end;
  1549. end else if ACol=3 then begin
  1550. if bcd.Volume>=0 then begin
  1551. s := TAccountComp.FormatMoney(bcd.Volume);
  1552. if FBlockChainDataList[ARow-1].Volume>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1553. else DrawGrid.Canvas.Font.Color := clGrayText;
  1554. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1555. end else begin
  1556. DrawGrid.Canvas.Font.Color := clGrayText;
  1557. s := '(no data)';
  1558. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1559. end;
  1560. end else if ACol=4 then begin
  1561. s := TAccountComp.FormatMoney(bcd.Reward);
  1562. if FBlockChainDataList[ARow-1].Reward>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1563. else DrawGrid.Canvas.Font.Color := clGrayText;
  1564. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1565. end else if ACol=5 then begin
  1566. s := TAccountComp.FormatMoney(bcd.Fee);
  1567. if bcd.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1568. else DrawGrid.Canvas.Font.Color := clGrayText;
  1569. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1570. end else if ACol=6 then begin
  1571. s := IntToHex(bcd.Target,8);
  1572. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1573. end else if ACol=7 then begin
  1574. if (HashRateAs = hr_Unit) then begin
  1575. s := Format('%.0n (%.0n)',[bcd.HashRateHs,bcd.HashRateTargetHs]);
  1576. end else if (HashRateAs = hr_Kilo) then begin
  1577. s := Format('%.2n (%.2n)',[bcd.HashRateHs/1000,bcd.HashRateTargetHs/1000]);
  1578. end else begin
  1579. case HashRateAs of
  1580. hr_Kilo : hr_base := 1;
  1581. hr_Mega : hr_base := 1000;
  1582. hr_Giga : hr_base := 1000000;
  1583. hr_Tera : hr_base := 1000000000;
  1584. hr_Peta : hr_base := 1000000000000;
  1585. hr_Exa : hr_base := 1000000000000000;
  1586. else hr_base := 1;
  1587. end;
  1588. s := Format('%.2n (%.2n)',[bcd.HashRateKhs/hr_base,bcd.HashRateTargetKhs/hr_base]);
  1589. end;
  1590. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1591. end else if ACol=8 then begin
  1592. if TCrypto.IsHumanReadable(bcd.MinerPayload) then
  1593. s := TEncoding.ANSI.GetString(bcd.MinerPayload)
  1594. else s := TCrypto.ToHexaString( bcd.MinerPayload );
  1595. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1596. end else if ACol=9 then begin
  1597. s := TCrypto.ToHexaString(bcd.PoW);
  1598. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1599. end else if ACol=10 then begin
  1600. s := TCrypto.ToHexaString(bcd.SafeBoxHash);
  1601. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1602. end else if ACol=11 then begin
  1603. s := Inttostr(bcd.BlockProtocolVersion)+'-'+IntToStr(bcd.BlockProtocolAvailable);
  1604. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1605. end else if ACol=12 then begin
  1606. deviation := ((CT_NewLineSecondsAvg - bcd.TimeAverage100) / CT_NewLineSecondsAvg)*100;
  1607. s := Format('%.2f',[deviation])+' %';
  1608. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1609. end else if ACol=13 then begin
  1610. s := Format('200:%.1f 150:%.1f 100:%.1f 50:%.1f 25:%.1f 10:%.1f 5:%.1f',[bcd.TimeAverage200,
  1611. bcd.TimeAverage150,
  1612. bcd.TimeAverage100,
  1613. bcd.TimeAverage50,
  1614. bcd.TimeAverage25,
  1615. bcd.TimeAverage10,
  1616. bcd.TimeAverage5]);
  1617. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  1618. end;
  1619. end;
  1620. end;
  1621. end;
  1622. procedure TBlockChainGrid.OnNodeNewAccount(Sender: TObject);
  1623. begin
  1624. if FBlockEnd<0 then UpdateBlockChainGrid;
  1625. end;
  1626. procedure TBlockChainGrid.SetBlockEnd(const Value: Int64);
  1627. begin
  1628. if FBlockEnd=Value then exit;
  1629. FBlockEnd := Value;
  1630. UpdateBlockChainGrid;
  1631. end;
  1632. procedure TBlockChainGrid.SetBlocks(bstart, bend: Int64);
  1633. begin
  1634. if (FBlockStart=bstart) And (FBlockEnd=bend) then exit;
  1635. FBlockStart := bstart;
  1636. FBlockEnd := bend;
  1637. UpdateBlockChainGrid;
  1638. end;
  1639. procedure TBlockChainGrid.SetBlockStart(const Value: Int64);
  1640. begin
  1641. If FBlockStart=Value then exit;
  1642. FBlockStart := Value;
  1643. UpdateBlockChainGrid;
  1644. end;
  1645. procedure TBlockChainGrid.SetDrawGrid(const Value: TDrawGrid);
  1646. begin
  1647. if FDrawGrid=Value then exit;
  1648. FDrawGrid := Value;
  1649. if Assigned(Value) then begin
  1650. Value.FreeNotification(self);
  1651. FDrawGrid.OnDrawCell := OnGridDrawCell;
  1652. InitGrid;
  1653. end;
  1654. end;
  1655. procedure TBlockChainGrid.SetHashRateAs(AValue: TShowHashRateAs);
  1656. begin
  1657. if FHashRateAs=AValue then Exit;
  1658. FHashRateAs:=AValue;
  1659. if Assigned(FDrawGrid) then begin
  1660. FDrawGrid.Invalidate;
  1661. end;
  1662. end;
  1663. procedure TBlockChainGrid.SetHashRateAverageBlocksCount(const Value: Integer);
  1664. begin
  1665. if FHashRateAverageBlocksCount=Value then exit;
  1666. FHashRateAverageBlocksCount := Value;
  1667. if FHashRateAverageBlocksCount<1 then FHashRateAverageBlocksCount := 1;
  1668. if FHashRateAverageBlocksCount>1000 then FHashRateAverageBlocksCount := 1000;
  1669. UpdateBlockChainGrid;
  1670. end;
  1671. procedure TBlockChainGrid.SetShowTimeAverageColumns(AValue: Boolean);
  1672. begin
  1673. if FShowTimeAverageColumns=AValue then Exit;
  1674. FShowTimeAverageColumns:=AValue;
  1675. InitGrid;
  1676. end;
  1677. procedure TBlockChainGrid.SetMaxBlocks(const Value: Integer);
  1678. begin
  1679. if FMaxBlocks=Value then exit;
  1680. FMaxBlocks := Value;
  1681. if (FMaxBlocks<=0) Or (FMaxBlocks>500) then FMaxBlocks := 300;
  1682. UpdateBlockChainGrid;
  1683. end;
  1684. procedure TBlockChainGrid.SetNode(const Value: TNode);
  1685. begin
  1686. FNodeNotifyEvents.Node := Value;
  1687. UpdateBlockChainGrid;
  1688. end;
  1689. procedure TBlockChainGrid.UpdateBlockChainGrid;
  1690. begin
  1691. If Assigned(FBlockChainGridUpdateThread) then begin
  1692. FBlockChainGridUpdateThread.Terminate;
  1693. FBlockChainGridUpdateThread.WaitFor;
  1694. FreeAndNil(FBlockChainGridUpdateThread);
  1695. end;
  1696. FBlockChainGridUpdateThread := TBlockChainGridUpdateThread.Create(Self);
  1697. end;
  1698. end.