Browse Source

PascalCoinMiner 5.1 with Stratum support

Tested on OpenPool and Nanopool
PascalCoin 5 years ago
parent
commit
aa9d16a3c1

+ 0 - 0
src/PascalCoinMiner.pp


+ 42 - 15
src/core/UPoolMinerThreads.pas

@@ -63,14 +63,14 @@ Type
     FTestingMode: Boolean;
     FTestingMode: Boolean;
     Procedure OnPoolMinerClientConnectionChanged(Sender : TObject);
     Procedure OnPoolMinerClientConnectionChanged(Sender : TObject);
     Procedure OnPoolMinerMustChangeValues(Sender : TObject);
     Procedure OnPoolMinerMustChangeValues(Sender : TObject);
-    Procedure OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; const usedMinerValuesForWork : TMinerValuesForWork; Timestamp : Cardinal; NOnce : Cardinal);
+    Procedure OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; const usedMinerValuesForWork : TMinerValuesForWork; Timestamp : Cardinal; NOnce : Cardinal; const AObtainedPoW : TRawBytes);
     Procedure NotifyPoolMinerConnectionChanged;
     Procedure NotifyPoolMinerConnectionChanged;
     procedure SetMinerAddName(AValue: String);
     procedure SetMinerAddName(AValue: String);
     procedure SetTestingPoWLeftBits(AValue: Byte);
     procedure SetTestingPoWLeftBits(AValue: Byte);
   protected
   protected
     procedure BCExecute; override;
     procedure BCExecute; override;
   public
   public
-    Constructor Create(RemoteHost : String; RemotePort : Integer; InitialAccountKey : TAccountKey);
+    Constructor Create(RemoteHost : String; RemotePort : Integer; const AUserName, APassword : String);
     Destructor Destroy; override;
     Destructor Destroy; override;
     Property PoolMinerClient : TPoolMinerClient read FPoolMinerClient;
     Property PoolMinerClient : TPoolMinerClient read FPoolMinerClient;
     Property OnConnectionStateChanged : TNotifyEvent read FOnConnectionStateChanged write FOnConnectionStateChanged;
     Property OnConnectionStateChanged : TNotifyEvent read FOnConnectionStateChanged write FOnConnectionStateChanged;
@@ -185,12 +185,15 @@ Var nID : Cardinal;
   i : Integer;
   i : Integer;
   ResponseMethod : String;
   ResponseMethod : String;
   l : TList<TCustomMinerDeviceThread>;
   l : TList<TCustomMinerDeviceThread>;
+  LParams : TPCJSONArray;
+  LPoolResult : TPCJSONObject;
 begin
 begin
   DebugStep:='Starting';
   DebugStep:='Starting';
   Try
   Try
     while not Terminated do begin
     while not Terminated do begin
       if FTestingMode then begin
       if FTestingMode then begin
       end else if not FPoolMinerClient.Connected then begin
       end else if not FPoolMinerClient.Connected then begin
+        FPoolMinerClient.Stratum_Authorized := False;
         DebugStep:='Not connected';
         DebugStep:='Not connected';
         If Not FPoolMinerClient.Connect then begin
         If Not FPoolMinerClient.Connect then begin
         end else begin
         end else begin
@@ -198,9 +201,12 @@ begin
         end;
         end;
       end else begin
       end else begin
           DebugStep:='Starting process';
           DebugStep:='Starting process';
-          // Start Process
-          nId:=FPoolMinerClient.GetNewId;
-          FPoolMinerClient.SendJSONRPCMethod(CT_PoolMining_Method_MINER_NOTIFY,nil,nId);
+          if FPoolMinerClient.PoolType = ptPoolSubscription then begin
+          end else begin
+            // Start Process Solo mining (direct to PascalCoin node)
+            nId:=FPoolMinerClient.GetNewId;
+            FPoolMinerClient.SendJSONRPCMethod(CT_PoolMining_Method_MINER_NOTIFY,nil,nId);
+          end;
           json := TPCJSONObject.create;
           json := TPCJSONObject.create;
           try
           try
             DebugStep:='Starting repeat';
             DebugStep:='Starting repeat';
@@ -232,7 +238,7 @@ begin
   End;
   End;
 end;
 end;
 
 
-constructor TPoolMinerThread.Create(RemoteHost: String; RemotePort: Integer; InitialAccountKey : TAccountKey);
+constructor TPoolMinerThread.Create(RemoteHost: String; RemotePort: Integer; const AUserName, APassword : String);
 begin
 begin
   FGlobalMinerValuesForWork := CT_TMinerValuesForWork_NULL;
   FGlobalMinerValuesForWork := CT_TMinerValuesForWork_NULL;
   FPoolMinerClient := TPoolMinerClient.Create(Nil);
   FPoolMinerClient := TPoolMinerClient.Create(Nil);
@@ -241,6 +247,13 @@ begin
   FPoolMinerClient.OnMinerMustChangeValues := OnPoolMinerMustChangeValues;
   FPoolMinerClient.OnMinerMustChangeValues := OnPoolMinerMustChangeValues;
   FPoolMinerClient.OnConnect := OnPoolMinerClientConnectionChanged;
   FPoolMinerClient.OnConnect := OnPoolMinerClientConnectionChanged;
   FPoolMinerClient.OnDisconnect := OnPoolMinerClientConnectionChanged;
   FPoolMinerClient.OnDisconnect := OnPoolMinerClientConnectionChanged;
+  if Length(AUserName)>0 then begin
+    FPoolMinerClient.PoolType := ptPoolSubscription;
+    FPoolMinerClient.UserName := AUserName;
+    FPoolMinerClient.Password := APassword;
+  end else begin
+    FPoolMinerClient.PoolType := ptSolomine;
+  end;
   FOnConnectionStateChanged := Nil;
   FOnConnectionStateChanged := Nil;
   FDevicesList := TPCThreadList<TCustomMinerDeviceThread>.Create('TPoolMinerThread_DevicesList');
   FDevicesList := TPCThreadList<TCustomMinerDeviceThread>.Create('TPoolMinerThread_DevicesList');
   FMinerThreads := 0;
   FMinerThreads := 0;
@@ -351,12 +364,11 @@ begin
   else FTestingPoWLeftBits:=0;
   else FTestingPoWLeftBits:=0;
 end;
 end;
 
 
-procedure TPoolMinerThread.OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; const usedMinerValuesForWork : TMinerValuesForWork; Timestamp : Cardinal; NOnce : Cardinal);
+procedure TPoolMinerThread.OnMinerNewBlockFound(sender : TCustomMinerDeviceThread; const usedMinerValuesForWork : TMinerValuesForWork; Timestamp : Cardinal; NOnce : Cardinal; const AObtainedPoW : TRawBytes);
 begin
 begin
   FDevicesList.LockList;
   FDevicesList.LockList;
   try
   try
-    TLog.NewLog(ltinfo,ClassName,'FOUND VALID NONCE!!! Block:'+IntToStr(usedMinerValuesForWork.block)+' Timestamp:'+Inttostr(Timestamp)+ ' Nonce:'+Inttostr(NOnce)+' Payload:'+usedMinerValuesForWork.payload_start.ToString);
-    FPoolMinerClient.SubmitBlockFound(usedMinerValuesForWork,usedMinerValuesForWork.payload_start,Timestamp,NOnce);
+    FPoolMinerClient.SubmitBlockFound(usedMinerValuesForWork,usedMinerValuesForWork.FinalPayload,Timestamp,NOnce,AObtainedPoW);
   finally
   finally
     FDevicesList.UnlockList;
     FDevicesList.UnlockList;
   end;
   end;
@@ -386,14 +398,19 @@ Var l : TList<TCustomMinerDeviceThread>;
   minervfw : TMinerValuesForWork;
   minervfw : TMinerValuesForWork;
   auxminervfw : TMinerValuesForWork;
   auxminervfw : TMinerValuesForWork;
   auxRaw : TRawBytes;
   auxRaw : TRawBytes;
+  s : String;
 begin
 begin
   FGlobalMinerValuesForWork := FPoolMinerClient.MinerValuesForWork;
   FGlobalMinerValuesForWork := FPoolMinerClient.MinerValuesForWork;
-  TLog.NewLog(ltupdate,ClassName,Format('New miner values. Block %d Target %s Payload %s',[FPoolMinerClient.MinerValuesForWork.block,
-    IntToHex(FPoolMinerClient.MinerValuesForWork.target,8), FPoolMinerClient.MinerValuesForWork.payload_start.ToPrintable]));
   l := FDevicesList.LockList;
   l := FDevicesList.LockList;
   Try
   Try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
       minervfw := FGlobalMinerValuesForWork;
       minervfw := FGlobalMinerValuesForWork;
+      if (FGlobalMinerValuesForWork.IsStratum) And (FGlobalMinerValuesForWork.extraNOnce2_Size>0) then begin
+        s := IntToStr(i+1);
+        while Length(s)<FGlobalMinerValuesForWork.extraNOnce2_Size do s := '0' + s;
+        minervfw.extraNOnce2_Used.FromString( s );
+      end else begin
+
       auxRaw.FromString(FMinerAddName);
       auxRaw.FromString(FMinerAddName);
       TBaseType.Concat(minervfw.payload_start,auxRaw,minervfw.payload_start);
       TBaseType.Concat(minervfw.payload_start,auxRaw,minervfw.payload_start);
       if (l.count>1) then begin
       if (l.count>1) then begin
@@ -410,6 +427,8 @@ begin
           end;
           end;
         until (Ok);
         until (Ok);
       end;
       end;
+
+      end;
       If FTestingPoWLeftBits>0 then begin
       If FTestingPoWLeftBits>0 then begin
         auxminervfw := minervfw;
         auxminervfw := minervfw;
         auxminervfw.target:= ((((auxminervfw.target AND $FF000000) SHR 24)-FTestingPoWLeftBits) SHL 24) + (minervfw.target AND $00FFFFFF);
         auxminervfw.target:= ((((auxminervfw.target AND $FF000000) SHR 24)-FTestingPoWLeftBits) SHL 24) + (minervfw.target AND $00FFFFFF);
@@ -420,6 +439,10 @@ begin
         TCustomMinerDeviceThread(l[i]).SetMinerValuesForWork(minervfw);
         TCustomMinerDeviceThread(l[i]).SetMinerValuesForWork(minervfw);
       end;
       end;
     end;
     end;
+    TLog.NewLog(ltupdate,ClassName,Format('Block %d Target %s Payload %s Devices %d PoW:%s',[FPoolMinerClient.MinerValuesForWork.block,
+      IntToHex(FPoolMinerClient.MinerValuesForWork.target,8), FPoolMinerClient.MinerValuesForWork.payload_start.ToPrintable,
+      l.Count,
+      FGlobalMinerValuesForWork.target_pow.ToHexaString ]));
   Finally
   Finally
     FDevicesList.UnlockList;
     FDevicesList.UnlockList;
   End;
   End;
@@ -507,7 +530,7 @@ begin
     LHash := TCrypto.DoSha256(TCrypto.DoSha256(digest));
     LHash := TCrypto.DoSha256(TCrypto.DoSha256(digest));
   if (TBaseType.BinStrComp(LHash,usedMinerValuesForWork.target_pow)<=0) then begin
   if (TBaseType.BinStrComp(LHash,usedMinerValuesForWork.target_pow)<=0) then begin
     inc(FGlobaDeviceStats.WinsCount);
     inc(FGlobaDeviceStats.WinsCount);
-    FPoolMinerThread.OnMinerNewBlockFound(self,usedMinerValuesForWork,Timestamp,nOnce);
+    FPoolMinerThread.OnMinerNewBlockFound(self,usedMinerValuesForWork,Timestamp,nOnce,LHash);
     If Assigned(FOnFoundNOnce) then FOnFoundNOnce(Self,Timestamp,nOnce);
     If Assigned(FOnFoundNOnce) then FOnFoundNOnce(Self,Timestamp,nOnce);
   end else begin
   end else begin
     inc(FGlobaDeviceStats.Invalids);
     inc(FGlobaDeviceStats.Invalids);
@@ -523,15 +546,18 @@ end;
 procedure TCustomMinerDeviceThread.CreateDigest(const AMinerValuesForWork: TMinerValuesForWork; Timestamp, nOnce: Cardinal; var ODigest: TRawBytes);
 procedure TCustomMinerDeviceThread.CreateDigest(const AMinerValuesForWork: TMinerValuesForWork; Timestamp, nOnce: Cardinal; var ODigest: TRawBytes);
 begin
 begin
   // Validation
   // Validation
-  SetLength(ODigest,Length(AMinerValuesForWork.part1) + Length(AMinerValuesForWork.payload_start) + Length(AMinerValuesForWork.part3) + 8);
+  SetLength(ODigest,Length(AMinerValuesForWork.part1) + Length(AMinerValuesForWork.payload_start) + Length(AMinerValuesForWork.extraNOnce2_Used) + Length(AMinerValuesForWork.part3) + 8);
   move(AMinerValuesForWork.part1[0],
   move(AMinerValuesForWork.part1[0],
     ODigest[0],
     ODigest[0],
     Length(AMinerValuesForWork.part1));
     Length(AMinerValuesForWork.part1));
   move(AMinerValuesForWork.payload_start[0],
   move(AMinerValuesForWork.payload_start[0],
     ODigest[Length(AMinerValuesForWork.part1)],
     ODigest[Length(AMinerValuesForWork.part1)],
     Length(AMinerValuesForWork.payload_start));
     Length(AMinerValuesForWork.payload_start));
+  move(AMinerValuesForWork.extraNOnce2_Used[0],
+    ODigest[Length(AMinerValuesForWork.part1) + Length(AMinerValuesForWork.payload_start) ],
+    Length(AMinerValuesForWork.extraNOnce2_Used));
   move(AMinerValuesForWork.part3[0],
   move(AMinerValuesForWork.part3[0],
-    ODigest[ Length(AMinerValuesForWork.part1) + Length(AMinerValuesForWork.payload_start) ],
+    ODigest[ Length(AMinerValuesForWork.part1) + Length(AMinerValuesForWork.payload_start) + Length(AMinerValuesForWork.extraNOnce2_Used) ],
     Length(AMinerValuesForWork.part3));
     Length(AMinerValuesForWork.part3));
   // Add timestamp and nonce
   // Add timestamp and nonce
   move(Timestamp,ODigest[length(ODigest)-8],4);
   move(Timestamp,ODigest[length(ODigest)-8],4);
@@ -582,7 +608,8 @@ var aux : Integer;
 begin
 begin
   FMinerValuesForWork := Value;
   FMinerValuesForWork := Value;
   UpdateMinerValuesForWorkLength(FMinerValuesForWork,aux);
   UpdateMinerValuesForWorkLength(FMinerValuesForWork,aux);
-  TLog.NewLog(ltinfo,classname,Format('Updated MinerValuesForWork: Target:%s Payload:%s Target_PoW:%s',[IntToHex(FMinerValuesForWork.target,8),FMinerValuesForWork.payload_start.ToString,TCrypto.ToHexaString(FMinerValuesForWork.target_pow)]));
+  TLog.NewLog(ltdebug,classname,
+    Format('Updated MinerValuesForWork: Target:%s Payload:%s Target_PoW:%s',[IntToHex(FMinerValuesForWork.target,8),FMinerValuesForWork.payload_start.ToString,TCrypto.ToHexaString(FMinerValuesForWork.target_pow)]));
   If Assigned(FOnMinerValuesChanged) then FOnMinerValuesChanged(Self);
   If Assigned(FOnMinerValuesChanged) then FOnMinerValuesChanged(Self);
 end;
 end;
 
 

+ 250 - 71
src/core/UPoolMining.pas

@@ -39,8 +39,11 @@ Const
   CT_PoolMining_Method_MINER_NOTIFY = 'miner-notify'; // Server message to clients to update miners PoW data
   CT_PoolMining_Method_MINER_NOTIFY = 'miner-notify'; // Server message to clients to update miners PoW data
   CT_PoolMining_Method_MINER_SUBMIT = 'miner-submit'; // Client message to server to notify a PoW found
   CT_PoolMining_Method_MINER_SUBMIT = 'miner-submit'; // Client message to server to notify a PoW found
 
 
-  CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE = 'mining-authorize';
-  CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE = 'mining-subscribe';
+  CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE = 'mining.authorize';
+  CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE = 'mining.subscribe';
+  CT_PoolMining_Method_STRATUM_MINING_SET_DIFFICULTY = 'mining.set_difficulty';
+  CT_PoolMining_Method_STRATUM_MINING_NOTIFY = 'mining.notify';
+  CT_PoolMining_Method_STRATUM_MINING_SUBMIT = 'mining.submit';
 
 
 Type
 Type
   TMinerValuesForWork = Record
   TMinerValuesForWork = Record
@@ -52,10 +55,20 @@ Type
      target : Cardinal;
      target : Cardinal;
      timestamp : Cardinal;
      timestamp : Cardinal;
      target_pow : TRawBytes;
      target_pow : TRawBytes;
-     // Stratum jobid
+     // Stratum information
      jobid : String;
      jobid : String;
+     extraNOnce2_Size : Integer;
+     extraNOnce2_Used : TRawBytes;
   End;
   End;
 
 
+  { TMinerValuesForWork_HELPER }
+
+  TMinerValuesForWork_HELPER = record helper for TMinerValuesForWork
+     function FinalPayload : TRawBytes;
+     function IsStratum : Boolean;
+  end;
+
+
   TProcessJSONObjectEvent = Procedure (json : TPCJSONObject; method : String) of object;
   TProcessJSONObjectEvent = Procedure (json : TPCJSONObject; method : String) of object;
 
 
   { TJSONRPCTcpIpClient }
   { TJSONRPCTcpIpClient }
@@ -79,7 +92,7 @@ Type
     Function GetNewId : Cardinal;
     Function GetNewId : Cardinal;
   End;
   End;
 
 
-  TPoolType = (ptNone,ptIdentify);
+  TPoolType = (ptSolomine,ptPoolSubscription);
 
 
   { TPoolMinerClient }
   { TPoolMinerClient }
 
 
@@ -92,6 +105,8 @@ Type
     FPoolType: TPoolType;
     FPoolType: TPoolType;
     FStratum_Target_PoW: TRawBytes;
     FStratum_Target_PoW: TRawBytes;
     FUserName: String;
     FUserName: String;
+    FStratumAuthorized : Boolean;
+    FStratum_ExtraNOnce2_Size: Integer;
     procedure SetMinerValuesForWork(const Value: TMinerValuesForWork);
     procedure SetMinerValuesForWork(const Value: TMinerValuesForWork);
   protected
   protected
     Procedure DoOnConnect; Override;
     Procedure DoOnConnect; Override;
@@ -99,13 +114,15 @@ Type
     Constructor Create(AOwner : TComponent); override;
     Constructor Create(AOwner : TComponent); override;
     Property OnMinerMustChangeValues : TNotifyEvent read FOnMinerMustChangeValues write FOnMinerMustChangeValues;
     Property OnMinerMustChangeValues : TNotifyEvent read FOnMinerMustChangeValues write FOnMinerMustChangeValues;
     Property MinerValuesForWork : TMinerValuesForWork read FMinerValuesForWork write SetMinerValuesForWork;
     Property MinerValuesForWork : TMinerValuesForWork read FMinerValuesForWork write SetMinerValuesForWork;
-    Procedure SubmitBlockFound(Const MinerValuesToGenerateBlock : TMinerValuesForWork; const Payload: TRawBytes; Timestamp, NOnce: Cardinal);
+    Procedure SubmitBlockFound(Const MinerValuesToGenerateBlock : TMinerValuesForWork; const Payload: TRawBytes; Timestamp, NOnce: Cardinal; const AObtainedPoW : TRawBytes);
     Procedure DoProcessJSONObject(json : TPCJSONObject; ResponseMethod : String);
     Procedure DoProcessJSONObject(json : TPCJSONObject; ResponseMethod : String);
     Property PoolType : TPoolType read FPoolType write FPoolType;
     Property PoolType : TPoolType read FPoolType write FPoolType;
     Property UserName : String read FUserName write FUserName;
     Property UserName : String read FUserName write FUserName;
     Property Password : String read FPassword write FPassword;
     Property Password : String read FPassword write FPassword;
     Property PoolFinalMinerName : TRawBytes read FPoolFinalMinerName;
     Property PoolFinalMinerName : TRawBytes read FPoolFinalMinerName;
     Property Stratum_Target_PoW : TRawBytes read FStratum_Target_PoW;
     Property Stratum_Target_PoW : TRawBytes read FStratum_Target_PoW;
+    Property Stratum_Authorized : Boolean read FStratumAuthorized write FStratumAuthorized;
+    Property Stratum_ExtraNOnce2_Size : Integer read FStratum_ExtraNOnce2_Size write FStratum_ExtraNOnce2_Size;
   End;
   End;
 
 
   TPoolMiningServer = Class;
   TPoolMiningServer = Class;
@@ -166,7 +183,7 @@ Type
 Function TBytesToString(Const bytes : TBytes):AnsiString;
 Function TBytesToString(Const bytes : TBytes):AnsiString;
 
 
 Const
 Const
-  CT_TMinerValuesForWork_NULL : TMinerValuesForWork = (block:0;version:0;part1:Nil;payload_start:Nil;part3:Nil;target:0;timestamp:0;target_pow:Nil;jobid:'');
+  CT_TMinerValuesForWork_NULL : TMinerValuesForWork = (block:0;version:0;part1:Nil;payload_start:Nil;part3:Nil;target:0;timestamp:0;target_pow:Nil;jobid:'';extraNOnce2_Size:0;extraNOnce2_Used:Nil);
 
 
 implementation
 implementation
 
 
@@ -191,6 +208,27 @@ Begin
   end;
   end;
 End;
 End;
 
 
+{ TMinerValuesForWork_HELPER }
+
+function TMinerValuesForWork_HELPER.FinalPayload: TRawBytes;
+begin
+  if IsStratum then begin
+    // Check extraNOnce2 valid value
+    while ( Self.extraNOnce2_Size>Length(Self.extraNOnce2_Used) ) do begin
+      SetLength(Self.extraNOnce2_Used, Length(Self.extraNOnce2_Used) + 1);
+      Self.extraNOnce2_Used[ High(Self.extraNOnce2_Used) ] := 48; // 48 = Char '0'
+    end;
+  end;
+  SetLength(Result, Length(Self.payload_start) + Length(Self.extraNOnce2_Used) );
+  Move(Self.payload_start[0],Result[0],Length(Self.payload_start));
+  Move(Self.extraNOnce2_Used[0],Result[Length(Self.payload_start)],Length(Self.extraNOnce2_Used));
+end;
+
+function TMinerValuesForWork_HELPER.IsStratum: Boolean;
+begin
+  Result := Length(Self.jobid)>0;
+end;
+
 { TJSONRPCTcpIpClient }
 { TJSONRPCTcpIpClient }
 
 
 constructor TJSONRPCTcpIpClient.Create(AOwner: TComponent);
 constructor TJSONRPCTcpIpClient.Create(AOwner: TComponent);
@@ -317,10 +355,11 @@ begin
           Try
           Try
             if jsonData is TPCJSONObject then begin
             if jsonData is TPCJSONObject then begin
               jsonObject.Assign(jsonData);
               jsonObject.Assign(jsonData);
-              If (Not jsonObject.IsNull('id')) And (jsonObject.IndexOfName('method')<0) then begin
+              If (Not jsonObject.IsNull('id')) then begin
                 // Is a Response!
                 // Is a Response!
                 FlushBufferPendingMessages(true,jsonObject.AsInteger('id',0));
                 FlushBufferPendingMessages(true,jsonObject.AsInteger('id',0));
               end;
               end;
+              TLog.NewLog(ltdebug,ClassName,'Received JSON: '+jsonObject.ToJSON(false));
               Result := true;
               Result := true;
               exit;
               exit;
             end else begin
             end else begin
@@ -413,7 +452,7 @@ begin
       P^.method:=method;
       P^.method:=method;
       FPendingResponseMessages.Add(P);
       FPendingResponseMessages.Add(P);
     end;
     end;
-    {$IFDEF HIGHLOG}TLog.NewLog(ltInfo,Classname,'Sending JSON: '+json.ToJSON(false));{$ENDIF}
+    TLog.NewLog(ltDebug,Classname,'Sending JSON: '+json.ToJSON(false));
     stream := TMemoryStream.Create;
     stream := TMemoryStream.Create;
     try
     try
       json.SaveToStream(stream);
       json.SaveToStream(stream);
@@ -1057,11 +1096,13 @@ end;
 constructor TPoolMinerClient.Create(AOwner: TComponent);
 constructor TPoolMinerClient.Create(AOwner: TComponent);
 begin
 begin
   FMinerValuesForWork := CT_TMinerValuesForWork_NULL;
   FMinerValuesForWork := CT_TMinerValuesForWork_NULL;
-  FPoolType:=ptNone;
+  FPoolType:=ptSolomine;
   FUserName:='';
   FUserName:='';
   FPassword:='';
   FPassword:='';
   FPoolFinalMinerName:=Nil;
   FPoolFinalMinerName:=Nil;
   FStratum_Target_PoW:=Nil;
   FStratum_Target_PoW:=Nil;
+  FStratumAuthorized := False;
+  FStratum_ExtraNOnce2_Size := 0;
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1073,44 +1114,24 @@ Var params : TPCJSONArray;
   i : Integer;
   i : Integer;
 begin
 begin
   inherited DoOnConnect;
   inherited DoOnConnect;
-  If FPoolType=ptIdentify then begin
+  If FPoolType=ptPoolSubscription then begin
     // Pool initialization
     // Pool initialization
     params := TPCJSONArray.Create;
     params := TPCJSONArray.Create;
     resultObject := TPCJSONObject.Create;
     resultObject := TPCJSONObject.Create;
     try
     try
-      params.GetAsVariant(0).Value:=UserName;
-      params.GetAsVariant(1).Value:=Password;
-      If SendJSONRPCMethodAndWait(CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE,params,1000,resultObject,nil) then begin
-        TLog.NewLog(ltInfo,Classname,CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE+' response: '+resultObject.ToJSON(false));
-        // Now subscribe
-        params.Clear;
-        resultObject.Clear;
-        If SendJSONRPCMethodAndWait(CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE,params,1000,resultObject,nil) then begin
-          //
-          TLog.NewLog(ltInfo,Classname,CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE+' response: '+resultObject.ToJSON(false));
-          // Decode response
-          If (resultObject.IsNull('error')) then begin
-            s := resultObject.GetAsArray('result').GetAsArray(0).GetAsArray(0).GetAsVariant(0).AsString('');
-            if (s<>'mining.nonce') then Raise Exception.Create('Not a mining.nonce');
-            s := resultObject.GetAsArray('result').GetAsVariant(1).AsString('');
-            raws := TCrypto.HexaToRaw(s);
-            If (length(s)>0) And (length(raws)=0) then begin
-              TLog.NewLog(lterror,ClassName,'Invalid value to assign as a Miner name. Not hexadecimal '+s);
-              FPoolFinalMinerName:=Nil;
-            end else begin
-              FPoolFinalMinerName := raws;
-              for i:=Low(raws) to High(raws) do begin
-                if Not (raws[i] in [32..254]) then begin
-                  TLog.NewLog(ltError,ClassName,'Invalid proposed miner name. Value at pos '+inttostr(i)+' is not #32..#254: '+IntToStr(integer(raws[i])));
-                  FPoolFinalMinerName:=Nil;
-                  break;
-                end;
-              end;
-            end;
-            TLog.NewLog(ltInfo,Classname,'Final miner name: "'+FPoolFinalMinerName.ToPrintable+'" (Length '+IntToStr(length(FPoolFinalMinerName)));
-          end;
-        end else raise Exception.Create('Not response to "'+CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE+'" method for user "'+UserName+'"');
-      end else raise Exception.Create('Not response to "'+CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE+'" method for user "'+UserName+'"');
+      If SendJSONRPCMethodAndWait(CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE,params,8000,resultObject,DoProcessJSONObject) then begin
+        //
+        DoProcessJSONObject(resultObject,CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE);
+        //
+        Sleep(100);
+        //
+        params.GetAsVariant(0).Value:=UserName;
+        params.GetAsVariant(1).Value:=Password;
+        If SendJSONRPCMethodAndWait(CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE,params,8000,resultObject,DoProcessJSONObject) then begin
+          DoProcessJSONObject(resultObject,CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE);
+          FStratumAuthorized := True;
+        end else raise Exception.Create('Not response to "'+CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE+'" method for user "'+UserName+'"');
+      end else raise Exception.Create('Not response to "'+CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE+'" method for user "'+UserName+'"');
     finally
     finally
       resultObject.free;
       resultObject.free;
       params.free;
       params.free;
@@ -1127,8 +1148,105 @@ Var method : String;
   params : TPCJSONData;
   params : TPCJSONData;
   mvfw : TMinerValuesForWork;
   mvfw : TMinerValuesForWork;
   prev_pow,proposed_pow : TRawBytes;
   prev_pow,proposed_pow : TRawBytes;
+
+  procedure StratumUpdatedDifficulty(ANewDifficultyValue : Double);
+  var LBigNumDiff : TBigNum;
+    LAuxPOW : TRawBytes;
+    LHexa : String;
+  begin
+    LBigNumDiff := TBigNum.Create('00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
+    try
+      if (ANewDifficultyValue<=0) then Exit;
+
+      if (ANewDifficultyValue<1) then begin
+        LBigNumDiff.Multiply( Round(1000.0/ANewDifficultyValue) ).Divide( 1000 );
+      end else begin
+        LBigNumDiff.Multiply( Round(ANewDifficultyValue*1000.0) ).Divide( 1000 );
+      end;
+      LHexa := LBigNumDiff.HexaValue;
+    finally
+      LBigNumDiff.Free;
+    end;
+    while (LHexa.Length<64) do LHexa.Insert(0,'0');
+    TCrypto.HexaToRaw( LHexa, LAuxPOW );
+    if TBaseType.Equals(LAuxPOW,FStratum_Target_PoW) then Exit; // Nothing to update
+
+    FStratum_Target_PoW := LAuxPOW;
+    TLog.NewLog(ltInfo,ClassName,Format('Set Difficulty to %.6f -> Target PoW:%s %s',[ANewDifficultyValue,
+      TPascalCoinProtocol.TargetToCompact(FStratum_Target_PoW,CT_PROTOCOL_4).ToHexString,
+      FStratum_Target_PoW.ToHexaString]));
+  end;
+
+  procedure ExtractStratumMinerValuesFromWork(const AJobID, ADigestPart_1, ADigestPart_2, AStratumTime : String);
+  var LMVFW : TMinerValuesForWork;
+    LStream : TStream;
+    LRaw : TRawBytes;
+  begin
+    LMVFW := CT_TMinerValuesForWork_NULL;
+    // Extracting Miner Values From Work from Digest parts:
+    if Not TCrypto.HexaToRaw( ADigestPart_1, LRaw) then begin
+      TLog.NewLog(ltError,ClassName,Format('Digest Part 1 obtained is not Hexadecimal: "%s" length %d',[ADigestPart_1,Length(ADigestPart_1)]));
+      Exit;
+    end;
+    if (Length(LRaw)<20) then begin
+      TLog.NewLog(ltError,ClassName,Format('Digest Part 1 is too short: "%s" length %d',[ADigestPart_1,Length(ADigestPart_1)]));
+      Exit;
+    end;
+    LMVFW.part1 := LRaw;
+    if Not TCrypto.HexaToRaw(ADigestPart_2,LMVFW.part3) then begin
+      TLog.NewLog(ltError,ClassName,Format('Digest Part 2 obtained is not Hexadecimal: "%s" length %d',[ADigestPart_2,Length(ADigestPart_2)]));
+      Exit;
+    end;
+    LStream := TMemoryStream.Create;
+    try
+      LStream.WriteBuffer( LRaw[0], Length(LRaw) );
+      LStream.Position := 0;
+      // Block number is stored as a Little Endian on first 4 bytes (8 hexa chars)
+      LStream.Read(LMVFW.block,4);
+
+      if LMVFW.block=0 then Exit;
+
+      // Latest 8 bytes are:
+      // 2 - protocol_version
+      // 2 - protocol_available
+      // 4 - target
+      LStream.Seek(-8,soFromEnd);
+      LStream.Read(LMVFW.version,2);
+      LStream.Seek(2,soFromCurrent);
+      LStream.Read(LMVFW.target,4);
+      LMVFW.jobid := AJobID;
+    finally
+      LStream.Free;
+    end;
+    // Capture timestamp
+    LMVFW.timestamp := StrToIntDef('$'+AStratumTime,0);
+    //
+    MinerValuesForWork := LMVFW;
+  end;
+
+  procedure ExtractStratumMinerValuesFromWorkFromParams;
+  var i : Integer;
+  begin
+    if Not Assigned(params_as_array) then Exit;
+    i := params_as_array.Count - 9;
+    if (i<0) or (i>1) then Exit;
+
+    if (i=1) then begin
+      // Extract difficulty from position 0
+      StratumUpdatedDifficulty( params_as_array.GetAsVariant(0).AsDouble(1) );
+    end;
+
+    // STRATUM
+    ExtractStratumMinerValuesFromWork(
+      params_as_array.GetAsVariant(0 + i).AsString(''),
+      params_as_array.GetAsVariant(2 + i).AsString(''),
+      params_as_array.GetAsVariant(3 + i).AsString(''),
+      params_as_array.GetAsVariant(7 + i).AsString('')
+    );
+  end;
+
+
 begin
 begin
-  TLog.NewLog(ltdebug,ClassName,'Received JSON: '+json.ToJSON(false));
   params := Nil;
   params := Nil;
   params_as_object := Nil;
   params_as_object := Nil;
   params_as_array := Nil;
   params_as_array := Nil;
@@ -1138,19 +1256,20 @@ begin
     if (i>=0) then begin
     if (i>=0) then begin
       params := json.Items[i];
       params := json.Items[i];
     end;
     end;
-    TLog.NewLog(ltinfo,classname,'Received response method:'+ResponseMethod+' JSON:'+json.ToJSON(false));
+    {$IFDEF HIGHLOG}TLog.NewLog(ltinfo,classname,'Received response method:'+ResponseMethod+' JSON:'+json.ToJSON(false));{$ENDIF}
   end else begin
   end else begin
     method := json.AsString('method','');
     method := json.AsString('method','');
-    i := json.IndexOfName('params');
-    if (i>=0) then begin
-      params := json.Items[i];
-    end;
+  end;
+  i := json.IndexOfName('params');
+  if (i>=0) then begin
+    params := json.Items[i];
   end;
   end;
   If Assigned(params) then begin
   If Assigned(params) then begin
     if (params is TPCJSONNameValue) then begin
     if (params is TPCJSONNameValue) then begin
       if (TPCJSONNameValue(params).Value is TPCJSONObject) then params_as_object := TPCJSONObject(TPCJSONNameValue(params).Value)
       if (TPCJSONNameValue(params).Value is TPCJSONObject) then params_as_object := TPCJSONObject(TPCJSONNameValue(params).Value)
       else if (TPCJSONNameValue(params).Value is TPCJSONArray) then params_as_array := TPCJSONArray(TPCJSONNameValue(params).Value);
       else if (TPCJSONNameValue(params).Value is TPCJSONArray) then params_as_array := TPCJSONArray(TPCJSONNameValue(params).Value);
-    end;
+    end else if (params is TPCJSONArray) then params_as_array := TPCJSONArray(params)
+    else if (params is TPCJSONObject) then params_as_object := TPCJSONObject(params)
   end;
   end;
   i := json.IndexOfName('id');
   i := json.IndexOfName('id');
   if i<0 then begin
   if i<0 then begin
@@ -1172,7 +1291,7 @@ begin
       mvfw.timestamp := pobject.AsInteger('timestamp',0);
       mvfw.timestamp := pobject.AsInteger('timestamp',0);
       mvfw.part1 := TCrypto.HexaToRaw(pobject.AsString('part1',''));
       mvfw.part1 := TCrypto.HexaToRaw(pobject.AsString('part1',''));
       mvfw.target_pow := TCrypto.HexaToRaw(pobject.AsString('target_pow',''));
       mvfw.target_pow := TCrypto.HexaToRaw(pobject.AsString('target_pow',''));
-      If FPoolType=ptIdentify then begin
+      If FPoolType=ptPoolSubscription then begin
         mvfw.jobid:=pobject.AsString('jobid','');
         mvfw.jobid:=pobject.AsString('jobid','');
       end;
       end;
       if (Not VarIsNull(id_value)) And (ResponseMethod='') then begin
       if (Not VarIsNull(id_value)) And (ResponseMethod='') then begin
@@ -1180,6 +1299,38 @@ begin
       end;
       end;
       MinerValuesForWork := mvfw;
       MinerValuesForWork := mvfw;
     end else TLog.NewLog(ltError,ClassName,'method '+method+' without JSON object '+params.ToJSON(false));
     end else TLog.NewLog(ltError,ClassName,'method '+method+' without JSON object '+params.ToJSON(false));
+  end else if (method=CT_PoolMining_Method_STRATUM_MINING_AUTHORIZE) And
+    (PoolType=ptPoolSubscription) And (Assigned(params_as_array)) then begin
+    //
+    FStratumAuthorized := True;
+    ExtractStratumMinerValuesFromWorkFromParams;
+  end else if (method=CT_PoolMining_Method_STRATUM_MINING_SUBSCRIBE) And
+    (PoolType=ptPoolSubscription) And (Assigned(params_as_array)) then begin
+    // STRATUM
+    // {"id":2,"result":[[["mining.notify","00000000000000000000000000000000"]],"303030303030303030",8],"error":null}
+    // Explained at: https://slushpool.com/help/stratum-protocol/
+    // params[0] -> Subscription details
+    // params[1] -> Extranonce1
+    // params[2] -> Extranonce2_size
+    FPoolFinalMinerName := TCrypto.HexaToRaw( params_as_array.GetAsVariant(1).AsString('') );
+    FStratum_ExtraNOnce2_Size := params_as_array.GetAsVariant(2).AsInteger(0);
+  end else if (method=CT_PoolMining_Method_STRATUM_MINING_SET_DIFFICULTY) And
+    (PoolType=ptPoolSubscription) And (Assigned(params_as_array)) then begin
+    // STRATUM
+    // {"id":null,"method":"mining.set_difficulty","params":[0.0000152588]}
+    StratumUpdatedDifficulty( params_as_array.GetAsVariant(0).AsDouble(1) );
+
+  end else if (method=CT_PoolMining_Method_STRATUM_MINING_NOTIFY) And
+    (PoolType=ptPoolSubscription) And (Assigned(params_as_array)) then begin
+    ExtractStratumMinerValuesFromWorkFromParams;
+  end else if (method=CT_PoolMining_Method_STRATUM_MINING_SUBMIT) And
+    (PoolType=ptPoolSubscription) then begin
+    // Response to a mining submit event
+    if (json.GetAsVariant('error').AsBoolean(False)) then begin
+      TLog.NewLog(lterror,ClassName,Format('Invalid SHARE %s',[method,json.ToJSON(False)]));
+    end;
+  end else begin
+    TLog.NewLog(lterror,ClassName,Format('Unknown method received "%s": %s',[method,json.ToJSON(False)]));
   end;
   end;
 end;
 end;
 
 
@@ -1218,32 +1369,60 @@ begin
       end;
       end;
     end;
     end;
   end;
   end;
-  If (FPoolType=ptIdentify) And (Length(FPoolFinalMinerName)>0) then FMinerValuesForWork.payload_start:=FPoolFinalMinerName;
+  If (FPoolType=ptPoolSubscription) And (Length(FPoolFinalMinerName)>0) then begin
+    FMinerValuesForWork.payload_start:=FPoolFinalMinerName;
+    FMinerValuesForWork.extraNOnce2_Size:=FStratum_ExtraNOnce2_Size;
+    FMinerValuesForWork.extraNOnce2_Used:=Nil;
+  end;
   if Assigned(FOnMinerMustChangeValues) then FOnMinerMustChangeValues(Self);
   if Assigned(FOnMinerMustChangeValues) then FOnMinerMustChangeValues(Self);
 end;
 end;
 
 
-procedure TPoolMinerClient.SubmitBlockFound(Const MinerValuesToGenerateBlock : TMinerValuesForWork; const Payload: TRawBytes; Timestamp, NOnce: Cardinal);
-Var json, resultJSON : TPCJSONObject;
-  nOnceAsSignedInt : Int32;
+procedure TPoolMinerClient.SubmitBlockFound(Const MinerValuesToGenerateBlock : TMinerValuesForWork; const Payload: TRawBytes; Timestamp, NOnce: Cardinal; const AObtainedPoW : TRawBytes);
+Var json : TPCJSONObject;
+  LnOnceAsSignedInt : Int32;
+  LArrJSON : TPCJSONArray;
 begin
 begin
-  json := TPCJSONObject.Create;
-  Try
-    nOnceAsSignedInt := NOnce;
-    If FPoolType=ptIdentify then begin
-      json.GetAsVariant('jobid').Value := MinerValuesToGenerateBlock.jobid;
-    end;
-    json.GetAsVariant('payload').Value := TCrypto.ToHexaString(Payload);
-    json.GetAsVariant('timestamp').Value := Timestamp;
-    json.GetAsVariant('nonce').Value := nOnceAsSignedInt;
-    resultJSON := TPCJSONObject.Create;
-    try
+  LnOnceAsSignedInt := NOnce;
+  If FPoolType=ptPoolSubscription then begin
+    LArrJSON := TPCJSONArray.Create;
+    Try
+      LArrJSON.GetAsVariant(0).Value := UserName;
+      LArrJSON.GetAsVariant(1).Value := MinerValuesToGenerateBlock.jobid;
+      LArrJSON.GetAsVariant(2).Value := MinerValuesToGenerateBlock.extraNOnce2_Used.ToHexaString; //  Payload.ToHexaString;// + '1234567812345678'; // '1234567812345678'; //Payload.ToHexaString;
+      LArrJSON.GetAsVariant(3).Value := IntToHex(Timestamp,8);
+      LArrJSON.GetAsVariant(4).Value := IntToHex(LnOnceAsSignedInt,8);
+      SendJSONRPCMethod(CT_PoolMining_Method_STRATUM_MINING_SUBMIT,LArrJSON,GetNewId);
+      TLog.NewLog(ltInfo,ClassName,Format('SHARE for job %s block %d Time %s NOnce %s ExtraNOnce2 %s PoW %s',
+       [MinerValuesToGenerateBlock.jobid,
+        MinerValuesToGenerateBlock.block,
+        IntToHex(Timestamp,8),
+        IntToHex(LnOnceAsSignedInt,8),
+        MinerValuesToGenerateBlock.extraNOnce2_Used.ToHexaString,
+        AObtainedPoW.ToHexaString]));
+    Finally
+      LArrJSON.Free;
+    End;
+  end else begin
+    json := TPCJSONObject.Create;
+    Try
+      If FPoolType=ptPoolSubscription then begin
+        json.GetAsVariant('jobid').Value := MinerValuesToGenerateBlock.jobid;
+      end;
+      json.GetAsVariant('payload').Value := TCrypto.ToHexaString(Payload);
+      json.GetAsVariant('timestamp').Value := Timestamp;
+      json.GetAsVariant('nonce').Value := LnOnceAsSignedInt;
       SendJSONRPCMethod(CT_PoolMining_Method_MINER_SUBMIT,json,GetNewId);
       SendJSONRPCMethod(CT_PoolMining_Method_MINER_SUBMIT,json,GetNewId);
+      TLog.NewLog(ltInfo,ClassName,Format('FOUND SOLUTION for block %d Time %s NOnce %s Payload %s PoW %s',
+       [
+        MinerValuesToGenerateBlock.block,
+        IntToHex(Timestamp,8),
+        IntToHex(LnOnceAsSignedInt,8),
+        Payload.ToHexaString,
+        AObtainedPoW.ToHexaString]));
     Finally
     Finally
-      resultJSON.free;
-    end;
-  Finally
-    json.Free;
-  End;
+      json.Free;
+    End;
+  end;
 end;
 end;
 
 
 { TPoolMiningServerThread }
 { TPoolMiningServerThread }

+ 3 - 1
src/core/UTCPIP.pas

@@ -264,7 +264,6 @@ begin
       if (FConnected) then begin
       if (FConnected) then begin
         FRemoteHost := FTcpBlockSocket.GetRemoteSinIP;
         FRemoteHost := FTcpBlockSocket.GetRemoteSinIP;
         FRemotePort := FTcpBlockSocket.GetRemoteSinPort;
         FRemotePort := FTcpBlockSocket.GetRemoteSinPort;
-        DoOnConnect;
       end{$IFDEF HIGHLOG} else TLog.NewLog(ltdebug,Classname,'Cannot connect to a server at: '+ClientRemoteAddr+' Reason: '+FTcpBlockSocket.GetErrorDescEx){$ENDIF};
       end{$IFDEF HIGHLOG} else TLog.NewLog(ltdebug,Classname,'Cannot connect to a server at: '+ClientRemoteAddr+' Reason: '+FTcpBlockSocket.GetErrorDescEx){$ENDIF};
     Except
     Except
       On E:Exception do begin
       On E:Exception do begin
@@ -278,6 +277,9 @@ begin
     FLock.Release;
     FLock.Release;
   end;
   end;
   Result := FConnected;
   Result := FConnected;
+  if FConnected then begin
+    DoOnConnect;
+  end;
 end;
 end;
 
 
 constructor TNetTcpIpClient.Create(AOwner : TComponent);
 constructor TNetTcpIpClient.Create(AOwner : TComponent);

+ 5 - 14
src/pascalcoin_miner.lpi

@@ -1,16 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <CONFIG>
 <CONFIG>
   <ProjectOptions>
   <ProjectOptions>
-    <Version Value="12"/>
+    <Version Value="10"/>
     <PathDelim Value="\"/>
     <PathDelim Value="\"/>
     <General>
     <General>
       <Flags>
       <Flags>
         <MainUnitHasCreateFormStatements Value="False"/>
         <MainUnitHasCreateFormStatements Value="False"/>
         <MainUnitHasTitleStatement Value="False"/>
         <MainUnitHasTitleStatement Value="False"/>
-        <CompatibilityMode Value="True"/>
       </Flags>
       </Flags>
       <SessionStorage Value="InProjectDir"/>
       <SessionStorage Value="InProjectDir"/>
-      <Title Value="PascalCoinMiner"/>
+      <MainUnit Value="0"/>      
       <UseAppBundle Value="False"/>
       <UseAppBundle Value="False"/>
       <ResourceType Value="res"/>
       <ResourceType Value="res"/>
     </General>
     </General>
@@ -25,16 +24,9 @@
     </PublishOptions>
     </PublishOptions>
     <RunParams>
     <RunParams>
       <local>
       <local>
+        <FormatVersion Value="1"/>
         <CommandLineParams Value="-c 1 -s -n TEST"/>
         <CommandLineParams Value="-c 1 -s -n TEST"/>
       </local>
       </local>
-      <FormatVersion Value="2"/>
-      <Modes Count="1">
-        <Mode0 Name="default">
-          <local>
-            <CommandLineParams Value="-c 1 -s -n TEST"/>
-          </local>
-        </Mode0>
-      </Modes>
     </RunParams>
     </RunParams>
     <RequiredPackages Count="1">
     <RequiredPackages Count="1">
       <Item1>
       <Item1>
@@ -44,8 +36,7 @@
     <Units Count="1">
     <Units Count="1">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_miner.pp"/>
         <Filename Value="pascalcoin_miner.pp"/>
-        <IsPartOfProject Value="True"/>
-        <UnitName Value="PascalCoinMiner"/>
+        <IsPartOfProject Value="True"/>        
       </Unit0>
       </Unit0>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
@@ -62,7 +53,7 @@
     </SearchPaths>
     </SearchPaths>
     <CodeGeneration>
     <CodeGeneration>
       <Optimizations>
       <Optimizations>
-        <OptimizationLevel Value="4"/>
+        <OptimizationLevel Value="3"/>
       </Optimizations>
       </Optimizations>
     </CodeGeneration>
     </CodeGeneration>
     <Linking>
     <Linking>

+ 24 - 29
src/pascalcoin_miner.pp

@@ -46,7 +46,6 @@ type
   protected
   protected
     FWindow32X1,FWindow32Y1,FWindow32X2,FWindow32Y2: DWord;
     FWindow32X1,FWindow32Y1,FWindow32X2,FWindow32Y2: DWord;
     FLock : TCriticalSection;
     FLock : TCriticalSection;
-    FPrivateKey : TECPrivateKey;
     FPoolMinerThread : TPoolMinerThread;
     FPoolMinerThread : TPoolMinerThread;
     FDeviceThreads : TList;
     FDeviceThreads : TList;
     FAppStartTime : TDateTime;
     FAppStartTime : TDateTime;
@@ -58,7 +57,7 @@ type
   end;
   end;
 
 
 Const
 Const
-  CT_MINER_VERSION = {$IFDEF PRODUCTION}'5.0'{$ELSE}{$IFDEF TESTNET}'5.0 TESTNET'{$ELSE}ERROR{$ENDIF}{$ENDIF};
+  CT_MINER_VERSION = {$IFDEF PRODUCTION}'5.1'{$ELSE}{$IFDEF TESTNET}'5.1 TESTNET'{$ELSE}ERROR{$ENDIF}{$ENDIF};
   CT_Line_DeviceStatus = 3;
   CT_Line_DeviceStatus = 3;
   CT_Line_ConnectionStatus = 4;
   CT_Line_ConnectionStatus = 4;
   CT_Line_MinerValues = 7;
   CT_Line_MinerValues = 7;
@@ -105,7 +104,7 @@ Const CT_state : Array[boolean] of String = ('Disconnected','Connected');
 var i : Integer;
 var i : Integer;
   s : String;
   s : String;
 begin
 begin
-  If FPoolMinerThread.PoolMinerClient.PoolType=ptNone then s:='MINING'
+  If FPoolMinerThread.PoolMinerClient.PoolType=ptSolomine then s:='MINING'
   else s:='POOL MINING USER "'+FPoolMinerThread.PoolMinerClient.UserName+'"';
   else s:='POOL MINING USER "'+FPoolMinerThread.PoolMinerClient.UserName+'"';
   If FPoolMinerThread.PoolMinerClient.Connected then begin
   If FPoolMinerThread.PoolMinerClient.Connected then begin
     WriteLine(CT_Line_ConnectionStatus,s + ' server: '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
     WriteLine(CT_Line_ConnectionStatus,s + ' server: '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
@@ -203,6 +202,7 @@ var
   ErrorMsg: String;
   ErrorMsg: String;
   s : String;
   s : String;
   nsarr : TNodeServerAddressArray;
   nsarr : TNodeServerAddressArray;
+  LLog : TLog;
 
 
   Function AddMiners : Boolean;
   Function AddMiners : Boolean;
   var p,d,c,i : Integer;
   var p,d,c,i : Integer;
@@ -345,17 +345,11 @@ var
 
 
   Procedure DoVisualprocess(minerName, UserName, Password : String);
   Procedure DoVisualprocess(minerName, UserName, Password : String);
   Var sc : tcrtcoord;
   Var sc : tcrtcoord;
-    Flog : TLog;
     devt : TCustomMinerDeviceThread;
     devt : TCustomMinerDeviceThread;
     i : Integer;
     i : Integer;
   Begin
   Begin
-    FPoolMinerThread := TPoolMinerThread.Create(nsarr[0].ip,nsarr[0].port,FPrivateKey.PublicKey);
+    FPoolMinerThread := TPoolMinerThread.Create(nsarr[0].ip,nsarr[0].port,UserName,Password);
     try
     try
-      If (UserName<>'') then begin
-        FPoolMinerThread.PoolMinerClient.PoolType:=ptIdentify;
-        FPoolMinerThread.PoolMinerClient.UserName:=UserName;
-        FPoolMinerThread.PoolMinerClient.Password:=Password;
-      end;
       If Not AddMiners then exit;
       If Not AddMiners then exit;
       if HasOption('t','testmode') then begin
       if HasOption('t','testmode') then begin
         i := StrToIntDef(GetOptionValue('t','testmode'),-1);
         i := StrToIntDef(GetOptionValue('t','testmode'),-1);
@@ -393,12 +387,11 @@ var
         end else begin
         end else begin
           WriteLine(2,'Mining using '+IntToStr(FDeviceThreads.Count)+' devices');
           WriteLine(2,'Mining using '+IntToStr(FDeviceThreads.Count)+' devices');
         end;
         end;
-        Flog := TLog.Create(Nil);
+        LLog.OnInThreadNewLog:=OnInThreadNewLog;
         try
         try
-          Flog.OnInThreadNewLog:=OnInThreadNewLog;
           DoWaitAndLog;
           DoWaitAndLog;
         finally
         finally
-          FLog.free;
+          LLog.OnInThreadNewLog:=Nil;
         end;
         end;
       finally
       finally
         cursoron;
         cursoron;
@@ -411,11 +404,21 @@ var
 
 
 Var username,password : String;
 Var username,password : String;
 begin
 begin
+  LLog := TLog.Create(Self);
+  Try
+    If HasOption('l','logfile') then begin
+      s := Trim(GetOptionValue('l','logile'));
+      if s='' then s := 'PascalCoinMiner_'+FormatDateTime('yyyy-mm-dd_hh_nn_ss',Now)+'.log';
+      if HasOption('logall') then LLog.SaveTypes:=CT_TLogTypes_ALL
+      else LLog.SaveTypes:=CT_TLogTypes_DEFAULT;
+      LLog.FileName:=ExtractFileDir(ExeName)+PathDelim+s;
+    end;
+
   FLastLogs := TStringList.Create;
   FLastLogs := TStringList.Create;
   FLock := TCriticalSection.Create;
   FLock := TCriticalSection.Create;
   Try
   Try
     // quick check parameters
     // quick check parameters
-    ErrorMsg:=CheckOptions('hp:d:s::c:n::t:u::x::', 'help platform device server cpu minername testmode user pwd');
+    ErrorMsg:=CheckOptions('hp:d:s::c:n::t:u::x::l::', 'help platform device server cpu minername testmode user pwd logfile logall');
     if ErrorMsg<>'' then begin
     if ErrorMsg<>'' then begin
       //ShowException(Exception.Create(ErrorMsg));
       //ShowException(Exception.Create(ErrorMsg));
       WriteLn(ErrorMsg);
       WriteLn(ErrorMsg);
@@ -486,37 +489,27 @@ begin
         WriteLn('Input Pool username (or empty for non pool connection):');
         WriteLn('Input Pool username (or empty for non pool connection):');
         Readln(username);
         Readln(username);
       end;
       end;
-      if (password='') And (username<>'') then begin
-        WriteLn('Input Pool password for user ',username,':');
-        Readln(password);
-      end;
     end;
     end;
 
 
-    FPrivateKey := TECPrivateKey.Create;
-    Try
-      FPrivateKey.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
-      DoVisualprocess(s,username,password);
-    finally
-      FreeAndNil(FPrivateKey);
-    end;
+    DoVisualprocess(s,username,password);
   finally
   finally
     FreeAndNil(FLock);
     FreeAndNil(FLock);
     FreeAndNil(FLastLogs);
     FreeAndNil(FLastLogs);
     if not terminated then
     if not terminated then
       Terminate;
       Terminate;
   end;
   end;
+
+  finally
+    FreeAndNil(LLog);
+  end;
 end;
 end;
 
 
 constructor TPascalMinerApp.Create(TheOwner: TComponent);
 constructor TPascalMinerApp.Create(TheOwner: TComponent);
-Var FLog : TLog;
 begin
 begin
   inherited Create(TheOwner);
   inherited Create(TheOwner);
   FDeviceThreads := TList.Create;
   FDeviceThreads := TList.Create;
   StopOnException:=True;
   StopOnException:=True;
   FAppStartTime := Now;
   FAppStartTime := Now;
-  FLog := TLog.Create(self);
-  FLog.SaveTypes:=CT_TLogTypes_DEFAULT;
-  FLog.FileName:=ExtractFileDir(ExeName)+PathDelim+'PascalCoinMiner.log';
 end;
 end;
 
 
 destructor TPascalMinerApp.Destroy;
 destructor TPascalMinerApp.Destroy;
@@ -537,6 +530,8 @@ begin
   writeln('    Y can be multiple devices. Example -d 0,2,3  Will use devices 0, 2 and 3');
   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('  -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('  -n MYNAME  (Will add MYNAME value to miner name assigned by server)');
+  writeln('  -l LOG_FILENAME  (Will log to specified filename or will generate a new filename)');
+  writeln('    --logall log filename will include extra information (like full JSON commands)');
   writeln('  ** POOL IDENTIFICATION PROTOCOL **');
   writeln('  ** POOL IDENTIFICATION PROTOCOL **');
   writeln('  (Not needed for PascalCoin core, only some third party pools)');
   writeln('  (Not needed for PascalCoin core, only some third party pools)');
   writeln('  -u USERNAME');
   writeln('  -u USERNAME');