UDataSources.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. unit UDataSources;
  2. { Copyright (c) 2018 by Herman Schoenfeld
  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. THIS LICENSE HEADER MUST NOT BE REMOVED.
  10. }
  11. {$mode delphi}
  12. {$modeswitch nestedprocvars}
  13. interface
  14. uses
  15. Classes, SysUtils, UAccounts, UNode, UBlockchain, UCrypto, UCoreObjects,
  16. UCommon, UMemory, UConst, UCommon.Data, UCoreUtils, UBaseTypes,
  17. UCommon.Collections, Generics.Collections, Generics.Defaults, syncobjs;
  18. type
  19. { TAccountsDataSourceBase }
  20. TAccountsDataSourceBase = class(TCustomDataSource<TAccount>)
  21. protected
  22. function GetColumns: TDataColumns; override;
  23. public
  24. function GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant; override;
  25. end;
  26. { TAccountsDataSource }
  27. TAccountsDataSource = class(TAccountsDataSourceBase)
  28. protected
  29. FIncludePending: boolean;
  30. FKeys: TSortedHashSet<TAccountKey>;
  31. function GetFilterKeys: TArray<TAccountKey>;
  32. procedure SetFilterKeys(const AKeys: TArray<TAccountKey>);
  33. public
  34. property IncludePending: boolean read FIncludePending write FIncludePending;
  35. property FilterKeys: TArray<TAccountKey> read GetFilterKeys write SetFilterKeys;
  36. constructor Create(AOwner: TComponent); override;
  37. destructor Destroy; override;
  38. procedure FetchAll(const AContainer: TList<TAccount>); override;
  39. end;
  40. { TMyAccountsDataSource }
  41. TMyAccountsDataSource = class(TAccountsDataSource)
  42. private
  43. FPBalanceSummary : PBalanceSummary;
  44. public
  45. property BalancePointer : PBalanceSummary read FPBalanceSummary write FPBalanceSummary;
  46. procedure FetchAll(const AContainer: TList<TAccount>); override;
  47. end;
  48. { TOperationsDataSourceBase }
  49. TOperationsDataSourceBase = class(TCustomDataSource<TOperationResume>)
  50. protected
  51. function GetColumns: TDataColumns; override;
  52. public
  53. function GetItemField(constref AItem: TOperationResume; const ABindingName: ansistring): variant; override;
  54. end;
  55. { TAccountsOperationsDataSource }
  56. TAccountsOperationsDataSource = class(TOperationsDataSourceBase)
  57. private
  58. FBlockDepth: Cardinal;
  59. FAccounts: TArray<cardinal>;
  60. FLastFetchID : String;
  61. FLastFetchBlockOperations : TArray<TOperationResume>;
  62. public
  63. property Accounts: TArray<cardinal> read FAccounts write FAccounts;
  64. property BlockDepth: cardinal read FBlockDepth write FBlockDepth;
  65. procedure FetchAll(const AContainer: TList<TOperationResume>); override;
  66. end;
  67. { TPendingOperationsDataSource }
  68. TPendingOperationsDataSource = class(TOperationsDataSourceBase)
  69. public
  70. procedure FetchAll(const AContainer: TList<TOperationResume>); override;
  71. end;
  72. { TOperationsDataSource }
  73. TOperationsDataSource = class(TOperationsDataSourceBase)
  74. private
  75. FStartBlock, FEndBlock: Cardinal;
  76. public
  77. property StartBlock : Cardinal read FStartBlock write FStartBlock;
  78. property EndBlock : Cardinal read FEndBlock write FEndBlock;
  79. procedure FetchAll(const AContainer: TList<TOperationResume>); override;
  80. end;
  81. { TBlockSummarySourceBase }
  82. TBlockSummarySourceBase = class(TCustomDataSource<TBlockSummary>)
  83. public type
  84. TShowHashRateAs = (hr_Kilo, hr_Mega, hr_Giga, hr_Tera);
  85. private
  86. FStart, FEnd: cardinal;
  87. FHashRateAs: TShowHashRateAs;
  88. FHashRateAverageBlocksCount: integer;
  89. function GetTimeSpan: TTimeSpan;
  90. procedure SetTimeSpan(const ASpan: TTimeSpan);
  91. protected
  92. function GetColumns: TDataColumns; override;
  93. public
  94. constructor Create(AOwner: TComponent); override;
  95. property TimeSpan: TTimeSpan read GetTimeSpan write SetTimeSpan;
  96. property StartBlock: cardinal read FStart write FStart;
  97. property EndBlock: cardinal read FEnd write FEnd;
  98. property HashRateAs: TShowHashRateAs read FHashRateAs write FHashRateAs;
  99. property HashRateAverageBlocksCount: integer read FHashRateAverageBlocksCount write FHashRateAverageBlocksCount;
  100. function GetItemField(constref AItem: TBlockSummary; const ABindingName: ansistring): variant; override;
  101. end;
  102. { TBlockSummarySource }
  103. TBlockSummarySource = class(TBlockSummarySourceBase)
  104. public
  105. procedure FetchAll(const AContainer: TList<TBlockSummary>); override;
  106. end;
  107. implementation
  108. uses
  109. Math, UWallet, UTime;
  110. { TAccountsDataSourceBase }
  111. function TAccountsDataSourceBase.GetColumns: TDataColumns;
  112. begin
  113. Result := TDataColumns.Create(
  114. TDataColumn.From('AccountNumber', True),
  115. TDataColumn.From('Account'),
  116. TDataColumn.From('Name'),
  117. TDataColumn.From('Display'),
  118. TDataColumn.From('Balance'),
  119. TDataColumn.From('BalanceDecimal'),
  120. TDataColumn.From('Key'),
  121. TDataColumn.From('Type'),
  122. TDataColumn.From('State'),
  123. TDataColumn.From('Price'),
  124. TDataColumn.From('PriceDecimal'),
  125. TDataColumn.From('LockedUntil'),
  126. TDataColumn.From('NOperation'),
  127. TDataColumn.From('LastUpdatedBlock')
  128. );
  129. end;
  130. function TAccountsDataSourceBase.GetItemField(constref AItem: TAccount; const ABindingName: ansistring): variant;
  131. var
  132. index: integer;
  133. begin
  134. if ABindingName = 'AccountNumber' then
  135. Result := AItem.account
  136. else if ABindingName = 'Account' then
  137. Result := AItem.AccountString
  138. else if ABindingName = 'Name' then
  139. Result := AItem.Name.ToPrintable
  140. else if ABindingName = 'Display' then
  141. Result := AItem.DisplayString
  142. else if ABindingName = 'Balance' then
  143. Result := AItem.Balance
  144. else if ABindingName = 'BalanceDecimal' then
  145. Result := TAccountComp.FormatMoneyDecimal(AItem.Balance)
  146. else if ABindingName = 'Key' then
  147. Result := TAccountComp.AccountPublicKeyExport(AItem.accountInfo.accountKey)
  148. else if ABindingName = 'Type' then
  149. Result := AItem.account_type
  150. else if ABindingName = 'State' then
  151. Result := AItem.accountInfo.state
  152. else if ABindingName = 'Price' then
  153. Result := AItem.accountInfo.price
  154. else if ABindingName = 'PriceDecimal' then
  155. Result := TAccountComp.FormatMoneyDecimal(AItem.accountInfo.price)
  156. else if ABindingName = 'LockedUntil' then
  157. Result := AItem.accountInfo.locked_until_block
  158. else if ABindingName = 'NOperation' then
  159. Result := AItem.n_operation
  160. else if ABindingName = 'LastUpdatedBlock' then
  161. Result := AItem.updated_block
  162. else
  163. raise Exception.Create(Format('Field not found "%s"', [ABindingName]));
  164. end;
  165. { TAccountsDataSource }
  166. constructor TAccountsDataSource.Create(AOwner: TComponent);
  167. begin
  168. inherited Create(AOwner);
  169. FKeys := TSortedHashSet<TAccountKey>.Create(TAccountKeyComparer.Create, TAccountKeyEqualityComparer.Create);
  170. end;
  171. destructor TAccountsDataSource.Destroy;
  172. begin
  173. FKeys.Free;
  174. end;
  175. function TAccountsDataSource.GetFilterKeys: TArray<TAccountKey>;
  176. begin
  177. EnterLock;
  178. try
  179. Result := FKeys.ToArray;
  180. finally
  181. ReleaseLock;
  182. end;
  183. end;
  184. procedure TAccountsDataSource.SetFilterKeys(const AKeys: TArray<TAccountKey>);
  185. var
  186. i: integer;
  187. begin
  188. EnterLock;
  189. try
  190. FKeys.Clear;
  191. for i := Low(AKeys) to High(AKeys) do
  192. FKeys.Add(AKeys[i]);
  193. finally
  194. ReleaseLock;
  195. end;
  196. end;
  197. procedure TAccountsDataSource.FetchAll(const AContainer: TList<TAccount>);
  198. var
  199. i: integer;
  200. acc: TAccount;
  201. safeBox: TPCSafeBox;
  202. begin
  203. safeBox := TNode.Node.Bank.SafeBox;
  204. safeBox.StartThreadSafe;
  205. try
  206. if FKeys.Count = 0 then
  207. for i := 0 to safeBox.AccountsCount - 1 do
  208. AContainer.Add(safeBox.Account(i)) // Load all accounts
  209. else
  210. for i := 0 to safeBox.AccountsCount - 1 do begin
  211. // Load key-matching accounts
  212. if FIncludePending then
  213. acc := TNode.Node.Operations.SafeBoxTransaction.Account(i)
  214. else
  215. acc := safeBox.Account(i);
  216. if FKeys.Contains(acc.accountInfo.accountKey) then
  217. AContainer.Add(acc);
  218. end;
  219. finally
  220. safeBox.EndThreadSave;
  221. end;
  222. end;
  223. { TMyAccountsDataSource }
  224. procedure TMyAccountsDataSource.FetchAll(const AContainer: TList<TAccount>);
  225. var
  226. i: integer;
  227. LAccs: TArray<TAccount>;
  228. LBalanceSummary : TBalanceSummary;
  229. begin
  230. LAccs := TCoreTool.GetUserAccounts(LBalanceSummary, FIncludePending);
  231. FPBalanceSummary^ := LBalanceSummary;
  232. if FKeys.Count > 0 then begin
  233. for i := Low(LAccs) to High(LAccs) do
  234. if FKeys.Contains(LAccs[i].accountInfo.accountKey) then
  235. AContainer.Add(LAccs[i]);
  236. end else AContainer.AddRange(LAccs);
  237. end;
  238. { TOperationsDataSourceBase }
  239. function TOperationsDataSourceBase.GetColumns: TDataColumns;
  240. begin
  241. Result := TDataColumns.Create(
  242. TDataColumn.From('OPHASH', True),
  243. TDataColumn.From('UnixTime'),
  244. TDataColumn.From('Time'),
  245. TDataColumn.From('Block'),
  246. TDataColumn.From('Index'),
  247. TDataColumn.From('BlockLocation'),
  248. TDataColumn.From('BlockLocationSortable'),
  249. TDataColumn.From('Account'),
  250. TDataColumn.From('AccountNumber'),
  251. TDataColumn.From('Type'),
  252. TDataColumn.From('SubType'),
  253. TDataColumn.From('Amount'),
  254. TDataColumn.From('AmountDecimal'),
  255. TDataColumn.From('Fee'),
  256. TDataColumn.From('FeeDecimal'),
  257. TDataColumn.From('Balance'),
  258. TDataColumn.From('BalanceDecimal'),
  259. TDataColumn.From('Payload'),
  260. TDataColumn.From('Description')
  261. );
  262. end;
  263. function TOperationsDataSourceBase.GetItemField(constref AItem: TOperationResume; const ABindingName: ansistring): variant;
  264. var
  265. index: integer;
  266. begin
  267. if ABindingName = 'OPHASH' then
  268. Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash)
  269. else if ABindingName = 'UnixTime' then
  270. Result := AItem.Time
  271. else if ABindingName = 'Time' then
  272. Result := UnixTimeToLocalStr(AItem.time)
  273. else if ABindingName = 'Block' then
  274. Result := AItem.Block
  275. else if ABindingName = 'Index' then
  276. Result := AItem.NOpInsideBlock
  277. else if ABindingName = 'BlockLocation' then
  278. Result := IIF(AItem.OpType <> CT_PseudoOp_Reward, IntToStr(AItem.Block) + '/' + IntToStr(AItem.NOpInsideBlock + 1), IntToStr(AItem.Block))
  279. else if ABindingName = 'BlockLocationSortable' then
  280. Result := IIF(AItem.OpType <> CT_PseudoOp_Reward, UInt64(AItem.Block) * 4294967296 + UInt32(AItem.NOpInsideBlock), 0) // number pattern = [block][opindex]
  281. else if ABindingName = 'Account' then
  282. Result := TAccountComp.AccountNumberToAccountTxtNumber(AItem.AffectedAccount)
  283. else if ABindingName = 'AccountNumber' then
  284. Result := AItem.AffectedAccount
  285. else if ABindingName = 'Type' then
  286. Result := AItem.OpType
  287. else if ABindingName = 'SubType' then
  288. Result := AItem.OpSubtype
  289. else if ABindingName = 'Amount' then
  290. Result := AItem.Amount
  291. else if ABindingName = 'AmountDecimal' then
  292. Result := TAccountComp.FormatMoneyDecimal(AItem.Amount)
  293. else if ABindingName = 'Fee' then
  294. Result := AItem.Fee
  295. else if ABindingName = 'FeeDecimal' then
  296. Result := TAccountComp.FormatMoneyDecimal(AItem.Fee)
  297. else if ABindingName = 'Balance' then
  298. Result := AItem.Balance
  299. else if ABindingName = 'BalanceDecimal' then
  300. Result := TAccountComp.FormatMoneyDecimal(AItem.Balance)
  301. else if ABindingName = 'Payload' then
  302. Result := AItem.PrintablePayload
  303. else if ABindingName = 'Description' then
  304. Result := AItem.OperationTxt
  305. else
  306. raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
  307. end;
  308. { TAccountsOperationsDataSource }
  309. procedure TAccountsOperationsDataSource.FetchAll(const AContainer: TList<TOperationResume>);
  310. var
  311. LNode: TNode;
  312. LBlockDepth : Integer;
  313. LFetchID : String;
  314. LAccounts : TArray<Cardinal>;
  315. function ComputeFetchID : String;
  316. var LAccFetchID : string;
  317. begin
  318. // note: FAccounts is never empty
  319. LAccFetchID := Length(FAccounts).ToString + FAccounts[Low(FAccounts)].ToString + FAccounts[High(FAccounts)].ToString;
  320. Result := LAccFetchID + FBlockDepth.ToString + TCrypto.ToHexaString(LNode.Bank.SafeBox.SafeBoxHash);
  321. end;
  322. begin
  323. if Length(FAccounts) = 0 then
  324. exit;
  325. LNode := TNode.Node;
  326. if not Assigned(LNode) then
  327. exit;
  328. LBlockDepth := ClipValue(FBlockDepth, 0, LNode.Bank.BlocksCount);
  329. LNode.Bank.SafeBox.StartThreadSafe;
  330. try
  331. AContainer.AddRange( LNode.GetPendingOperationsAffectingAccounts(FAccounts, 0, MaxInt) );
  332. // Performance: only fetch from storage if state/args are different from last call
  333. LFetchID := ComputeFetchID;
  334. if LFetchID <> FLastFetchID then begin
  335. FLastFetchID := LFetchID;
  336. FLastFetchBlockOperations := LNode.GetStoredOperationsAffectingAccounts(FAccounts, LBlockDepth, 0, MaxInt);
  337. end;
  338. AContainer.AddRange( FLastFetchBlockOperations );
  339. finally
  340. LNode.Bank.SafeBox.EndThreadSave;
  341. end;
  342. end;
  343. { TPendingOperationsDataSource }
  344. procedure TPendingOperationsDataSource.FetchAll(const AContainer: TList<TOperationResume>);
  345. var
  346. i: integer;
  347. node: TNode;
  348. Op: TPCOperation;
  349. OPR: TOperationResume;
  350. begin
  351. node := TNode.Node;
  352. if not Assigned(Node) then
  353. exit;
  354. for i := Node.Operations.Count - 1 downto 0 do
  355. begin
  356. Op := Node.Operations.OperationsHashTree.GetOperation(i);
  357. if TPCOperation.OperationToOperationResume(0, Op, False, Op.SignerAccount, OPR) then
  358. begin
  359. OPR.NOpInsideBlock := i;
  360. OPR.Block := Node.Bank.BlocksCount;
  361. OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SignerAccount).balance;
  362. AContainer.Add(OPR);
  363. end;
  364. end;
  365. end;
  366. { TOperationsDataSource }
  367. procedure TOperationsDataSource.FetchAll(const AContainer: TList<TOperationResume>);
  368. var
  369. block, i, j, keyIndex: integer;
  370. OPR: TOperationResume;
  371. blockOps: TPCOperationsComp;
  372. node: TNode;
  373. GC: TDisposables;
  374. begin
  375. node := TNode.Node;
  376. if not Assigned(Node) then
  377. exit;
  378. blockOps := GC.AddObject(TPCOperationsComp.Create(nil)) as TPCOperationsComp;
  379. for block := FEndBlock downto FStartBlock do
  380. begin /// iterate blocks correctly
  381. opr := CT_TOperationResume_NUL;
  382. if (Node.Bank.Storage.LoadBlockChainBlock(blockOps, block)) then begin
  383. AContainer.Add(blockOps.GetMinerRewardPseudoOperation);
  384. // if blockOps.Count = 0 then exit;
  385. for i := blockOps.Count - 1 downto 0 do
  386. if TPCOperation.OperationToOperationResume(block, blockOps.Operation[i], False, blockOps.Operation[i].SignerAccount, opr) then begin
  387. opr.NOpInsideBlock := i;
  388. opr.Block := block;
  389. opr.time := blockOps.OperationBlock.timestamp;
  390. AContainer.Add(opr);
  391. end; // reverse order
  392. end else break;
  393. end;
  394. end;
  395. { TBlockSummarySourceBase }
  396. function TBlockSummarySourceBase.GetTimeSpan: TTimeSpan;
  397. begin
  398. Result := TTimeSpan.FromSeconds(CT_NewLineSecondsAvg * (FEnd - FStart + 1));
  399. end;
  400. procedure TBlockSummarySourceBase.SetTimeSpan(const ASpan: TTimeSpan);
  401. var
  402. LNode: TNode;
  403. begin
  404. LNode := TNode.Node;
  405. if not Assigned(LNode) then
  406. exit;
  407. FEnd := LNode.Bank.BlocksCount - 1;
  408. FStart := ClipValue(FEnd - (ASpan.TotalBlockCount + 1), 0, FEnd);
  409. end;
  410. function TBlockSummarySourceBase.GetColumns: TDataColumns;
  411. var
  412. LHashType: string;
  413. begin
  414. case HashRateAs of
  415. hr_Kilo: LHashType := 'Kh/s';
  416. hr_Mega: LHashType := 'Mh/s';
  417. hr_Giga: LHashType := 'Gh/s';
  418. hr_Tera: LHashType := 'Th/s';
  419. else LHashType := '?h/s';
  420. end;
  421. Result := TDataColumns.Create(
  422. TDataColumn.From('UnixTime'),
  423. TDataColumn.From('Time'),
  424. TDataColumn.From('Block'),
  425. TDataColumn.From('Ops'),
  426. TDataColumn.From(LHashType),
  427. TDataColumn.From('Volume'),
  428. TDataColumn.From('Reward'),
  429. TDataColumn.From('Fee'),
  430. TDataColumn.From('FeeDecimal'),
  431. TDataColumn.From('Target'),
  432. TDataColumn.From('MinerPayload'),
  433. TDataColumn.From('POW'),
  434. TDataColumn.From('SBH'),
  435. TDataColumn.From('Protocol'),
  436. TDataColumn.From('Deviation'),
  437. TDataColumn.From('TimeAverage')
  438. );
  439. end;
  440. constructor TBlockSummarySourceBase.Create(AOwner: TComponent);
  441. var
  442. LNode: TNode;
  443. begin
  444. inherited Create(AOwner);
  445. LNode := TNode.Node;
  446. if Assigned(LNode) then begin
  447. FStart := 0;
  448. FEnd := LNode.Bank.BlocksCount - 1;
  449. end else begin
  450. FStart := 0;
  451. FEnd := 0;
  452. end;
  453. end;
  454. function TBlockSummarySourceBase.GetItemField(constref AItem: TBlockSummary; const ABindingName: ansistring): variant;
  455. var
  456. LHR_Base: int64;
  457. LHashType: string;
  458. LDeviation: double;
  459. begin
  460. case FHashRateAs of
  461. hr_Kilo: LHashType := 'Kh/s';
  462. hr_Mega: LHashType := 'Mh/s';
  463. hr_Giga: LHashType := 'Gh/s';
  464. hr_Tera: LHashType := 'Th/s';
  465. else LHashType := '?h/s';
  466. end;
  467. //if ABindingName = 'UnixTime' then
  468. // Result := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime((AItem.Timestamp))))
  469. //else if ABindingName = 'Time' then
  470. // Result := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime((AItem.Timestamp))))
  471. if ABindingName = 'UnixTime' then
  472. Result := AItem.Timestamp
  473. else if ABindingName = 'Time' then
  474. Result := UnixTimeToLocalStr(AItem.Timestamp)
  475. else if ABindingName = 'Block' then
  476. Result := AItem.Block
  477. else if ABindingName = 'Ops' then
  478. Result := AItem.OperationsCount
  479. else if ABindingName = 'Volume' then
  480. Result := TAccountComp.FormatMoney(AItem.Volume)
  481. else if ABindingName = 'Reward' then
  482. Result := TAccountComp.FormatMoney(AItem.Reward)
  483. else if ABindingName = 'Fee' then
  484. Result := AItem.Fee
  485. else if ABindingName = 'FeeDecimal' then
  486. Result := TAccountComp.FormatMoneyDecimal(AItem.Fee)
  487. else if ABindingName = 'Target' then
  488. Result := IntToHex(AItem.Target, 8)
  489. else if ABindingName = LHashType then begin
  490. case HashRateAs of
  491. hr_Kilo: LHR_Base := 1;
  492. hr_Mega: LHR_Base := 1000;
  493. hr_Giga: LHR_Base := 1000000;
  494. hr_Tera: LHR_Base := 1000000000;
  495. else
  496. Result := 1;
  497. end;
  498. Result := Format('%.2n (%.2n)', [AItem.HashRateKhs / LHR_Base, AItem.HashRateTargetKhs / LHR_Base]);
  499. end else if ABindingName = 'MinerPayload' then begin
  500. if TCrypto.IsHumanReadable(AItem.MinerPayload) then
  501. Result := AItem.MinerPayload
  502. else
  503. Result := TCrypto.ToHexaString(AItem.MinerPayload);
  504. end else if ABindingName = 'POW' then
  505. Result := TCrypto.ToHexaString(AItem.PoW)
  506. else if ABindingName = 'SBH' then
  507. Result := TCrypto.ToHexaString(AItem.SafeBoxHash)
  508. else if ABindingName = 'Protocol' then
  509. Result := IntToStr(AItem.BlockProtocolVersion) + '-' + IntToStr(AItem.BlockProtocolAvailable)
  510. else if ABindingName = 'Deviation' then begin
  511. LDeviation := ((CT_NewLineSecondsAvg - AItem.TimeAverage100) / CT_NewLineSecondsAvg) * 100;
  512. Result := Format('%.2f', [LDeviation]) + ' %';
  513. end else if ABindingName = 'TimeAverage' then
  514. Result := Format('200:%.1f 150:%.1f 100:%.1f 75:%.1f 50:%.1f 25:%.1f 10:%.1f', [AItem.TimeAverage200, AItem.TimeAverage150, AItem.TimeAverage100, AItem.TimeAverage75, AItem.TimeAverage50, AItem.TimeAverage25, AItem.TimeAverage10])
  515. else
  516. raise Exception.Create(Format('Field not found [%s]', [ABindingName]));
  517. end;
  518. { TBlockSummarySource }
  519. procedure TBlockSummarySource.FetchAll(const AContainer: TList<TBlockSummary>);
  520. var
  521. LStart, LEnd, LIdx: cardinal;
  522. LOperationComp: TPCOperationsComp;
  523. LBlockChainData: TBlockSummary;
  524. LOperationBlock: TOperationBlock;
  525. LBigNum: TBigNum;
  526. LNode: TNode;
  527. begin
  528. LNode := TNode.Node;
  529. if not Assigned(LNode) then
  530. Exit;
  531. if LNode.Bank.BlocksCount <= 0 then
  532. Exit;
  533. LEnd := EndBlock;
  534. LStart := StartBlock;
  535. LOperationComp := TPCOperationsComp.Create(nil);
  536. try
  537. LOperationComp.bank := LNode.Bank;
  538. for LIdx := LEnd downto LStart do begin
  539. LBlockChainData := CT_BlockSummary_NUL;
  540. LOperationBlock := LNode.Bank.SafeBox.Block(LIdx).blockchainInfo;
  541. LBlockChainData.Block := LOperationBlock.block;
  542. LBlockChainData.Timestamp := LOperationBlock.timestamp;
  543. LBlockChainData.BlockProtocolVersion := LOperationBlock.protocol_version;
  544. LBlockChainData.BlockProtocolAvailable := LOperationBlock.protocol_available;
  545. LBlockChainData.Reward := LOperationBlock.reward;
  546. LBlockChainData.Fee := LOperationBlock.fee;
  547. LBlockChainData.Target := LOperationBlock.compact_target;
  548. LBlockChainData.HashRateKhs := LNode.Bank.SafeBox.CalcBlockHashRateInKhs(LBlockChainData.Block, HashRateAverageBlocksCount);
  549. LBigNum := TBigNum.TargetToHashRate(LOperationBlock.compact_target);
  550. try
  551. LBlockChainData.HashRateTargetKhs := LBigNum.Divide(1024).Divide(CT_NewLineSecondsAvg).Value;
  552. finally
  553. LBigNum.Free;
  554. end;
  555. LBlockChainData.MinerPayload := LOperationBlock.block_payload;
  556. LBlockChainData.PoW := LOperationBlock.proof_of_work;
  557. LBlockChainData.SafeBoxHash := LOperationBlock.initial_safe_box_hash;
  558. LBlockChainData.AccumulatedWork := LNode.Bank.SafeBox.Block(LBlockChainData.Block).AccumulatedWork;
  559. if (LNode.Bank.LoadOperations(LOperationComp, LIdx)) then begin
  560. LBlockChainData.OperationsCount := LOperationComp.Count;
  561. LBlockChainData.Volume := LOperationComp.OperationsHashTree.TotalAmount + LOperationComp.OperationsHashTree.TotalFee;
  562. end;
  563. LBlockChainData.TimeAverage200 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 200);
  564. LBlockChainData.TimeAverage150 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 150);
  565. LBlockChainData.TimeAverage100 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 100);
  566. LBlockChainData.TimeAverage75 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 75);
  567. LBlockChainData.TimeAverage50 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 50);
  568. LBlockChainData.TimeAverage25 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 25);
  569. LBlockChainData.TimeAverage10 := LNode.Bank.GetTargetSecondsAverage(LBlockChainData.Block, 10);
  570. AContainer.Add(LBlockChainData);
  571. end;
  572. finally
  573. LOperationComp.Free;
  574. end;
  575. end;
  576. end.