浏览代码

Build 1.2

PascalCoin 8 年之前
父节点
当前提交
3f37623e42

+ 0 - 91
PascalCoinServer.dpr

@@ -1,91 +0,0 @@
-program PascalCoinServer;
-
-{$APPTYPE CONSOLE}
-
-uses
-  SysUtils,
-  SyncObjs,
-  UAES in 'Units\PascalCoin\UAES.pas',
-  UCrypto in 'Units\PascalCoin\UCrypto.pas',
-  UConst in 'Units\PascalCoin\UConst.pas',
-  ULog in 'Units\PascalCoin\ULog.pas',
-  UServerApp in 'Units\PascalCoin\UServerApp.pas',
-  UAccounts in 'Units\PascalCoin\UAccounts.pas',
-  UBlockChain in 'Units\PascalCoin\UBlockChain.pas',
-  UECIES in 'Units\PascalCoin\UECIES.pas',
-  UFileStorage in 'Units\PascalCoin\UFileStorage.pas',
-  UNetProtocol in 'Units\PascalCoin\UNetProtocol.pas',
-  UNode in 'Units\PascalCoin\UNode.pas',
-  UOpenSSL in 'Units\PascalCoin\UOpenSSL.pas',
-  UOpenSSLdef in 'Units\PascalCoin\UOpenSSLdef.pas',
-  UOpTransaction in 'Units\PascalCoin\UOpTransaction.pas',
-  URPC in 'Units\PascalCoin\URPC.pas',
-  UTCPIP in 'Units\PascalCoin\UTCPIP.pas',
-  UThread in 'Units\PascalCoin\UThread.pas',
-  UTime in 'Units\PascalCoin\UTime.pas',
-  UWalletKeys in 'Units\PascalCoin\UWalletKeys.pas',
-  UMiner in 'Units\PascalCoin\UMiner.pas',
-  UFolderHelper in 'Units\Utils\UFolderHelper.pas',
-  UJSONFunctions in 'Units\Utils\UJSONFunctions.pas';
-
-type
-  TOutputLogger = class
-  protected
-    FLock : TCriticalSection;
-    procedure ServerAppLog(LogType: TPascalCoinServerLogType;
-      Msg: String; Level: Integer);
-  public
-    constructor Create;
-    destructor Destroy; override;
-  end;
-
-constructor TOutputLogger.Create;
-begin
-  inherited Create;
-  FLock := TCriticalSection.Create;
-end;
-
-destructor TOutputLogger.Destroy;
-begin
-  FreeAndNil(FLock);
-  inherited Destroy;
-end;
-
-procedure TOutputLogger.ServerAppLog(LogType: TPascalCoinServerLogType;
-          Msg: String; Level: Integer);
-var
-  M : String;
-begin
-  FLock.Acquire;
-  try
-    M := FormatDateTime('hhnnss.zzz', Now) + ' ' + Msg;
-    Writeln(M);
-  finally
-    FLock.Release;
-  end;
-end;
-
-var
-  OutputLogger : TOutputLogger = nil;
-
-begin
-  try
-    OutputLogger := TOutputLogger.Create;
-    try
-      ServerApp := TPascalCoinServerApp.Create;
-      try
-        ServerApp.OnLog := OutputLogger.ServerAppLog;
-        ServerApp.Init;
-        ServerApp.Run;
-        ServerApp.Stop;
-      finally
-        FreeAndNil(ServerApp);
-      end;
-    finally
-      FreeAndNil(OutputLogger);
-    end;
-  except
-    on E: Exception do
-      Writeln('Fatal error:', E.ClassName, ': ', E.Message);
-  end;
-end.

二进制
PascalCoinWallet.res


+ 13 - 0
README.md

@@ -34,6 +34,19 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.2.0.0 - 2016-11-16
+
+- Account checksum values modified to be more easy and more distributed: Checksum = ((N * 101) MOD 89)+10
+- Allow find operations by "ophash"
+- Show Operation "ophash" in operation payload decoder
+- Added param "enc_pubkey" to "getwalletaccounts" JSON-RPC method to return only accounts from this public key
+- Added params "pow" and "sbh" to "nodestatus" JSON-RPC method
+- Added method "getwalletaccountscount" returning accounts count of the entire wallet or for a single "enc_pubkey"
+- Added method "getwalletcoins" returning coins of the entire wallet or for a signle "enc_pubkey"
+- Modified seed nodes distribution to send only checked IP nodes
+- Corrected invalid operation block index when showing account operations
+
+
 ### Build 1.1.0.0 - 2016-11-03
 
 - JSON-RPC Server included

+ 13 - 0
README.txt

@@ -34,6 +34,19 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.2.0.0 - 2016-11-16
+
+- Account checksum values modified to be more easy and more distributed: Checksum = ((N * 101) MOD 89)+10
+- Allow find operations by "ophash"
+- Show Operation "ophash" in operation payload decoder
+- Added param "enc_pubkey" to "getwalletaccounts" JSON-RPC method to return only accounts from this public key
+- Added params "pow" and "sbh" to "nodestatus" JSON-RPC method
+- Added method "getwalletaccountscount" returning accounts count of the entire wallet or for a single "enc_pubkey"
+- Added method "getwalletcoins" returning coins of the entire wallet or for a signle "enc_pubkey"
+- Modified seed nodes distribution to send only checked IP nodes
+- Corrected invalid operation block index when showing account operations
+
+
 ### Build 1.1.0.0 - 2016-11-03
 
 - JSON-RPC Server included

+ 1 - 1
Units/Forms/UFRMNodesIp.pas

@@ -112,7 +112,7 @@ begin
     TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
   end else begin
     cbTryOnlyWithThisServers.Checked := false;
-    nsarr := TNetData.NetData.GetValidNodeServers;
+    nsarr := TNetData.NetData.GetValidNodeServers(false);
   end;
   for i := low(nsarr) to high(nsarr) do begin
     aux := nsarr[i].ip;

+ 4 - 3
Units/Forms/UFRMOperation.pas

@@ -27,7 +27,7 @@ uses
 {$ENDIF}
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UNode, UWalletKeys, UCrypto, Buttons, UBlockChain,
-  UAccounts, ActnList, ComCtrls;
+  UAccounts, ActnList, ComCtrls, Types;
 
 type
 
@@ -594,15 +594,16 @@ begin
       lblGlobalErrors.Caption := '';
     Finally
       if lblGlobalErrors.Caption<>'' then begin
-        PageControl.ActivePage := tsGlobalError;
         tsGlobalError.visible := true;
         tsGlobalError.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
         tsOperation.TabVisible := false;
+        PageControl.ActivePage := tsGlobalError;
+        ActiveControl := bbPassword;
       end else begin
-        PageControl.ActivePage := tsOperation;
         tsOperation.visible := true;
         tsOperation.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
         tsGlobalError.TabVisible := false;
+        PageControl.ActivePage := tsOperation;
       end;
     End;
     if rbTransaction.Checked then begin

+ 184 - 32
Units/Forms/UFRMPayloadDecoder.dfm

@@ -1,11 +1,12 @@
 object FRMPayloadDecoder: TFRMPayloadDecoder
   Left = 0
   Top = 0
+  ActiveControl = ebOphash
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
-  Caption = 'Payload Decoder'
-  ClientHeight = 360
-  ClientWidth = 569
+  Caption = 'Operation Information/Decoder'
+  ClientHeight = 406
+  ClientWidth = 674
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
@@ -19,17 +20,17 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
   TextHeight = 13
   object Label1: TLabel
     Left = 20
-    Top = 20
-    Width = 28
+    Top = 56
+    Width = 46
     Height = 13
-    Caption = 'Block:'
+    Caption = 'Block/Op:'
   end
   object lblBlock: TLabel
-    Left = 54
-    Top = 15
-    Width = 30
+    Left = 72
+    Top = 51
+    Width = 109
     Height = 19
-    Caption = '000'
+    Caption = '000000/0000'
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
@@ -38,8 +39,8 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     ParentFont = False
   end
   object lblDateTime: TLabel
-    Left = 169
-    Top = 15
+    Left = 255
+    Top = 51
     Width = 30
     Height = 19
     Caption = '000'
@@ -51,24 +52,24 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     ParentFont = False
   end
   object Label6: TLabel
-    Left = 111
-    Top = 20
+    Left = 195
+    Top = 56
     Width = 52
     Height = 13
     Caption = 'Date Time:'
   end
   object Label2: TLabel
     Left = 20
-    Top = 45
+    Top = 106
     Width = 52
     Height = 13
     Caption = 'Operation:'
   end
   object lblOperationTxt: TLabel
     Left = 90
-    Top = 40
-    Width = 457
-    Height = 39
+    Top = 101
+    Width = 561
+    Height = 22
     AutoSize = False
     Caption = '000'
     Font.Charset = DEFAULT_CHARSET
@@ -79,13 +80,113 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     ParentFont = False
     WordWrap = True
   end
+  object lblAmountCaption: TLabel
+    Left = 220
+    Top = 81
+    Width = 41
+    Height = 13
+    Caption = 'Amount:'
+  end
+  object lblAmount: TLabel
+    Left = 270
+    Top = 76
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblFeeCaption: TLabel
+    Left = 517
+    Top = 56
+    Width = 22
+    Height = 13
+    Caption = 'Fee:'
+  end
+  object lblFee: TLabel
+    Left = 547
+    Top = 51
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object Label4: TLabel
+    Left = 20
+    Top = 24
+    Width = 38
+    Height = 13
+    Caption = 'OpHash'
+  end
+  object lblSenderCaption: TLabel
+    Left = 20
+    Top = 81
+    Width = 38
+    Height = 13
+    Caption = 'Sender:'
+  end
+  object lblSender: TLabel
+    Left = 64
+    Top = 76
+    Width = 97
+    Height = 19
+    Caption = '9999999-99'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblReceiverCaption: TLabel
+    Left = 411
+    Top = 81
+    Width = 46
+    Height = 13
+    Caption = 'Receiver:'
+  end
+  object lblReceiver: TLabel
+    Left = 463
+    Top = 76
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblReceiverInfo: TLabel
+    Left = 481
+    Top = 50
+    Width = 121
+    Height = 19
+    Caption = '(Receiver info)'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clRed
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
   object PageControl: TPageControl
     Left = 20
-    Top = 90
-    Width = 521
+    Top = 140
+    Width = 631
     Height = 206
     ActivePage = tsDecoded
-    TabOrder = 0
+    TabOrder = 2
     OnChanging = PageControlChanging
     object tsDecoded: TTabSheet
       Caption = 'Payload'
@@ -97,7 +198,7 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
         Caption = 'Decoded Payload:'
       end
       object lblDecodedMethod: TLabel
-        Left = 457
+        Left = 562
         Top = 94
         Width = 44
         Height = 13
@@ -120,7 +221,7 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       object memoDecoded: TMemo
         Left = 15
         Top = 111
-        Width = 486
+        Width = 591
         Height = 55
         TabStop = False
         Font.Charset = DEFAULT_CHARSET
@@ -138,7 +239,7 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       object memoOriginalPayloadInHexa: TMemo
         Left = 15
         Top = 28
-        Width = 486
+        Width = 591
         Height = 55
         TabStop = False
         Color = clBtnFace
@@ -158,10 +259,6 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'
       ImageIndex = 1
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object lblPasswordsInfo: TLabel
         Left = 235
         Top = 162
@@ -199,7 +296,7 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       object memoPasswords: TMemo
         Left = 235
         Top = 10
-        Width = 261
+        Width = 371
         Height = 146
         ScrollBars = ssBoth
         TabOrder = 3
@@ -236,9 +333,9 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       end
     end
   end
-  object BitBtn1: TBitBtn
-    Left = 462
-    Top = 310
+  object bbClose: TBitBtn
+    Left = 572
+    Top = 362
     Width = 79
     Height = 25
     Cancel = True
@@ -260,6 +357,61 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     ModalResult = 2
     NumGlyphs = 2
     ParentDoubleBuffered = False
+    TabOrder = 3
+  end
+  object bbFind: TBitBtn
+    Left = 599
+    Top = 19
+    Width = 52
+    Height = 25
+    Caption = '&Find'
+    DoubleBuffered = True
+    Glyph.Data = {
+      36030000424D3603000000000000360000002800000010000000100000000100
+      18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+      BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+      2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+      00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+      B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+      EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+      FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+      C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+      FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+      E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+      C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+      C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+      DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+      86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+      00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+    ParentDoubleBuffered = False
     TabOrder = 1
+    TabStop = False
+    OnClick = bbFindClick
+  end
+  object ebOphash: TEdit
+    Left = 64
+    Top = 20
+    Width = 529
+    Height = 22
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -12
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 0
+    Text = '12345678901234567890123456789012345678901234567890123456789012'
+    OnExit = ebOphashExit
+    OnKeyPress = ebOphashKeyPress
   end
 end

+ 224 - 84
Units/Forms/UFRMPayloadDecoder.lfm

@@ -1,220 +1,310 @@
 object FRMPayloadDecoder: TFRMPayloadDecoder
-  Left = 507
-  Height = 360
-  Top = 250
-  Width = 569
+  Left = 0
+  Top = 0
+  ActiveControl = ebOphash
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
-  Caption = 'Payload Decoder'
-  ClientHeight = 360
-  ClientWidth = 569
+  Caption = 'Operation Information/Decoder'
+  ClientHeight = 406
+  ClientWidth = 674
   Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
   Font.Height = -11
   Font.Name = 'Tahoma'
-  OnCreate = FormCreate
+  Font.Style = []
   Position = poOwnerFormCenter
-  LCLVersion = '1.6.0.4'
+  OnCreate = FormCreate
+  PixelsPerInch = 96
   object Label1: TLabel
     Left = 20
+    Top = 56
+    Width = 46
     Height = 13
-    Top = 20
-    Width = 28
-    Caption = 'Block:'
-    ParentColor = False
+    Caption = 'Block/Op:'
   end
   object lblBlock: TLabel
-    Left = 54
+    Left = 72
+    Top = 51
+    Width = 109
     Height = 19
-    Top = 15
-    Width = 30
-    Caption = '000'
+    Caption = '000000/0000'
+    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
-    ParentColor = False
     ParentFont = False
   end
   object lblDateTime: TLabel
-    Left = 169
-    Height = 19
-    Top = 15
+    Left = 255
+    Top = 51
     Width = 30
+    Height = 19
     Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
-    ParentColor = False
     ParentFont = False
   end
   object Label6: TLabel
-    Left = 111
-    Height = 13
-    Top = 20
+    Left = 195
+    Top = 56
     Width = 52
+    Height = 13
     Caption = 'Date Time:'
-    ParentColor = False
   end
   object Label2: TLabel
     Left = 20
-    Height = 13
-    Top = 45
+    Top = 106
     Width = 52
+    Height = 13
     Caption = 'Operation:'
-    ParentColor = False
   end
   object lblOperationTxt: TLabel
     Left = 90
-    Height = 39
-    Top = 40
-    Width = 457
+    Top = 101
+    Width = 561
+    Height = 22
     AutoSize = False
     Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
-    ParentColor = False
     ParentFont = False
     WordWrap = True
   end
+  object lblAmountCaption: TLabel
+    Left = 220
+    Top = 81
+    Width = 41
+    Height = 13
+    Caption = 'Amount:'
+  end
+  object lblAmount: TLabel
+    Left = 270
+    Top = 76
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblFeeCaption: TLabel
+    Left = 517
+    Top = 56
+    Width = 22
+    Height = 13
+    Caption = 'Fee:'
+  end
+  object lblFee: TLabel
+    Left = 547
+    Top = 51
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object Label4: TLabel
+    Left = 20
+    Top = 24
+    Width = 38
+    Height = 13
+    Caption = 'OpHash'
+  end
+  object lblSenderCaption: TLabel
+    Left = 20
+    Top = 81
+    Width = 38
+    Height = 13
+    Caption = 'Sender:'
+  end
+  object lblSender: TLabel
+    Left = 64
+    Top = 76
+    Width = 97
+    Height = 19
+    Caption = '9999999-99'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblReceiverCaption: TLabel
+    Left = 411
+    Top = 81
+    Width = 46
+    Height = 13
+    Caption = 'Receiver:'
+  end
+  object lblReceiver: TLabel
+    Left = 463
+    Top = 76
+    Width = 30
+    Height = 19
+    Caption = '000'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object lblReceiverInfo: TLabel
+    Left = 481
+    Top = 50
+    Width = 121
+    Height = 19
+    Caption = '(Receiver info)'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clRed
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
   object PageControl: TPageControl
     Left = 20
+    Top = 140
+    Width = 631
     Height = 206
-    Top = 90
-    Width = 521
     ActivePage = tsDecoded
-    TabIndex = 0
-    TabOrder = 0
+    TabOrder = 2
     OnChanging = PageControlChanging
     object tsDecoded: TTabSheet
       Caption = 'Payload'
-      ClientHeight = 180
-      ClientWidth = 513
       object Label7: TLabel
         Left = 15
-        Height = 13
         Top = 94
         Width = 87
+        Height = 13
         Caption = 'Decoded Payload:'
-        ParentColor = False
       end
       object lblDecodedMethod: TLabel
-        Left = 113
-        Height = 13
+        Left = 562
         Top = 94
-        Width = 388
+        Width = 44
+        Height = 13
         Alignment = taRightJustify
-        AutoSize = False
         Caption = '(Method)'
+        Font.Charset = DEFAULT_CHARSET
         Font.Color = clGray
         Font.Height = -11
         Font.Name = 'Tahoma'
-        ParentColor = False
+        Font.Style = []
         ParentFont = False
       end
       object Label3: TLabel
         Left = 15
-        Height = 13
         Top = 9
         Width = 155
+        Height = 13
         Caption = 'Original Payload in Hexadecimal:'
-        ParentColor = False
       end
       object memoDecoded: TMemo
         Left = 15
-        Height = 55
         Top = 111
-        Width = 486
+        Width = 591
+        Height = 55
+        TabStop = False
+        Font.Charset = DEFAULT_CHARSET
         Font.Color = clBlack
         Font.Height = -13
         Font.Name = 'Tahoma'
         Font.Style = [fsBold]
         Lines.Strings = (
-          'memoDecoded'
-        )
-        OnKeyDown = memoDecodedKeyDown
+          'memoDecoded')
         ParentFont = False
         ReadOnly = True
         TabOrder = 0
-        TabStop = False
+        OnKeyDown = memoDecodedKeyDown
       end
       object memoOriginalPayloadInHexa: TMemo
         Left = 15
-        Height = 55
         Top = 28
-        Width = 486
+        Width = 591
+        Height = 55
+        TabStop = False
         Color = clBtnFace
+        Font.Charset = DEFAULT_CHARSET
         Font.Color = clBlack
         Font.Height = -13
         Font.Name = 'Tahoma'
         Font.Style = [fsBold]
         Lines.Strings = (
-          'memoDecoded'
-        )
-        OnKeyDown = memoDecodedKeyDown
+          'memoDecoded')
         ParentFont = False
         ReadOnly = True
         TabOrder = 1
-        TabStop = False
+        OnKeyDown = memoDecodedKeyDown
       end
     end
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'
-      ClientHeight = 0
-      ClientWidth = 0
       ImageIndex = 1
       object lblPasswordsInfo: TLabel
         Left = 235
-        Height = 13
         Top = 162
         Width = 81
+        Height = 13
         Caption = 'lblPasswordsInfo'
-        ParentColor = False
       end
       object cbMethodPublicPayload: TCheckBox
         Left = 16
-        Height = 17
         Top = 15
         Width = 225
+        Height = 17
         Caption = 'Not encrypted (Public payload)'
-        OnClick = cbMethodPublicPayloadClick
         TabOrder = 0
+        OnClick = cbMethodPublicPayloadClick
       end
       object cbUsingPrivateKeys: TCheckBox
         Left = 16
-        Height = 17
         Top = 38
         Width = 225
+        Height = 17
         Caption = 'Using Private keys of my Wallet'
-        OnClick = cbMethodPublicPayloadClick
         TabOrder = 1
+        OnClick = cbMethodPublicPayloadClick
       end
       object cbUsingPasswords: TCheckBox
         Left = 16
-        Height = 17
         Top = 61
         Width = 225
+        Height = 17
         Caption = 'Using Passwords of the list'
-        OnClick = cbMethodPublicPayloadClick
         TabOrder = 2
+        OnClick = cbMethodPublicPayloadClick
       end
       object memoPasswords: TMemo
         Left = 235
-        Height = 146
         Top = 10
-        Width = 261
-        OnChange = cbMethodPublicPayloadClick
+        Width = 371
+        Height = 146
         ScrollBars = ssBoth
         TabOrder = 3
+        OnChange = cbMethodPublicPayloadClick
       end
       object bbSaveMethods: TBitBtn
         Left = 60
-        Height = 25
         Top = 110
         Width = 75
+        Height = 25
         Caption = 'Save'
         Glyph.Data = {
           DE010000424DDE01000000000000760000002800000024000000120000000100
@@ -232,19 +322,18 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
           33333333A222433333333333338F338F00003333333333333A22433333333333
           3338F38F000033333333333333A223333333333333338F830000333333333333
           333A333333333333333338330000333333333333333333333333333333333333
-          0000
-        }
+          0000}
         NumGlyphs = 2
-        OnClick = bbSaveMethodsClick
         TabOrder = 4
+        OnClick = bbSaveMethodsClick
       end
     end
   end
-  object BitBtn1: TBitBtn
-    Left = 462
-    Height = 25
-    Top = 310
+  object bbClose: TBitBtn
+    Left = 572
+    Top = 362
     Width = 79
+    Height = 25
     Cancel = True
     Caption = 'Close'
     Glyph.Data = {
@@ -259,11 +348,62 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       55557775555777FF5555555555599905555555555557777F5555555555559905
       555555555555777FF5555555555559905555555555555777FF55555555555579
       05555555555555777FF5555555555557905555555555555777FF555555555555
-      5990555555555555577755555555555555555555555555555555
-    }
+      5990555555555555577755555555555555555555555555555555}
     ModalResult = 2
     NumGlyphs = 2
-    OnClick = BitBtn1Click
+    TabOrder = 3
+  end
+  object bbFind: TBitBtn
+    Left = 599
+    Top = 19
+    Width = 52
+    Height = 25
+    Caption = '&Find'
+    Glyph.Data = {
+      36030000424D3603000000000000360000002800000010000000100000000100
+      18000000000000030000120B0000120B00000000000000000000FF00FF4A667C
+      BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+      2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+      00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+      B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+      EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+      FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+      C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+      FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+      E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+      C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+      C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+      DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+      86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+      00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
     TabOrder = 1
+    TabStop = False
+    OnClick = bbFindClick
+  end
+  object ebOphash: TEdit
+    Left = 64
+    Top = 20
+    Width = 529
+    Height = 22
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -12
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 0
+    Text = '12345678901234567890123456789012345678901234567890123456789012'
+    OnExit = ebOphashExit
+    OnKeyPress = ebOphashKeyPress
   end
 end

+ 178 - 37
Units/Forms/UFRMPayloadDecoder.pas

@@ -51,30 +51,46 @@ type
     lblDecodedMethod: TLabel;
     Label3: TLabel;
     bbSaveMethods: TBitBtn;
-    BitBtn1: TBitBtn;
+    bbClose: TBitBtn;
     memoDecoded: TMemo;
     memoOriginalPayloadInHexa: TMemo;
     lblPasswordsInfo: TLabel;
-    procedure BitBtn1Click(Sender: TObject);
+    lblAmountCaption: TLabel;
+    lblAmount: TLabel;
+    lblFeeCaption: TLabel;
+    lblFee: TLabel;
+    Label4: TLabel;
+    bbFind: TBitBtn;
+    ebOphash: TEdit;
+    lblSenderCaption: TLabel;
+    lblSender: TLabel;
+    lblReceiverCaption: TLabel;
+    lblReceiver: TLabel;
+    lblReceiverInfo: TLabel;
     procedure FormCreate(Sender: TObject);
     procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean);
     procedure cbMethodPublicPayloadClick(Sender: TObject);
     procedure bbSaveMethodsClick(Sender: TObject);
     procedure memoDecodedKeyDown(Sender: TObject; var Key: Word;
       Shift: TShiftState);
+    procedure bbFindClick(Sender: TObject);
+    procedure ebOphashExit(Sender: TObject);
+    procedure ebOphashKeyPress(Sender: TObject; var Key: Char);
   private
-    FPayloadData : TRawBytes;
+    FOpResume : TOperationResume;
     FWalletKeys : TWalletKeys;
-    FOldECPrivateKey : TECPrivateKey;
-    FAccountECPrivateKey : TECPrivateKey;
     FSavedDecodeMethods : boolean;
     FAppParams : TAppParams;
+    FSemaphor : Boolean;
     { Private declarations }
     Procedure TryToDecode;
     Procedure SaveMethods;
+    procedure SetOpResume(const Value: TOperationResume);
   public
     { Public declarations }
-    Procedure Init(block, timestamp : Cardinal; const OperationText : AnsiString; Const PayloadData : TRawBytes; WalletKeys : TWalletKeys; AppParams : TAppParams);
+    Procedure Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
+    Property OpResume : TOperationResume read FOpResume write SetOpResume;
+    Procedure DoFind(Const OpHash : String);
   end;
 
 implementation
@@ -96,52 +112,94 @@ begin
   TryToDecode;
 end;
 
+procedure TFRMPayloadDecoder.bbFindClick(Sender: TObject);
+Var oph : String;
+begin
+  oph := TCrypto.ToHexaString( FOpResume.OperationHash );
+  if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
+  DoFind(oph);
+end;
+
 procedure TFRMPayloadDecoder.cbMethodPublicPayloadClick(Sender: TObject);
 begin
   FSavedDecodeMethods := false;
   lblPasswordsInfo.Caption := Format('Possible passwords: %d',[memoPasswords.Lines.Count]);
 end;
 
-procedure TFRMPayloadDecoder.FormCreate(Sender: TObject);
+procedure TFRMPayloadDecoder.DoFind(Const OpHash : String);
+Var
+  r : TRawBytes;
+  pcops : TPCOperationsComp;
+  b : Cardinal;
+  opbi : Integer;
+  opr : TOperationResume;
 begin
-  FWalletKeys := Nil;
-  FAppParams := Nil;
-  memoDecoded.Lines.Clear;
-  memoOriginalPayloadInHexa.Lines.Clear;
-  lblPasswordsInfo.Caption := '';
+  // Search for an operation based on "ophash"
+  if (trim(OpHash)='') then begin
+    OpResume := CT_TOperationResume_NUL;
+    exit;
+  end;
+  try
+    r := TCrypto.HexaToRaw(trim(ophash));
+    if (r='') then begin
+      raise Exception.Create('Value is not an hexadecimal string');
+    end;
+    pcops := TPCOperationsComp.Create(Nil);
+    try
+      If not TNode.Node.FindOperation(pcops,r,b,opbi) then begin
+        raise Exception.Create('Value is not a valid OpHash');
+      end;
+      If not TPCOperation.OperationToOperationResume(b,pcops.Operation[opbi],pcops.Operation[opbi].SenderAccount,opr) then begin
+        raise Exception.Create('Internal error 20161114-1');
+      end;
+      opr.NOpInsideBlock:=opbi;
+      opr.time:=pcops.OperationBlock.timestamp;
+      OpResume := opr;
+    finally
+      pcops.Free;
+    end;
+  Except
+    OpResume := CT_TOperationResume_NUL;
+    try
+      FSemaphor := true;
+      ebOphash.Text := trim(ophash);
+    finally
+      FSemaphor := false;
+    end;
+    Raise;
+  end;
 end;
 
-procedure TFRMPayloadDecoder.BitBtn1Click(Sender: TObject);
+procedure TFRMPayloadDecoder.ebOphashExit(Sender: TObject);
 begin
+  DoFind(ebOphash.Text);
+end;
 
+procedure TFRMPayloadDecoder.ebOphashKeyPress(Sender: TObject; var Key: Char);
+begin
+  if Key=#13 then DoFind(ebOphash.Text);
 end;
 
-procedure TFRMPayloadDecoder.Init(block, timestamp : Cardinal; const OperationText : AnsiString; Const PayloadData : TRawBytes; WalletKeys : TWalletKeys; AppParams : TAppParams);
+procedure TFRMPayloadDecoder.FormCreate(Sender: TObject);
+begin
+  FSemaphor := true;
+  try
+    FWalletKeys := Nil;
+    FAppParams := Nil;
+    memoDecoded.Lines.Clear;
+    memoOriginalPayloadInHexa.Lines.Clear;
+    lblPasswordsInfo.Caption := '';
+    OpResume := CT_TOperationResume_NUL;
+  finally
+    FSemaphor := false;
+  end;
+end;
+
+procedure TFRMPayloadDecoder.Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
 begin
   FWalletKeys := WalletKeys;
   FAppParams := AppParams;
-  lblBlock.Caption := inttostr(block);
-  if timestamp>10000 then begin
-    lblDateTime.Caption := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(timestamp)));
-    lblDateTime.Font.Color := clBlack;
-  end else begin
-    lblDateTime.Caption := '(Pending block)';
-    lblDateTime.Font.Color := clRed;
-  end;
-  lblOperationTxt.Caption := OperationText;
-  FPayloadData := PayloadData;
-  memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(FPayloadData);
-  if Assigned(FWalletKeys) then begin
-    cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
-    cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
-    cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
-    memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
-  end else begin
-    cbMethodPublicPayload.Checked := true;
-    cbUsingPrivateKeys.Checked := true;
-    cbUsingPasswords.Checked := true;
-    memoPasswords.Lines.Text := '';
-  end;
+  OpResume := AOperationResume;
   FSavedDecodeMethods := true;
   PageControl.ActivePage := tsDecoded;
   TryToDecode;
@@ -183,6 +241,84 @@ begin
   FSavedDecodeMethods := true;
 end;
 
+procedure TFRMPayloadDecoder.SetOpResume(const Value: TOperationResume);
+Var sem : Boolean;
+begin
+  sem := FSemaphor;
+  Try
+    FSemaphor := false;
+    FOpResume := Value;
+    if Not Value.valid then begin
+      lblBlock.Caption := '';
+      lblDateTime.Caption := '';
+      lblOperationTxt.Caption := '';
+      lblDecodedMethod.Caption := '';
+      lblFee.Caption := '';
+      lblPasswordsInfo.Caption := '';
+      lblAmount.Caption := '';
+      lblSender.Caption := '';
+      lblReceiver.Caption := '';
+      lblReceiverInfo.Visible := false;
+      exit;
+    end;
+    If (Value.NOpInsideBlock>=0) then
+      lblBlock.Caption := inttostr(Value.Block)+'/'+inttostr(Value.NOpInsideBlock+1)
+    else lblBlock.Caption := inttostr(Value.Block);
+    if Value.time>10000 then begin
+      lblDateTime.Caption := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(Value.time)));
+      lblDateTime.Font.Color := clBlack;
+    end else begin
+      lblDateTime.Caption := '(Pending block)';
+      lblDateTime.Font.Color := clRed;
+    end;
+    lblOperationTxt.Caption := Value.OperationTxt;
+    lblAmount.Caption := TAccountComp.FormatMoney(value.Amount);
+    if Value.Amount>0 then lblAmount.Font.Color := clGreen
+    else if Value.Amount=0 then lblAmount.Font.Color := clGray
+    else lblAmount.Font.Color := clRed;
+    If (Value.SenderAccount>=0) And (Value.DestAccount>=0) then begin
+      lblSenderCaption.Caption := 'Sender:';
+      lblSender.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.SenderAccount);
+      lblReceiverCaption.Visible := true;
+      lblReceiver.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.DestAccount);
+      lblReceiver.Visible := true;
+      lblFeeCaption.Visible := Value.AffectedAccount=Value.SenderAccount;
+      lblFee.Visible := lblFeeCaption.Visible;
+      lblReceiverInfo.Visible := Not lblFee.Visible;
+    end else begin
+      lblSenderCaption.Caption := 'Account:';
+      lblSender.caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.AffectedAccount);
+      lblReceiverCaption.Visible := false;
+      lblReceiver.Visible := false;
+      lblFeeCaption.Visible := true;
+      lblFee.Visible := true;
+      lblReceiverInfo.Visible := false;
+    end;
+    lblFee.Caption := TAccountComp.FormatMoney(value.Fee);
+    if Value.Fee>0 then lblFee.Font.Color := clGreen
+    else if Value.Fee=0 then lblFee.Font.Color := clGray
+    else lblFee.Font.Color := clRed;
+    ebOpHash.text := TCrypto.ToHexaString(Value.OperationHash);
+    memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload);
+    if Assigned(FWalletKeys) then begin
+      cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
+      cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
+      cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
+      memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
+    end else begin
+      cbMethodPublicPayload.Checked := true;
+      cbUsingPrivateKeys.Checked := true;
+      cbUsingPasswords.Checked := true;
+      memoPasswords.Lines.Text := '';
+    end;
+    FSavedDecodeMethods := true;
+    PageControl.ActivePage := tsDecoded;
+    TryToDecode;
+  Finally
+    FSemaphor := sem;
+  End;
+end;
+
 procedure TFRMPayloadDecoder.TryToDecode;
   Function UseWallet(Const raw : TRawBytes; var Decrypted : AnsiString; var WalletKey : TWalletKey) : Boolean;
   Var i : Integer;
@@ -224,7 +360,8 @@ Var raw : TRawBytes;
   ok : boolean;
 begin
   ok := true;
-    raw := FPayloadData;
+  if Assigned(FWalletKeys) And Assigned(FAppParams) then begin
+    raw := FOpResume.OriginalPayload;
     if raw<>'' then begin
       // First try to a human readable...
       if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
@@ -254,6 +391,10 @@ begin
       memoDecoded.Color := clLtGray;
       lblDecodedMethod.Caption := '';
     end;
+  end else begin
+    memoDecoded.Lines.Text := '';
+    lblDecodedMethod.Caption := '';
+  end;
 end;
 
 end.

+ 6 - 37
Units/Forms/UFRMWallet.dfm

@@ -374,10 +374,6 @@ object FRMWallet: TFRMWallet
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Splitter1: TSplitter
         Left = 380
         Top = 66
@@ -583,10 +579,6 @@ object FRMWallet: TFRMWallet
         TabOrder = 2
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
-          ExplicitLeft = 0
-          ExplicitTop = 0
-          ExplicitWidth = 0
-          ExplicitHeight = 0
           object dgAccountOperations: TDrawGrid
             Left = 0
             Top = 0
@@ -606,10 +598,6 @@ object FRMWallet: TFRMWallet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
           ImageIndex = 1
-          ExplicitLeft = 0
-          ExplicitTop = 0
-          ExplicitWidth = 0
-          ExplicitHeight = 0
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Top = 31
@@ -799,10 +787,6 @@ object FRMWallet: TFRMWallet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       ImageIndex = 5
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object dgPendingOperations: TDrawGrid
         Left = 0
         Top = 86
@@ -850,10 +834,6 @@ object FRMWallet: TFRMWallet
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
       ImageIndex = 1
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Panel2: TPanel
         Left = 0
         Top = 0
@@ -899,10 +879,6 @@ object FRMWallet: TFRMWallet
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
       ImageIndex = 1
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Panel1: TPanel
         Left = 0
         Top = 0
@@ -948,10 +924,6 @@ object FRMWallet: TFRMWallet
     object tsLogs: TTabSheet
       Caption = 'Logs'
       ImageIndex = 2
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object pnlTopLogs: TPanel
         Left = 0
         Top = 0
@@ -981,10 +953,6 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       ImageIndex = 3
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1047,10 +1015,6 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       ImageIndex = 6
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1225,6 +1189,11 @@ object FRMWallet: TFRMWallet
         ShortCut = 120
         OnClick = miNewOperationClick
       end
+      object MiFindOperationbyOpHash: TMenuItem
+        Caption = 'Find Operation by OpHash'
+        ShortCut = 116
+        OnClick = MiFindOperationbyOpHashClick
+      end
       object MiDecodePayload: TMenuItem
         Caption = 'Decode Payload'
         ShortCut = 113
@@ -1279,7 +1248,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Top = 180
     Bitmap = {
-      494C0101020008007C0110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800840110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

文件差异内容过多而无法显示
+ 216 - 203
Units/Forms/UFRMWallet.lfm


+ 20 - 1
Units/Forms/UFRMWallet.pas

@@ -160,6 +160,7 @@ type
     bbAccountsRefresh: TBitBtn;
     dgBlockChainExplorer: TDrawGrid;
     dgOperationsExplorer: TDrawGrid;
+    MiFindOperationbyOpHash: TMenuItem;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
@@ -204,6 +205,7 @@ type
     procedure ebFilterAccountByBalanceMinKeyPress(Sender: TObject;
       var Key: Char);
     procedure cbFilterAccountsClick(Sender: TObject);
+    procedure MiFindOperationbyOpHashClick(Sender: TObject);
   private
     FMinersBlocksFound: Integer;
     procedure SetMinersBlocksFound(const Value: Integer);
@@ -997,6 +999,23 @@ begin
     TAccountComp.FormatMoney(start.balance));
 end;
 
+procedure TFRMWallet.MiFindOperationbyOpHashClick(Sender: TObject);
+Var FRM : TFRMPayloadDecoder;
+  oph : String;
+begin
+  oph := '';
+  if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
+  //
+  FRM := TFRMPayloadDecoder.Create(Self);
+  try
+    FRM.Init(CT_TOperationResume_NUL,WalletKeys,FAppParams);
+    FRM.DoFind(oph);
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+end;
+
 procedure TFRMWallet.MiFindpreviousaccountwithhighbalanceClick(Sender: TObject);
 Var an  : Cardinal;
   an64 : Int64;
@@ -1311,7 +1330,7 @@ Var nsarr : TNodeServerAddressArray;
 begin
   //CheckMining;
   // Update node servers Peer Cache
-  nsarr := TNetData.NetData.GetValidNodeServers;
+  nsarr := TNetData.NetData.GetValidNodeServers(true);
   s := '';
   for i := low(nsarr) to High(nsarr) do begin
     if (s<>'') then s := s+';';

+ 14 - 4
Units/PascalCoin/UAccounts.pas

@@ -379,7 +379,9 @@ class function TAccountComp.AccountNumberToAccountTxtNumber(account_number: Card
 Var an : int64;
 begin
   an := account_number;
-  an := ((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10;
+  an := ((an * 101) MOD 89)+10;
+  //BUILD 1.1.1 change cheksum calculation
+  //Prior was: an := ((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10;
   Result := IntToStr(account_number)+'-'+Inttostr(an);
 end;
 
@@ -488,7 +490,9 @@ begin
   if (account_txt_number[i] in ['-','.',' ']) then inc(i);
   if length(account_txt_number)-1<>i then exit;
   rn := StrToIntDef(copy(account_txt_number,i,length(account_txt_number)),0);
-  anaux := (((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10);
+  //BUILD 1.1.1 change cheksum calculation
+  //Prior was: anaux := (((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10);
+  anaux := ((an * 101) MOD 89)+10;
   Result := rn = anaux;
 end;
 
@@ -562,8 +566,14 @@ begin
     s.WriteBuffer(rawaccstr[1],length(rawaccstr));
     s.Position := 0;
     s.Read(Result.EC_OpenSSL_NID,SizeOf(Result.EC_OpenSSL_NID));
-    TStreamOp.ReadAnsiString(s,Result.x);
-    TStreamOp.ReadAnsiString(s,Result.y);
+    If (TStreamOp.ReadAnsiString(s,Result.x)<=0) then begin
+      Result := CT_TECDSA_Public_Nul;
+      exit;
+    end;
+    if (TStreamOp.ReadAnsiString(s,Result.y)<=0) then begin
+      Result := CT_TECDSA_Public_Nul;
+      exit;
+    end;
   finally
     s.Free;
   end;

+ 4 - 4
Units/PascalCoin/UBlockChain.pas

@@ -130,6 +130,7 @@ Type
   TPCOperationClass = Class of TPCOperation;
 
   TOperationResume = Record
+    valid : Boolean;
     Block : Cardinal;
     NOpInsideBlock : Integer;
     OpType : Word;
@@ -166,7 +167,6 @@ Type
   TPCOperation = Class
   Private
     Ftag: integer;
-    //FAuxBalance: Int64;
   Protected
     FPrevious_Sender_updated_block: Cardinal;
     FPrevious_Destination_updated_block : Cardinal;
@@ -184,8 +184,6 @@ Type
     function SenderAccount : Cardinal; virtual; abstract;
     function N_Operation : Cardinal; virtual; abstract;
     Property tag : integer read Ftag Write Ftag;
-    // Property AuxBalance : Int64 read FAuxBalance Write FAuxBalance; Deprecated, not used
-    // New Build 1.0.8 To save previous updated block in storage
     function SaveToStorage(Stream: TStream): Boolean;
     function LoadFromStorage(Stream: TStream): Boolean;
     Property Previous_Sender_updated_block : Cardinal read FPrevious_Sender_updated_block;
@@ -392,7 +390,7 @@ Type
   End;
 
 Const
-  CT_TOperationResume_NUL : TOperationResume = (Block:0;NOpInsideBlock:-1;OpType:0;time:0;AffectedAccount:0;SenderAccount:-1;DestAccount:-1;newKey:(EC_OpenSSL_NID:0;x:'';y:'');OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:'';PrintablePayload:'';OperationHash:'');
+  CT_TOperationResume_NUL : TOperationResume = (valid:false;Block:0;NOpInsideBlock:-1;OpType:0;time:0;AffectedAccount:0;SenderAccount:-1;DestAccount:-1;newKey:(EC_OpenSSL_NID:0;x:'';y:'');OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:'';PrintablePayload:'';OperationHash:'');
 
   CT_OperationBlock_NUL : TOperationBlock = (block:0;account_key:(EC_OpenSSL_NID:0;x:'';y:'');reward:0;fee:0;protocol_version:0;
     protocol_available:0;timestamp:0;compact_target:0;nonce:0;block_payload:'';initial_safe_box_hash:'';operations_hash:'';proof_of_work:'');
@@ -1901,6 +1899,7 @@ begin
       newOp.FPrevious_Sender_updated_block := op.Previous_Sender_updated_block;
       newOp.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
       h := TCrypto.DoSha256(ms.Memory,ms.Size);
+      newOp.tag := list.Count;
       list.Add(newOp);
   finally
       ms.Free;
@@ -2109,6 +2108,7 @@ begin
   If TCrypto.IsHumanReadable(OperationResume.OriginalPayload) then OperationResume.PrintablePayload := OperationResume.OriginalPayload
   else OperationResume.PrintablePayload := TCrypto.ToHexaString(OperationResume.OriginalPayload);
   OperationResume.OperationHash:=TPCOperation.OperationHash(Operation,Block);
+  OperationResume.valid := true;
 end;
 
 function TPCOperation.SaveToStorage(Stream: TStream): Boolean;

+ 3 - 2
Units/PascalCoin/UConst.pas

@@ -75,7 +75,8 @@ Const
   CT_MaxPayloadSize = 255; // Max payload size in bytes
   CT_MaxSecondsDifferenceOfNetworkNodes = 180; // 3 minutes. If a Node has a +- value difference, will be blacklisted
 
-  CT_MaxServersConnected = 3; // Build 1.0.8 downgrading from 5 to 3 servers...
+  CT_MinServersConnected = 3;
+  CT_MaxServersConnected = 5;
 
   CT_MaxClientsConnected = 100;
 
@@ -103,7 +104,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.1.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.2.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 

+ 26 - 19
Units/PascalCoin/ULog.pas

@@ -20,7 +20,7 @@ unit ULog;
 interface
 
 uses
-  Classes, UThread;
+  Classes, UThread, SyncObjs;
 
 type
   TLogType = (ltinfo, ltupdate, lterror, ltdebug);
@@ -58,6 +58,7 @@ type
     FSaveTypes: TLogTypes;
     FThreadSafeLogEvent : TThreadSafeLogEvent;
     FProcessGlobalLogs: Boolean;
+    FLock : TCriticalSection;
     procedure SetFileName(const Value: AnsiString);
   protected
     Procedure DoLog(logtype : TLogType; sender, logtext : AnsiString); virtual;
@@ -92,6 +93,7 @@ constructor TLog.Create(AOwner: TComponent);
 Var l : TList;
 begin
   inherited;
+  FLock := TCriticalSection.Create;
   FProcessGlobalLogs := true;
   FLogDataList := TThreadList.Create;
   FFileStream := Nil;
@@ -126,6 +128,7 @@ begin
     FLogDataList.UnlockList;
   end;
   FreeAndNil(FLogDataList);
+  FreeAndNil(FLock);
   inherited;
 end;
 
@@ -147,26 +150,30 @@ end;
 
 procedure TLog.NotifyNewLog(logtype: TLogType; Const sender, logtext: String);
 Var s,tid : AnsiString;
-  tsle : TThreadSafeLogEvent;
   P : PLogData;
 begin
-  if assigned(FFileStream) And (logType in FSaveTypes) then begin
-    if TThread.CurrentThread.ThreadID=MainThreadID then tid := ' MAIN:' else tid:=' TID:';
-    s := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',now)+tid+IntToHex(TThread.CurrentThread.ThreadID,8)+' ['+CT_LogType[logtype]+'] <'+sender+'> '+logtext+#13#10;
-    FFileStream.Write(s[1],length(s));
-  end;
-  if Assigned(FOnInThreadNewLog) then begin
-    FOnInThreadNewLog(logtype,now,TThread.CurrentThread.ThreadID,sender,logtext);
-  end;
-  if Assigned(FOnNewLog) then begin
-    // Add to a thread safe list
-    New(P);
-    P^.Logtype := logtype;
-    P^.Time := now;
-    P^.ThreadID :=TThread.CurrentThread.ThreadID;
-    P^.Sender := sender;
-    P^.Logtext := logtext;
-    FLogDataList.Add(P);
+  FLock.Acquire;
+  try
+    if assigned(FFileStream) And (logType in FSaveTypes) then begin
+      if TThread.CurrentThread.ThreadID=MainThreadID then tid := ' MAIN:' else tid:=' TID:';
+      s := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',now)+tid+IntToHex(TThread.CurrentThread.ThreadID,8)+' ['+CT_LogType[logtype]+'] <'+sender+'> '+logtext+#13#10;
+      FFileStream.Write(s[1],length(s));
+    end;
+    if Assigned(FOnInThreadNewLog) then begin
+      FOnInThreadNewLog(logtype,now,TThread.CurrentThread.ThreadID,sender,logtext);
+    end;
+    if Assigned(FOnNewLog) then begin
+      // Add to a thread safe list
+      New(P);
+      P^.Logtype := logtype;
+      P^.Time := now;
+      P^.ThreadID :=TThread.CurrentThread.ThreadID;
+      P^.Sender := sender;
+      P^.Logtext := logtext;
+      FLogDataList.Add(P);
+    end;
+  finally
+    FLock.Release;
   end;
   DoLog(logtype,sender,logtext);
 end;

+ 36 - 19
Units/PascalCoin/UNetProtocol.pas

@@ -233,7 +233,7 @@ Type
     Property IsGettingNewBlockChainFromClient : Boolean read FIsGettingNewBlockChainFromClient;
     Property MaxRemoteOperationBlock : TOperationBlock read FMaxRemoteOperationBlock;
     Property NodePrivateKey : TECPrivateKey read FNodePrivateKey;
-    Function GetValidNodeServers: TNodeServerAddressArray;
+    Function GetValidNodeServers(OnlyWhereIConnected : Boolean): TNodeServerAddressArray;
     Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
     Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
     Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
@@ -412,9 +412,9 @@ begin
 end;
 
 procedure TNetData.CleanBlackList;
-Var P : PNodeServerAddress;
-  i,n : Integer;
-  l : TList;
+Var P,Pns : PNodeServerAddress;
+  i,n,j : Integer;
+  l,lns : TList;
 begin
   // This procedure cleans old blacklisted IPs
   n := 0;
@@ -422,10 +422,20 @@ begin
   Try
     for i := l.Count - 1 downto 0 do begin
       P := l[i];
-      if
-        // Is an old blacklisted IP? (More than 1 hour)
-        (((P^.last_connection+(60*60)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) And (Not P^.its_myself))
-        then begin
+      // Is an old blacklisted IP? (More than 1 hour)
+      If ((P^.last_connection+(60*60)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) then begin
+        // Clean from FNodeServers
+        lns := FNodeServers.LockList;
+        Try
+          j := IndexOfNetClient(lns,P^.ip,P^.port);
+          if (j>=0) then begin
+            Pns := lns[j];
+            Pns^.its_myself := false;
+            Pns^.BlackListText := '';
+          end;
+        Finally
+          FNodeServers.UnlockList;
+        End;
         l.Delete(i);
         Dispose(P);
         inc(n);
@@ -712,7 +722,11 @@ begin
     exit;
   end;
   CleanBlackList;
-  j := CT_MaxServersConnected - ConnectionsCount(true);
+  If NetStatistics.ClientsConnections>0 then begin
+    j := CT_MinServersConnected - NetStatistics.ServersConnectionsWithResponse;
+  end else begin
+    j := CT_MaxServersConnected - NetStatistics.ServersConnectionsWithResponse;
+  end;
   if j<=0 then exit;
   // can discover up to j servers
   l := TList.Create;
@@ -1103,7 +1117,7 @@ begin
   end;
 end;
 
-function TNetData.GetValidNodeServers: TNodeServerAddressArray;
+function TNetData.GetValidNodeServers(OnlyWhereIConnected : Boolean): TNodeServerAddressArray;
 var i : Integer;
   nsa : TNodeServerAddress;
   currunixtimestamp : Cardinal;
@@ -1116,7 +1130,7 @@ begin
   try
     for i := 0 to l.Count - 1 do begin
       nsa := PNodeServerAddress( l[i] )^;
-      If ((nsa.its_myself) Or (nsa.BlackListText='')) // Not a blacklist IP except duplicate connections
+      if (Not IsBlackListed(nsa.ip,0))
         And
         ( // I've connected 24h before
          ((nsa.last_connection>0) And ((Assigned(nsa.netConnection)) Or ((nsa.last_connection + (60*60*24)) > (currunixtimestamp))))
@@ -1129,6 +1143,12 @@ begin
         ( // Never tried to connect or successfully connected
           (nsa.total_failed_attemps_to_connect=0)
         )
+        And
+        (
+          (Not OnlyWhereIConnected)
+          Or
+          (nsa.last_connection>0)
+        )
         then begin
         SetLength(Result,length(Result)+1);
         Result[high(Result)] := nsa;
@@ -1389,14 +1409,10 @@ begin
         // Wait some time before close connection
         sleep(5000);
       end else begin
-        DebugStep := 'Adding client';
-        DebugStep := '   ';
+        DebugStep := 'Processing buffer and sleep...';
         while (n.Connected) And (Active) do begin
-          DebugStep[1] := '1';
           n.DoProcessBuffer;
-          DebugStep[1] := '2';
           Sleep(10);
-          DebugStep[1] := '3';
         end;
       end;
     Finally
@@ -1576,7 +1592,7 @@ begin
       i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,Client.RemotePort);
       if i>=0 then begin
         P := l[i];
-        P^.its_myself := true;
+        P^.its_myself := ItsMyself;
       end;
     finally
       TNetData.NetData.FNodeServers.UnlockList;
@@ -1982,7 +1998,8 @@ Begin
       nsa := CT_TNodeServerAddress_NUL;
       nsa.ip := Client.RemoteHost;
       nsa.port := connection_has_a_server;
-      nsa.last_connection_by_server := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+      // BUG corrected 1.1.1: nsa.last_connection_by_server := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+      nsa.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       TNetData.NetData.AddServer(nsa);
     end;
 
@@ -2525,7 +2542,7 @@ begin
     try
       if (TNode.Node.Bank.BlocksCount>0) then TNode.Node.Bank.LoadOperations(op,TNode.Node.Bank.BlocksCount-1);
       op.SaveBlockToStream(true,data);
-      nsarr := TNetData.NetData.GetValidNodeServers;
+      nsarr := TNetData.NetData.GetValidNodeServers(true);
       i := length(nsarr);
       data.Write(i,4);
       for i := 0 to High(nsarr) do begin

+ 2 - 1
Units/PascalCoin/UNode.pas

@@ -659,7 +659,7 @@ procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperatio
             else next_block_number := op.Previous_Destination_updated_block;
           end;
           If TPCOperation.OperationToOperationResume(block_number,Op,account_number,OPR) then begin
-            OPR.NOpInsideBlock := i;
+            OPR.NOpInsideBlock := Op.tag; // Note: Used Op.tag to include operation index inside a list
             OPR.time := opc.OperationBlock.timestamp;
             OPR.Block := block_number;
             OPR.Balance := last_balance;
@@ -670,6 +670,7 @@ procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperatio
         // Is a new block operation?
         if (TAccountComp.AccountBlock(account_number)=block_number) And ((account_number MOD CT_AccountsPerBlock)=0) then begin
           OPR := CT_TOperationResume_NUL;
+          OPR.valid := true;
           OPR.Block := block_number;
           OPR.time := opc.OperationBlock.timestamp;
           OPR.AffectedAccount := account_number;

+ 94 - 8
Units/PascalCoin/URPC.pas

@@ -126,11 +126,9 @@ end;
 
 function TRPCServer.IsValidClientIP(const clientIp: String; clientPort: Word): Boolean;
 begin
-  Result := (clientIp='127.0.0.1');
-  If Not Result then begin
-    // TODO: Allow other IP clients
-  end;
-  //
+  Result := true;
+  // TODO: Allow only specific IP's listed in IniFile
+  // Result := (clientIp='127.0.0.1');
 end;
 
 constructor TRPCServer.Create;
@@ -722,14 +720,99 @@ begin
   end else if (method='getwalletaccounts') then begin
     // Returns JSON array with accounts in Wallet
     jsonarr := jsonresponse.GetAsArray('result');
-    for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
+    if (params.IndexOfName('enc_pubkey')>=0) then begin
+      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
+      opr.newKey := TAccountComp.RawString2Accountkey(r);
+      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+        ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
+        exit;
+      end;
+      i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
+      if (i<0) then begin
+        ErrorNum := CT_RPC_ErrNum_NotFound;
+        ErrorDesc := 'Public key not found in wallet';
+        exit;
+      end;
       ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       for j := 0 to ocl.Count - 1 do begin
         account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
         FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
       end;
+      Result := true;
+    end else begin
+      for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
+        ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+        for j := 0 to ocl.Count - 1 do begin
+          account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+          FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+        end;
+      end;
+      Result := true;
+    end;
+  end else if (method='getwalletaccountscount') then begin
+    // New Build 1.1.1
+    // Returns a number with count value
+    if (params.IndexOfName('enc_pubkey')>=0) then begin
+      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
+      opr.newKey := TAccountComp.RawString2Accountkey(r);
+      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+        ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
+        exit;
+      end;
+      i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
+      if (i<0) then begin
+        ErrorNum := CT_RPC_ErrNum_NotFound;
+        ErrorDesc := 'Public key not found in wallet';
+        exit;
+      end;
+      ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+      jsonresponse.GetAsVariant('result').value := ocl.count;
+      Result := true;
+    end else begin
+      c :=0;
+      for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
+        ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+        inc(c,ocl.count);
+      end;
+      jsonresponse.GetAsVariant('result').value := c;
+      Result := true;
+    end;
+  end else if (method='getwalletcoins') then begin
+    if (params.IndexOfName('enc_pubkey')>=0) then begin
+      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
+      opr.newKey := TAccountComp.RawString2Accountkey(r);
+      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+        ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
+        exit;
+      end;
+      i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
+      if (i<0) then begin
+        ErrorNum := CT_RPC_ErrNum_NotFound;
+        ErrorDesc := 'Public key not found in wallet';
+        exit;
+      end;
+      ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+      account.balance := 0;
+      for j := 0 to ocl.Count - 1 do begin
+        inc(account.balance, TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j)).balance );
+      end;
+      jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
+      Result := true;
+    end else begin
+      c :=0;
+      account.balance := 0;
+      for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
+        ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+        for j := 0 to ocl.Count - 1 do begin
+          inc(account.balance, TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j)).balance );
+        end;
+      end;
+      jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
+      Result := true;
     end;
-    Result := true;
   end else if (method='getwalletpubkeys') then begin
     // Returns JSON array with pubkeys in wallet
     jsonarr := jsonresponse.GetAsArray('result');
@@ -894,6 +977,7 @@ begin
       end;
       opr.NOpInsideBlock:=i;
       opr.time:=pcops.OperationBlock.timestamp;
+      opr.Balance := -1; // don't include
       FillOperationResumeToJSONObject(opr,GetResultObject);
       Result := True;
     finally
@@ -958,6 +1042,8 @@ begin
     GetResultObject.GetAsObject('netprotocol').GetAsVariant('ver').Value := CT_NetProtocol_Version;
     GetResultObject.GetAsObject('netprotocol').GetAsVariant('ver_a').Value := CT_NetProtocol_Available;
     GetResultObject.GetAsVariant('blocks').Value:=TNode.Node.Bank.BlocksCount;
+    GetResultObject.GetAsVariant('sbh').Value:=TCrypto.ToHexaString(TNode.Node.Bank.LastOperationBlock.initial_safe_box_hash);
+    GetResultObject.GetAsVariant('pow').Value:=TCrypto.ToHexaString(TNode.Node.Bank.LastOperationBlock.proof_of_work);
     GetResultObject.GetAsObject('netstats').GetAsVariant('active').Value:=TNetData.NetData.NetStatistics.ActiveConnections;
     GetResultObject.GetAsObject('netstats').GetAsVariant('clients').Value:=TNetData.NetData.NetStatistics.ClientsConnections;
     GetResultObject.GetAsObject('netstats').GetAsVariant('servers').Value:=TNetData.NetData.NetStatistics.ServersConnectionsWithResponse;
@@ -967,7 +1053,7 @@ begin
     GetResultObject.GetAsObject('netstats').GetAsVariant('tservers').Value:=TNetData.NetData.NetStatistics.TotalServersConnections;
     GetResultObject.GetAsObject('netstats').GetAsVariant('breceived').Value:=TNetData.NetData.NetStatistics.BytesReceived;
     GetResultObject.GetAsObject('netstats').GetAsVariant('bsend').Value:=TNetData.NetData.NetStatistics.BytesSend;
-    nsaarr := TNetData.NetData.GetValidNodeServers;
+    nsaarr := TNetData.NetData.GetValidNodeServers(true);
     for i := low(nsaarr) to High(nsaarr) do begin
       jso := GetResultObject.GetAsArray('nodeservers').GetAsObject(i);
       jso.GetAsVariant('ip').Value := nsaarr[i].ip;

+ 78 - 49
Units/PascalCoin/UWalletKeys.pas

@@ -28,11 +28,12 @@ Type
     AccountKey : TAccountKey;
     CryptedKey : TRawBytes;
     PrivateKey : TECPrivateKey;
+    SearchableAccountKey : TRawBytes;
   End;
 
   TWalletKeys = Class(TComponent)
   private
-    FKeys : TList;
+    FSearchableKeys : TList;
     FFileName: AnsiString;
     FWalletPassword: AnsiString;
     FWalletFileStream : TFileStream;
@@ -44,6 +45,7 @@ Type
     procedure SetWalletPassword(const Value: AnsiString);
     Procedure GeneratePrivateKeysFromPassword;
     procedure SetWalletFileName(const Value: AnsiString);
+    Function Find(Const AccountKey: TAccountKey; var Index: Integer): Boolean;
   public
     Property Key[index : Integer] : TWalletKey read GetKey; default;
     Constructor Create(AOwner : TComponent); override;
@@ -81,7 +83,7 @@ Type
   End;
 
 
-Const CT_TWalletKey_NUL  : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil);
+Const CT_TWalletKey_NUL  : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil;SearchableAccountKey:'');
 
 implementation
 
@@ -100,8 +102,8 @@ function TWalletKeys.AddPrivateKey(Const Name : AnsiString; ECPrivateKey: TECPri
 Var P : PWalletKey;
   s : AnsiString;
 begin
-  Result := IndexOfAccountKey(ECPrivateKey.PublicKey);
-  if Result<0 then begin
+  if Not Find(ECPrivateKey.PublicKey,Result) then begin
+    // Result is new position
     New(P);
     P^ := CT_TWalletKey_NUL;
     P^.Name := Name;
@@ -109,9 +111,10 @@ begin
     P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey),WalletPassword);
     P^.PrivateKey := TECPrivateKey.Create;
     P^.PrivateKey.SetPrivateKeyFromHexa(ECPrivateKey.EC_OpenSSL_NID, TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
-    Result := FKeys.Add(P);
+    P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECPrivateKey.PublicKey);
+    FSearchableKeys.Insert(Result,P);
   end else begin
-    P := Fkeys[Result];
+    P := FSearchableKeys[Result];
     P^.Name := Name;
   end;
   if Not FIsReadingStream then SaveToStream(FWalletFileStream);
@@ -121,16 +124,17 @@ end;
 function TWalletKeys.AddPublicKey(const Name: AnsiString; ECDSA_Public: TECDSA_Public): Integer;
 Var P : PWalletKey;
 begin
-  Result := IndexOfAccountKey(ECDSA_Public);
-  if Result<0 then begin
+  if Not Find(ECDSA_Public,Result) then begin
+    // Result is new position
     New(P);
     P^ := CT_TWalletKey_NUL;
     P^.Name := Name;
     P^.AccountKey := ECDSA_Public;
     P^.PrivateKey := Nil;
-    Result := FKeys.Add(P);
+    P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECDSA_Public);
+    FSearchableKeys.Insert(Result,P);
   end else begin
-    P := Fkeys[Result];
+    P := FSearchableKeys[Result];
     P^.Name := Name;
   end;
   if Not FIsReadingStream then SaveToStream(FWalletFileStream);
@@ -141,18 +145,18 @@ procedure TWalletKeys.Clear;
 Var P : PWalletKey;
   i : Integer;
 begin
-  for i := FKeys.Count - 1 downto 0 do begin
-    P := FKeys[i];
-    P^.PrivateKey.Free;
+  for i := FSearchableKeys.Count-1 downto 0 do begin
+    P := FSearchableKeys[i];
+    FreeAndNil(P^.PrivateKey);
     Dispose(P);
   end;
-  FKeys.Clear;
+  FSearchableKeys.Clear;
   FIsValidPassword := true;
 end;
 
 function TWalletKeys.Count: Integer;
 begin
-  Result := FKeys.Count;
+  Result := FSearchableKeys.Count;
 end;
 
 constructor TWalletKeys.Create(AOwner : TComponent);
@@ -161,7 +165,7 @@ begin
   FIsValidPassword := false;
   FWalletFileStream := Nil;
   FWalletPassword := '';
-  FKeys := TList.Create;
+  FSearchableKeys := TList.Create;
   FIsReadingStream := false;
   FOnChanged := Nil;
 end;
@@ -169,10 +173,10 @@ end;
 procedure TWalletKeys.Delete(index: Integer);
 Var P : PWalletKey;
 begin
-  P := FKeys[index];
-  P^.PrivateKey.Free;
+  P := FSearchableKeys[index];
+  FreeAndNil(P^.PrivateKey);
   Dispose(P);
-  FKeys.Delete(index);
+  FSearchableKeys.Delete(index);
   SaveToStream(FWalletFileStream);
   if Assigned(FOnChanged) then FOnChanged(Self);
 end;
@@ -182,10 +186,35 @@ begin
   FOnChanged := Nil;
   FreeAndNil(FWalletFileStream);
   Clear;
-  FKeys.Free;
+  FreeAndNil(FSearchableKeys);
   inherited;
 end;
 
+function TWalletKeys.Find(const AccountKey: TAccountKey; var Index: Integer): Boolean;
+var L, H, I, C: Integer;
+  rak : TRawBytes;
+begin
+  Result := False;
+  rak := TAccountComp.AccountKey2RawString(AccountKey);
+  L := 0;
+  H := FSearchableKeys.Count - 1;
+  while L <= H do
+  begin
+    I := (L + H) shr 1;
+    C := CompareStr( PWalletKey(FSearchableKeys[I]).SearchableAccountKey, rak );
+    if C < 0 then L := I + 1 else
+    begin
+      H := I - 1;
+      if C = 0 then
+      begin
+        Result := True;
+        L := I;
+      end;
+    end;
+  end;
+  Index := L;
+end;
+
 procedure TWalletKeys.GeneratePrivateKeysFromPassword;
 Var i : Integer;
  P : PWalletKey;
@@ -194,13 +223,13 @@ Var i : Integer;
 begin
   FIsValidPassword := false;
   isOk := true;
-  for i := 0 to FKeys.Count - 1 do begin
-    P := FKeys[i];
+  for i := 0 to FSearchableKeys.Count - 1 do begin
+    P := FSearchableKeys[i];
     FreeAndNil(P^.PrivateKey);
   end;
   // try to unencrypt
-  for i := 0 to FKeys.Count - 1 do begin
-    P := FKeys[i];
+  for i := 0 to FSearchableKeys.Count - 1 do begin
+    P := FSearchableKeys[i];
     if P^.CryptedKey<>'' then begin
       isOk := TAESComp.EVP_Decrypt_AES256( P^.CryptedKey, FWalletPassword, s );
       If isOk then begin
@@ -210,8 +239,9 @@ begin
         except on E: Exception do begin
             P^.PrivateKey.Free;
             P^.PrivateKey := Nil;
-            TLog.NewLog(lterror,ClassName,Format('Fatal error when generating EC private key %d/%d: %s',[i+1,FKeys.Count,E.Message]));
-            exit;
+            isOk := false;
+            TLog.NewLog(lterror,ClassName,Format('Fatal error when generating EC private key %d/%d: %s',[i+1,FSearchableKeys.Count,E.Message]));
+            //disabled exit... continue: exit;
           end;
         end;
       end;
@@ -222,21 +252,19 @@ end;
 
 function TWalletKeys.GetKey(index: Integer): TWalletKey;
 begin
-  Result := PWalletKey(FKeys[index])^;
+  Result := PWalletKey(FSearchableKeys[index])^;
 end;
 
 function TWalletKeys.IndexOfAccountKey(AccountKey: TAccountKey): Integer;
 begin
-  for result := 0 to FKeys.Count - 1 do begin
-    if TAccountComp.equal( PWalletKey(FKeys[result])^.AccountKey, AccountKey) then exit;
-  end;
-  Result := -1;
+  if Not find(AccountKey,Result) then Result := -1;
 end;
 
 procedure TWalletKeys.LoadFromStream(Stream: TStream);
-Var fileversion,i,l : Integer;
+Var fileversion,i,l,j : Integer;
   s : AnsiString;
   P : PWalletKey;
+  wk : TWalletKey;
 begin
   Clear;
   FIsValidPassword := false;
@@ -254,15 +282,16 @@ begin
       end;
       Stream.Read(l,4);
       for i := 0 to l - 1 do begin
-        New(P);
-        P^ := CT_TWalletKey_NUL;
-        TStreamOp.ReadAnsiString(Stream,P^.Name);
-        Stream.Read(P^.AccountKey.EC_OpenSSL_NID,sizeof(P^.AccountKey.EC_OpenSSL_NID));
-        TStreamOp.ReadAnsiString(Stream,P^.AccountKey.x);
-        TStreamOp.ReadAnsiString(Stream,P^.AccountKey.y);
-        TStreamOp.ReadAnsiString(Stream,P^.CryptedKey);
-        P^.PrivateKey := Nil;
-        FKeys.Add(P);
+        wk := CT_TWalletKey_NUL;
+        TStreamOp.ReadAnsiString(Stream,wk.Name);
+        Stream.Read(wk.AccountKey.EC_OpenSSL_NID,sizeof(wk.AccountKey.EC_OpenSSL_NID));
+        TStreamOp.ReadAnsiString(Stream,wk.AccountKey.x);
+        TStreamOp.ReadAnsiString(Stream,wk.AccountKey.y);
+        TStreamOp.ReadAnsiString(Stream,wk.CryptedKey);
+        wk.PrivateKey := Nil;
+        j :=AddPublicKey(wk.Name,wk.AccountKey);
+        P := PWalletKey(FSearchableKeys[j]);
+        P^.CryptedKey := wk.CryptedKey; // Adding encrypted data
       end;
     end;
     GeneratePrivateKeysFromPassword;
@@ -283,10 +312,10 @@ begin
   TStreamOp.WriteAnsiString(Stream,CT_PrivateKeyFile_Magic);
   i := CT_PrivateKeyFile_Version;
   Stream.Write(i,4);
-  i := FKeys.Count;
+  i := FSearchableKeys.Count;
   Stream.Write(i,4);
-  for i := 0 to FKeys.Count - 1 do begin
-    P := FKeys[i];
+  for i := 0 to FSearchableKeys.Count - 1 do begin
+    P := FSearchableKeys[i];
     TStreamOp.WriteAnsiString(Stream,P^.Name);
     Stream.Write(P^.AccountKey.EC_OpenSSL_NID,sizeof(P^.AccountKey.EC_OpenSSL_NID));
     TStreamOp.WriteAnsiString(Stream,P^.AccountKey.x);
@@ -297,8 +326,8 @@ end;
 
 procedure TWalletKeys.SetName(index: Integer; const newName: AnsiString);
 begin
-  if PWalletKey(FKeys[index])^.Name=newName then exit;
-  PWalletKey(FKeys[index])^.Name := newName;
+  if PWalletKey(FSearchableKeys[index])^.Name=newName then exit;
+  PWalletKey(FSearchableKeys[index])^.Name := newName;
   SaveToStream(FWalletFileStream);
   if Assigned(FOnChanged) then  FOnChanged(Self);
 end;
@@ -325,13 +354,13 @@ Var i : Integer;
 begin
   if FWalletPassword=Value then exit;
   FWalletPassword := Value;
-  for i := 0 to FKeys.Count - 1 do begin
-    P := FKeys[i];
+  for i := 0 to FSearchableKeys.Count - 1 do begin
+    P := FSearchableKeys[i];
     If Assigned(P^.PrivateKey) then begin
       P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(TCrypto.PrivateKey2Hexa(P^.PrivateKey.PrivateKey),FWalletPassword);
     end else begin
       if FIsValidPassword then begin
-        TLog.NewLog(lterror,Classname,Format('Fatal error: Private key not found %d/%d',[i+1,FKeys.Count]));
+        TLog.NewLog(lterror,Classname,Format('Fatal error: Private key not found %d/%d',[i+1,FSearchableKeys.Count]));
       end;
       FIsValidPassword := false;
     end;

+ 2 - 11
Units/Utils/UGridUtils.pas

@@ -688,16 +688,6 @@ begin
     if (AccountNumber<0) then begin
       If (FPendingOperations) then UpdateAccountOperations;
     end else begin
-      { BUG on Build 1.0.7 -> Corrected on Build 1.0.8
-      Op := TPCOperation(Sender);
-      l := TList.Create;
-      Try
-        Op.AffectedAccounts(l);
-        if l.IndexOf(TObject(PtrInt(AccountNumber)))>=0 then UpdateAccountOperations;
-      Finally
-        l.Free;
-      End;
-      }
       l := TList.Create;
       Try
         If Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,l)>0 then begin
@@ -779,7 +769,7 @@ begin
   opr := FOperationsResume.OperationResume[FDrawGrid.Row-1];
   FRM := TFRMPayloadDecoder.Create(FDrawGrid.Owner);
   try
-    FRM.Init(opr.Block,opr.time,opr.OperationTxt,opr.OriginalPayload,WalletKeys,AppParams);
+    FRM.Init(opr,WalletKeys,AppParams);
     FRM.ShowModal;
   finally
     FRM.Free;
@@ -827,6 +817,7 @@ begin
             if (Node.Bank.Storage.LoadBlockChainBlock(opc,bend)) then begin
               // Reward operation
               OPR := CT_TOperationResume_NUL;
+              OPR.valid := true;
               OPR.Block := bend;
               OPR.time := opc.OperationBlock.timestamp;
               OPR.AffectedAccount := bend * CT_AccountsPerBlock;

部分文件因为文件数量过多而无法显示