UGridUtils.pas 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  1. unit UGridUtils;
  2. {$IFDEF FPC}
  3. {$MODE Delphi}
  4. {$ENDIF}
  5. { Copyright (c) 2016 by Albert Molina
  6. Distributed under the MIT software license, see the accompanying file LICENSE
  7. or visit http://www.opensource.org/licenses/mit-license.php.
  8. This unit is a part of Pascal Coin, a P2P crypto currency without need of
  9. historical operations.
  10. If you like it, consider a donation using BitCoin:
  11. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  12. }
  13. interface
  14. uses
  15. {$IFnDEF FPC}
  16. Windows,
  17. {$ELSE}
  18. LCLIntf, LCLType, LMessages,
  19. {$ENDIF}
  20. Classes, Grids, UNode, UAccounts, UBlockChain, UAppParams,
  21. UWallet, UCrypto, UPoolMining, URPC;
  22. Type
  23. // TAccountsGrid implements a visual integration of TDrawGrid
  24. // to show accounts information
  25. TAccountColumnType = (act_account_number,act_account_key,act_balance,act_updated,act_n_operation,act_updated_state,act_name,act_type,act_saleprice);
  26. TAccountColumn = Record
  27. ColumnType : TAccountColumnType;
  28. width : Integer;
  29. End;
  30. TAccountsGrid = Class(TComponent)
  31. private
  32. FAccountsBalance : Int64;
  33. FAccountsList : TOrderedCardinalList;
  34. FColumns : Array of TAccountColumn;
  35. FDrawGrid : TDrawGrid;
  36. FNodeNotifyEvents : TNodeNotifyEvents;
  37. FShowAllAccounts: Boolean;
  38. FOnUpdated: TNotifyEvent;
  39. FAccountsCount: Integer;
  40. FAllowMultiSelect: Boolean;
  41. procedure SetDrawGrid(const Value: TDrawGrid);
  42. Procedure InitGrid;
  43. Procedure OnNodeNewOperation(Sender : TObject);
  44. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  45. procedure SetNode(const Value: TNode);
  46. function GetNode: TNode;
  47. procedure SetShowAllAccounts(const Value: Boolean);
  48. procedure SetAllowMultiSelect(const Value: Boolean);
  49. protected
  50. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  51. public
  52. Constructor Create(AOwner : TComponent); override;
  53. Destructor Destroy; override;
  54. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  55. Function LockAccountsList : TOrderedCardinalList;
  56. Procedure UnlockAccountsList;
  57. Property Node : TNode read GetNode write SetNode;
  58. Function AccountNumber(GridRow : Integer) : Int64;
  59. Procedure SaveToStream(Stream : TStream);
  60. Procedure LoadFromStream(Stream : TStream);
  61. Property ShowAllAccounts : Boolean read FShowAllAccounts write SetShowAllAccounts;
  62. Property AccountsBalance : Int64 read FAccountsBalance;
  63. Property AccountsCount : Integer read FAccountsCount;
  64. Function MoveRowToAccount(nAccount : Cardinal) : Boolean;
  65. Property OnUpdated : TNotifyEvent read FOnUpdated write FOnUpdated;
  66. Property AllowMultiSelect : Boolean read FAllowMultiSelect write SetAllowMultiSelect;
  67. Function SelectedAccounts(accounts : TOrderedCardinalList) : Integer;
  68. End;
  69. TOperationsGrid = Class(TComponent)
  70. private
  71. FDrawGrid: TDrawGrid;
  72. FAccountNumber: Int64;
  73. FOperationsResume : TOperationsResumeList;
  74. FNodeNotifyEvents : TNodeNotifyEvents;
  75. FPendingOperations: Boolean;
  76. FBlockStart: Int64;
  77. FBlockEnd: Int64;
  78. FMustShowAlwaysAnAccount: Boolean;
  79. Procedure OnNodeNewOperation(Sender : TObject);
  80. Procedure OnNodeNewAccount(Sender : TObject);
  81. Procedure InitGrid;
  82. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  83. procedure SetDrawGrid(const Value: TDrawGrid);
  84. procedure SetAccountNumber(const Value: Int64);
  85. procedure SetNode(const Value: TNode);
  86. function GetNode: TNode;
  87. procedure SetPendingOperations(const Value: Boolean);
  88. procedure SetBlockEnd(const Value: Int64);
  89. procedure SetBlockStart(const Value: Int64);
  90. procedure SetMustShowAlwaysAnAccount(const Value: Boolean);
  91. function GetSelectedOperation : TOperationResume;
  92. protected
  93. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  94. public
  95. property SelectedOperation : TOperationResume read GetSelectedOperation;
  96. Constructor Create(AOwner : TComponent); override;
  97. Destructor Destroy; override;
  98. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  99. Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
  100. Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
  101. Property MustShowAlwaysAnAccount : Boolean read FMustShowAlwaysAnAccount write SetMustShowAlwaysAnAccount;
  102. Property Node : TNode read GetNode write SetNode;
  103. Procedure UpdateAccountOperations; virtual;
  104. Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
  105. Property BlockStart : Int64 read FBlockStart write SetBlockStart;
  106. Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
  107. Procedure SetBlocks(bstart,bend : Int64);
  108. Property OperationsResume : TOperationsResumeList read FOperationsResume;
  109. End;
  110. TBlockChainData = Record
  111. Block : Cardinal;
  112. Timestamp : Cardinal;
  113. BlockProtocolVersion,
  114. BlockProtocolAvailable : Word;
  115. OperationsCount : Integer;
  116. Volume : Int64;
  117. Reward, Fee : Int64;
  118. Target : Cardinal;
  119. HashRateKhs : Int64;
  120. MinerPayload : TRawBytes;
  121. PoW : TRawBytes;
  122. SafeBoxHash : TRawBytes;
  123. AccumulatedWork : UInt64;
  124. TimeAverage200 : Real;
  125. TimeAverage150 : Real;
  126. TimeAverage100 : Real;
  127. TimeAverage75 : Real;
  128. TimeAverage50 : Real;
  129. TimeAverage25 : Real;
  130. TimeAverage10 : Real;
  131. End;
  132. TBlockChainDataArray = Array of TBlockChainData;
  133. { TBlockChainGrid }
  134. TBlockChainGrid = Class(TComponent)
  135. private
  136. FBlockChainDataArray : TBlockChainDataArray;
  137. FBlockStart: Int64;
  138. FMaxBlocks: Integer;
  139. FBlockEnd: Int64;
  140. FDrawGrid: TDrawGrid;
  141. FNodeNotifyEvents : TNodeNotifyEvents;
  142. FHashRateAverageBlocksCount: Integer;
  143. FShowTimeAverageColumns: Boolean;
  144. Procedure OnNodeNewAccount(Sender : TObject);
  145. Procedure InitGrid;
  146. procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
  147. function GetNode: TNode;
  148. procedure SetBlockEnd(const Value: Int64);
  149. procedure SetBlockStart(const Value: Int64);
  150. procedure SetDrawGrid(const Value: TDrawGrid);
  151. procedure SetMaxBlocks(const Value: Integer);
  152. procedure SetNode(const Value: TNode);
  153. procedure SetHashRateAverageBlocksCount(const Value: Integer);
  154. procedure SetShowTimeAverageColumns(AValue: Boolean);
  155. public
  156. protected
  157. procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  158. public
  159. Constructor Create(AOwner : TComponent); override;
  160. Destructor Destroy; override;
  161. Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
  162. Property Node : TNode read GetNode write SetNode;
  163. Procedure UpdateBlockChainGrid; virtual;
  164. Property BlockStart : Int64 read FBlockStart write SetBlockStart;
  165. Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
  166. Procedure SetBlocks(bstart,bend : Int64);
  167. Property MaxBlocks : Integer read FMaxBlocks write SetMaxBlocks;
  168. Property HashRateAverageBlocksCount : Integer read FHashRateAverageBlocksCount write SetHashRateAverageBlocksCount;
  169. Property ShowTimeAverageColumns : Boolean read FShowTimeAverageColumns write SetShowTimeAverageColumns;
  170. End;
  171. Const
  172. CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateKhs:0;MinerPayload:'';PoW:'';SafeBoxHash:'';AccumulatedWork:0;TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0);
  173. implementation
  174. uses
  175. Graphics, SysUtils, UTime, UOpTransaction, UConst,
  176. UFRMPayloadDecoder, ULog;
  177. { TAccountsGrid }
  178. Const CT_ColumnHeader : Array[TAccountColumnType] Of String =
  179. ('Account N.','Key','Balance','Updated','N Op.','S','Name','Type','Price');
  180. function TAccountsGrid.AccountNumber(GridRow: Integer): Int64;
  181. begin
  182. if GridRow<1 then Result := -1
  183. else if FShowAllAccounts then begin
  184. if Assigned(Node) then begin
  185. Result := GridRow-1;
  186. end else Result := -1;
  187. end else if GridRow<=FAccountsList.Count then begin
  188. Result := (FAccountsList.Get(GridRow-1));
  189. end else Result := -1;
  190. end;
  191. constructor TAccountsGrid.Create(AOwner: TComponent);
  192. Var i : Integer;
  193. begin
  194. inherited;
  195. FAllowMultiSelect := false;
  196. FOnUpdated := Nil;
  197. FAccountsBalance := 0;
  198. FAccountsCount := 0;
  199. FShowAllAccounts := false;
  200. FAccountsList := TOrderedCardinalList.Create;
  201. FDrawGrid := Nil;
  202. SetLength(FColumns,7);
  203. FColumns[0].ColumnType := act_account_number;
  204. FColumns[0].width := 65;
  205. FColumns[1].ColumnType := act_name;
  206. FColumns[1].width := 80;
  207. FColumns[2].ColumnType := act_balance;
  208. FColumns[2].width := 80;
  209. FColumns[3].ColumnType := act_n_operation;
  210. FColumns[3].width := 40;
  211. FColumns[4].ColumnType := act_type;
  212. FColumns[4].width := 40;
  213. FColumns[5].ColumnType := act_saleprice;
  214. FColumns[5].width := 45;
  215. FColumns[6].ColumnType := act_updated_state;
  216. FColumns[6].width := 25;
  217. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  218. FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
  219. end;
  220. destructor TAccountsGrid.Destroy;
  221. begin
  222. FNodeNotifyEvents.Free;
  223. FAccountsList.Free;
  224. inherited;
  225. end;
  226. function TAccountsGrid.GetNode: TNode;
  227. begin
  228. Result := FNodeNotifyEvents.Node;
  229. end;
  230. procedure TAccountsGrid.InitGrid;
  231. Var i : Integer;
  232. acc : TAccount;
  233. begin
  234. FAccountsBalance := 0;
  235. FAccountsCount := FAccountsList.Count;
  236. if Not assigned(DrawGrid) then exit;
  237. if FShowAllAccounts then begin
  238. if Assigned(Node) then begin
  239. if Node.Bank.AccountsCount<1 then DrawGrid.RowCount := 2
  240. else DrawGrid.RowCount := Node.Bank.AccountsCount+1;
  241. FAccountsBalance := Node.Bank.SafeBox.TotalBalance;
  242. end else DrawGrid.RowCount := 2;
  243. end else begin
  244. if FAccountsList.Count<1 then DrawGrid.RowCount := 2
  245. else DrawGrid.RowCount := FAccountsList.Count+1;
  246. if Assigned(Node) then begin
  247. for i := 0 to FAccountsList.Count - 1 do begin
  248. acc := Node.Bank.SafeBox.Account( FAccountsList.Get(i) );
  249. inc(FAccountsBalance, acc.balance);
  250. end;
  251. end;
  252. end;
  253. DrawGrid.FixedRows := 1;
  254. if Length(FColumns)=0 then DrawGrid.ColCount := 1
  255. else DrawGrid.ColCount := Length(FColumns);
  256. DrawGrid.FixedCols := 0;
  257. for i := low(FColumns) to high(FColumns) do begin
  258. DrawGrid.ColWidths[i] := FColumns[i].width;
  259. end;
  260. FDrawGrid.DefaultRowHeight := 18;
  261. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  262. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  263. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  264. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  265. if FAllowMultiSelect then DrawGrid.Options := DrawGrid.Options + [goRangeSelect];
  266. FDrawGrid.Invalidate;
  267. if Assigned(FOnUpdated) then FOnUpdated(Self);
  268. end;
  269. procedure TAccountsGrid.LoadFromStream(Stream: TStream);
  270. Var c,i,j : Integer;
  271. begin
  272. if Stream.Read(c,sizeof(c))<sizeof(c) then exit;
  273. if c<=0 then exit;
  274. SetLength(FColumns,c);
  275. for i := 0 to c - 1 do begin
  276. Stream.Read(j,sizeof(j));
  277. if (j>=Integer(Low(TAccountColumnType))) And (j<=Integer(High(TAccountColumnType))) then begin
  278. FColumns[i].ColumnType := TAccountColumnType(j);
  279. end else FColumns[i].ColumnType := act_account_number;
  280. Stream.Read(FColumns[i].width,sizeof(FColumns[i].width));
  281. end;
  282. Stream.Read(j,sizeof(j));
  283. If Assigned(FDrawGrid) then FDrawGrid.Width := j;
  284. Stream.Read(j,sizeof(j));
  285. If Assigned(FDrawGrid) then FDrawGrid.Height := j;
  286. end;
  287. function TAccountsGrid.LockAccountsList: TOrderedCardinalList;
  288. begin
  289. Result := FAccountsList;
  290. end;
  291. function TAccountsGrid.MoveRowToAccount(nAccount: Cardinal): Boolean;
  292. Var oal : TOrderedCardinalList;
  293. idx : Integer;
  294. begin
  295. Result := false;
  296. if Not Assigned(FDrawGrid) then exit;
  297. if Not Assigned(Node) then exit;
  298. if FDrawGrid.RowCount<=1 then exit;
  299. if FShowAllAccounts then begin
  300. If (FDrawGrid.RowCount>nAccount+1) And (nAccount>=0) And (nAccount<Node.Bank.AccountsCount) then begin
  301. FDrawGrid.Row := nAccount+1;
  302. Result := true;
  303. end else begin
  304. FDrawGrid.Row := FDrawGrid.RowCount-1;
  305. end;
  306. end else begin
  307. oal := LockAccountsList;
  308. try
  309. If oal.Find(nAccount,idx) then begin
  310. If FDrawGrid.RowCount>idx+1 then begin
  311. FDrawGrid.Row := idx+1;
  312. Result := true;
  313. end else begin
  314. FDrawGrid.Row := FDrawGrid.RowCount-1;
  315. end;
  316. end else begin
  317. If FDrawGrid.RowCount>idx+1 then begin
  318. FDrawGrid.Row := idx+1;
  319. end else begin
  320. FDrawGrid.Row := FDrawGrid.RowCount-1;
  321. end;
  322. end;
  323. finally
  324. UnlockAccountsList;
  325. end;
  326. end;
  327. end;
  328. procedure TAccountsGrid.Notification(AComponent: TComponent;
  329. Operation: TOperation);
  330. begin
  331. inherited;
  332. if Operation=opRemove then begin
  333. if (AComponent=FDrawGrid) then begin
  334. SetDrawGrid(Nil);
  335. end;
  336. end;
  337. end;
  338. {$IFDEF FPC}
  339. Type
  340. TTextFormats = (tfBottom, tfCalcRect, tfCenter, tfEditControl, tfEndEllipsis,
  341. tfPathEllipsis, tfExpandTabs, tfExternalLeading, tfLeft, tfModifyString,
  342. tfNoClip, tfNoPrefix, tfRight, tfRtlReading, tfSingleLine, tfTop,
  343. tfVerticalCenter, tfWordBreak);
  344. TTextFormat = set of TTextFormats;
  345. Procedure Canvas_TextRect(Canvas : TCanvas; var Rect: TRect; var Text: string; State: TGridDrawState; TextFormat: TTextFormat = []);
  346. Var ts : TTextStyle;
  347. Begin
  348. if (tfRight in TextFormat) then ts.Alignment:=taRightJustify
  349. else if (tfCenter in TextFormat) then ts.Alignment:=taCenter
  350. else ts.Alignment:=taLeftJustify;
  351. if (tfWordBreak in TextFormat) then ts.Wordbreak:=true
  352. else ts.Wordbreak:=false;
  353. if (tfVerticalCenter in TextFormat) then ts.Layout:=tlCenter
  354. else if (tfBottom in TextFormat) then ts.Layout:=tlBottom
  355. else ts.Layout:=tlTop;
  356. ts.Clipping:=Not (tfNoClip in TextFormat);
  357. ts.SingleLine := (tfSingleLine in TextFormat);
  358. ts.Wordbreak:= (tfWordBreak in TextFormat);
  359. ts.EndEllipsis:= (tfEndEllipsis in TextFormat);
  360. ts.ExpandTabs:=false;
  361. ts.Opaque:=false;
  362. ts.ShowPrefix:= not (tfNoPrefix in TextFormat);
  363. ts.SystemFont:=false;
  364. Canvas.TextRect(Rect,Rect.Left,Rect.Top,Text,ts);
  365. end;
  366. {$ELSE}
  367. Procedure Canvas_TextRect(Canvas : TCanvas; var Rect: TRect; var Text: string; State: TGridDrawState; TextFormat: TTextFormat = []);
  368. Begin
  369. Canvas.TextRect(Rect,Text,TextFormat);
  370. end;
  371. {$ENDIF}
  372. procedure TAccountsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
  373. Function FromColorToColor(colorstart,colordest : Integer; step,totalsteps : Integer) : Integer;
  374. var sr,sg,sb,dr,dg,db : Byte;
  375. i : Integer;
  376. begin
  377. i := colorstart;
  378. sr := GetRValue(i);
  379. sg := GetGValue(i);
  380. sb := GetBValue(i);
  381. i := colordest;
  382. dr := GetRValue(i);
  383. dg := GetGValue(i);
  384. db := GetBValue(i);
  385. sr := sr + (((dr-sr) DIV totalsteps)*step);
  386. sg := sg + (((dg-sg) DIV totalsteps)*step);
  387. sb := sb + (((db-sb) DIV totalsteps)*step);
  388. Result :=RGB(sr,sg,sb);
  389. end;
  390. Var C : TAccountColumn;
  391. s : String;
  392. n_acc : Int64;
  393. account : TAccount;
  394. ndiff : Cardinal;
  395. begin
  396. if Not Assigned(Node) then exit;
  397. if (ACol>=0) AND (ACol<length(FColumns)) then begin
  398. C := FColumns[ACol];
  399. end else begin
  400. C.ColumnType := act_account_number;
  401. C.width := -1;
  402. end;
  403. {.$IFDEF FPC}
  404. DrawGrid.Canvas.Font.Color:=clBlack;
  405. {.$ENDIF}
  406. if (ARow=0) then begin
  407. // Header
  408. s := CT_ColumnHeader[C.ColumnType];
  409. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  410. end else begin
  411. n_acc := AccountNumber(ARow);
  412. if (n_acc>=0) then begin
  413. if (n_acc>=Node.Bank.AccountsCount) then account := CT_Account_NUL
  414. else account := Node.Operations.SafeBoxTransaction.Account(n_acc);
  415. ndiff := Node.Bank.BlocksCount - account.updated_block;
  416. if (gdSelected in State) then
  417. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  418. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  419. else DrawGrid.Canvas.Brush.Color := clWindow;
  420. DrawGrid.Canvas.FillRect(Rect);
  421. InflateRect(Rect,-2,-1);
  422. case C.ColumnType of
  423. act_account_number : Begin
  424. s := TAccountComp.AccountNumberToAccountTxtNumber(n_acc);
  425. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  426. End;
  427. act_account_key : Begin
  428. s := Tcrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.accountKey));
  429. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  430. End;
  431. act_balance : Begin
  432. if ndiff=0 then begin
  433. // Pending operation... showing final balance
  434. DrawGrid.Canvas.Font.Color := clBlue;
  435. s := '('+TAccountComp.FormatMoney(account.balance)+')';
  436. end else begin
  437. s := TAccountComp.FormatMoney(account.balance);
  438. if account.balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
  439. else if account.balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
  440. else DrawGrid.Canvas.Font.Color := clRed;
  441. end;
  442. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  443. End;
  444. act_updated : Begin
  445. s := Inttostr(account.updated_block);
  446. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  447. End;
  448. act_n_operation : Begin
  449. s := InttoStr(account.n_operation);
  450. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  451. End;
  452. act_updated_state : Begin
  453. if TAccountComp.IsAccountBlockedByProtocol(account.account,Node.Bank.BlocksCount) then begin
  454. DrawGrid.Canvas.Brush.Color := clRed;
  455. end else if ndiff=0 then begin
  456. DrawGrid.Canvas.Brush.Color := RGB(255,128,0);
  457. end else if ndiff<=8 then begin
  458. DrawGrid.Canvas.Brush.Color := FromColorToColor(RGB(253,250,115),ColorToRGB(clGreen),ndiff-1,8-1);
  459. end else begin
  460. DrawGrid.Canvas.Brush.Color := clGreen;
  461. end;
  462. DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
  463. End;
  464. act_name : Begin
  465. s := account.name;
  466. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  467. end;
  468. act_type : Begin
  469. s := IntToStr(account.account_type);
  470. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  471. end;
  472. act_saleprice : Begin
  473. if TAccountComp.IsAccountForSale(account.accountInfo) then begin
  474. // Show price for sale
  475. s := TAccountComp.FormatMoney(account.accountInfo.price);
  476. if TAccountComp.IsAccountForSaleAcceptingTransactions(account.accountInfo) then begin
  477. if TAccountComp.IsAccountLocked(account.accountInfo,Node.Bank.BlocksCount) then begin
  478. DrawGrid.Canvas.Font.Color := clNavy;
  479. end else begin
  480. DrawGrid.Canvas.Font.Color := clRed;
  481. end;
  482. end else begin
  483. DrawGrid.Canvas.Font.Color := clGrayText
  484. end;
  485. end else s := '';
  486. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  487. end;
  488. else
  489. s := '(???)';
  490. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  491. end;
  492. end;
  493. end;
  494. end;
  495. procedure TAccountsGrid.OnNodeNewOperation(Sender: TObject);
  496. begin
  497. If Assigned(FDrawGrid) then FDrawGrid.Invalidate;
  498. end;
  499. procedure TAccountsGrid.SaveToStream(Stream: TStream);
  500. Var c,i,j : Integer;
  501. begin
  502. c := Length(FColumns);
  503. Stream.Write(c,sizeof(c));
  504. for i := 0 to c - 1 do begin
  505. j := Integer(FColumns[i].ColumnType);
  506. Stream.Write(j,sizeof(j));
  507. if Assigned(FDrawGrid) then begin
  508. FColumns[i].width := FDrawGrid.ColWidths[i];
  509. end;
  510. Stream.Write(FColumns[i].width,sizeof(FColumns[i].width));
  511. end;
  512. j := FDrawGrid.Width;
  513. Stream.Write(j,sizeof(j));
  514. j := FDrawGrid.Height;
  515. Stream.Write(j,sizeof(j));
  516. end;
  517. function TAccountsGrid.SelectedAccounts(accounts: TOrderedCardinalList): Integer;
  518. var i64 : Int64;
  519. i : Integer;
  520. begin
  521. accounts.Clear;
  522. Result := 0;
  523. if not assigned(FDrawGrid) then exit;
  524. if FAllowMultiSelect then begin
  525. for i := FDrawGrid.Selection.Top to FDrawGrid.Selection.Bottom do begin
  526. i64 := AccountNumber(i);
  527. if i64>=0 then accounts.Add(i64);
  528. end;
  529. end;
  530. If accounts.Count=0 then begin
  531. i64 := AccountNumber(DrawGrid.Row);
  532. if i64>=0 then accounts.Add(i64);
  533. end;
  534. Result := accounts.Count;
  535. end;
  536. procedure TAccountsGrid.SetAllowMultiSelect(const Value: Boolean);
  537. begin
  538. FAllowMultiSelect := Value;
  539. InitGrid;
  540. end;
  541. procedure TAccountsGrid.SetDrawGrid(const Value: TDrawGrid);
  542. begin
  543. if FDrawGrid=Value then exit;
  544. FDrawGrid := Value;
  545. if Assigned(Value) then begin
  546. Value.FreeNotification(self);
  547. FDrawGrid.OnDrawCell := OnGridDrawCell;
  548. InitGrid;
  549. end;
  550. end;
  551. procedure TAccountsGrid.SetNode(const Value: TNode);
  552. begin
  553. if GetNode=Value then exit;
  554. FNodeNotifyEvents.Node := Value;
  555. InitGrid;
  556. end;
  557. procedure TAccountsGrid.SetShowAllAccounts(const Value: Boolean);
  558. begin
  559. if FShowAllAccounts=Value then exit;
  560. FShowAllAccounts := Value;
  561. InitGrid;
  562. end;
  563. procedure TAccountsGrid.UnlockAccountsList;
  564. begin
  565. InitGrid;
  566. end;
  567. { TOperationsGrid }
  568. constructor TOperationsGrid.Create(AOwner: TComponent);
  569. begin
  570. FAccountNumber := 0;
  571. FDrawGrid := Nil;
  572. MustShowAlwaysAnAccount := false;
  573. FOperationsResume := TOperationsResumeList.Create;
  574. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  575. FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
  576. FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
  577. FBlockStart := -1;
  578. FBlockEnd := -1;
  579. FPendingOperations := false;
  580. inherited;
  581. end;
  582. destructor TOperationsGrid.Destroy;
  583. begin
  584. FOperationsResume.Free;
  585. FNodeNotifyEvents.Free;
  586. inherited;
  587. end;
  588. function TOperationsGrid.GetNode: TNode;
  589. begin
  590. Result := FNodeNotifyEvents.Node;
  591. end;
  592. procedure TOperationsGrid.InitGrid;
  593. begin
  594. if Not Assigned(FDrawGrid) then exit;
  595. if FOperationsResume.Count>0 then FDrawGrid.RowCount := FOperationsResume.Count+1
  596. else FDrawGrid.RowCount := 2;
  597. DrawGrid.FixedRows := 1;
  598. DrawGrid.DefaultDrawing := true;
  599. DrawGrid.FixedCols := 0;
  600. DrawGrid.ColCount := 8;
  601. DrawGrid.ColWidths[0] := 110; // Time
  602. DrawGrid.ColWidths[1] := 70; // Block/Op
  603. DrawGrid.ColWidths[2] := 60; // Account
  604. DrawGrid.ColWidths[3] := 180; // OpType
  605. DrawGrid.ColWidths[4] := 70; // Amount
  606. DrawGrid.ColWidths[5] := 60; // Operation Fee
  607. DrawGrid.ColWidths[6] := 80; // Balance
  608. DrawGrid.ColWidths[7] := 500; // Payload
  609. FDrawGrid.DefaultRowHeight := 18;
  610. FDrawGrid.Invalidate;
  611. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  612. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  613. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  614. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  615. end;
  616. procedure TOperationsGrid.Notification(AComponent: TComponent; Operation: TOperation);
  617. begin
  618. inherited;
  619. if Operation=opRemove then begin
  620. if (AComponent=FDrawGrid) then begin
  621. SetDrawGrid(Nil);
  622. end;
  623. end;
  624. end;
  625. procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
  626. Var s : String;
  627. opr : TOperationResume;
  628. begin
  629. {.$IFDEF FPC}
  630. DrawGrid.Canvas.Font.Color:=clBlack;
  631. {.$ENDIF}
  632. opr := CT_TOperationResume_NUL;
  633. Try
  634. if (ARow=0) then begin
  635. // Header
  636. case ACol of
  637. 0 : s := 'Time';
  638. 1 : s := 'Block/Op';
  639. 2 : s := 'Account';
  640. 3 : s := 'Operation';
  641. 4 : s := 'Amount';
  642. 5 : s := 'Fee';
  643. 6 : s := 'Balance';
  644. 7 : s := 'Payload';
  645. else s:= '';
  646. end;
  647. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  648. end else begin
  649. if (gdSelected in State) then
  650. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  651. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  652. else DrawGrid.Canvas.Brush.Color := clWindow;
  653. DrawGrid.Canvas.FillRect(Rect);
  654. InflateRect(Rect,-2,-1);
  655. if (ARow<=FOperationsResume.Count) then begin
  656. opr := FOperationsResume.OperationResume[ARow-1];
  657. If (opr.AffectedAccount=opr.SignerAccount) then begin
  658. end else begin
  659. if (gdSelected in State) or (gdFocused in State) then begin
  660. end else DrawGrid.Canvas.font.Color := clGrayText;
  661. end;
  662. if ACol=0 then begin
  663. if opr.time=0 then s := '(Pending)'
  664. else s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(opr.time)));
  665. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  666. end else if ACol=1 then begin
  667. s := Inttostr(opr.Block);
  668. if opr.NOpInsideBlock>=0 then s := s + '/'+Inttostr(opr.NOpInsideBlock+1);
  669. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  670. end else if ACol=2 then begin
  671. s := TAccountComp.AccountNumberToAccountTxtNumber(opr.AffectedAccount);
  672. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  673. end else if ACol=3 then begin
  674. s := opr.OperationTxt;
  675. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  676. end else if ACol=4 then begin
  677. s := TAccountComp.FormatMoney(opr.Amount);
  678. if opr.Amount>0 then DrawGrid.Canvas.Font.Color := ClGreen
  679. else if opr.Amount=0 then DrawGrid.Canvas.Font.Color := clGrayText
  680. else DrawGrid.Canvas.Font.Color := clRed;
  681. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  682. end else if ACol=5 then begin
  683. s := TAccountComp.FormatMoney(opr.Fee);
  684. if opr.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
  685. else if opr.Fee=0 then DrawGrid.Canvas.Font.Color := clGrayText
  686. else DrawGrid.Canvas.Font.Color := clRed;
  687. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  688. end else if ACol=6 then begin
  689. if opr.time=0 then begin
  690. // Pending operation... showing final balance
  691. DrawGrid.Canvas.Font.Color := clBlue;
  692. s := '('+TAccountComp.FormatMoney(opr.Balance)+')';
  693. end else begin
  694. s := TAccountComp.FormatMoney(opr.Balance);
  695. if opr.Balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
  696. else if opr.Balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
  697. else DrawGrid.Canvas.Font.Color := clRed;
  698. end;
  699. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  700. end else if ACol=7 then begin
  701. s := opr.PrintablePayload;
  702. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  703. end else begin
  704. s := '(???)';
  705. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  706. end;
  707. end;
  708. end;
  709. Except
  710. On E:Exception do begin
  711. TLog.NewLog(lterror,Classname,Format('Error at OnGridDrawCell row %d col %d Block %d - %s',[ARow,ACol,opr.Block,E.Message]));
  712. end;
  713. End;
  714. end;
  715. procedure TOperationsGrid.OnNodeNewAccount(Sender: TObject);
  716. begin
  717. If (AccountNumber<0) And (FBlockEnd<0) And (Not FPendingOperations) then UpdateAccountOperations;
  718. end;
  719. procedure TOperationsGrid.OnNodeNewOperation(Sender: TObject);
  720. Var //Op : TPCOperation;
  721. l : TList;
  722. begin
  723. Try
  724. if (AccountNumber<0) then begin
  725. If (FPendingOperations) then UpdateAccountOperations;
  726. end else begin
  727. l := TList.Create;
  728. Try
  729. If Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,l)>0 then begin
  730. if l.IndexOf(TObject(PtrInt(AccountNumber)))>=0 then UpdateAccountOperations;
  731. end;
  732. Finally
  733. l.Free;
  734. End;
  735. end;
  736. Except
  737. On E:Exception do begin
  738. E.message := 'Exception on updating OperationsGrid '+inttostr(AccountNumber)+': '+E.Message;
  739. Raise;
  740. end;
  741. end;
  742. end;
  743. procedure TOperationsGrid.SetAccountNumber(const Value: Int64);
  744. begin
  745. if FAccountNumber=Value then exit;
  746. FAccountNumber := Value;
  747. if FAccountNumber>=0 then FPendingOperations := false;
  748. UpdateAccountOperations;
  749. end;
  750. procedure TOperationsGrid.SetBlockEnd(const Value: Int64);
  751. begin
  752. FBlockEnd := Value;
  753. end;
  754. procedure TOperationsGrid.SetBlocks(bstart, bend: Int64);
  755. begin
  756. if (bstart=FBlockStart) And (bend=FBlockEnd) then exit;
  757. FBlockStart := bstart;
  758. FBlockEnd := bend;
  759. if (FBlockEnd>0) And (FBlockStart>FBlockEnd) then FBlockStart := -1;
  760. FAccountNumber := -1;
  761. FPendingOperations := false;
  762. UpdateAccountOperations;
  763. end;
  764. procedure TOperationsGrid.SetBlockStart(const Value: Int64);
  765. begin
  766. FBlockStart := Value;
  767. end;
  768. procedure TOperationsGrid.SetDrawGrid(const Value: TDrawGrid);
  769. begin
  770. if FDrawGrid=Value then exit;
  771. FDrawGrid := Value;
  772. if Assigned(Value) then begin
  773. Value.FreeNotification(self);
  774. FDrawGrid.OnDrawCell := OnGridDrawCell;
  775. InitGrid;
  776. end;
  777. end;
  778. procedure TOperationsGrid.SetMustShowAlwaysAnAccount(const Value: Boolean);
  779. begin
  780. if FMustShowAlwaysAnAccount=Value then exit;
  781. FMustShowAlwaysAnAccount := Value;
  782. UpdateAccountOperations;
  783. end;
  784. procedure TOperationsGrid.SetNode(const Value: TNode);
  785. begin
  786. if GetNode=Value then exit;
  787. FNodeNotifyEvents.Node := Value;
  788. UpdateAccountOperations; // New Build 1.0.3
  789. end;
  790. procedure TOperationsGrid.SetPendingOperations(const Value: Boolean);
  791. begin
  792. FPendingOperations := Value;
  793. if FPendingOperations then FAccountNumber := -1;
  794. UpdateAccountOperations;
  795. end;
  796. function TOperationsGrid.GetSelectedOperation : TOperationResume;
  797. Var i : Integer;
  798. opr : TOperationResume;
  799. FRM : TFRMPayloadDecoder;
  800. begin
  801. if Not Assigned(FDrawGrid) then exit;
  802. if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then begin
  803. Result := CT_TOperationResume_NUL;
  804. exit;
  805. end;
  806. Result := FOperationsResume.OperationResume[FDrawGrid.Row-1];
  807. end;
  808. procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
  809. Var i : Integer;
  810. opr : TOperationResume;
  811. FRM : TFRMPayloadDecoder;
  812. begin
  813. if Not Assigned(FDrawGrid) then exit;
  814. if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then exit;
  815. opr := FOperationsResume.OperationResume[FDrawGrid.Row-1];
  816. FRM := TFRMPayloadDecoder.Create(FDrawGrid.Owner);
  817. try
  818. FRM.Init(opr,WalletKeys,AppParams);
  819. FRM.ShowModal;
  820. finally
  821. FRM.Free;
  822. end;
  823. end;
  824. procedure TOperationsGrid.UpdateAccountOperations;
  825. Var list : TList;
  826. i,j : Integer;
  827. OPR : TOperationResume;
  828. Op : TPCOperation;
  829. opc : TPCOperationsComp;
  830. bstart,bend : int64;
  831. begin
  832. FOperationsResume.Clear;
  833. Try
  834. if Not Assigned(Node) then exit;
  835. if (MustShowAlwaysAnAccount) And (AccountNumber<0) then exit;
  836. if FPendingOperations then begin
  837. for i := Node.Operations.Count - 1 downto 0 do begin
  838. Op := Node.Operations.OperationsHashTree.GetOperation(i);
  839. If TPCOperation.OperationToOperationResume(0,Op,Op.SignerAccount,OPR) then begin
  840. OPR.NOpInsideBlock := i;
  841. OPR.Block := Node.Bank.BlocksCount;
  842. OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SignerAccount).balance;
  843. FOperationsResume.Add(OPR);
  844. end;
  845. end;
  846. end else begin
  847. if AccountNumber<0 then begin
  848. opc := TPCOperationsComp.Create(Nil);
  849. try
  850. opc.bank := Node.Bank;
  851. If FBlockEnd<0 then begin
  852. If Node.Bank.BlocksCount>0 then bend := Node.Bank.BlocksCount-1
  853. else bend := 0;
  854. end else bend := FBlockEnd;
  855. if FBlockStart<0 then begin
  856. if (bend > 300) then bstart := bend - 300
  857. else bstart := 0;
  858. end else bstart:= FBlockStart;
  859. If bstart<0 then bstart := 0;
  860. if bend>=Node.Bank.BlocksCount then bend:=Node.Bank.BlocksCount;
  861. while (bstart<=bend) do begin
  862. opr := CT_TOperationResume_NUL;
  863. if (Node.Bank.Storage.LoadBlockChainBlock(opc,bend)) then begin
  864. // Reward operation
  865. OPR := CT_TOperationResume_NUL;
  866. OPR.valid := true;
  867. OPR.Block := bend;
  868. OPR.time := opc.OperationBlock.timestamp;
  869. OPR.AffectedAccount := bend * CT_AccountsPerBlock;
  870. OPR.Amount := opc.OperationBlock.reward;
  871. OPR.Fee := opc.OperationBlock.fee;
  872. OPR.Balance := OPR.Amount+OPR.Fee;
  873. OPR.OperationTxt := 'Blockchain reward';
  874. FOperationsResume.Add(OPR);
  875. // Reverse operations inside a block
  876. for i := opc.Count - 1 downto 0 do begin
  877. if TPCOperation.OperationToOperationResume(bend,opc.Operation[i],opc.Operation[i].SignerAccount,opr) then begin
  878. opr.NOpInsideBlock := i;
  879. opr.Block := bend;
  880. opr.time := opc.OperationBlock.timestamp;
  881. FOperationsResume.Add(opr);
  882. end;
  883. end;
  884. end else break;
  885. dec(bend);
  886. end;
  887. finally
  888. opc.Free;
  889. end;
  890. end else begin
  891. list := TList.Create;
  892. Try
  893. Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
  894. for i := list.Count - 1 downto 0 do begin
  895. Op := Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
  896. If TPCOperation.OperationToOperationResume(0,Op,AccountNumber,OPR) then begin
  897. OPR.NOpInsideBlock := i;
  898. OPR.Block := Node.Operations.OperationBlock.block;
  899. OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
  900. FOperationsResume.Add(OPR);
  901. end;
  902. end;
  903. Finally
  904. list.Free;
  905. End;
  906. Node.GetStoredOperationsFromAccount(FOperationsResume,AccountNumber,100,0,5000);
  907. end;
  908. end;
  909. Finally
  910. InitGrid;
  911. End;
  912. end;
  913. { TBlockChainGrid }
  914. constructor TBlockChainGrid.Create(AOwner: TComponent);
  915. begin
  916. inherited;
  917. FBlockStart:=-1;
  918. FBlockEnd:=-1;
  919. FMaxBlocks := 300;
  920. FDrawGrid := Nil;
  921. FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
  922. FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
  923. FHashRateAverageBlocksCount := 50;
  924. SetLength(FBlockChainDataArray,0);
  925. FShowTimeAverageColumns:=False;
  926. end;
  927. destructor TBlockChainGrid.Destroy;
  928. begin
  929. FNodeNotifyEvents.OnBlocksChanged := Nil;
  930. FNodeNotifyEvents.Node := Nil;
  931. FreeAndNil(FNodeNotifyEvents);
  932. inherited;
  933. end;
  934. function TBlockChainGrid.GetNode: TNode;
  935. begin
  936. Result := FNodeNotifyEvents.Node;
  937. end;
  938. procedure TBlockChainGrid.InitGrid;
  939. begin
  940. if Not Assigned(FDrawGrid) then exit;
  941. FDrawGrid.RowCount := 2;
  942. DrawGrid.FixedRows := 1;
  943. DrawGrid.DefaultDrawing := true;
  944. DrawGrid.FixedCols := 0;
  945. If ShowTimeAverageColumns then DrawGrid.ColCount:=15
  946. else DrawGrid.ColCount:=12;
  947. DrawGrid.ColWidths[0] := 50; // Block
  948. DrawGrid.ColWidths[1] := 110; // Time
  949. DrawGrid.ColWidths[2] := 30; // Ops
  950. DrawGrid.ColWidths[3] := 80; // Volume
  951. DrawGrid.ColWidths[4] := 50; // Reward
  952. DrawGrid.ColWidths[5] := 50; // Fee
  953. DrawGrid.ColWidths[6] := 60; // Target
  954. DrawGrid.ColWidths[7] := 80; // Hash Rate
  955. DrawGrid.ColWidths[8] := 190; // Miner Payload
  956. DrawGrid.ColWidths[9] := 190; // PoW
  957. DrawGrid.ColWidths[10] := 190; // SafeBox Hash
  958. DrawGrid.ColWidths[11] := 50; // Protocol
  959. If ShowTimeAverageColumns then begin
  960. DrawGrid.ColWidths[12] := 95; // Accumulated work
  961. DrawGrid.ColWidths[13] := 55; // Deviation
  962. DrawGrid.ColWidths[14] := 340; // Time average
  963. end;
  964. FDrawGrid.DefaultRowHeight := 18;
  965. FDrawGrid.Invalidate;
  966. DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  967. {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
  968. {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
  969. goThumbTracking{$IFnDEF FPC}, goFixedColClick, goFixedRowClick, goFixedHotTrack{$ENDIF}];
  970. UpdateBlockChainGrid;
  971. end;
  972. procedure TBlockChainGrid.Notification(AComponent: TComponent;
  973. Operation: TOperation);
  974. begin
  975. inherited;
  976. if Operation=opRemove then begin
  977. if (AComponent=FDrawGrid) then begin
  978. SetDrawGrid(Nil);
  979. end;
  980. end;
  981. end;
  982. procedure TBlockChainGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Longint;
  983. Rect: TRect; State: TGridDrawState);
  984. Var s : String;
  985. bcd : TBlockChainData;
  986. deviation : Real;
  987. begin
  988. {.$IFDEF FPC}
  989. DrawGrid.Canvas.Font.Color:=clBlack;
  990. {.$ENDIF}
  991. if (ARow=0) then begin
  992. // Header
  993. case ACol of
  994. 0 : s := 'Block';
  995. 1 : s := 'Time';
  996. 2 : s := 'Ops';
  997. 3 : s := 'Volume';
  998. 4 : s := 'Reward';
  999. 5 : s := 'Fee';
  1000. 6 : s := 'Target';
  1001. 7 : s := 'Mh/s';
  1002. 8 : s := 'Miner Payload';
  1003. 9 : s := 'Proof of Work';
  1004. 10 : s := 'SafeBox Hash';
  1005. 11 : s := 'Protocol';
  1006. 12 : s := 'Acc.Work';
  1007. 13 : s := 'Deviation';
  1008. 14 : s := 'Time average';
  1009. else s:= '';
  1010. end;
  1011. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
  1012. end else begin
  1013. if (gdSelected in State) then
  1014. If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
  1015. else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
  1016. else DrawGrid.Canvas.Brush.Color := clWindow;
  1017. DrawGrid.Canvas.FillRect(Rect);
  1018. InflateRect(Rect,-2,-1);
  1019. if ((ARow-1)<=High(FBlockChainDataArray)) then begin
  1020. bcd := FBlockChainDataArray[ARow-1];
  1021. if ACol=0 then begin
  1022. s := IntToStr(bcd.Block);
  1023. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1024. end else if ACol=1 then begin
  1025. s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime((bcd.Timestamp))));
  1026. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfleft,tfVerticalCenter,tfSingleLine]);
  1027. end else if ACol=2 then begin
  1028. if bcd.OperationsCount>=0 then begin
  1029. s := IntToStr(bcd.OperationsCount);
  1030. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1031. end else begin
  1032. DrawGrid.Canvas.Font.Color := clGrayText;
  1033. s := '(no data)';
  1034. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1035. end;
  1036. end else if ACol=3 then begin
  1037. if bcd.Volume>=0 then begin
  1038. s := TAccountComp.FormatMoney(bcd.Volume);
  1039. if FBlockChainDataArray[ARow-1].Volume>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1040. else DrawGrid.Canvas.Font.Color := clGrayText;
  1041. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1042. end else begin
  1043. DrawGrid.Canvas.Font.Color := clGrayText;
  1044. s := '(no data)';
  1045. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1046. end;
  1047. end else if ACol=4 then begin
  1048. s := TAccountComp.FormatMoney(bcd.Reward);
  1049. if FBlockChainDataArray[ARow-1].Reward>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1050. else DrawGrid.Canvas.Font.Color := clGrayText;
  1051. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1052. end else if ACol=5 then begin
  1053. s := TAccountComp.FormatMoney(bcd.Fee);
  1054. if bcd.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
  1055. else DrawGrid.Canvas.Font.Color := clGrayText;
  1056. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1057. end else if ACol=6 then begin
  1058. s := IntToHex(bcd.Target,8);
  1059. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1060. end else if ACol=7 then begin
  1061. s := Format('%.2n',[bcd.HashRateKhs/1024]);
  1062. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1063. end else if ACol=8 then begin
  1064. if TCrypto.IsHumanReadable(bcd.MinerPayload) then
  1065. s := bcd.MinerPayload
  1066. else s := TCrypto.ToHexaString( bcd.MinerPayload );
  1067. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1068. end else if ACol=9 then begin
  1069. s := TCrypto.ToHexaString(bcd.PoW);
  1070. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1071. end else if ACol=10 then begin
  1072. s := TCrypto.ToHexaString(bcd.SafeBoxHash);
  1073. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
  1074. end else if ACol=11 then begin
  1075. s := Inttostr(bcd.BlockProtocolVersion)+'-'+IntToStr(bcd.BlockProtocolAvailable);
  1076. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1077. end else if ACol=12 then begin
  1078. if bcd.AccumulatedWork>0 then begin
  1079. s := Inttostr(bcd.AccumulatedWork);
  1080. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
  1081. end else begin
  1082. DrawGrid.Canvas.Font.Color := clGrayText;
  1083. s := '(no data)';
  1084. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
  1085. end;
  1086. end else if ACol=13 then begin
  1087. deviation := ((CT_NewLineSecondsAvg - bcd.TimeAverage100) / CT_NewLineSecondsAvg)*100;
  1088. s := Format('%.2f',[deviation])+' %';
  1089. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
  1090. end else if ACol=14 then begin
  1091. s := Format('200:%.1f 150:%.1f 100:%.1f 75:%.1f 50:%.1f 25:%.1f 10:%.1f',[bcd.TimeAverage200,
  1092. bcd.TimeAverage150,bcd.TimeAverage100,bcd.TimeAverage75,bcd.TimeAverage50,bcd.TimeAverage25,bcd.TimeAverage10]);
  1093. Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
  1094. end;
  1095. end;
  1096. end;
  1097. end;
  1098. procedure TBlockChainGrid.OnNodeNewAccount(Sender: TObject);
  1099. begin
  1100. if FBlockEnd<0 then UpdateBlockChainGrid;
  1101. end;
  1102. procedure TBlockChainGrid.SetBlockEnd(const Value: Int64);
  1103. begin
  1104. if FBlockEnd=Value then exit;
  1105. FBlockEnd := Value;
  1106. UpdateBlockChainGrid;
  1107. end;
  1108. procedure TBlockChainGrid.SetBlocks(bstart, bend: Int64);
  1109. begin
  1110. if (FBlockStart=bstart) And (FBlockEnd=bend) then exit;
  1111. FBlockStart := bstart;
  1112. FBlockEnd := bend;
  1113. UpdateBlockChainGrid;
  1114. end;
  1115. procedure TBlockChainGrid.SetBlockStart(const Value: Int64);
  1116. begin
  1117. If FBlockStart=Value then exit;
  1118. FBlockStart := Value;
  1119. UpdateBlockChainGrid;
  1120. end;
  1121. procedure TBlockChainGrid.SetDrawGrid(const Value: TDrawGrid);
  1122. begin
  1123. if FDrawGrid=Value then exit;
  1124. FDrawGrid := Value;
  1125. if Assigned(Value) then begin
  1126. Value.FreeNotification(self);
  1127. FDrawGrid.OnDrawCell := OnGridDrawCell;
  1128. InitGrid;
  1129. end;
  1130. end;
  1131. procedure TBlockChainGrid.SetHashRateAverageBlocksCount(const Value: Integer);
  1132. begin
  1133. if FHashRateAverageBlocksCount=Value then exit;
  1134. FHashRateAverageBlocksCount := Value;
  1135. if FHashRateAverageBlocksCount<1 then FHashRateAverageBlocksCount := 1;
  1136. if FHashRateAverageBlocksCount>1000 then FHashRateAverageBlocksCount := 1000;
  1137. UpdateBlockChainGrid;
  1138. end;
  1139. procedure TBlockChainGrid.SetShowTimeAverageColumns(AValue: Boolean);
  1140. begin
  1141. if FShowTimeAverageColumns=AValue then Exit;
  1142. FShowTimeAverageColumns:=AValue;
  1143. InitGrid;
  1144. end;
  1145. procedure TBlockChainGrid.SetMaxBlocks(const Value: Integer);
  1146. begin
  1147. if FMaxBlocks=Value then exit;
  1148. FMaxBlocks := Value;
  1149. if (FMaxBlocks<=0) Or (FMaxBlocks>500) then FMaxBlocks := 300;
  1150. UpdateBlockChainGrid;
  1151. end;
  1152. procedure TBlockChainGrid.SetNode(const Value: TNode);
  1153. begin
  1154. FNodeNotifyEvents.Node := Value;
  1155. UpdateBlockChainGrid;
  1156. end;
  1157. procedure TBlockChainGrid.UpdateBlockChainGrid;
  1158. Var nstart,nend : Cardinal;
  1159. opc : TPCOperationsComp;
  1160. bcd : TBlockChainData;
  1161. i : Integer;
  1162. opb : TOperationBlock;
  1163. begin
  1164. if (FBlockStart>FBlockEnd) And (FBlockStart>=0) then FBlockEnd := -1;
  1165. if (FBlockEnd>=0) And (FBlockEnd<FBlockStart) then FBlockStart:=-1;
  1166. if Not Assigned(FNodeNotifyEvents.Node) then exit;
  1167. if FBlockStart>(FNodeNotifyEvents.Node.Bank.BlocksCount-1) then FBlockStart := -1;
  1168. try
  1169. if Node.Bank.BlocksCount<=0 then begin
  1170. SetLength(FBlockChainDataArray,0);
  1171. exit;
  1172. end;
  1173. if (FBlockEnd>=0) And (FBlockEnd<Node.Bank.BlocksCount) then begin
  1174. nend := FBlockEnd
  1175. end else begin
  1176. if (FBlockStart>=0) And (FBlockStart+MaxBlocks<=Node.Bank.BlocksCount) then nend := FBlockStart + MaxBlocks - 1
  1177. else nend := Node.Bank.BlocksCount-1;
  1178. end;
  1179. if (FBlockStart>=0) And (FBlockStart<Node.Bank.BlocksCount) then nstart := FBlockStart
  1180. else begin
  1181. if nend>MaxBlocks then nstart := nend - MaxBlocks + 1
  1182. else nstart := 0;
  1183. end;
  1184. SetLength(FBlockChainDataArray,nend - nstart +1);
  1185. opc := TPCOperationsComp.Create(Nil);
  1186. try
  1187. opc.bank := Node.Bank;
  1188. while (nstart<=nend) do begin
  1189. i := length(FBlockChainDataArray) - (nend-nstart+1);
  1190. bcd := CT_TBlockChainData_NUL;
  1191. opb := Node.Bank.SafeBox.Block(nend).blockchainInfo;
  1192. bcd.Block:=opb.block;
  1193. bcd.Timestamp := opb.timestamp;
  1194. bcd.BlockProtocolVersion := opb.protocol_version;
  1195. bcd.BlockProtocolAvailable := opb.protocol_available;
  1196. bcd.Reward := opb.reward;
  1197. bcd.Fee := opb.fee;
  1198. bcd.Target := opb.compact_target;
  1199. bcd.HashRateKhs := Node.Bank.SafeBox.CalcBlockHashRateInKhs(bcd.Block,HashRateAverageBlocksCount);
  1200. bcd.MinerPayload := opb.block_payload;
  1201. bcd.PoW := opb.proof_of_work;
  1202. bcd.SafeBoxHash := opb.initial_safe_box_hash;
  1203. bcd.AccumulatedWork := Node.Bank.SafeBox.Block(bcd.Block).AccumulatedWork;
  1204. if (Node.Bank.LoadOperations(opc,nend)) then begin
  1205. bcd.OperationsCount := opc.Count;
  1206. bcd.Volume := opc.OperationsHashTree.TotalAmount + opc.OperationsHashTree.TotalFee;
  1207. end;
  1208. bcd.TimeAverage200:=Node.Bank.GetTargetSecondsAverage(bcd.Block,200);
  1209. bcd.TimeAverage150:=Node.Bank.GetTargetSecondsAverage(bcd.Block,150);
  1210. bcd.TimeAverage100:=Node.Bank.GetTargetSecondsAverage(bcd.Block,100);
  1211. bcd.TimeAverage75:=Node.Bank.GetTargetSecondsAverage(bcd.Block,75);
  1212. bcd.TimeAverage50:=Node.Bank.GetTargetSecondsAverage(bcd.Block,50);
  1213. bcd.TimeAverage25:=Node.Bank.GetTargetSecondsAverage(bcd.Block,25);
  1214. bcd.TimeAverage10:=Node.Bank.GetTargetSecondsAverage(bcd.Block,10);
  1215. FBlockChainDataArray[i] := bcd;
  1216. if (nend>0) then dec(nend) else break;
  1217. end;
  1218. finally
  1219. opc.Free;
  1220. end;
  1221. finally
  1222. if Assigned(FDrawGrid) then begin
  1223. if Length(FBlockChainDataArray)>0 then FDrawGrid.RowCount := length(FBlockChainDataArray)+1
  1224. else FDrawGrid.RowCount := 2;
  1225. FDrawGrid.Invalidate;
  1226. end;
  1227. end;
  1228. end;
  1229. end.