Browse Source

Merge pull request #43 from PascalCoinDev/master

5.4.Beta3 release
Pascal Coin 4 years ago
parent
commit
7dd0801f15

+ 1 - 1
CHANGELOG.md

@@ -1,7 +1,7 @@
 # Changelog
 
 ## Build 5.4 - (PENDING RELEASE)
-- CURRENT 5.4.Beta2
+- CURRENT 5.4.Beta3
 - Added usage of AbstractMem library to allow build a PascalCoin version using virtual memory and efficient caching mechanism
   - Use AbstractMem library v1.2
   - Must activate {$DEFINE USE_ABSTRACTMEM} at config.inc file (Enabled by default)

+ 1 - 1
src/core/UConst.pas

@@ -198,7 +198,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
 
-  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4.Beta2'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4.Beta2'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4.Beta3'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4.Beta3'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};

+ 15 - 10
src/core/UNetProtocol.pas

@@ -3397,7 +3397,7 @@ end;
 procedure TNetConnection.DoProcess_GetPubkeyAccounts_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
 Const CT_Max_Accounts_per_call = 1000;
 var responseStream, accountsStream : TMemoryStream;
-  start,max : Integer;
+  start,max,i : Integer;
   c, nAccounts : Cardinal;
   acc : TAccount;
   DoDisconnect : Boolean;
@@ -3405,6 +3405,7 @@ var responseStream, accountsStream : TMemoryStream;
   pubKey : TAccountKey;
   sbakl : TSafeboxPubKeysAndAccounts;
   ocl : TAccountsNumbersList;
+  LAccountsList : TList<Integer>;
 begin
   {
   This call is used to obtain Accounts used by a Public key
@@ -3451,15 +3452,19 @@ begin
     if Assigned(sbakl) then begin
       ocl := sbakl.GetAccountsUsingThisKey(pubKey);
       if Assigned(ocl) then begin
-        while (start<ocl.Count) And (max>0) do begin
-          acc := TNode.Node.GetMempoolAccount(ocl.Get(start));
-          if (HeaderData.protocol.protocol_available>9) then
-            TAccountComp.SaveAccountToAStream(accountsStream,acc,CT_PROTOCOL_5)
-          else
-            TAccountComp.SaveAccountToAStream(accountsStream,acc,CT_PROTOCOL_4);
-          inc(nAccounts);
-          inc(start);
-          dec(max);
+        LAccountsList := TList<Integer>.Create;
+        try
+          ocl.FillList(start,max,LAccountsList);
+          for i := 0 to LaccountsList.Count-1 do begin
+            acc := TNode.Node.GetMempoolAccount(LAccountsList[i]);
+            if (HeaderData.protocol.protocol_available>9) then
+              TAccountComp.SaveAccountToAStream(accountsStream,acc,CT_PROTOCOL_5)
+            else
+              TAccountComp.SaveAccountToAStream(accountsStream,acc,CT_PROTOCOL_4);
+          end;
+          nAccounts := LaccountsList.Count;
+        finally
+          LaccountsList.Free;
         end;
       end;
       // Save & send

+ 74 - 0
src/core/UNode.pas

@@ -128,6 +128,9 @@ Type
     class function NodeVersion : String;
     class function GetPascalCoinDataFolder : String;
     class procedure SetPascalCoinDataFolder(const ANewDataFolder : String);
+    //
+    function TryFindAccountByKey(const APubKey : TAccountKey; out AAccountNumber : Cardinal) : Boolean;
+    function TryFindPublicSaleAccount(AMaximumPrice : Int64; APreventRaceCondition : Boolean; out AAccountNumber : Cardinal) : Boolean;
   End;
 
   TThreadSafeNodeNotifyEvent = Class(TPCThread)
@@ -766,6 +769,77 @@ begin
   dec(FDisabledsNewBlocksCount);
 end;
 
+function TNode.TryFindAccountByKey(const APubKey: TAccountKey;
+  out AAccountNumber: Cardinal): Boolean;
+  // Finds the smallest numbered account with selected key (or returns false)
+var Lpka : TSafeboxPubKeysAndAccounts;
+  LAccountsNumberList : TAccountsNumbersList;
+begin
+  Result := False;
+  Lpka := Bank.SafeBox.OrderedAccountKeysList;
+  if Assigned(Lpka) then begin
+    LAccountsNumberList := Lpka.GetAccountsUsingThisKey(APubKey);
+    if Assigned(LAccountsNumberList) then begin
+      if LAccountsNumberList.Count>0 then begin
+        AAccountNumber := LAccountsNumberList.Get(0);
+        Result := True;
+      end;
+    end;
+  end;
+end;
+
+function TNode.TryFindPublicSaleAccount(AMaximumPrice: Int64; APreventRaceCondition : Boolean;
+  out AAccountNumber: Cardinal): Boolean;
+  // Finds an account at or below argument purchase price (or returns false)
+  // APreventRaceCondition: When True will return a random account in valid range price
+  // Limitations: Account must be >0
+var LtempAccNumber : Integer;
+  LLastValidAccount, LCurrAccount : TAccount;
+  LContinueSearching : Boolean;
+begin
+  Result := False;
+
+  // Sorted list: Bank.SafeBox.AccountsOrderedBySalePrice
+  // Note: List is sorted by Sale price (ASCENDING), but NOT by public/private sale, must check
+
+  if Not Bank.SafeBox.AccountsOrderedBySalePrice.FindLowest(LtempAccNumber) then Exit(False);
+  LCurrAccount := GetMempoolAccount(LtempAccNumber);
+
+  if (LCurrAccount.accountInfo.price<=AMaximumPrice)
+    and (TAccountComp.IsAccountForPublicSale(LCurrAccount.accountInfo)) then begin
+    LLastValidAccount := LCurrAccount;
+    LContinueSearching := (APreventRaceCondition) And (Random(50)=0);
+  end else begin
+    LLastValidAccount := CT_Account_NUL;
+    LContinueSearching := True;
+  end;
+
+  while (LCurrAccount.accountInfo.price<=AMaximumPrice) and (LContinueSearching) do begin
+
+    if TAccountComp.IsAccountForPublicSale(LCurrAccount.accountInfo) then LLastValidAccount := LCurrAccount;
+
+    if Not (Bank.SafeBox.AccountsOrderedBySalePrice.FindSuccessor(LtempAccNumber,LtempAccNumber)) then Break;
+    LCurrAccount := GetMempoolAccount(LtempAccNumber);
+
+    // If price increased, then do not continue and use LastValidAccount
+    if (LLastValidAccount.account>0)
+      and (LLastValidAccount.accountInfo.price <> LCurrAccount.accountInfo.price) then Break;
+
+    // Continue?
+    LContinueSearching :=
+      (LLastValidAccount.account=0) // This means that no valid account has been found yet...
+      or
+      (LContinueSearching And (Random(50)=0)); // Random prevention
+  end;
+  if (LLastValidAccount.account>0) then begin
+    AAccountNumber := LLastValidAccount.account;
+    Result := True;
+  end else begin
+    AAccountNumber := 0;
+    Result := False;
+  end;
+end;
+
 function TNode.TryLockNode(MaxWaitMilliseconds: Cardinal): Boolean;
 begin
   Result := TPCThread.TryProtectEnterCriticalSection(Self,MaxWaitMilliseconds,FLockMempool);

+ 1 - 0
src/core/UPCAbstractMem.pas

@@ -545,6 +545,7 @@ begin
   FreeAndNil(FBufferBlocksHash);
   FreeAndNil(FAggregatedHashrate);
   FreeAndNil(FAccountsOrderedByUpdatedBlock);
+  FreeAndNil(FAccountsOrderedBySalePrice);
   if (FFileName<>'') And (FAbstractMem is TMem) And (Not FAbstractMem.ReadOnly) then begin
     LFile := TFileStream.Create(FFileName,fmCreate);
     try

+ 32 - 0
src/core/UPCOrderedLists.pas

@@ -56,6 +56,8 @@ Type
     Procedure Disable;
     Procedure Enable;
     Function ToArray : TCardinalsArray;
+    function FillList(AStartIndex, ACount : Integer; const AList : TList<Cardinal>) : Integer; overload;
+    function FillList(AStartIndex, ACount : Integer; const AList : TList<Integer>) : Integer; overload;
   End;
 
 
@@ -180,6 +182,36 @@ begin
   if (FDisabledsCount=0) And (FModifiedWhileDisabled) then NotifyChanged;
 end;
 
+function TOrderedCardinalList.FillList(AStartIndex, ACount : Integer; const AList : TList<Cardinal>) : Integer;
+var i : Integer;
+begin
+  AList.Clear;
+  AList.Capacity := ACount;
+  if (AStartIndex=0) and (ACount=FOrderedList.Count) then begin
+    AList.InsertRange(AStartIndex,FOrderedList);
+  end else begin
+    while (ACount>0) and (AStartIndex < FOrderedList.Count) do begin
+      AList.Add( FOrderedList.Items[AStartIndex] );
+      Inc(AStartIndex);
+      Dec(ACount);
+    end;
+  end;
+  Result := AList.Count;
+end;
+
+function TOrderedCardinalList.FillList(AStartIndex, ACount: Integer; const AList: TList<Integer>): Integer;
+var i : Integer;
+begin
+  AList.Clear;
+  AList.Capacity := ACount;
+  while (ACount>0) and (AStartIndex < FOrderedList.Count) do begin
+    AList.Add( FOrderedList.Items[AStartIndex] );
+    Inc(AStartIndex);
+    Dec(ACount);
+  end;
+  Result := AList.Count;
+end;
+
 function TOrderedCardinalList.Find(const Value: Cardinal; var Index: Integer): Boolean;
 var L, H, I: Integer;
   C : Int64;

+ 24 - 12
src/core/UPCRPCFindAccounts.pas

@@ -152,6 +152,7 @@ var
   LAccPubKey : TAccountKey;
   LOutput : TPCJSONArray;
   LStartsWith : TOrderedRawList;
+  LAccountsList : TList<Integer>;
 begin
   // Get Parameters
   Result := False;
@@ -277,21 +278,32 @@ begin
     end;
   end else begin
     // Search by type-forSale-balance
-    i := LStart;
-    while (Not ASender.Terminated) And (i < LEnd) do begin
-      if (LSearchByPubkey) then begin
-        if (i>=LAccountsNumbersList.Count) then Break;
-        LAccount := ASender.Node.GetMempoolAccount( LAccountsNumbersList.Get(i) );
-      end else begin
-        LAccount := ASender.Node.GetMempoolAccount(i);
+    if (LSearchByPubkey) then begin
+      LAccountsList := TList<Integer>.Create;
+      try
+        LAccountsNumbersList.FillList(LStart,LEnd-LStart+1,LAccountsList);
+        for i := 0 to LAccountsList.Count-1 do begin
+          LAccount := ASender.Node.GetMempoolAccount( LAccountsList[i] );
+          if (_IsValidAccount(LAccount)) then begin
+            TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+            if LOutput.Count>=LMax then break;
+          end;
+        end;
+      finally
+        LAccountsList.Free;
       end;
+    end else begin
+      i := LStart;
+      while (Not ASender.Terminated) And (i < LEnd) do begin
+        LAccount := ASender.Node.GetMempoolAccount(i);
 
-      if (_IsValidAccount(LAccount)) then begin
-        TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
-        if LOutput.Count>=LMax then break;
-      end;
-      inc(i);
+        if (_IsValidAccount(LAccount)) then begin
+          TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+          if LOutput.Count>=LMax then break;
+        end;
+        inc(i);
 
+      end;
     end;
   end;
   Result := True;

+ 44 - 19
src/core/URPC.pas

@@ -2737,6 +2737,7 @@ Var c,c2,c3 : Cardinal;
   jsonarr : TPCJSONArray;
   jso : TPCJSONObject;
   LRPCProcessMethod : TRPCProcessMethod;
+  LAccountsList : TList<Integer>;
 begin
   _ro := Nil;
   _ra := Nil;
@@ -2791,13 +2792,15 @@ begin
       Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       k := params.AsInteger('max',100);
       l := params.AsInteger('start',0);
-      for j := 0 to Lanl.Count - 1 do begin
-        if (j>=l) then begin
-          account := FNode.GetMempoolAccount(Lanl.Get(j));
-          TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+      LAccountsList := TList<Integer>.Create;
+      Try
+        Lanl.FillList(l,k,LAccountsList);
+        for j := 0 to LAccountsList.Count - 1 do begin
+          account := FNode.GetMempoolAccount(LAccountsList[j]);
         end;
-        if (k>0) And ((j+1)>=(k+l)) then break;
-      end;
+      Finally
+        LAccountsList.Free;
+      End;
       Result := true;
     end else begin
       k := params.AsInteger('max',100);
@@ -2805,14 +2808,20 @@ begin
       c := 0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
-        for j := 0 to Lanl.Count - 1 do begin
-          if (c>=l) then begin
-            account := FNode.GetMempoolAccount(Lanl.Get(j));
-            TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+        LAccountsList := TList<Integer>.Create;
+        Try
+          Lanl.FillList(0,Lanl.Count,LAccountsList);
+          for j := 0 to LAccountsList.Count - 1 do begin
+            if (c>=l) then begin
+              account := FNode.GetMempoolAccount(LAccountsList[j]);
+              TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+            end;
+            inc(c);
+            if (k>0) And (c>=(k+l)) then break;
           end;
-          inc(c);
-          if (k>0) And (c>=(k+l)) then break;
-        end;
+        Finally
+          LAccountsList.Free;
+        End;
         if (k>0) And (c>=(k+l)) then break;
       end;
       Result := true;
@@ -2868,9 +2877,17 @@ begin
       end;
       Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       account.balance := 0;
-      for j := 0 to Lanl.Count - 1 do begin
-        inc(account.balance, FNode.GetMempoolAccount(Lanl.Get(j)).balance );
-      end;
+
+      LAccountsList := TList<Integer>.Create;
+      Try
+        Lanl.FillList(0,Lanl.Count,LAccountsList);
+        for j := 0 to LAccountsList.Count - 1 do begin
+          inc(account.balance, FNode.GetMempoolAccount(LAccountsList[j]).balance );
+        end;
+      Finally
+        LAccountsList.Free;
+      End;
+
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       Result := true;
     end else begin
@@ -2879,9 +2896,17 @@ begin
       account.balance := 0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
-        for j := 0 to Lanl.Count - 1 do begin
-          inc(account.balance, FNode.GetMempoolAccount(Lanl.Get(j)).balance );
-        end;
+
+        LAccountsList := TList<Integer>.Create;
+        Try
+          Lanl.FillList(0,Lanl.Count,LAccountsList);
+          for j := 0 to LAccountsList.Count - 1 do begin
+            inc(account.balance, FNode.GetMempoolAccount(LAccountsList[j]).balance );
+          end;
+        Finally
+          LAccountsList.Free;
+        End;
+
       end;
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       Result := true;

+ 1 - 5
src/core/upcdaemon.pas

@@ -105,9 +105,7 @@ Type
 
 implementation
 
-{$IFDEF TESTNET}
 uses UPCTNetDataExtraMessages;
-{$ENDIF}
 
 Var _FLog : TLog;
 
@@ -276,9 +274,6 @@ begin
       FNode.Bank.SafeBox.PCAbstractMem.MaxAccountsCache := LCacheMaxAccounts;
       FNode.Bank.SafeBox.PCAbstractMem.MaxAccountKeysCache := LCacheMaxPubKeys;
       {$ENDIF}
-      {$IFDEF TESTNET}
-      TPCTNetDataExtraMessages.InitNetDataExtraMessages(FNode,TNetData.NetData,FWalletKeys);
-      {$ENDIF}
       // RPC Server
       InitRPCServer;
       Try
@@ -301,6 +296,7 @@ begin
         // RPC Miner Server
         InitRPCMinerServer;
         Try
+          TPCTNetDataExtraMessages.InitNetDataExtraMessages(FNode,TNetData.NetData,FWalletKeys);
           Repeat
             Sleep(100);
           Until (Terminated) or (Application.Terminated);

+ 6 - 1
src/gui-classic/UFRMAskForAccount.pas

@@ -25,7 +25,12 @@ interface
 {$I ../config.inc}
 
 uses
-  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+{$IFnDEF FPC}
+  pngimage, Windows, Messages,
+{$ELSE}
+  LCLIntf, LCLType, LMessages,
+{$ENDIF}
+  SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UAccounts, Buttons, ActnList,
   ExtCtrls, ComCtrls,
   {$IFNDEF FPC}System.Actions, System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},

+ 6 - 1
src/gui-classic/UFRMSplash.pas

@@ -25,7 +25,12 @@ interface
 {$I ../config.inc}
 
 uses
-  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+{$IFnDEF FPC}
+  pngimage, Windows, Messages,
+{$ELSE}
+  LCLIntf, LCLType, LMessages,
+{$ENDIF}
+  SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UAccounts, Buttons, ActnList,
   ExtCtrls, ComCtrls,
   UNode, UWallet, UNetProtocol, UPCDataTypes, UThread,

+ 35 - 32
src/gui-classic/UGridUtils.pas

@@ -289,66 +289,69 @@ uses
 
 procedure TAccountsGridUpdateThread.BCExecute;
 Var
-  l : TAccountsNumbersList;
-  i,j, j_min, j_max : Integer;
+  LAccountsNumbersList : TAccountsNumbersList;
+  i,j, j_min : Integer;
   c  : Cardinal;
   LApplyfilter : Boolean;
   LAccount : TAccount;
   LNode : TNode;
+  LAccountsList : TList<Integer>;
 begin
   LApplyfilter := ((FAccountsGridFilter.MinBalance>0) Or ((FAccountsGridFilter.MaxBalance>=0) And (FAccountsGridFilter.MaxBalance<CT_MaxWalletAmount)));
   FBalance := 0;
   LNode := FAccountsGrid.Node;
   try
-      if (Assigned(FAccountsGridFilter.OrderedAccountsKeyList)) then begin
-        if (FAccountsGridFilter.indexAccountsKeyList<0) then i := 0
-        else i := FAccountsGridFilter.indexAccountsKeyList;
+    if (Assigned(FAccountsGridFilter.OrderedAccountsKeyList)) then begin
+      if (FAccountsGridFilter.indexAccountsKeyList<0) then i := 0
+      else i := FAccountsGridFilter.indexAccountsKeyList;
 
-        while (Not Terminated) and (i<FAccountsGridFilter.OrderedAccountsKeyList.Count)
-          and ((FAccountsGridFilter.indexAccountsKeyList<0) or (FAccountsGridFilter.indexAccountsKeyList=i)) do begin
+      while (Not Terminated) and (i<FAccountsGridFilter.OrderedAccountsKeyList.Count)
+        and ((FAccountsGridFilter.indexAccountsKeyList<0) or (FAccountsGridFilter.indexAccountsKeyList=i)) do begin
 
-          j_min := 0;
+        j_min := 0;
 
           while (j_min>=0) do begin
 
           LNode.bank.SafeBox.StartThreadSafe;
           FAccountsGridFilter.OrderedAccountsKeyList.Lock; // Protection v4
           Try
-            l := FAccountsGridFilter.OrderedAccountsKeyList.AccountKeyList[i];
-            if Assigned(l) then begin
-
-              j_max := (j_min + 500);
-              if j_max>=l.Count then j_max := l.Count-1;
-
-              for j := j_min to j_max do begin
-                LAccount := LNode.Bank.SafeBox.Account(l.Get(j));
-                if LApplyfilter then begin
-                  if (LAccount.balance>=FAccountsGridFilter.MinBalance) And ((FAccountsGridFilter.MaxBalance<0) Or (LAccount.balance<=FAccountsGridFilter.MaxBalance)) then begin
+            LAccountsNumbersList := FAccountsGridFilter.OrderedAccountsKeyList.AccountKeyList[i];
+            if Assigned(LAccountsNumbersList) then begin
+
+              LAccountsList := TList<Integer>.Create;
+              Try
+                LAccountsNumbersList.FillList(j_min,500,LAccountsList);
+                for j := 0 to LAccountsList.Count - 1 do begin
+                  LAccount := LNode.Bank.SafeBox.Account(LAccountsList[j]);
+
+                  if LApplyfilter then begin
+                    if (LAccount.balance>=FAccountsGridFilter.MinBalance) And ((FAccountsGridFilter.MaxBalance<0) Or (LAccount.balance<=FAccountsGridFilter.MaxBalance)) then begin
+                      FProcessedList.Add(LAccount.account);
+                      FBalance := FBalance + LAccount.balance;
+                    end;
+                  end else begin
                     FProcessedList.Add(LAccount.account);
                     FBalance := FBalance + LAccount.balance;
                   end;
-                end else begin
-                  FProcessedList.Add(LAccount.account);
-                  FBalance := FBalance + LAccount.balance;
+                  if Terminated then Exit;
                 end;
-                if Terminated then Exit;
-              end;
-              j_min := j_max+1;
-              if (j_max>=(l.Count-1)) then begin
-                j_min := -1;
-                break;
-              end;
+                if LAccountsList.Count>0 then inc(j_min,LAccountsList.Count)
+                else break;
+
+              Finally
+                LAccountsList.Free;
+              End;
+
             end;
           finally
             FAccountsGridFilter.OrderedAccountsKeyList.Unlock;
             LNode.Bank.SafeBox.EndThreadSave;
           end;
-            if j_max>=0 then Sleep(0);
 
-          end;
-          inc(i);
         end;
-      end else begin
+        inc(i);
+      end;
+    end else begin
         c := 0;
         while (c<LNode.Bank.SafeBox.AccountsCount) and (Not Terminated) do begin
           LAccount := LNode.Bank.SafeBox.Account(c);