pascalcoin_miner.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. program PascalCoinMiner;
  2. {$mode delphi}{$H+}
  3. {$DEFINE UseCThreads}
  4. {$I config.inc}
  5. { Copyright (c) 2017 by Albert Molina
  6. Distributed under the MIT software license, see the accompanying file LICENSE
  7. or visit http://www.opensource.org/licenses/mit-license.php.
  8. This unit is a part of Pascal Coin, a P2P crypto currency without need of
  9. historical operations.
  10. If you like it, consider a donation using BitCoin:
  11. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  12. }
  13. {$I config.inc}
  14. uses
  15. {$IFDEF UNIX}{$IFDEF UseCThreads}
  16. cthreads,
  17. {$ENDIF}{$ENDIF}
  18. Classes, SysUtils, CustApp, crt, SyncObjs,
  19. UBlockChain, UPoolMinerThreads, UGPUMining,
  20. UPoolMining, ULog, UThread, UAccounts, UCrypto,
  21. UConst, UTime, UNode, UNetProtocol, USha256,
  22. UOpenSSL, UBaseTypes, UCommon, DelphiCL;
  23. type
  24. { TPascalMinerApp }
  25. TPascalMinerApp = class(TCustomApplication)
  26. FLastLogs : TStringList;
  27. procedure ShowGPUDrivers;
  28. procedure OnConnectionStateChanged(Sender : TObject);
  29. procedure OnDeviceStateChanged(Sender : TObject);
  30. procedure OnMinerValuesChanged(Sender : TObject);
  31. procedure OnFoundNOnce(Sender : TCustomMinerDeviceThread; const AUsedMinerValuesForWork : TMinerValuesForWork; ATimestamp, AnOnce : Cardinal; const APoW : TRawBytes);
  32. procedure WriteLine(nline : Integer; txt : String);
  33. procedure OnInThreadNewLog(logtype : TLogType; Time : TDateTime; ThreadID : TThreadID; Const sender, logtext : AnsiString);
  34. protected
  35. FOutputAsLogs : Boolean;
  36. FWindow32X1,FWindow32Y1,FWindow32X2,FWindow32Y2: DWord;
  37. FLock : TCriticalSection;
  38. FPoolMinerThread : TPoolMinerThread;
  39. FDeviceThreads : TList;
  40. FAppStartTime : TDateTime;
  41. procedure DoRun; override;
  42. public
  43. constructor Create(TheOwner: TComponent); override;
  44. destructor Destroy; override;
  45. procedure WriteHelp; virtual;
  46. end;
  47. Const
  48. CT_MINER_VERSION = {$IFDEF PRODUCTION}'5.4'{$ELSE}{$IFDEF TESTNET}'5.4 TESTNET'{$ELSE}ERROR{$ENDIF}{$ENDIF};
  49. CT_Line_DeviceStatus = 3;
  50. CT_Line_ConnectionStatus = 4;
  51. CT_Line_MinerValues = 7;
  52. CT_Line_MiningStatus = 10;
  53. CT_Line_LastFound = 12;
  54. CT_Line_Logs = 15;
  55. CT_MaxLogs = 10;
  56. CT_OpenCL_FileName = 'pascalsha.cl';
  57. { TPascalMinerApp }
  58. procedure TPascalMinerApp.ShowGPUDrivers;
  59. Var i,j,n : Integer;
  60. dev : TDCLDevice;
  61. begin
  62. n := 0;
  63. If Not TGPUDriver.GPUDriver.HasOpenCL then WriteLn('No GPU driver found')
  64. else begin
  65. Writeln('');
  66. WriteLn('** Platforms (Total ',TGPUDriver.GPUDriver.Platforms.PlatformCount,')');
  67. for i:=0 to TGPUDriver.GPUDriver.Platforms.PlatformCount-1 do begin
  68. WriteLn('Platform ',i,' Name:',Trim(TGPUDriver.GPUDriver.Platforms.Platforms[i]^.Name),
  69. ' Version:',Trim(TGPUDriver.GPUDriver.Platforms.Platforms[i]^.Version),
  70. ' Vendor:',Trim(TGPUDriver.GPUDriver.Platforms.Platforms[i]^.Vendor),
  71. ' CPU''s:',TGPUDriver.GPUDriver.Platforms.Platforms[i]^.CPUCount,
  72. ' GPU''s:',TGPUDriver.GPUDriver.Platforms.Platforms[i]^.GPUCount,
  73. ' Devices: ',TGPUDriver.GPUDriver.Platforms.Platforms[i]^.DeviceCount
  74. );
  75. inc(n,TGPUDriver.GPUDriver.Platforms.Platforms[i]^.DeviceCount);
  76. end;
  77. Writeln('');
  78. Writeln('** Platforms and devices available: (Total ',n,')');
  79. for i:=0 to TGPUDriver.GPUDriver.Platforms.PlatformCount-1 do begin
  80. for j:=0 to TGPUDriver.GPUDriver.Platforms.Platforms[i]^.DeviceCount-1 do begin
  81. dev := TGPUDriver.GPUDriver.Platforms.Platforms[i]^.Devices[j]^;
  82. Writeln('-p ',i,' -d ',j,' Name:',Trim(dev.Name),' Compute Units:',dev.MaxComputeUnits,' Max Freq.:',dev.MaxClockFrequency);
  83. end;
  84. end;
  85. end;
  86. end;
  87. procedure TPascalMinerApp.OnConnectionStateChanged(Sender: TObject);
  88. var i : Integer;
  89. s : String;
  90. begin
  91. If FPoolMinerThread.PoolMinerClient.PoolType=ptSolomine then s:='MINING'
  92. else s:='POOL MINING USER "'+FPoolMinerThread.PoolMinerClient.UserName+'"';
  93. If FPoolMinerThread.PoolMinerClient.Connected then begin
  94. WriteLine(CT_Line_ConnectionStatus,s + ' server: '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
  95. For i:=0 to FDeviceThreads.Count-1 do begin
  96. TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=false;
  97. end;
  98. end else begin
  99. For i:=0 to FDeviceThreads.Count-1 do begin
  100. TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=true;
  101. end;
  102. WriteLine(CT_Line_ConnectionStatus,'** NOT CONNECTED '+s + ' Connecting to '+FPoolMinerThread.PoolMinerClient.ClientRemoteAddr);
  103. end;
  104. end;
  105. procedure TPascalMinerApp.OnDeviceStateChanged(Sender: TObject);
  106. begin
  107. If Sender is TCustomMinerDeviceThread then begin
  108. If TCustomMinerDeviceThread(Sender).IsMining then WriteLine(CT_Line_DeviceStatus,'') // clear line
  109. else WriteLine(CT_Line_DeviceStatus,'*** Not mining ***');
  110. end;
  111. end;
  112. procedure TPascalMinerApp.OnMinerValuesChanged(Sender: TObject);
  113. begin
  114. If Sender is TCustomMinerDeviceThread then begin
  115. If TCustomMinerDeviceThread(Sender).MinerValuesForWork.block>0 then begin
  116. WriteLine(CT_Line_MinerValues,Format('Current block: %d Wallet Name: "%s" Target: %s',
  117. [TCustomMinerDeviceThread(Sender).MinerValuesForWork.block,
  118. FPoolMinerThread.GlobalMinerValuesForWork.payload_start.ToPrintable,
  119. IntToHex(TCustomMinerDeviceThread(Sender).MinerValuesForWork.target,8)
  120. ]));
  121. end;
  122. end;
  123. end;
  124. procedure TPascalMinerApp.OnFoundNOnce(Sender : TCustomMinerDeviceThread; const AUsedMinerValuesForWork : TMinerValuesForWork; ATimestamp, AnOnce : Cardinal; const APoW : TRawBytes);
  125. begin
  126. WriteLine(CT_Line_LastFound + FDeviceThreads.Count,FormatDateTime('hh:nn:ss',now)+' Block:'+IntToStr(Sender.MinerValuesForWork.block)+' NOnce:'+Inttostr(AnOnce)+
  127. ' Timestamp:'+inttostr(ATimestamp)+' Miner:'+Sender.MinerValuesForWork.payload_start.ToPrintable);
  128. end;
  129. procedure TPascalMinerApp.WriteLine(nline: Integer; txt: String);
  130. Var i : Integer;
  131. begin
  132. FLock.Acquire;
  133. try
  134. if FOutputAsLogs then begin
  135. WriteLn(Format('%s %s',[FormatDateTime('hh:nn:ss.zzz',Now()),txt]));
  136. Exit;
  137. end;
  138. i := length(txt);
  139. if i<=(FWindow32X2-FWindow32X1+1) then begin
  140. setlength(txt,FWindow32X2-FWindow32X1+1);
  141. fillchar(txt[i+1],FWindow32X2-FWindow32X1+1-i,' ');
  142. end else begin
  143. txt := copy(txt,1,FWindow32X2-FWindow32X1+1);
  144. end;
  145. if (nline<=(FWindow32Y2-FWindow32Y1)) then begin
  146. GotoXY(FWindow32X1,nline);
  147. write(txt);
  148. end;
  149. finally
  150. FLock.Release;
  151. end;
  152. end;
  153. procedure TPascalMinerApp.OnInThreadNewLog(logtype: TLogType; Time: TDateTime;
  154. ThreadID: TThreadID; const sender, logtext: AnsiString);
  155. var msg : String;
  156. i,nline : Integer;
  157. begin
  158. If logtype=ltdebug then exit;
  159. FLock.Acquire;
  160. try
  161. msg := formatdatetime('hh:nn:ss',now)+' '+CT_LogType[logtype]+' '+logtext;
  162. // TODO - test logtype is properly casted/stored/retrieved/accessed.
  163. // Confirm casting doesn't lose bits in 32/64 bit archs
  164. // OLD: FLastLogs.AddObject(msg,TObject(PtrInt(logtype)));
  165. FLastLogs.AddObject(msg,Pointer(logtype));
  166. i := FLastLogs.Count-CT_MaxLogs;
  167. if (i<0) then i:=0;
  168. nline := CT_Line_Logs+FDeviceThreads.Count;
  169. while (i<FLastLogs.Count) do begin
  170. WriteLine(nline,FLastLogs[i]);
  171. inc(nline); inc(i);
  172. end;
  173. if FLastLogs.Count>(CT_MaxLogs*2) then begin
  174. for i:=1 to CT_MaxLogs do FLastLogs.Delete(0);
  175. end;
  176. Finally
  177. FLock.Release;
  178. end;
  179. end;
  180. procedure TPascalMinerApp.DoRun;
  181. var
  182. ErrorMsg: String;
  183. s : String;
  184. nsarr : TNodeServerAddressArray;
  185. LLog : TLog;
  186. Function AddMiners : Boolean;
  187. var p,d,c,i : Integer;
  188. strl : TStringList;
  189. devt : TCustomMinerDeviceThread;
  190. begin
  191. Result := false;
  192. if (Not HasOption('p','platform')) And (Not HasOption('d','device')) And (Not HasOption('c','cpu')) then begin
  193. Writeln('Need to specify -p X and -d Y for GPU mining or -c N for CPU mining. See -h for more info');
  194. ShowGPUDrivers;
  195. Terminate;
  196. Exit;
  197. end;
  198. if HasOption('c','cpu') then begin
  199. c := StrToIntDef(GetOptionValue('c','cpu'),-1);
  200. if (c<=0) or (c>TCPUTool.GetLogicalCPUCount()) then begin
  201. WriteLn('Invalid cpu value ',c,'. Valid values: 1..',TCPUTool.GetLogicalCPUCount());
  202. Terminate;
  203. exit;
  204. end;
  205. devt:= TCPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
  206. devt.OnStateChanged:=OnDeviceStateChanged;
  207. devt.OnMinerValuesChanged:=OnMinerValuesChanged;
  208. devt.OnFoundNOnce:=OnFoundNOnce;
  209. TCPUDeviceThread(devt).CPUs:=c;
  210. devt.Paused:=true;
  211. FDeviceThreads.Add(devt);
  212. end else begin
  213. p := StrToIntDef(GetOptionValue('p','platform'),-1);
  214. d := StrToIntDef(GetOptionValue('d','device'),-1);
  215. if (p<0) or (p>=TGPUDriver.GPUDriver.Platforms.PlatformCount) then begin
  216. WriteLn('Invalid Platform ',p,'. Valid values: 0..',TGPUDriver.GPUDriver.Platforms.PlatformCount-1);
  217. Terminate;
  218. exit;
  219. end;
  220. If Not FileExists(ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName) then begin
  221. Writeln('**********************');
  222. Writeln('OpenCL file not found!');
  223. Writeln('File: ',CT_OpenCL_FileName);
  224. Terminate;
  225. Exit;
  226. end;
  227. strl := TStringList.Create;
  228. try
  229. if (d<0) then begin
  230. // Is a value separated by commas?
  231. strl.Delimiter:=',';
  232. strl.DelimitedText:=GetOptionValue('d','device');
  233. end else strl.Text:=inttostr(d);
  234. for i:=0 to strl.Count-1 do begin
  235. d := StrToIntDef(strl[i],-1);
  236. if (d<0) or (d>=TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount) then begin
  237. WriteLn('Invalid device ',d,'. Valid values: 0..',TGPUDriver.GPUDriver.Platforms.Platforms[p]^.DeviceCount-1);
  238. Terminate;
  239. exit;
  240. end;
  241. //
  242. devt := TGPUDeviceThread.Create(FPoolMinerThread,CT_TMinerValuesForWork_NULL);
  243. devt.OnStateChanged:=OnDeviceStateChanged;
  244. devt.OnMinerValuesChanged:=OnMinerValuesChanged;
  245. devt.OnFoundNOnce:=OnFoundNOnce;
  246. TGPUDeviceThread(devt).Platform:=p;
  247. TGPUDeviceThread(devt).Device:=d;
  248. TGPUDeviceThread(devt).ProgramFileName:=ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName;
  249. devt.Paused:=true;
  250. FDeviceThreads.Add(devt);
  251. end;
  252. finally
  253. strl.Free;
  254. end;
  255. end;
  256. Result := true;
  257. end;
  258. Procedure DoWaitAndLog;
  259. Var tc, LMaxElapsed : TTickCount;
  260. gs,ms : TMinerStats;
  261. hrHashing : Real;
  262. i : Integer;
  263. devt : TCustomMinerDeviceThread;
  264. s : String;
  265. kpressed : Char;
  266. Begin
  267. tc := TPlatform.GetTickCount;
  268. repeat
  269. If FPoolMinerThread.PoolMinerClient.Connected then begin
  270. for i:=0 to FDeviceThreads.Count-1 do begin
  271. TCustomMinerDeviceThread(FDeviceThreads[i]).Paused:=false;
  272. end;
  273. end;
  274. while (Not Terminated) do begin
  275. sleep(100);
  276. if FOutputAsLogs then LMaxElapsed := 10000
  277. else LMaxElapsed:=1000;
  278. If TPlatform.GetElapsedMilliseconds(tc)>LMaxElapsed then begin
  279. tc := TPlatform.GetTickCount;
  280. For i:=0 to FDeviceThreads.Count-1 do begin
  281. devt := TCustomMinerDeviceThread(FDeviceThreads[i]);
  282. ms := devt.DeviceStats;
  283. if ((devt.MinerValuesForWork.version>=CT_PROTOCOL_4) AND (CT_ACTIVATE_RANDOMHASH_V4)) then begin
  284. if ms.WorkingMillisecondsHashing>0 then hrHashing := (((ms.RoundsCount / (ms.WorkingMillisecondsHashing/1000))))
  285. else hrHashing := 0;
  286. gs := devt.GlobalDeviceStats;
  287. If ms.RoundsCount>0 then begin
  288. s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" at %0.1f H/s (%d %0.2f) - Rounds: %0.2f K Found: %d',[devt.MinerValuesForWork.payload_start.ToString,hrHashing, ms.InternalComputingRounds, ms.RoundsCount/1000, gs.RoundsCount/1000, gs.WinsCount]);
  289. If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
  290. WriteLine(CT_Line_MiningStatus+i,s);
  291. end else begin
  292. If gs.RoundsCount>0 then begin
  293. s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" **NOT MINING** - Rounds: %0.2f K Found: %d',[devt.MinerValuesForWork.payload_start.ToString,gs.RoundsCount/1000, gs.WinsCount]);
  294. If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
  295. end else begin
  296. s := FormatDateTime('hh:nn:ss',now)+' Not mining...';
  297. end;
  298. WriteLine(CT_Line_MiningStatus+i,s);
  299. end;
  300. end else begin
  301. if ms.WorkingMillisecondsHashing>0 then hrHashing := (((ms.RoundsCount DIV Int64(ms.WorkingMillisecondsHashing)))/(1000))
  302. else hrHashing := 0;
  303. gs := devt.GlobalDeviceStats;
  304. If ms.RoundsCount>0 then begin
  305. s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" at %0.2f MH/s - Rounds: %0.2f G Found: %d',[devt.MinerValuesForWork.payload_start.ToString,hrHashing, gs.RoundsCount/1000000000, gs.WinsCount]);
  306. If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
  307. WriteLine(CT_Line_MiningStatus+i,s);
  308. end else begin
  309. If gs.RoundsCount>0 then begin
  310. s := FormatDateTime('hh:nn:ss',now)+Format(' Miner:"%s" **NOT MINING** - Rounds: %0.2f G Found: %d',[devt.MinerValuesForWork.payload_start.ToString,gs.RoundsCount/1000000000, gs.WinsCount]);
  311. If (gs.Invalids>0) then s := s +' '+inttostr(gs.Invalids)+' ERRORS!';
  312. end else begin
  313. s := FormatDateTime('hh:nn:ss',now)+' Not mining...';
  314. end;
  315. WriteLine(CT_Line_MiningStatus+i,s);
  316. end;
  317. end;
  318. end;
  319. 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) );
  320. end;
  321. If KeyPressed then begin
  322. kpressed := ReadKey;
  323. If kpressed in ['c','C','q','Q'] then begin
  324. TLog.NewLog(ltinfo,ClassName,'Finalizing by keypressing '+kpressed);
  325. WriteLine(CT_Line_Logs+FDeviceThreads.Count+CT_MaxLogs,'Finalizing...');
  326. terminate;
  327. end;
  328. end;
  329. end;
  330. until (Terminated) Or (FPoolMinerThread.Terminated);
  331. end;
  332. Procedure DoVisualprocess(minerName, UserName, Password : String);
  333. Var sc : tcrtcoord;
  334. devt : TCustomMinerDeviceThread;
  335. i : Integer;
  336. Begin
  337. FPoolMinerThread := TPoolMinerThread.Create(nsarr[0].ip,nsarr[0].port,UserName,Password);
  338. try
  339. If Not AddMiners then exit;
  340. if HasOption('t','testmode') then begin
  341. i := StrToIntDef(GetOptionValue('t','testmode'),-1);
  342. if (i>=0) And (i<=32) then begin
  343. FPoolMinerThread.TestingPoWLeftBits:=i;
  344. end else begin
  345. WriteLn('Invalid bits for testing mode. value ',i,'. Valid values: 0..32 (0=No testing mode)');
  346. Terminate;
  347. exit;
  348. end;
  349. end;
  350. //
  351. cursoroff;
  352. try
  353. clrscr;
  354. FWindow32X1:=WindMinX;
  355. FWindow32X2:=WindMaxX;
  356. FWindow32Y1:=WindMinY;
  357. FWindow32Y2:=WindMaxY;
  358. WriteLine(1,'** PascalCoin miner ** Version: '+CT_MINER_VERSION);
  359. WriteLine(CT_Line_MinerValues-1,'MINER VALUES:');
  360. WriteLine(CT_Line_MiningStatus-1,'MINING STATUS:');
  361. WriteLine(CT_Line_LastFound+FDeviceThreads.Count-1,'MY VALID BLOCKS FOUND: 0');
  362. WriteLine(CT_Line_Logs+FDeviceThreads.Count-1,'LOGS:');
  363. FPoolMinerThread.MinerAddName:=minerName;
  364. WriteLine(CT_Line_MinerValues-1,'MINER VALUES: (My miner name="'+minerName+'")');
  365. FPoolMinerThread.OnConnectionStateChanged:=OnConnectionStateChanged;
  366. OnConnectionStateChanged(FPoolMinerThread);
  367. If (FDeviceThreads.Count)=1 then begin
  368. devt := TCustomMinerDeviceThread(FDeviceThreads[0]);
  369. WriteLine(2,devt.MinerDeviceName);
  370. end else begin
  371. WriteLine(2,'Mining using '+IntToStr(FDeviceThreads.Count)+' devices');
  372. end;
  373. LLog.OnInThreadNewLog:=OnInThreadNewLog;
  374. try
  375. DoWaitAndLog;
  376. finally
  377. LLog.OnInThreadNewLog:=Nil;
  378. end;
  379. finally
  380. cursoron;
  381. end;
  382. Finally
  383. FPoolMinerThread.Terminate;
  384. FPoolMinerThread.Free;
  385. end;
  386. end;
  387. Var username,password : String;
  388. begin
  389. LLog := TLog.Create(Self);
  390. Try
  391. If HasOption('l','logfile') then begin
  392. s := Trim(GetOptionValue('l','logile'));
  393. if s='' then s := 'PascalCoinMiner_'+FormatDateTime('yyyy-mm-dd_hh_nn_ss',Now)+'.log';
  394. if HasOption('logall') then LLog.SaveTypes:=CT_TLogTypes_ALL
  395. else LLog.SaveTypes:=CT_TLogTypes_DEFAULT;
  396. LLog.FileName:=ExtractFileDir(ExeName)+PathDelim+s;
  397. end;
  398. FLastLogs := TStringList.Create;
  399. FLock := TCriticalSection.Create;
  400. Try
  401. // quick check parameters
  402. ErrorMsg:=CheckOptions('hp:d:s::c:n::t:u::x::l::', 'help platform: device: server: cpu: minername: testmode: user: pwd: logfile: logall: outputlogs:');
  403. if ErrorMsg<>'' then begin
  404. //ShowException(Exception.Create(ErrorMsg));
  405. WriteLn(ErrorMsg);
  406. Exit;
  407. end;
  408. // parse parameters
  409. if HasOption('h', 'help') then begin
  410. WriteHelp;
  411. Exit;
  412. end;
  413. if HasOption('outputlogs') then begin
  414. s := Trim(GetOptionValue('outputlogs'));
  415. if (s='0') or (s='false') then FOutputAsLogs:=False
  416. else if (s='1') or (s='-1') or (s='true') then FOutputAsLogs:=True
  417. else begin
  418. Writeln('Invalid outputlogs argument "'+s+'"');
  419. Exit;
  420. end;
  421. end;
  422. if (Not HasOption('p','platform')) And (Not HasOption('d','device')) And (Not HasOption('c','cpu')) then begin
  423. Writeln('Need to specify -p X and -d Y for GPU mining or -c N for CPU mining');
  424. Writeln('Execute ',ExtractFileName(ExeName),' -h for more info');
  425. Exit;
  426. end;
  427. If HasOption('s','server') then begin
  428. s := Trim(GetOptionValue('s','server'));
  429. if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);
  430. end else s:='';
  431. if (s='') then begin
  432. WriteLn('Input server name (default is localhost:',CT_JSONRPCMinerServer_Port,'):');
  433. Readln(s);
  434. trim(s);
  435. if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);
  436. end;
  437. if (pos(':',s)=0) then begin
  438. s := trim(s) + ':'+inttostr(CT_JSONRPCMinerServer_Port);
  439. end;
  440. TNode.DecodeIpStringToNodeServerAddressArray(s,nsarr);
  441. if (length(nsarr)<>1) then begin
  442. Writeln('INVALID SERVER VALUE ',s);
  443. WriteHelp;
  444. Exit;
  445. end;
  446. If (Not HasOption('n','minername')) then begin
  447. WriteLn('Input miner name that will be added to server miner name:');
  448. Readln(s);
  449. end else s:=GetOptionValue('n','minername');
  450. Try
  451. TCrypto.InitCrypto;
  452. Except
  453. On E:Exception do begin
  454. Writeln('**************************');
  455. Writeln('Error initializing library '+SSL_C_LIB+' (Not found or not valid)');
  456. Writeln('Error message: '+E.Message);
  457. Writeln('**************************');
  458. Exit;
  459. end;
  460. end;
  461. username:='';
  462. password:='';
  463. If (HasOption('u','user')) Or (HasOption('x','pwd')) then begin
  464. username:=trim(GetOptionValue('u','user'));
  465. password:=trim(GetOptionValue('x','pwd'));
  466. if (username='') then begin
  467. WriteLn('Input Pool username (or empty for non pool connection):');
  468. Readln(username);
  469. end;
  470. end;
  471. DoVisualprocess(s,username,password);
  472. finally
  473. FreeAndNil(FLock);
  474. FreeAndNil(FLastLogs);
  475. if not terminated then
  476. Terminate;
  477. end;
  478. finally
  479. FreeAndNil(LLog);
  480. end;
  481. end;
  482. constructor TPascalMinerApp.Create(TheOwner: TComponent);
  483. begin
  484. inherited Create(TheOwner);
  485. FDeviceThreads := TList.Create;
  486. StopOnException:=True;
  487. FAppStartTime := Now;
  488. {$IF Defined(WINDOWS)}
  489. FOutputAsLogs := False;
  490. {$ELSE}
  491. FOutputAsLogs := True;
  492. {$ENDIF}
  493. end;
  494. destructor TPascalMinerApp.Destroy;
  495. begin
  496. FreeAndNil(FDeviceThreads);
  497. inherited Destroy;
  498. end;
  499. procedure TPascalMinerApp.WriteHelp;
  500. begin
  501. { add your help code here }
  502. writeln('PascalCoin Miner - Version: ',CT_MINER_VERSION);
  503. writeln('Usage: ', ExtractFileName(ExeName), ' -h -s S -p X -d Y -c N -n MYNAME');
  504. writeln(' -h for help');
  505. writeln(' -s S (S is PascalCoin server:port where default value is localhost:',CT_JSONRPCMinerServer_Port,')');
  506. writeln(' -p X (X is GPU platform)');
  507. writeln(' -d Y (Y is GPU device for platform)');
  508. writeln(' Y can be multiple devices. Example -d 0,2,3 Will use devices 0, 2 and 3');
  509. writeln(' -c N (For CPU mining, where N is CPU''s to use. Activating this disable GPU mining)');
  510. writeln(' -n MYNAME (Will add MYNAME value to miner name assigned by server)');
  511. writeln(' -l LOG_FILENAME (Will log to specified filename or will generate a new filename)');
  512. writeln(' --logall log filename will include extra information (like full JSON commands)');
  513. writeln(' ** POOL IDENTIFICATION PROTOCOL **');
  514. writeln(' (Not needed for PascalCoin core, only some third party pools)');
  515. writeln(' -u USERNAME');
  516. writeln(' -x PASSWORD');
  517. writeln(' --outputlogs=BOOLEAN (Show output style as a log)');
  518. writeln('');
  519. writeln('Basic example GPU mining over multiple devices: ');
  520. writeln(' ',ExtractFileName(ExeName),' -p 0 -d 0,1,2,3 -s -n ABC');
  521. writeln(' (Devices 0,1,2,3 at server localhost:',CT_JSONRPCMinerServer_Port,' miner name ABC)');
  522. writeln('');
  523. ShowGPUDrivers;
  524. end;
  525. var
  526. Application: TPascalMinerApp;
  527. begin
  528. Application:=TPascalMinerApp.Create(nil);
  529. Application.Title:='Pascal Miner';
  530. Application.Run;
  531. Application.Free;
  532. end.