Răsfoiți Sursa

Build 1.4.2

PascalCoin 8 ani în urmă
părinte
comite
683a1945e2

+ 2 - 2
PascalCoinMiner.lpi

@@ -7,7 +7,6 @@
       <Flags>
         <MainUnitHasCreateFormStatements Value="False"/>
         <MainUnitHasTitleStatement Value="False"/>
-        <UseDefaultCompilerOptions Value="True"/>
       </Flags>
       <SessionStorage Value="InProjectDir"/>
       <MainUnit Value="0"/>
@@ -30,6 +29,7 @@
     <RunParams>
       <local>
         <FormatVersion Value="1"/>
+        <CommandLineParams Value="-p 0 -d 1 -s -n a"/>
       </local>
     </RunParams>
     <Units Count="1">
@@ -47,7 +47,7 @@
     </Target>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
-      <OtherUnitFiles Value="Units\PascalCoin;PasOpenCL;Units\Utils"/>
+      <OtherUnitFiles Value="Units\PascalCoin;PasOpenCL;Units\Utils;Synapse\lib"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     <CodeGeneration>

+ 172 - 88
PascalCoinMiner.pp

@@ -38,7 +38,6 @@ type
     procedure OnDeviceStateChanged(Sender : TObject);
     procedure OnMinerValuesChanged(Sender : TObject);
     procedure OnFoundNOnce(Sender : TCustomMinerDeviceThread; Timestamp, nOnce : Cardinal);
-    procedure WriteLog(LogTxt : String);
     procedure WriteLine(nline : Integer; txt : String);
     procedure OnInThreadNewLog(logtype : TLogType; Time : TDateTime; ThreadID : Cardinal; Const sender, logtext : AnsiString);
   protected
@@ -46,7 +45,8 @@ type
     FLock : TCriticalSection;
     FPrivateKey : TECPrivateKey;
     FPoolMinerThread : TPoolMinerThread;
-    FDeviceThread : TCustomMinerDeviceThread;
+    FDeviceThreads : TList;
+    FAppStartTime : TDateTime;
     procedure DoRun; override;
   public
     constructor Create(TheOwner: TComponent); override;
@@ -55,15 +55,14 @@ type
   end;
 
 Const
-  CT_MINER_VERSION = 'Beta 0.1';
+  CT_MINER_VERSION = '0.2';
   CT_Line_DeviceStatus = 3;
-  CT_Line_ConnectionStatus = 5;
-  CT_Line_MinerValues = 8;
-  CT_Line_MiningStatus = 11;
-  CT_Line_LastFound = 14;
-  CT_Line_Logs = 17;
+  CT_Line_ConnectionStatus = 4;
+  CT_Line_MinerValues = 7;
+  CT_Line_MiningStatus = 10;
+  CT_Line_LastFound = 12;
+  CT_Line_Logs = 15;
   CT_MaxLogs = 10;
-  CT_Line_End = 28;
   CT_OpenCL_FileName = 'pascalsha.cl';
 
 { TPascalMinerApp }
@@ -100,30 +99,39 @@ end;
 
 procedure TPascalMinerApp.OnConnectionStateChanged(Sender: TObject);
 Const CT_state : Array[boolean] of String = ('Disconnected','Connected');
+var i : Integer;
 begin
   If FPoolMinerThread.PoolMinerClient.Connected then begin
     WriteLine(CT_Line_ConnectionStatus,'Connected to '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
-    If Assigned(FDeviceThread) then FDeviceThread.Paused:=false;
+    For i:=0 to FDeviceThreads.Count-1 do begin
+      TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=false;
+    end;
   end else begin
-    If Assigned(FDeviceThread) then FDeviceThread.Paused:=true;
-    WriteLine(CT_Line_ConnectionStatus,'Trying to connect to '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
+    For i:=0 to FDeviceThreads.Count-1 do begin
+      TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=true;
+    end;
+    WriteLine(CT_Line_ConnectionStatus,'** NO CONNECTED... Connecting to '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
   end;
 end;
 
 procedure TPascalMinerApp.OnDeviceStateChanged(Sender: TObject);
+Var i : Integer;
+  s : String;
 begin
-  If Sender is TCustomMinerDeviceThread then WriteLine(CT_Line_DeviceStatus,TCustomMinerDeviceThread(Sender).GetState);
+  If Sender is TCustomMinerDeviceThread then begin
+    If TCustomMinerDeviceThread(Sender).IsMining then WriteLine(CT_Line_DeviceStatus,'') // clear line
+    else WriteLine(CT_Line_DeviceStatus,'*** Not mining ***');
+  end;
 end;
 
 procedure TPascalMinerApp.OnMinerValuesChanged(Sender: TObject);
 begin
   If Sender is TCustomMinerDeviceThread then begin
     If TCustomMinerDeviceThread(Sender).MinerValuesForWork.block>0 then begin
-      WriteLine(CT_Line_MinerValues,Format('Current block: %d Miner name: %s Target: %s',
+      WriteLine(CT_Line_MinerValues,Format('Current block: %d Wallet Name: "%s" Target: %s',
         [TCustomMinerDeviceThread(Sender).MinerValuesForWork.block,
-         TCustomMinerDeviceThread(Sender).MinerValuesForWork.payload_start,
+         FPoolMinerThread.GlobalMinerValuesForWork.payload_start,
          IntToHex(TCustomMinerDeviceThread(Sender).MinerValuesForWork.target,8)
-//         ,TCrypto.ToHexaString(TCustomMinerDeviceThread(Sender).MinerValuesForWork.target_pow)
          ]));
     end;
   end;
@@ -131,22 +139,15 @@ end;
 
 procedure TPascalMinerApp.OnFoundNOnce(Sender: TCustomMinerDeviceThread; Timestamp, nOnce: Cardinal);
 begin
-  WriteLine(CT_Line_LastFound,FormatDateTime('hh:nn:ss',now)+' Block:'+IntToStr(Sender.MinerValuesForWork.block)+' NOnce:'+Inttostr(nOnce)+
+  WriteLine(CT_Line_LastFound + FDeviceThreads.Count,FormatDateTime('hh:nn:ss',now)+' Block:'+IntToStr(Sender.MinerValuesForWork.block)+' NOnce:'+Inttostr(nOnce)+
     ' Timestamp:'+inttostr(Timestamp)+' Miner:'+Sender.MinerValuesForWork.payload_start);
 end;
 
-procedure TPascalMinerApp.WriteLog(LogTxt: String);
-begin
-  WriteLine(CT_Line_MiningStatus,FormatDateTime('hh:nn:ss',now)+' '+LogTxt);
-end;
-
 procedure TPascalMinerApp.WriteLine(nline: Integer; txt: String);
-Var x,y,i : Integer;
+Var i : Integer;
 begin
   FLock.Acquire;
   try
-    x := WhereX32;
-    y := WhereY32;
     i := length(txt);
     if i<=(FWindow32X2-FWindow32X1+1) then begin
       setlength(txt,FWindow32X2-FWindow32X1+1);
@@ -154,8 +155,10 @@ begin
     end else begin
       txt := copy(txt,1,FWindow32X2-FWindow32X1+1);
     end;
-    GotoXY32(FWindow32X1,nline);
-    write(txt);
+    if (nline<=(FWindow32Y2-FWindow32Y1)) then begin
+      GotoXY32(FWindow32X1,nline);
+      write(txt);
+    end;
   finally
     FLock.Release;
   end;
@@ -173,7 +176,7 @@ begin
     FLastLogs.AddObject(msg,TObject(PtrInt(logtype)));
     i := FLastLogs.Count-CT_MaxLogs;
     if (i<0) then i:=0;
-    nline := CT_Line_Logs;
+    nline := CT_Line_Logs+FDeviceThreads.Count;
     while (i<FLastLogs.Count) do begin
       WriteLine(nline,FLastLogs[i]);
       inc(nline); inc(i);
@@ -181,8 +184,6 @@ begin
     if FLastLogs.Count>(CT_MaxLogs*2) then begin
       for i:=1 to CT_MaxLogs do FLastLogs.Delete(0);
     end;
-//    If logtype=lterror then WriteLine(CT_Line_LogError,'Error: '+logtext)
-//    else if logtype=ltinfo then WriteLine(CT_Line_LogInfo,'Info: '+logtext)
   Finally
     FLock.Release;
   end;
@@ -194,12 +195,14 @@ var
   s : String;
   nsarr : TNodeServerAddressArray;
 
-  Function AddMiner : Boolean;
-  var p,d,c : Integer;
+  Function AddMiners : Boolean;
+  var p,d,c,i : Integer;
+    strl : TStringList;
+    devt : TCustomMinerDeviceThread;
   begin
     Result := false;
     if (Not HasOption('p','platform')) And (Not HasOption('d','device')) And (Not HasOption('c','cpu:')) then begin
-      Writeln('Need to specify -pX and -dY for GPU mining or -cN for CPU mining. See -h for more info');
+      Writeln('Need to specify -p X and -d Y for GPU mining or -c N for CPU mining. See -h for more info');
       ShowGPUDrivers;
       Terminate;
       Exit;
@@ -211,12 +214,13 @@ var
         Terminate;
         exit;
       end;
-      FDeviceThread:= TCPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
-      FDeviceThread.OnStateChanged:=@OnDeviceStateChanged;
-      FDeviceThread.OnMinerValuesChanged:=@OnMinerValuesChanged;
-      FDeviceThread.OnFoundNOnce:=@OnFoundNOnce;
-      TCPUDeviceThread(FDeviceThread).CPUs:=c;
-      FDeviceThread.Paused:=true;
+      devt:= TCPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
+      devt.OnStateChanged:=@OnDeviceStateChanged;
+      devt.OnMinerValuesChanged:=@OnMinerValuesChanged;
+      devt.OnFoundNOnce:=@OnFoundNOnce;
+      TCPUDeviceThread(devt).CPUs:=c;
+      devt.Paused:=true;
+      FDeviceThreads.Add(devt);
     end else begin
       p := StrToIntDef(GetOptionValue('p','platform'),-1);
       d := StrToIntDef(GetOptionValue('d','device'),-1);
@@ -225,49 +229,99 @@ var
         Terminate;
         exit;
       end;
-      if (d<0) or (d>=TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount) then begin
-        WriteLn('Invalid device ',d,'. Valid values: 0..',TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount-1);
-        Terminate;
-        exit;
+      strl := TStringList.Create;
+      try
+        if (d<0) then begin
+          // Is a value separated by commas?
+          strl.Delimiter:=',';
+          strl.DelimitedText:=GetOptionValue('d','device');
+        end else strl.Text:=inttostr(d);
+        for i:=0 to strl.Count-1 do begin
+          d := StrToIntDef(strl[i],-1);
+          if (d<0) or (d>=TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount) then begin
+            WriteLn('Invalid device ',d,'. Valid values: 0..',TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount-1);
+            Terminate;
+            exit;
+          end;
+          //
+          devt := TGPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
+          devt.OnStateChanged:=@OnDeviceStateChanged;
+          devt.OnMinerValuesChanged:=@OnMinerValuesChanged;
+          devt.OnFoundNOnce:=@OnFoundNOnce;
+          TGPUDeviceThread(devt).Platform:=p;
+          TGPUDeviceThread(devt).Device:=d;
+          TGPUDeviceThread(devt).ProgramFileName:=ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName;
+          devt.Paused:=true;
+          FDeviceThreads.Add(devt);
+        end;
+      finally
+        strl.Free;
       end;
-      //
-      FDeviceThread := TGPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
-      FDeviceThread.OnStateChanged:=@OnDeviceStateChanged;
-      FDeviceThread.OnMinerValuesChanged:=@OnMinerValuesChanged;
-      FDeviceThread.OnFoundNOnce:=@OnFoundNOnce;
-      TGPUDeviceThread(FDeviceThread).Platform:=p;
-      TGPUDeviceThread(FDeviceThread).Device:=d;
-      TGPUDeviceThread(FDeviceThread).ProgramFileName:=ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName;
-      FDeviceThread.Paused:=true;
     end;
+    Result := true;
   end;
 
   Procedure DoWaitAndLog;
   Var tc : Cardinal;
     gs,ms : TMinerStats;
-    hr : Int64;
+    hrReal,hrHashing, glhrHashing, glhrReal : Real;
+    i : Integer;
+    devt : TCustomMinerDeviceThread;
+    s : String;
   Begin
     tc := GetTickCount;
     repeat
-      If FPoolMinerThread.PoolMinerClient.Connected then FDeviceThread.Paused:=false;
+      If FPoolMinerThread.PoolMinerClient.Connected then begin
+        for i:=0 to FDeviceThreads.Count-1 do begin
+          TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=false;
+        end;
+      end;
       while (Not Terminated) do begin
         sleep(100);
+        //devt := TCustomMinerDeviceThread(FDeviceThreads[0]);
         If (tc + 1000)<GetTickCount then begin
           tc := GetTickCount;
-          ms := FDeviceThread.DeviceStats;
+          //ms := devt.DeviceStats;
+          For i:=0 to FDeviceThreads.Count-1 do begin
+            devt := TCustomMinerDeviceThread(FDeviceThreads[i]);
+            ms := devt.DeviceStats;
+            if ms.WorkingMillisecondsHashing>0 then hrHashing := (((ms.RoundsCount DIV Int64(ms.WorkingMillisecondsHashing)))/(1000))
+            else hrHashing := 0;
+            gs := devt.GlobalDeviceStats;
+            If ms.RoundsCount>0 then begin
+              s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" at %0.2f MH/s - Rounds: %0.2f G Found: %d',[devt.MinerValuesForWork.payload_start,hrHashing, gs.RoundsCount/1000000000, gs.WinsCount]);
+              If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
+              WriteLine(CT_Line_MiningStatus+i,s);
+            end else begin
+              If gs.RoundsCount>0 then begin
+                s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" **NOT MINING** - Rounds: %0.2f G Found: %d',[devt.MinerValuesForWork.payload_start,gs.RoundsCount/1000000000, gs.WinsCount]);
+                If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
+              end else begin
+                s := FormatDateTime('hh:nn:ss',now)+' Not mining...';
+              end;
+              WriteLine(CT_Line_MiningStatus+i,s);
+            end;
+          end;
+          {
           gs := FPoolMinerThread.GlobalMinerStats;
-          if ms.WorkingMilliseconds>0 then hr := (ms.RoundsCount DIV Int64(ms.WorkingMilliseconds)) * 1000
-          else hr := 0;
+          if ms.WorkingMillisecondsHashing>0 then hrHashing := (((ms.RoundsCount DIV Int64(ms.WorkingMillisecondsHashing)))/(1000))
+          else hrHashing := 0;
+          if ms.WorkingMillisecondsTotal>0 then hrReal := (((ms.RoundsCount DIV Int64(ms.WorkingMillisecondsTotal)))/(1000))
+          else hrReal := 0;
+          if gs.WorkingMillisecondsHashing>0 then glhrHashing := (((gs.RoundsCount DIV Int64(gs.WorkingMillisecondsHashing)))/(1000))
+          else glhrHashing := 0;
+          if gs.WorkingMillisecondsTotal>0 then glhrReal := (((gs.RoundsCount DIV Int64(gs.WorkingMillisecondsTotal)))/(1000))
+          else glhrReal := 0;
           If gs.RoundsCount>0 then begin
-            WriteLog(Format('Mining at %0.2f MHash/s - Total Rounds: %0.2f G ',[hr / (1024*1024),gs.RoundsCount/1073741824]));
+            WriteLog(Format('Mining at %0.2f MHash/s %0.2f %0.2f %0.2f - Total Rounds: %0.2f G ',[hrHashing,glhrHashing, hrReal, glhrReal, gs.RoundsCount/1073741824]));
           end else begin
             WriteLog('Not mining... check connection or paused state...');
-          end;
-          WriteLine(CT_Line_LastFound-1,'MY VALID BLOCKS FOUND: '+IntToStr(gs.WinsCount) );
+          end; }
+          WriteLine(CT_Line_LastFound+FDeviceThreads.Count-1,'MY VALID BLOCKS FOUND: '+IntToStr(gs.WinsCount) +' Working time: '+IntToStr(Trunc(now - FAppStartTime))+'d '+FormatDateTime('hh:nn:ss',Now-FAppStartTime) );
         end;
         If KeyPressed then begin
           If ReadKey in ['c','C','q','Q'] then begin
-            WriteLine(CT_Line_End,'Finalizing...');
+            WriteLine(CT_Line_Logs+FDeviceThreads.Count+CT_MaxLogs,'Finalizing...');
             terminate;
           end;
         end;
@@ -278,28 +332,47 @@ var
   Procedure DoVisualprocess(minerName : String);
   Var sc : tcrtcoord;
     Flog : TLog;
+    devt : TCustomMinerDeviceThread;
+    i : Integer;
   Begin
-    cursoroff;
+    FPoolMinerThread := TPoolMinerThread.Create(nsarr[0].ip,nsarr[0].port,FPrivateKey.PublicKey);
     try
-      clrscr;
-      FWindow32X1:=WindMinX;
-      FWindow32X2:=WindMaxX;
-      FWindow32Y1:=WindMinY;
-      FWindow32Y2:=WindMaxY;
-      WriteLine(1,'** PascalCoin miner ** Version: '+CT_MINER_VERSION);
-      WriteLine(CT_Line_MinerValues-1,'MINER VALUES:');
-      WriteLine(CT_Line_MiningStatus-1,'MINING STATUS:');
-      WriteLine(CT_Line_LastFound-1,'MY VALID BLOCKS FOUND: 0');
-      WriteLine(CT_Line_Logs-1,'LOGS:');
-
-      FPoolMinerThread := TPoolMinerThread.Create(nsarr[0].ip,nsarr[0].port,FPrivateKey.PublicKey);
+      If Not AddMiners then exit;
+      if HasOption('t','testmode') then begin
+        i := StrToIntDef(GetOptionValue('t','testmode'),-1);
+        if (i>=0) And (i<=32) then begin
+          FPoolMinerThread.TestingPoWLeftBits:=i;
+        end else begin
+          WriteLn('Invalid bits for testing mode. value ',i,'. Valid values: 0..32  (0=No testing mode)');
+          Terminate;
+          exit;
+        end;
+      end;
+      cursoroff;
       try
+        clrscr;
+        FWindow32X1:=WindMinX;
+        FWindow32X2:=WindMaxX;
+        FWindow32Y1:=WindMinY;
+        FWindow32Y2:=WindMaxY;
+        WriteLine(1,'** PascalCoin miner ** Version: '+CT_MINER_VERSION);
+        WriteLine(CT_Line_MinerValues-1,'MINER VALUES:');
+        WriteLine(CT_Line_MiningStatus-1,'MINING STATUS:');
+        WriteLine(CT_Line_LastFound+FDeviceThreads.Count-1,'MY VALID BLOCKS FOUND: 0');
+        WriteLine(CT_Line_Logs+FDeviceThreads.Count-1,'LOGS:');
+
         FPoolMinerThread.MinerAddName:=minerName;
         WriteLine(CT_Line_MinerValues-1,'MINER VALUES: (My miner name="'+minerName+'")');
+
         FPoolMinerThread.OnConnectionStateChanged:=@OnConnectionStateChanged;
         OnConnectionStateChanged(FPoolMinerThread);
-        AddMiner;
-        WriteLine(2,FDeviceThread.MinerDeviceName);
+
+        If (FDeviceThreads.Count)=1 then begin
+          devt := TCustomMinerDeviceThread(FDeviceThreads[0]);
+          WriteLine(2,devt.MinerDeviceName);
+        end else begin
+          WriteLine(2,'Mining using '+IntToStr(FDeviceThreads.Count)+' devices');
+        end;
         Flog := TLog.Create(Nil);
         try
           Flog.OnInThreadNewLog:=@OnInThreadNewLog;
@@ -307,12 +380,12 @@ var
         finally
           FLog.free;
         end;
-        FPoolMinerThread.Terminate;
-      Finally
-        FPoolMinerThread.Free;
+      finally
+        cursoron;
       end;
-    finally
-      cursoron;
+    Finally
+      FPoolMinerThread.Terminate;
+      FPoolMinerThread.Free;
     end;
   end;
 
@@ -321,7 +394,7 @@ begin
   FLock := TCriticalSection.Create;
   Try
     // quick check parameters
-    ErrorMsg:=CheckOptions('hp:d:s:c:n:', 'help platform device server cpu minername');
+    ErrorMsg:=CheckOptions('hp:d:s::c:n::t:', 'help platform device server cpu minername testmode');
     if ErrorMsg<>'' then begin
       //ShowException(Exception.Create(ErrorMsg));
       WriteLn(ErrorMsg);
@@ -335,7 +408,8 @@ begin
     end;
 
     if (Not HasOption('p','platform')) And (Not HasOption('d','device')) And (Not HasOption('c','cpu:')) then begin
-      Writeln('Need to specify -p X and -d Y for GPU mining or -c N for CPU mining. See -h for more info');
+      Writeln('Need to specify -p X and -d Y for GPU mining or -c N for CPU mining');
+      Writeln('Execute ',ExtractFileName(ExeName),' -h for more info');
       ShowGPUDrivers;
       Exit;
     end;
@@ -348,13 +422,19 @@ begin
     end;
 
 
-    If HasOption('s','server') then s := GetOptionValue('s','server')
-    else s:='';
+    If HasOption('s','server') then begin
+      s := Trim(GetOptionValue('s','server'));
+      if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);
+    end else s:='';
     if (s='') then begin
       WriteLn('Input server name (default is localhost:',CT_JSONRPCMinerServer_Port,'):');
       Readln(s);
+      trim(s);
       if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);
     end;
+    if (pos(':',s)=0) then begin
+      s := trim(s) + ':'+inttostr(CT_JSONRPCMinerServer_Port);
+    end;
     TNode.DecodeIpStringToNodeServerAddressArray(s,nsarr);
     if (length(nsarr)<>1) then begin
       Writeln('INVALID SERVER VALUE ',s);
@@ -394,11 +474,14 @@ end;
 constructor TPascalMinerApp.Create(TheOwner: TComponent);
 begin
   inherited Create(TheOwner);
+  FDeviceThreads := TList.Create;
   StopOnException:=True;
+  FAppStartTime := Now;
 end;
 
 destructor TPascalMinerApp.Destroy;
 begin
+  FreeAndNil(FDeviceThreads);
   inherited Destroy;
 end;
 
@@ -406,11 +489,12 @@ procedure TPascalMinerApp.WriteHelp;
 begin
   { add your help code here }
   writeln('PascalCoin Miner - Version: ',CT_MINER_VERSION);
-  writeln('Usage: ', ExeName, ' -h -s S -p X -d Y -c N -n MYNAME');
+  writeln('Usage: ', ExtractFileName(ExeName), ' -h -s S -p X -d Y -c N -n MYNAME');
   writeln('  -h for help');
   writeln('  -s S  (S is PascalCoin server:port where default value is localhost:',CT_JSONRPCMinerServer_Port,')');
   writeln('  -p X  (X is GPU platform)');
   writeln('  -d Y  (Y is GPU device for platform)');
+  writeln('    Y can be multiple devices. Example -d 0,2,3  Will use devices 0, 2 and 3');
   writeln('  -c N  (For CPU mining, where N is CPU''s to use. Activating this disable GPU mining)');
   writeln('  -n MYNAME  (Will add MYNAME value to miner name assigned by server)');
   writeln('');
@@ -418,8 +502,8 @@ begin
   writeln('  ',ExtractFileName(ExeName),' -s 192.168.1.77:4009 -c 2 -n USER_1');
   writeln('  (2 CPU''s to server 192.168.1.77 port 4009 and miner name USER_1)');
   writeln('Basic example GPU mining: ');
-  writeln('  ',ExtractFileName(ExeName),' -p 0 -d 0 -n ABC');
-  writeln('  (p 0 d 0 at server localhost and port ',CT_JSONRPCMinerServer_Port,' miner name ABC)');
+  writeln('  ',ExtractFileName(ExeName),' -p 0 -d 0 -s -n ABC');
+  writeln('  (p 0 d 0 at server localhost:',CT_JSONRPCMinerServer_Port,' miner name ABC)');
   writeln('');
   ShowGPUDrivers;
 end;

+ 3 - 0
PascalCoinWalletLazarus.lpi

@@ -204,6 +204,9 @@
   <CompilerOptions>
     <Version Value="11"/>
     <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="PascalCoinWalletLazarus"/>
+    </Target>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
       <OtherUnitFiles Value="Synapse\lib;Units\Forms;Units\PascalCoin;Units\Utils"/>

+ 7 - 0
README.md

@@ -34,6 +34,13 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.4.2.0 - 2017-01-23
+
+- Max JSON-RPC miner connections is now 1000 (before, 10)
+- JSON-RPC miner enabled at pascalcoin_daemon (linux daemon)
+- Screen messages for daemon
+- pascalcoin_daemon.ini file for daemon
+
 ### Build 1.4.1.0 - 2017-01-18
 
 - Improved JSON communications with Miner client (Port 4009 by default)

+ 7 - 0
README.txt

@@ -34,6 +34,13 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.4.2.0 - 2017-01-23
+
+- Max JSON-RPC miner connections is now 1000 (before, 10)
+- JSON-RPC miner enabled at pascalcoin_daemon (linux daemon)
+- Screen messages for daemon
+- pascalcoin_daemon.ini file for daemon
+
 ### Build 1.4.1.0 - 2017-01-18
 
 - Improved JSON communications with Miner client (Port 4009 by default)

+ 1 - 1
Units/PascalCoin/UConst.pas

@@ -100,7 +100,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.4.1'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.4.2'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 

+ 91 - 81
Units/PascalCoin/UGPUMining.pas

@@ -126,51 +126,29 @@ end;
 
 { TGPUDeviceThread }
 
-procedure TGPUDeviceThread.SetDevice(AValue: Integer);
-begin
-  if FDevice=AValue then Exit;
-  FDevice:=AValue;
-  FNeedNewDevice := true;
-  UpdateState;
-end;
-
-procedure TGPUDeviceThread.SetPlatform(AValue: Integer);
-begin
-  if FPlatform=AValue then Exit;
-  FPlatform:=AValue;
-  FNeedNewDevice := true;
-  UpdateState;
-end;
-
-procedure TGPUDeviceThread.SetProgramFileName(AValue: String);
-begin
-  if FProgramFileName=AValue then Exit;
-  FProgramFileName:=AValue;
-  FNeedNewDevice:=true;
-  UpdateState;
-end;
-
 procedure TGPUDeviceThread.BCExecute;
-Const CT_LAPS_ROUND = 4194304; // 2^22 = 4194304     2^20 = 1048576
-      CT_MAX_LAPS = 1024; // 2^10 = 1024
+Const CT_LAPS_ROUND = 16777216; // 2^24 = 16777216 2^22 = 4194304     2^20 = 1048576
+      CT_MAX_LAPS = 256; // 2^8 = 256 2^10 = 1024
 Var Timestamp, nOnce : Cardinal;
   nLap : Cardinal;
-  TC : Cardinal;
+  baseRealTC,baseHashingTC,finalHashingTC,lastNotifyTC : Cardinal;
   AuxStats : TMinerStats;
 begin
   UpdateState;
   nLap := 0;
+  AuxStats := CT_TMinerStats_NULL;
+  lastNotifyTC :=GetTickCount;
   while Not Terminated do begin
     If (Paused) then begin
       sleep(1);
     end else begin
-      TC := GetTickCount;
+      baseRealTC := GetTickCount;
       FLock.Acquire;
       try
+      //  AuxStats := CT_TMinerStats_NULL;
         If FReadyToGPU then begin
-          AuxStats := CT_TMinerStats_NULL;
           Timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
-          if Timestamp<=FPoolMinerThread.GlobalMinerValuesForWork.timestamp then Timestamp := FPoolMinerThread.GlobalMinerValuesForWork.timestamp+1;
+          if Timestamp<=PoolMinerThread.GlobalMinerValuesForWork.timestamp then Timestamp := PoolMinerThread.GlobalMinerValuesForWork.timestamp+1;
           FKernelArg1[ (FChangeTimestampAndNOnceBytePos DIV 4) ] := bswap(Timestamp);
           // FKernelArg1[24] = Position to save nOnce
           FKernelArg1[24] := (FChangeTimestampAndNOnceBytePos DIV 4)+1;
@@ -181,7 +159,9 @@ begin
           try
             FDCLKernel.SetArg(0,FKernelInputBuffer);
             FDCLKernel.SetArg(1,FKernelOutputBuffer);
+            baseHashingTC := GetTickCount;
             FDCLCommandQueue.Execute(FDCLKernel,CT_LAPS_ROUND);
+            finalHashingTC := GetTickCount;
           finally
             FreeAndNil(FKernelInputBuffer);
           end;
@@ -202,23 +182,97 @@ begin
           end;
           if (nLap<CT_MAX_LAPS) then inc(nLap) else nLap := 0;
           inc(AuxStats.RoundsCount,CT_LAPS_ROUND);
-          inc(AuxStats.WorkingMilliseconds,GetTickCount-TC);
-          UpdateDeviceStats(AuxStats);
         end;
       finally
         FLock.Release;
       end;
+      If (AuxStats.RoundsCount>0) then begin
+        inc(AuxStats.WorkingMillisecondsTotal,GetTickCount - baseRealTC);
+        inc(AuxStats.WorkingMillisecondsHashing,finalHashingTC-baseHashingTC);
+      end;
+    end;
+    If (lastNotifyTC + 200 < GetTickCount) then begin
       sleep(1);
+      lastNotifyTC := GetTickCount;
+      UpdateDeviceStats(AuxStats);
+      AuxStats := CT_TMinerStats_NULL;
     end;
   end;
 end;
 
+constructor TGPUDeviceThread.Create(PoolMinerThread: TPoolMinerThread; InitialMinerValuesForWork: TMinerValuesForWork);
+begin
+  FReadyToGPU := false;
+  FDevice:=-1;
+  FPlatform:=-1;
+  FNeedNewDevice:=false;
+  FProgramFileName:='';
+  FLock := TCriticalSection.Create;
+  FDCLDevice := Nil;
+  FDCLProgram := Nil;
+  FDCLCommandQueue := Nil;
+  FDCLKernel := Nil;
+  FKernelInputBuffer := Nil;
+  FKernelOutputBuffer := Nil;
+  inherited Create(PoolMinerThread, InitialMinerValuesForWork);
+end;
+
+destructor TGPUDeviceThread.Destroy;
+begin
+  FreeAndNil(FLock);
+  FreeAndNil(FDCLCommandQueue);
+  FreeAndNil(FKernelOutputBuffer);
+  FreeAndNil(FKernelInputBuffer);
+  FreeAndNil(FDCLKernel);
+  FreeAndNil(FDCLProgram);
+  inherited Destroy;
+end;
+
+function TGPUDeviceThread.GetState: String;
+begin
+  If Paused then result := 'GPU miner is paused'
+  else if (IsMining) And Assigned(FDCLDevice) then Result := 'GPU is mining on p '+IntToStr(Platform)+' d '+IntToStr(Device)+' Compute units:'+IntToStr(FDCLDevice.MaxComputeUnits)+' Freq:'+IntToStr(FDCLDevice.MaxClockFrequency)
+  else Result := 'GPU miner is waiting for configuration...';
+end;
+
+function TGPUDeviceThread.MinerDeviceName: String;
+begin
+  Result := 'GPU p'+inttostr(FPlatform)+' d'+IntToStr(FDevice);
+  If assigned(FDCLDevice) then begin
+    Result := Result+' Name:'+Trim(FDCLDevice.Name)+' CU:'+IntToStr(FDCLDevice.MaxComputeUnits)+' Freq:'+IntToStr(FDCLDevice.MaxClockFrequency);
+  end else Result := Result + ' (no info)';
+end;
+
+procedure TGPUDeviceThread.SetDevice(AValue: Integer);
+begin
+  if FDevice=AValue then Exit;
+  FDevice:=AValue;
+  FNeedNewDevice := true;
+  UpdateState;
+end;
+
 procedure TGPUDeviceThread.SetMinerValuesForWork(const Value: TMinerValuesForWork);
 begin
   inherited;
   UpdateBuffers;
 end;
 
+procedure TGPUDeviceThread.SetPlatform(AValue: Integer);
+begin
+  if FPlatform=AValue then Exit;
+  FPlatform:=AValue;
+  FNeedNewDevice := true;
+  UpdateState;
+end;
+
+procedure TGPUDeviceThread.SetProgramFileName(AValue: String);
+begin
+  if FProgramFileName=AValue then Exit;
+  FProgramFileName:=AValue;
+  FNeedNewDevice:=true;
+  UpdateState;
+end;
+
 procedure TGPUDeviceThread.UpdateState;
 begin
   FLock.Acquire;
@@ -264,18 +318,18 @@ Var stateforlastchunk : TSHA256HASH;
 begin
   FLock.Acquire;
   try
-    FReadyToGPU := (FMinerValuesForWork.part1<>'') And (Assigned(FDCLKernel));
+    FReadyToGPU := (MinerValuesForWork.part1<>'') And (Assigned(FDCLKernel));
     If (Not FReadyToGPU) then begin
       IsMining := false;
       exit;
     end;
     Repeat
-      i := Length(FMinerValuesForWork.part1)+Length(FMinerValuesForWork.payload_start)+Length(FMinerValuesForWork.part3)+8;
+      i := Length(MinerValuesForWork.part1)+Length(MinerValuesForWork.payload_start)+Length(MinerValuesForWork.part3)+8;
       canWork := CanBeModifiedOnLastChunk(i,FChangeTimestampAndNOnceBytePos);
-      If Not canWork then FMinerValuesForWork.payload_start:=FMinerValuesForWork.payload_start+'.';
+      If Not canWork then FMinerValuesForWork.payload_start:=MinerValuesForWork.payload_start+'.';
     until (canWork);
     FillChar(FKernelArg1[0],29*4,#0);
-    s := FMinerValuesForWork.part1+FMinerValuesForWork.payload_start+FMinerValuesForWork.part3+'00000000';
+    s := MinerValuesForWork.part1+MinerValuesForWork.payload_start+MinerValuesForWork.part3+'00000000';
     PascalCoinPrepareLastChunk(s,stateforlastchunk,bufferForLastChunk);
     // FKernelArg1[0..15] = data for last chunk
     move(bufferForLastChunk[0],FKernelArg1[0],16*4);
@@ -288,7 +342,7 @@ begin
     // FKernelArg1[25] = high-order 12 bits for nOnce (see .cl file to know)
     // FKernelArg1[26..28] = Mask (obtained  from target_pow)
     FillChar(FKernelArg1[26],4*3,#0);
-    s := FMinerValuesForWork.target_pow;
+    s := MinerValuesForWork.target_pow;
     i := 1;
     while (length(s)>=i) And (i<=4*3) do begin
       b := Byte(s[i]);
@@ -306,50 +360,6 @@ begin
   end;
 end;
 
-constructor TGPUDeviceThread.Create(PoolMinerThread: TPoolMinerThread; InitialMinerValuesForWork: TMinerValuesForWork);
-begin
-  FReadyToGPU := false;
-  FDevice:=-1;
-  FPlatform:=-1;
-  FNeedNewDevice:=false;
-  FProgramFileName:='';
-  FLock := TCriticalSection.Create;
-  FDCLDevice := Nil;
-  FDCLProgram := Nil;
-  FDCLCommandQueue := Nil;
-  FDCLKernel := Nil;
-  FKernelInputBuffer := Nil;
-  FKernelOutputBuffer := Nil;
-  inherited Create(PoolMinerThread, InitialMinerValuesForWork);
-end;
-
-destructor TGPUDeviceThread.Destroy;
-begin
-  FreeAndNil(FLock);
-  FreeAndNil(FDCLCommandQueue);
-  FreeAndNil(FKernelOutputBuffer);
-  FreeAndNil(FKernelInputBuffer);
-  FreeAndNil(FDCLKernel);
-  FreeAndNil(FDCLProgram);
-  inherited Destroy;
-end;
-
-function TGPUDeviceThread.MinerDeviceName: String;
-begin
-  Result := 'GPU miner Platform '+inttostr(FPlatform)+' Device '+IntToStr(FDevice);
-  If assigned(FDCLDevice) then begin
-    Result := Result+' '+FDCLDevice.Name+' Vendor: '+FDCLDevice.Vendor;
-  end else Result := Result + ' (Unknown)';
-end;
-
-function TGPUDeviceThread.GetState: String;
-begin
-  If Paused then result := 'GPU miner is paused'
-  else if (IsMining) And Assigned(FDCLDevice) then Result := 'GPU is mining on p '+IntToStr(Platform)+' d '+IntToStr(Device)+' Compute units:'+IntToStr(FDCLDevice.MaxComputeUnits)+' Freq:'+IntToStr(FDCLDevice.MaxClockFrequency)
-//  else if (Assigned(FDCLKernel)) then Result := 'GPU miner platform '+IntToStr(Platform)+' device '+IntToStr(Device)
-  else Result := 'GPU miner is waiting for configuration...';
-end;
-
 initialization
   _initstatus := 0;
 finalization

+ 7 - 1
Units/PascalCoin/ULog.pas

@@ -92,18 +92,20 @@ Type PLogData = ^TLogData;
 constructor TLog.Create(AOwner: TComponent);
 Var l : TList;
 begin
-  inherited;
   FLock := TCriticalSection.Create;
   FProcessGlobalLogs := true;
   FLogDataList := TThreadList.Create;
   FFileStream := Nil;
   FFileName := '';
   FSaveTypes := CT_TLogTypes_DEFAULT;
+  FOnInThreadNewLog:=Nil;
+  FOnNewLog:=Nil;
   if (Not assigned(_logs)) then _logs := TList.Create;
   _logs.Add(self);
   FThreadSafeLogEvent := TThreadSafeLogEvent.Create(true);
   FThreadSafeLogEvent.FLog := Self;
   FThreadSafeLogEvent.Suspended := false;
+  inherited;
 end;
 
 destructor TLog.Destroy;
@@ -112,6 +114,8 @@ var
   i : Integer;
   P : PLogData;
 begin
+  FOnNewLog:=Nil;
+  FOnInThreadNewLog:=Nil;
   FThreadSafeLogEvent.Terminate;
   FThreadSafeLogEvent.WaitFor;
   FreeAndNil(FThreadSafeLogEvent);
@@ -241,5 +245,7 @@ end;
 initialization
   _logs := Nil;
 finalization
+  {$IFnDEF FPC}
   FreeAndNil(_logs);
+  {$ENDIF}
 end.

+ 11 - 5
Units/PascalCoin/UOpenSSL.pas

@@ -213,11 +213,13 @@ end;
 
 function LoadSSLCrypt: Boolean;
 begin
-  {$IFDEF UNIX}
-  hCrypt := LoadLibrary(SSL_C_LIB);
-  {$ELSE}
-  hCrypt := LoadLibraryA(PAnsiChar(SSL_C_LIB));
-  {$ENDIF}
+  If hCrypt=0 then begin
+    {$IFDEF UNIX}
+    hCrypt := LoadLibrary(SSL_C_LIB);
+    {$ELSE}
+    hCrypt := LoadLibraryA(PAnsiChar(SSL_C_LIB));
+    {$ENDIF}
+  end;
   Result := hCrypt <> 0;
 end;
 
@@ -245,6 +247,10 @@ end;
 
 function InitSSLFunctions : Boolean;
 Begin
+  If not LoadSSLCrypt then begin
+    result := false;
+    exit;
+  end else result := true;
   if @ERR_get_error = nil then begin
     @ERR_get_error:= LoadFunctionCLib('ERR_get_error');
     @ERR_clear_error:= LoadFunctionCLib('ERR_clear_error');

+ 69 - 28
Units/PascalCoin/UPoolMinerThreads.pas

@@ -24,12 +24,14 @@ type
   TMinerStats = Record
     Miners : Integer;
     RoundsCount : UInt64;
-    WorkingMilliseconds : Cardinal;
+    WorkingMillisecondsHashing : Cardinal;
+    WorkingMillisecondsTotal : Cardinal;
     WinsCount : Integer;
+    Invalids : Integer;
   End;
 
 Const
-  CT_TMinerStats_NULL : TMinerStats = (Miners:0;RoundsCount:0;WorkingMilliseconds:0;WinsCount:0);
+  CT_TMinerStats_NULL : TMinerStats = (Miners:0;RoundsCount:0;WorkingMillisecondsHashing:0;WorkingMillisecondsTotal:0;WinsCount:0;Invalids:0);
 
 Type
 
@@ -48,11 +50,13 @@ Type
     FDevicesList : TPCThreadList;
     FMinerThreads: Integer;
     FGlobalMinerValuesForWork : TMinerValuesForWork;
+    FTestingPoWLeftBits: Byte;
     Procedure OnPoolMinerClientConnectionChanged(Sender : TObject);
     Procedure OnPoolMinerMustChangeValues(Sender : TObject);
     Procedure OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; Timestamp : Cardinal; NOnce : Cardinal);
     Procedure NotifyPoolMinerConnectionChanged;
     procedure SetMinerAddName(AValue: String);
+    procedure SetTestingPoWLeftBits(AValue: Byte);
   protected
     procedure BCExecute; override;
   public
@@ -66,6 +70,7 @@ Type
     Function DevicesLock : TList;
     procedure DevicesUnlock;
     Property MinerAddName : String read FMinerAddName write SetMinerAddName;
+    Property TestingPoWLeftBits : Byte read FTestingPoWLeftBits write SetTestingPoWLeftBits;
   End;
 
   { TCustomMinerDeviceThread }
@@ -78,19 +83,19 @@ Type
     FPaused: Boolean;
     FLastStats : TPCThreadList;
     FLastActiveTC : Cardinal;
+    FGlobaDeviceStats : TMinerStats;
+    FPartialDeviceStats : TMinerStats;
+    FPoolMinerThread : TPoolMinerThread;
     procedure SetIsMining(AValue: Boolean);
     procedure SetPaused(AValue: Boolean);
   protected
     FMinerValuesForWork : TMinerValuesForWork;
-    FPoolMinerThread : TPoolMinerThread;
-    FPartialDeviceStats : TMinerStats;
-    FGlobaDeviceStats : TMinerStats;
     Procedure SetMinerValuesForWork(const Value : TMinerValuesForWork); virtual;
     Procedure UpdateState; virtual;
     Procedure UpdateDeviceStats(Stats : TMinerStats); virtual;
     Procedure FoundNOnce(Timestamp,nOnce : Cardinal);
   public
-    Constructor Create(PoolMinerThread : TPoolMinerThread; InitialMinerValuesForWork : TMinerValuesForWork); virtual;
+    Constructor Create(APoolMinerThread : TPoolMinerThread; InitialMinerValuesForWork : TMinerValuesForWork); virtual;
     Destructor Destroy; override;
     Function DeviceStats : TMinerStats;
     Function GlobalDeviceStats : TMinerStats;
@@ -102,6 +107,7 @@ Type
     Function GetState : String; virtual; abstract;
     property MinerValuesForWork : TMinerValuesForWork read FMinerValuesForWork;
     Property IsMining : Boolean read FIsMining write SetIsMining;
+    Property PoolMinerThread : TPoolMinerThread read FPoolMinerThread;
   end;
 
 
@@ -217,6 +223,7 @@ begin
   FDevicesList := TPCThreadList.Create;
   FMinerThreads := 0;
   FMinerAddName:='';
+  FTestingPoWLeftBits := 0;
   inherited Create(false);
 end;
 
@@ -233,7 +240,8 @@ begin
       ms := TCustomMinerDeviceThread(l[i]).DeviceStats;
       inc(Result.Miners, ms.Miners);
       inc(Result.RoundsCount, ms.RoundsCount);
-      inc(Result.WorkingMilliseconds, ms.WorkingMilliseconds);
+      inc(Result.WorkingMillisecondsHashing, ms.WorkingMillisecondsHashing);
+      inc(Result.WorkingMillisecondsTotal, ms.WorkingMillisecondsTotal);
       inc(Result.WinsCount, ms.WinsCount);
     end;
   finally
@@ -285,7 +293,8 @@ begin
       ms := TCustomMinerDeviceThread(l[i]).GlobalDeviceStats;
       inc(Result.Miners, ms.Miners);
       inc(Result.RoundsCount, ms.RoundsCount);
-      inc(Result.WorkingMilliseconds, ms.WorkingMilliseconds);
+      inc(Result.WorkingMillisecondsHashing, ms.WorkingMillisecondsHashing);
+      inc(Result.WorkingMillisecondsTotal, ms.WorkingMillisecondsTotal);
       inc(Result.WinsCount, ms.WinsCount);
     end;
   finally
@@ -306,6 +315,14 @@ begin
   If Assigned(FPoolMinerClient) then OnPoolMinerMustChangeValues(Nil);
 end;
 
+procedure TPoolMinerThread.SetTestingPoWLeftBits(AValue: Byte);
+begin
+  if FTestingPoWLeftBits=AValue then Exit;
+  If (AValue>=0) And (AValue<=32) then
+    FTestingPoWLeftBits:=AValue
+  else FTestingPoWLeftBits:=0;
+end;
+
 procedure TPoolMinerThread.OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; Timestamp : Cardinal; NOnce : Cardinal);
 Var mvfw : TMinerValuesForWork;
 begin
@@ -338,23 +355,35 @@ end;
 
 procedure TPoolMinerThread.OnPoolMinerMustChangeValues(Sender: TObject);
 Var l : TList;
-  i : Integer;
+  i,j : Integer;
   digest : TRawBytes;
   ok : Boolean;
+  minervfw : TMinerValuesForWork;
+  auxXXXXX : TMinerValuesForWork;
 begin
   FGlobalMinerValuesForWork := FPoolMinerClient.MinerValuesForWork;
-  FGlobalMinerValuesForWork.payload_start:=FGlobalMinerValuesForWork.payload_start+FMinerAddName;
-  repeat
-    digest := FGlobalMinerValuesForWork.part1 + FGlobalMinerValuesForWork.payload_start + FGlobalMinerValuesForWork.part3 + '00000000';
-    ok := CanBeModifiedOnLastChunk(length(digest),i);
-    if (not ok) then FGlobalMinerValuesForWork.payload_start:=FGlobalMinerValuesForWork.payload_start+'-';
-  until (Ok);
   TLog.NewLog(ltupdate,ClassName,Format('New miner values. Block %d Payload %s',[FPoolMinerClient.MinerValuesForWork.block,
     FPoolMinerClient.MinerValuesForWork.payload_start]));
   l := FDevicesList.LockList;
   Try
     for i := 0 to l.Count - 1 do begin
-      TCustomMinerDeviceThread(l[i]).SetMinerValuesForWork(FGlobalMinerValuesForWork);
+      minervfw := FGlobalMinerValuesForWork;
+      minervfw.payload_start:=minervfw.payload_start+FMinerAddName;
+      if (l.count>1) then minervfw.payload_start:=minervfw.payload_start+'/'+inttostr(i);
+      repeat
+        digest := minervfw.part1 + minervfw.payload_start + minervfw.part3 + '00000000';
+        ok := CanBeModifiedOnLastChunk(length(digest),j);
+        if (not ok) then minervfw.payload_start:=minervfw.payload_start+'-';
+      until (Ok);
+      If FTestingPoWLeftBits>0 then begin
+        auxXXXXX := minervfw;
+        auxXXXXX.target:= ((((auxXXXXX.target AND $FF000000) SHR 24)-FTestingPoWLeftBits) SHL 24) + (minervfw.target AND $00FFFFFF);
+        If auxXXXXX.target<CT_MinCompactTarget then auxXXXXX.target:=CT_MinCompactTarget;
+        auxXXXXX.target_pow:=TPCBank.TargetFromCompact(auxXXXXX.target);
+        TCustomMinerDeviceThread(l[i]).SetMinerValuesForWork(auxXXXXX);
+      end else begin
+        TCustomMinerDeviceThread(l[i]).SetMinerValuesForWork(minervfw);
+      end;
     end;
   Finally
     FDevicesList.UnlockList;
@@ -370,9 +399,9 @@ Type
 
 { TCustomMinerDeviceThread }
 
-constructor TCustomMinerDeviceThread.Create(PoolMinerThread: TPoolMinerThread; InitialMinerValuesForWork: TMinerValuesForWork);
+constructor TCustomMinerDeviceThread.Create(APoolMinerThread: TPoolMinerThread; InitialMinerValuesForWork: TMinerValuesForWork);
 begin
-  FPoolMinerThread := PoolMinerThread;
+  FPoolMinerThread := APoolMinerThread;
   FMinerValuesForWork := CT_TMinerValuesForWork_NULL;
   FPartialDeviceStats := CT_TMinerStats_NULL;
   FGlobaDeviceStats := CT_TMinerStats_NULL;
@@ -436,6 +465,7 @@ begin
     FPoolMinerThread.OnMinerNewBlockFound(self,Timestamp,nOnce);
     If Assigned(FOnFoundNOnce) then FOnFoundNOnce(Self,Timestamp,nOnce);
   end else begin
+    inc(FGlobaDeviceStats.Invalids);
     TLog.NewLog(lterror,Self.Classname,Format('Invalid Double Sha256 found. Timestamp %s nOnce %s DSHA256 %s Valid POW %s',
       [IntToHex(Timestamp,8),IntToHex(nOnce,8),TCrypto.ToHexaString(dsha256),TCrypto.ToHexaString(self.FMinerValuesForWork.target_pow)]));
   end;
@@ -448,7 +478,8 @@ begin
   try
     g := FGlobaDeviceStats;
     If Not FPaused then begin
-      g.WorkingMilliseconds:= g.WorkingMilliseconds + (GetTickCount - FLastActiveTC);
+      g.WorkingMillisecondsHashing:= g.WorkingMillisecondsHashing + (GetTickCount - FLastActiveTC);
+      g.WorkingMillisecondsTotal:= g.WorkingMillisecondsTotal + (GetTickCount - FLastActiveTC);
     end;
     Result := g;
   finally
@@ -484,7 +515,10 @@ begin
   if FPaused=AValue then Exit;
   FPaused:=AValue;
   If Not FPaused then FLastActiveTC := GetTickCount
-  else FGlobaDeviceStats.WorkingMilliseconds:=FGlobaDeviceStats.WorkingMilliseconds + (GetTickCount - FLastActiveTC);
+  else begin
+    FGlobaDeviceStats.WorkingMillisecondsHashing:=FGlobaDeviceStats.WorkingMillisecondsHashing + (GetTickCount - FLastActiveTC);
+    FGlobaDeviceStats.WorkingMillisecondsTotal:=FGlobaDeviceStats.WorkingMillisecondsTotal + (GetTickCount - FLastActiveTC);
+  end;
   UpdateState;
 end;
 
@@ -503,10 +537,10 @@ begin
   Try
     FPartialDeviceStats := CT_TMinerStats_NULL;
     New(P);
-    P^.tc:=(GetTickCount - stats.WorkingMilliseconds);
+    P^.tc:=(GetTickCount - stats.WorkingMillisecondsTotal);
     P^.stats:=stats;
     l.add(P);
-    minTC := GetTickCount - 30000; // Last 30 seconds average
+    minTC := GetTickCount - 10000; // Last 10 seconds average
     foundMaxMiners:=0;
     for i:=l.Count-1 downto 0 do begin
       P := l[i];
@@ -520,7 +554,9 @@ begin
       end;
     end;
     If l.count>0 then begin
-      FPartialDeviceStats.WorkingMilliseconds:=PTimeMinerStats(l[l.count-1]).tc - PTimeMinerStats(l[0]).tc + PTimeMinerStats(l[l.count-1]).stats.WorkingMilliseconds;
+      P := PTimeMinerStats(l[l.count-1]);
+      FPartialDeviceStats.WorkingMillisecondsHashing:=P^.tc - PTimeMinerStats(l[0]).tc + P^.stats.WorkingMillisecondsHashing;
+      FPartialDeviceStats.WorkingMillisecondsTotal:=P^.tc - PTimeMinerStats(l[0]).tc + P^.stats.WorkingMillisecondsTotal;
     end;
     FPartialDeviceStats.Miners:= foundMaxMiners;
     If foundMaxMiners>FGlobaDeviceStats.Miners then FGlobaDeviceStats.Miners:=foundMaxMiners;
@@ -571,6 +607,7 @@ begin
   finally
     FCPUsThreads.UnlockList;
   end;
+  IsMining := needminers>0;
 end;
 
 constructor TCPUDeviceThread.Create(PoolMinerThread: TPoolMinerThread; InitialMinerValuesForWork: TMinerValuesForWork);
@@ -597,7 +634,7 @@ end;
 
 function TCPUDeviceThread.MinerDeviceName: String;
 begin
-  Result := 'CPU miner ('+inttostr(CPUCount)+' CPU''s available)';
+  Result := 'CPU miner with '+inttostr(FCPUs)+' ('+inttostr(CPUCount)+' CPU''s available)';
 end;
 
 procedure TCPUDeviceThread.SetCPUs(AValue: Integer);
@@ -674,7 +711,7 @@ Const CT_Rounds = 10000;
 Var
   ts : Cardinal;
   i : Integer;
-  nonce, baseTC : Cardinal;
+  nonce, baseRealTC,baseHashingTC,finalHashingTC : Cardinal;
   resultPoW : TRawBytes;
   //
   AuxStats : TMinerStats;
@@ -687,7 +724,7 @@ begin
       else begin
         FLock.Acquire;
         try
-          baseTC := GetTickCount;
+          baseRealTC := GetTickCount;
           If (nonce<FMinNOnce) Or (nonce>FMaxNOnce) then nonce:=FMinNOnce;
           // Timestamp
           ts := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
@@ -696,6 +733,7 @@ begin
             if FCPUDeviceThread.FUseOpenSSLFunctions then begin
               FDigestStreamMsg.Position:=FDigestStreamMsg.Size - 8;
               FDigestStreamMsg.Write(ts,4);
+              baseHashingTC:=GetTickCount;
               for i := 1 to CT_Rounds do begin
                 FDigestStreamMsg.Position := FDigestStreamMsg.Size - 4;
                 FDigestStreamMsg.Write(nonce,4);
@@ -712,7 +750,9 @@ begin
                 end;
                 if (nonce)<FMaxNOnce then inc(nonce) else nonce := FMinNOnce;
               end;
+              finalHashingTC:=GetTickCount;
             end else begin
+              baseHashingTC:=GetTickCount;
               for i := 1 to CT_Rounds do begin
                 PascalCoinExecuteLastChunkAndDoSha256(FInternalSha256,FInternalChunk,FChangeTimestampAndNOnceBytePos,nonce,ts,resultPoW);
                 if resultPoW < FCPUDeviceThread.FMinerValuesForWork.target_pow then begin
@@ -727,11 +767,12 @@ begin
                 end;
                 if (nonce)<FMaxNOnce then inc(nonce) else nonce := FMinNOnce;
               end;
+              finalHashingTC:=GetTickCount;
             end;
-            baseTC := GetTickCount - baseTC;
             AuxStats.Miners:=FCPUDeviceThread.FCPUs;
             AuxStats.RoundsCount:=CT_Rounds;
-            AuxStats.WorkingMilliseconds:=baseTC;
+            AuxStats.WorkingMillisecondsTotal:=GetTickCount - baseRealTC;
+            AuxStats.WorkingMillisecondsHashing:= finalHashingTC - baseHashingTC;
             FCPUDeviceThread.UpdateDeviceStats(AuxStats);
           end; // FDigestStreamMsg.size>8
         finally

+ 2 - 0
Units/PascalCoin/UPoolMining.pas

@@ -459,11 +459,13 @@ begin
   FIncomingsCounter := 0;
   FClientsWins := 0;
   FClientsCount := 0;
+  MaxConnections:=1000;
   NetTcpIpClientClass := TJSONRPCTcpIpClient;
   FNodeNotifyEvents := TNodeNotifyEvents.Create(Nil);
   FNodeNotifyEvents.OnBlocksChanged := OnNodeNewBlock;
   FNodeNotifyEvents.OnOperationsChanged := OnNodeOperationsChanged;
   FNodeNotifyEvents.Node := TNode.Node;
+  FMinerAccountKey := CT_TECDSA_Public_Nul;
 end;
 
 destructor TPoolMiningServer.Destroy;

+ 3 - 1
Units/PascalCoin/UThread.pas

@@ -260,7 +260,7 @@ begin
     inherited Destroy;
   finally
     UnlockList;
-    FLock.Free;
+    FreeAndNil(FLock);
   end;
 end;
 
@@ -295,6 +295,8 @@ end;
 initialization
   _threads := TPCThreadList.Create;
 finalization
+  {$IFnDEF FPC}
   FreeAndNil(_threads);
+  {$ENDIF}
 end.
 

+ 168 - 37
Units/PascalCoin/upcdaemon.pas

@@ -20,16 +20,30 @@ interface
 uses
   Classes, SysUtils, daemonapp,
   SyncObjs, UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWalletKeys, UConst, ULog, UNetProtocol,
-  UThread, URPC;
+  IniFiles,
+  UThread, URPC, UPoolMining, UAccounts;
+
+Const
+  CT_INI_SECTION_GLOBAL = 'GLOBAL';
+  CT_INI_IDENT_SAVELOGS = 'SAVELOGS';
+  CT_INI_IDENT_RPC_PORT = 'RPC_PORT';
+  CT_INI_IDENT_RPC_SAVELOGS = 'RPC_SAVELOGS';
+  CT_INI_IDENT_RPC_SERVERMINER_PORT = 'RPC_SERVERMINER_PORT';
+  CT_INI_IDENT_MINER_B58_PUBLICKEY = 'RPC_SERVERMINER_B58_PUBKEY';
+  CT_INI_IDENT_MINER_NAME = 'RPC_SERVERMINER_NAME';
+  CT_INI_IDENT_MINER_MAX_CONNECTIONS = 'RPC_SERVERMINER_MAX_CONNECTIONS';
 
 Type
   { TPCDaemonThread }
 
   TPCDaemonThread = Class(TPCThread)
   private
+    FIniFile : TIniFile;
   protected
     Procedure BCExecute; override;
   public
+    constructor Create;
+    destructor Destroy; override;
   end;
 
   { TPCDaemon }
@@ -54,16 +68,18 @@ Type
   TPCDaemonMapper = Class(TCustomDaemonMapper)
   private
     FLog : TLog;
-    FLogRPCCalls : TLog;
     procedure OnPascalCoinInThreadLog(logtype : TLogType; Time : TDateTime; AThreadID : Cardinal; Const sender, logtext : AnsiString);
+  protected
+    Procedure DoOnCreate; override;
+    Procedure DoOnDestroy; override;
   public
-    Constructor Create(AOwner : TComponent); override;
-    Destructor Destroy; override;
   end;
 
 
 implementation
 
+Var _FLog : TLog;
+
 { TPCDaemonThread }
 
 procedure TPCDaemonThread.BCExecute;
@@ -71,40 +87,133 @@ var
   FNode : TNode;
   FWalletKeys : TWalletKeysExt;
   FRPC : TRPCServer;
+  FMinerServer : TPoolMiningServer;
+
+  Procedure InitRPCServer;
+  Var port : Integer;
+  Begin
+    port := FIniFile.ReadInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_PORT,-1);
+    if (port<=0) then begin
+      FIniFile.WriteInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_PORT,CT_JSONRPC_Port);
+      port:=CT_JSONRPC_Port;
+      TLog.NewLog(ltInfo,ClassName,'Saving RPC server port to IniFile: '+IntToStr(port));
+    end;
+    FRPC := TRPCServer.Create;
+    FRPC.WalletKeys := FWalletKeys;
+    FRPC.Port:=port;
+    FRPC.Active:=true;
+    TLog.NewLog(ltInfo,ClassName,'RPC server is active on port '+IntToStr(port));
+    If FIniFile.ReadBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SAVELOGS,true) then begin
+      FIniFile.WriteBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SAVELOGS,true);
+      FRPC.LogFileName:= TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_rpc.log';
+      TLog.NewLog(ltInfo,ClassName,'Activating RPC logs on file '+FRPC.LogFileName);
+    end else begin
+      FIniFile.WriteBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SAVELOGS,false);
+      TLog.NewLog(ltInfo,ClassName,'RPC logs not enabled on IniFile value '+CT_INI_IDENT_RPC_SAVELOGS+'=0');
+    end;
+  end;
+
+  Procedure InitRPCMinerServer;
+  Var i, port, maxconnections : Integer;
+    s : String;
+    pubkey : TAccountKey;
+    errors : AnsiString;
+    ECPK : TECPrivateKey;
+  Begin
+    i := FIniFile.ReadInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SERVERMINER_PORT,-1);
+    if (i<0) then i:=CT_JSONRPCMinerServer_Port;
+    if (i>0) then begin
+      port := i;
+      FIniFile.WriteInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SERVERMINER_PORT,port);
+      pubkey := CT_TECDSA_Public_Nul;
+      s := Trim(FIniFile.ReadString(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_MINER_B58_PUBLICKEY,''));
+      If (s='') Or (Not TAccountComp.AccountKeyFromImport(s,pubkey,errors)) then begin
+        If s<>'' then TLog.NewLog(lterror,Classname,'Invalid INI file public key: '+errors);
+        i := 0;
+        While (i<FWalletKeys.Count) And (pubkey.EC_OpenSSL_NID=CT_TECDSA_Public_Nul.EC_OpenSSL_NID) do begin
+          if (FWalletKeys.Key[i].CryptedKey<>'') then pubkey := FWalletKeys[i].AccountKey
+          else inc(i);
+        end;
+        if (pubkey.EC_OpenSSL_NID=CT_TECDSA_Public_Nul.EC_OpenSSL_NID) then begin
+          // New key
+          ECPK := TECPrivateKey.Create;
+          try
+            ECPK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
+            FWalletKeys.AddPrivateKey('RANDOM NEW BY DAEMON '+FormatDateTime('yyyy-mm-dd hh:nn:dd',now),ECPK);
+            pubkey := ECPK.PublicKey;
+            FIniFile.WriteString(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_MINER_B58_PUBLICKEY,
+              TAccountComp.AccountKeyToExport(pubkey));
+            TLog.NewLog(ltInfo,ClassName, 'Generated new pubkey for miner: '+TAccountComp.AccountKeyToExport(pubkey));
+          finally
+            ECPK.Free;
+          end;
+        end;
+      end else begin
+        // pubkey is mine?
+        if (FWalletKeys.IndexOfAccountKey(pubkey)<0) then begin
+          TLog.NewLog(lterror,classname,'WARNING: Using a public key without private key in wallet! '+TAccountComp.AccountKeyToExport(pubkey));
+        end;
+      end;
+      i := FWalletKeys.IndexOfAccountKey(pubkey);
+      s := Trim(FIniFile.ReadString(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_MINER_NAME,''));
+      if (SameText(s,'TIME')) then begin
+        s := FormatDateTime('yyyy-mm-dd hh:nn',Now);
+        TLog.NewLog(ltInfo,ClassName,'Generated new miner name: '+s);
+      end;
+      maxconnections:=FIniFile.ReadInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_MINER_MAX_CONNECTIONS,1000);
+      TLog.NewLog(ltinfo,ClassName,Format('Activating RPC Miner Server on port %d, name "%s", max conections %d and public key %s',
+        [port,s,maxconnections,TAccountComp.AccountKeyToExport(pubkey)]));
+      FMinerServer := TPoolMiningServer.Create;
+      FMinerServer.UpdateAccountAndPayload(pubkey,s);
+      FMinerServer.Port:=port;
+      FMinerServer.Active:=True;
+      FMinerServer.MaxConnections:=maxconnections;
+    end else begin
+      TLog.NewLog(ltinfo,ClassName,'RPC Miner Server NOT ACTIVE (Ini file is '+CT_INI_IDENT_RPC_SERVERMINER_PORT+'=0)');
+    end;
+  end;
+
 begin
+  FMInerServer := Nil;
   TLog.NewLog(ltinfo,Classname,'START PascalCoin Server');
   try
     try
       FWalletKeys := TWalletKeysExt.Create(Nil);
       // Load Node
       // Check OpenSSL dll
-      if Not LoadSSLCrypt then raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
+      if Not LoadSSLCrypt then begin
+        WriteLn('Cannot load '+SSL_C_LIB);
+        WriteLn('To use this software make sure this file is available on you system or reinstall the application');
+        raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
+      end;
       TCrypto.InitCrypto;
       FWalletKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
       // Creating Node:
       FNode := TNode.Node;
       // RPC Server
-      FRPC := TRPCServer.Create;
-      FRPC.WalletKeys := FWalletKeys;
-      FRPC.Active:=true;
-      // Check Database
-      FNode.Bank.StorageClass := TFileStorage;
-      TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
-      // Reading database
-      FNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
-      FWalletKeys.SafeBox := FNode.Node.Bank.SafeBox;
-      FNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
-      FNode.Node.NetServer.Active := true;
-
-      if (Application.HasOption('r','logrpc')) then begin
-        FRPC.LogFileName:= TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_rpc.log';
+      InitRPCServer;
+      Try
+        // Check Database
+        FNode.Bank.StorageClass := TFileStorage;
+        TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
+        // Reading database
+        FNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
+        FWalletKeys.SafeBox := FNode.Node.Bank.SafeBox;
+        FNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
+        FNode.Node.NetServer.Active := true;
+
+        // RPC Miner Server
+        InitRPCMinerServer;
+        Try
+          Repeat
+            Sleep(100);
+          Until Terminated;
+        finally
+          FreeAndNil(FMinerServer);
+        end;
+      Finally
+        FreeAndNil(FRPC);
       end;
-
-      Repeat
-        Sleep(100);
-      Until Terminated;
-
-      FreeAndNil(FRPC);
       FNode.NetServer.Active := false;
       TNetData.NetData.Free;
       FreeAndNil(FNode);
@@ -118,6 +227,25 @@ begin
   end;
 end;
 
+constructor TPCDaemonThread.Create;
+begin
+  inherited Create(True);
+  FIniFile := TIniFile.Create(ExtractFileDir(Application.ExeName)+PathDelim+'pascalcoin_daemon.ini');
+  If FIniFile.ReadBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_SAVELOGS,true) then begin
+    _FLog.SaveTypes:=CT_TLogTypes_ALL;
+    _FLog.FileName:=TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_'+FormatDateTime('yyyymmddhhnn',Now)+'.log';
+    FIniFile.WriteBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_SAVELOGS,true);
+  end else begin
+    FIniFile.WriteBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_SAVELOGS,false);
+  end;
+end;
+
+destructor TPCDaemonThread.Destroy;
+begin
+  FreeAndNil(FIniFile);
+  inherited Destroy;
+end;
+
 
 { TPCDaemon }
 
@@ -130,7 +258,7 @@ function TPCDaemon.Start: Boolean;
 begin
   Result:=inherited Start;
   TLog.NewLog(ltinfo,ClassName,'Daemon Start '+BoolToStr(Result));
-  FThread:=TPCDaemonThread.Create(True);
+  FThread:=TPCDaemonThread.Create;
   FThread.OnTerminate:=@ThreadStopped;
   FThread.FreeOnTerminate:=False;
   FThread.Resume;
@@ -188,19 +316,22 @@ procedure TPCDaemonMapper.OnPascalCoinInThreadLog(logtype: TLogType;
   Time: TDateTime; AThreadID: Cardinal; const sender, logtext: AnsiString);
 Var s : AnsiString;
 begin
-  if AThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
-  WriteLn(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',Time)+s+IntToHex(AThreadID,8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
+//  If Not SameText(sender,TPCDaemonThread.ClassName) then exit;
+  If logtype in [lterror,ltinfo] then begin
+    if AThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
+    WriteLn(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',Time)+s+IntToHex(AThreadID,8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
+  end;
 end;
 
-constructor TPCDaemonMapper.Create(AOwner: TComponent);
+procedure TPCDaemonMapper.DoOnCreate;
 Var D : TDaemonDef;
 begin
-  inherited Create(AOwner);
-  if (Application.HasOption('l','log')) then begin
-    FLog := TLog.Create(Nil);
-    FLog.SaveTypes:=CT_TLogTypes_ALL;
-    FLog.FileName:=TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_'+FormatDateTime('yyyymmddhhnn',Now)+'.log';
-  end;
+  inherited DoOnCreate;
+  WriteLn('');
+  WriteLn(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',now)+' Starting PascalCoin server');
+  FLog := TLog.Create(Nil);
+  FLog.OnInThreadNewLog:=@OnPascalCoinInThreadLog;
+  _FLog := FLog;
   D:=DaemonDefs.Add as TDaemonDef;
   D.DisplayName:='Pascal Coin Daemon';
   D.Name:='PascalCoinDaemon';
@@ -208,13 +339,13 @@ begin
   D.WinBindings.ServiceType:=stWin32;
 end;
 
-destructor TPCDaemonMapper.Destroy;
+procedure TPCDaemonMapper.DoOnDestroy;
 begin
   If Assigned(FLog) then begin
     FLog.OnInThreadNewLog:=Nil;
     FreeAndNil(FLog);
   end;
-  inherited Destroy;
+  inherited DoOnDestroy;
 end;
 
 end.

+ 24 - 0
pascalcoin_daemon.ini

@@ -0,0 +1,24 @@
+[GLOBAL]
+;SAVELOGS : Boolean
+;If 1 (true) logs will be saved to a file at $HOME/PascalCoin
+SAVELOGS=0
+;RPC_PORT : Integer (Default 4003)
+;Port to use by TCP/IP JSON-RPC commands
+RPC_PORT=4003
+;RPC_SAVELOGS : Boolean
+;Save RPC commands log file $HOME/PascalCoin
+RPC_SAVELOGS=1
+;RPC_SERVERMINER_PORT : Integer (Default 4009)
+;When value<>0 will activate Server mining port using PascalCoin JSON-RPC mining protocol
+RPC_SERVERMINER_PORT=4009
+;RPC_SERVERMINER_NAME : String
+;Basic name of the miner when allowing
+;If value=TIME then will set Date Time in yyyy-mm-dd hh:nn format
+RPC_SERVERMINER_NAME=TIME
+;RPC_SERVERMINER_B58_PUBKEY : String
+;Public key value to use as a server miner Public key
+;If empty, will use first avaiable public key of the wallet or generate a new one
+RPC_SERVERMINER_B58_PUBKEY=
+;RPC_SERVERMINER_MAX_CONNECTIONS : Integer
+;Max connections that RPC Miner server can accept
+RPC_SERVERMINER_MAX_CONNECTIONS=1000

+ 78 - 0
pascalcoin_daemon.lpi

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="pascalcoin_daemon"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <CommandLineParams Value="-r"/>
+        <Display Use="True" Value=""/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="pascalcoin_daemon.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="pascalcoin_daemon"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="Synapse\lib;Units\PascalCoin;Units\Utils"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <CodeGeneration>
+      <Optimizations>
+        <OptimizationLevel Value="2"/>
+      </Optimizations>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+      </Debugging>
+    </Linking>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 104 - 0
pascalcoin_daemon.lps

@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectSession>
+    <PathDelim Value="\"/>
+    <Version Value="9"/>
+    <BuildModes Active="Default"/>
+    <Units Count="13">
+      <Unit0>
+        <Filename Value="pascalcoin_daemon.pp"/>
+        <IsPartOfProject Value="True"/>
+        <EditorIndex Value="-1"/>
+        <CursorPos X="14" Y="13"/>
+        <UsageCount Value="20"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="C:\lazarus\fpc\3.0.0\source\packages\fcl-extra\src\daemonapp.pp"/>
+        <EditorIndex Value="-1"/>
+        <UsageCount Value="10"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="Units\PascalCoin\upcdaemon.pas"/>
+        <IsVisibleTab Value="True"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="198"/>
+        <CursorPos X="95" Y="233"/>
+        <UsageCount Value="10"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="Units\PascalCoin\UNetProtocol.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="1363"/>
+        <CursorPos X="11" Y="1384"/>
+        <UsageCount Value="10"/>
+      </Unit3>
+      <Unit4>
+        <Filename Value="Units\PascalCoin\UPoolMining.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="74"/>
+        <CursorPos X="3" Y="83"/>
+        <UsageCount Value="10"/>
+      </Unit4>
+      <Unit5>
+        <Filename Value="Units\PascalCoin\UAccounts.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="266"/>
+        <CursorPos X="47" Y="280"/>
+        <UsageCount Value="10"/>
+      </Unit5>
+      <Unit6>
+        <Filename Value="Units\PascalCoin\UThread.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="12"/>
+        <CursorPos X="3" Y="33"/>
+        <UsageCount Value="10"/>
+      </Unit6>
+      <Unit7>
+        <Filename Value="C:\lazarus\fpc\3.0.0\source\rtl\objpas\classes\classesh.inc"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="1632"/>
+        <CursorPos Y="1646"/>
+        <UsageCount Value="10"/>
+      </Unit7>
+      <Unit8>
+        <Filename Value="Units\PascalCoin\UConst.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="42"/>
+        <CursorPos X="22" Y="77"/>
+        <UsageCount Value="10"/>
+      </Unit8>
+      <Unit9>
+        <Filename Value="Units\PascalCoin\UWalletKeys.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="91"/>
+        <CursorPos X="35" Y="102"/>
+        <UsageCount Value="10"/>
+      </Unit9>
+      <Unit10>
+        <Filename Value="Units\PascalCoin\ULog.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="8"/>
+        <CursorPos X="133" Y="29"/>
+        <UsageCount Value="10"/>
+      </Unit10>
+      <Unit11>
+        <Filename Value="Units\PascalCoin\UOpenSSL.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="191"/>
+        <CursorPos X="22" Y="214"/>
+        <UsageCount Value="10"/>
+      </Unit11>
+      <Unit12>
+        <Filename Value="Units\PascalCoin\UTCPIP.pas"/>
+        <EditorIndex Value="-1"/>
+        <TopLine Value="145"/>
+        <CursorPos X="15" Y="161"/>
+        <UsageCount Value="10"/>
+      </Unit12>
+    </Units>
+    <General>
+      <ActiveWindowIndexAtStart Value="-1"/>
+    </General>
+    <JumpHistory HistoryIndex="-1"/>
+  </ProjectSession>
+</CONFIG>

+ 4 - 4
pascalsha.cl

@@ -32,7 +32,7 @@ __kernel void pascalcoin(__global uint *midstateIn, __global int *nonceOut) {
     midstateIn[0..15] = data for last chunk
     midstateIn[16..23] = previous chunk result
     midstateIn[24] = Position to save nOnce
-    midstateIn[25] = Highest 10 bits for nOnce
+    midstateIn[25] = Highest 8 bits for nOnce
     midstateIn[26..28] = Mask (obtained  from target_pow)
 
     When found a valid nOnce, is returned at nonceOut
@@ -40,9 +40,9 @@ __kernel void pascalcoin(__global uint *midstateIn, __global int *nonceOut) {
   uint buffer[16];
   uint midstate[8];
 
-  // midstateIn[25] high-order 10 bits for nOnce, we must bit shift left value 22 bits.
-  // get_global_id(0) is the current ROUND. ROUND is a value between 0..(2^22)-1
-  uint nonce = (midstateIn[25] << 22) + (uint)get_global_id(0);
+  // midstateIn[25] high-order 8 bits for nOnce, we must bit shift left value 24 bits.
+  // get_global_id(0) is the current ROUND. ROUND is a value between 0..(2^24)-1
+  uint nonce = (midstateIn[25] << 24) + (uint)get_global_id(0);
 
   uint whereToSavenOnce = (midstateIn[24]);