UNetProtocol.pas 200 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138
  1. unit UNetProtocol;
  2. { Copyright (c) 2016 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. THIS LICENSE HEADER MUST NOT BE REMOVED.
  12. }
  13. {$IFDEF FPC}
  14. {$MODE Delphi}
  15. {$ENDIF}
  16. interface
  17. Uses
  18. {$IFnDEF FPC}
  19. {$IFDEF MSWINDOWS}
  20. Windows,
  21. {$ENDIF}
  22. {$ELSE}
  23. {$ENDIF}
  24. UBlockChain, Classes, SysUtils, UAccounts, UThread,
  25. UCrypto, UTCPIP, SyncObjs, UBaseTypes, UCommon, UPCOrderedLists,
  26. {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults
  27. {$ELSE}Generics.Collections,Generics.Defaults{$ENDIF},
  28. UNetProtection;
  29. {$I ./../config.inc}
  30. Const
  31. CT_MagicRequest = $0001;
  32. CT_MagicResponse = $0002;
  33. CT_MagicAutoSend = $0003;
  34. CT_NetOp_Hello = $0001; // Sends my last operationblock + servers. Receive last operationblock + servers + same operationblock number of sender
  35. CT_NetOp_Error = $0002;
  36. CT_NetOp_Message = $0003;
  37. CT_NetOp_GetBlockHeaders = $0005; // Sends from and to. Receive a number of OperationsBlock to check
  38. CT_NetOp_GetBlocks = $0010;
  39. CT_NetOp_NewBlock = $0011;
  40. CT_NetOp_NewBlock_Fast_Propagation = $0012; // New V4 protocol: Allows PIP-0015 Fast block propagation
  41. CT_NetOp_GetBlockchainOperations = $0013; // New V4 protocol: Allows PIP-0015 Fast block propagation
  42. CT_NetOp_AddOperations = $0020;
  43. CT_NetOp_GetSafeBox = $0021; // V2 Protocol: Allows to send/receive Safebox in chunk parts
  44. CT_NetOp_GetPendingOperations = $0030; // Obtain pending operations
  45. CT_NetOp_GetAccount = $0031; // Obtain account info
  46. CT_NetOp_GetPubkeyAccounts = $0032; // Obtain public key accounts
  47. CT_NetOp_Reserved_Start = $1000; // This will provide a reserved area
  48. CT_NetOp_Reserved_End = $1FFF; // End of reserved area
  49. CT_NetOp_ERRORCODE_NOT_IMPLEMENTED = $00FF;// This will be error code returned when using Reserved area and Op is not implemented
  50. CT_NetError_InvalidProtocolVersion = $0001;
  51. CT_NetError_IPBlackListed = $0002;
  52. CT_NetError_NotFound = $0003;
  53. CT_NetError_InvalidDataBufferInfo = $0010;
  54. CT_NetError_InternalServerError = $0011;
  55. CT_NetError_InvalidNewAccount = $0012;
  56. CT_NetError_SafeboxNotFound = $0020;
  57. CT_NetError_NotAvailable = $0021;
  58. CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES = 60*60*3;
  59. CT_LAST_CONNECTION_MAX_MINUTES = 60*60;
  60. CT_MAX_NODESERVERS_ON_HELLO = 10;
  61. CT_MIN_NODESERVERS_BUFFER = 50;
  62. CT_MAX_NODESERVERS_BUFFER = 300;
  63. CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS = 10000;
  64. CT_MAX_SAFEBOXCHUNK_BLOCKS = 30000;
  65. Type
  66. {
  67. Net Protocol:
  68. 3 different types: Request,Response or Auto-send
  69. Request: <Magic Net Identification (4b)><request (2b)><operation (2b)><0x0000 (2b)><request_id(4b)><protocol info(4b)><data_length(4b)><request_data (data_length bytes)>
  70. Response: <Magic Net Identification (4b)><response (2b)><operation (2b)><error_code (2b)><request_id(4b)><protocol info(4b)><data_length(4b)><response_data (data_length bytes)>
  71. Auto-send: <Magic Net Identification (4b)><autosend (2b)><operation (2b)><0x0000 (2b)><0x00000000 (4b)><protocol info(4b)><data_length(4b)><data (data_length bytes)>
  72. Min size: 4b+2b+2b+2b+4b+4b+4b = 22 bytes
  73. Max size: (depends on last 4 bytes) = 22..(2^32)-1
  74. }
  75. TNetTransferType = (ntp_unknown, ntp_request, ntp_response, ntp_autosend);
  76. TNetProtocolVersion = Record
  77. protocol_version,
  78. protocol_available : Word;
  79. end;
  80. TNetHeaderData = Record
  81. header_type : TNetTransferType;
  82. protocol : TNetProtocolVersion;
  83. operation : Word;
  84. request_id : Cardinal;
  85. buffer_data_length : Cardinal;
  86. //
  87. is_error : Boolean;
  88. error_code : Integer;
  89. error_text : String;
  90. end;
  91. TNetConnection = Class;
  92. TNodeServerAddress = Record
  93. ip : String;
  94. port : Word;
  95. last_connection : Cardinal;
  96. last_connection_by_server : Cardinal;
  97. last_connection_by_me : Cardinal;
  98. //
  99. netConnection : TNetConnection;
  100. its_myself : Boolean;
  101. last_attempt_to_connect : TDateTime;
  102. total_failed_attemps_to_connect : Integer;
  103. is_blacklisted : Boolean; // Build 1.4.4
  104. BlackListText : String;
  105. end;
  106. TNodeServerAddressArray = Array of TNodeServerAddress;
  107. PNodeServerAddress = ^TNodeServerAddress;
  108. TNetData = Class;
  109. // This will maintain a list sorted by 2 values: ip/port and netConnection in thread safe mode
  110. // Using this object, NodeServerAddress can be more high in length and also more quick to search
  111. { TOrderedServerAddressListTS }
  112. TOrderedServerAddressListTS = Class
  113. private
  114. FAllowDeleteOnClean: Boolean;
  115. FNetData : TNetData;
  116. FCritical : TPCCriticalSection;
  117. FListByIp : TList<Pointer>;
  118. FListByNetConnection : TList<Pointer>;
  119. Procedure SecuredDeleteFromListByIp(index : Integer);
  120. Function SecuredFindByIp(const ip : String; port : Word; var Index: Integer): Boolean;
  121. Function SecuredFindByNetConnection(const search : TNetConnection; var Index: Integer): Boolean;
  122. protected
  123. function DeleteNetConnection(netConnection : TNetConnection) : Boolean;
  124. public
  125. Constructor Create(ANetData : TNetData);
  126. Destructor Destroy; Override;
  127. Procedure Clear;
  128. Function Count : Integer;
  129. Function CleanBlackList(forceCleanAll : Boolean) : Integer;
  130. procedure CleanNodeServersList;
  131. Function LockList : TList<Pointer>;
  132. Procedure UnlockList;
  133. function IsBlackListed(const ip: String): Boolean;
  134. function GetNodeServerAddress(const ip : String; port:Word; CanAdd : Boolean; var nodeServerAddress : TNodeServerAddress) : Boolean;
  135. procedure SetNodeServerAddress(const nodeServerAddress : TNodeServerAddress);
  136. Procedure UpdateNetConnection(netConnection : TNetConnection);
  137. procedure GetNodeServersToConnnect(maxNodes : Integer; useArray : Boolean; var nsa : TNodeServerAddressArray);
  138. Function GetValidNodeServers(OnlyWhereIConnected : Boolean; Max : Integer): TNodeServerAddressArray;
  139. property AllowDeleteOnClean : Boolean read FAllowDeleteOnClean write FAllowDeleteOnClean;
  140. End;
  141. TNetMessage_Hello = Record
  142. last_operation : TOperationBlock;
  143. servers_address : Array of TNodeServerAddress;
  144. end;
  145. TNetRequestRegistered = Record
  146. NetClient : TNetConnection;
  147. Operation : Word;
  148. RequestId : Cardinal;
  149. SendTime : TDateTime;
  150. end;
  151. TNetStatistics = Record
  152. ActiveConnections : Integer; // All connections wiht "connected" state
  153. ClientsConnections : Integer; // All clients connected to me like a server with "connected" state
  154. ServersConnections : Integer; // All servers where I'm connected
  155. ServersConnectionsWithResponse : Integer; // All servers where I'm connected and I've received data
  156. TotalConnections : Integer;
  157. TotalClientsConnections : Integer;
  158. TotalServersConnections : Integer;
  159. BytesReceived : Int64;
  160. BytesSend : Int64;
  161. NodeServersListCount : Integer;
  162. NodeServersDeleted : Integer;
  163. end;
  164. { TNetDataNotifyEventsThread ensures that notifications of TNetData object
  165. will be in main Thread calling a Synchronized method }
  166. TNetDataNotifyEventsThread = Class(TPCThread)
  167. private
  168. FNetData: TNetData;
  169. FNotifyOnReceivedHelloMessage : Boolean;
  170. FNotifyOnStatisticsChanged : Boolean;
  171. FNotifyOnNetConnectionsUpdated : Boolean;
  172. FNotifyOnNodeServersUpdated : Boolean;
  173. FNotifyOnBlackListUpdated : Boolean;
  174. protected
  175. procedure SynchronizedNotify;
  176. procedure BCExecute; override;
  177. public
  178. Constructor Create(ANetData : TNetData);
  179. End;
  180. TNetClientsDestroyThread = Class(TPCThread)
  181. private
  182. FNetData : TNetData;
  183. FTerminatedAllConnections : Boolean;
  184. protected
  185. procedure BCExecute; override;
  186. public
  187. Constructor Create(NetData : TNetData);
  188. Procedure WaitForTerminatedAllConnections;
  189. End;
  190. TThreadCheckConnections = Class(TPCThread)
  191. private
  192. FNetData : TNetData;
  193. FLastCheckTS : TTickCount;
  194. protected
  195. procedure BCExecute; override;
  196. public
  197. Constructor Create(NetData : TNetData);
  198. End;
  199. TNetworkAdjustedTime = Class
  200. private
  201. FTimesList : TPCThreadList<Pointer>;
  202. FTimeOffset : Integer;
  203. FTotalCounter : Integer;
  204. Function IndexOfClientIp(list : TList<Pointer>; const clientIp : String) : Integer;
  205. Procedure UpdateMedian(list : TList<Pointer>);
  206. public
  207. constructor Create;
  208. destructor Destroy; override;
  209. procedure UpdateIp(const clientIp : String; clientTimestamp : Cardinal);
  210. procedure AddNewIp(const clientIp : String; clientTimestamp : Cardinal);
  211. procedure RemoveIp(const clientIp : String);
  212. function GetAdjustedTime : Cardinal;
  213. property TimeOffset : Integer read FTimeOffset;
  214. function GetMaxAllowedTimestampForNewBlock : Cardinal;
  215. end;
  216. TProcessReservedAreaMessage = procedure (netData : TNetData; senderConnection : TNetConnection; const HeaderData : TNetHeaderData; receivedData : TStream; responseData : TStream) of object;
  217. TGetNewBlockchainFromClientDownloadNewSafebox = procedure (netData : TNetData; clientConnection : TNetConnection; my_blocks_count, client_blocks_count : Integer; var download_new_safebox : Boolean) of object;
  218. TNetData = Class(TComponent)
  219. private
  220. FMaxNodeServersAddressesBuffer: Integer;
  221. FMaxServersConnected: Integer;
  222. FMinServersConnected: Integer;
  223. FNetDataNotifyEventsThread : TNetDataNotifyEventsThread;
  224. FNodePrivateKey : TECPrivateKey;
  225. FNetConnections : TPCThreadList<TNetConnection>;
  226. FNodeServersAddresses : TOrderedServerAddressListTS;
  227. FLastRequestId : Cardinal;
  228. FOnProcessReservedAreaMessage: TProcessReservedAreaMessage;
  229. FRegisteredRequests : TPCThreadList<Pointer>;
  230. FIsDiscoveringServers : Boolean;
  231. FLockGettingNewBlockChainFromClient : TPCCriticalSection;
  232. FNewBlockChainFromClientStatus : String;
  233. FOnConnectivityChanged : TNotifyManyEvent;
  234. FOnNetConnectionsUpdated: TNotifyEvent;
  235. FOnNodeServersUpdated: TNotifyEvent;
  236. FOnBlackListUpdated: TNotifyEvent;
  237. FThreadCheckConnections : TThreadCheckConnections;
  238. FOnReceivedHelloMessage: TNotifyEvent;
  239. FNetStatistics: TNetStatistics;
  240. FOnStatisticsChanged: TNotifyEvent;
  241. FMaxRemoteOperationBlock : TOperationBlock;
  242. FFixedServers : TNodeServerAddressArray;
  243. FNetClientsDestroyThread : TNetClientsDestroyThread;
  244. FNetConnectionsActive: Boolean;
  245. FMaxConnections : Integer;
  246. FNetworkAdjustedTime : TNetworkAdjustedTime;
  247. FIpInfos : TIpInfos;
  248. FMinFutureBlocksToDownloadNewSafebox: Integer;
  249. FOnGetNewBlockchainFromClientDownloadNewSafebox: TGetNewBlockchainFromClientDownloadNewSafebox;
  250. Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
  251. procedure SetMaxNodeServersAddressesBuffer(AValue: Integer);
  252. procedure SetMaxServersConnected(AValue: Integer);
  253. procedure SetMinServersConnected(AValue: Integer);
  254. procedure SetNetConnectionsActive(const Value: Boolean);
  255. procedure SetMinFutureBlocksToDownloadNewSafebox(const Value: Integer);
  256. protected
  257. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  258. Procedure DiscoverServersTerminated(Sender : TObject);
  259. procedure DoProcessReservedAreaMessage(senderConnection : TNetConnection; const headerData : TNetHeaderData; receivedData : TStream; responseData : TStream); virtual;
  260. public
  261. Class function HeaderDataToText(const HeaderData : TNetHeaderData) : String;
  262. Class function ExtractHeaderInfo(buffer : TStream; var HeaderData : TNetHeaderData; DataBuffer : TStream; var IsValidHeaderButNeedMoreData : Boolean) : Boolean;
  263. Class Function OperationToText(operation : Word) : String;
  264. // Only 1 NetData
  265. Class Function NetData : TNetData;
  266. Class Function NetDataExists : Boolean;
  267. //
  268. Constructor Create(AOwner : TComponent); override;
  269. Destructor Destroy; override;
  270. Function Bank : TPCBank;
  271. Function NewRequestId : Cardinal;
  272. Procedure RegisterRequest(Sender: TNetConnection; operation : Word; request_id : Cardinal);
  273. Function UnRegisterRequest(Sender: TNetConnection; operation : Word; request_id : Cardinal) : Boolean;
  274. Function PendingRequest(Sender : TNetConnection; var requests_data : String ) : Integer;
  275. Procedure AddServer(NodeServerAddress : TNodeServerAddress);
  276. //
  277. Procedure DiscoverFixedServersOnly(const FixedServers : TNodeServerAddressArray);
  278. //
  279. Function ConnectionsCountAll : Integer;
  280. Function ConnectionsCountServerClients : Integer;
  281. Function ConnectionsCountClients : Integer;
  282. Function GetConnection(index : Integer; var NetConnection : TNetConnection) : Boolean;
  283. Function ConnectionsCount(CountOnlyNetClients : Boolean) : Integer;
  284. Function Connection(index : Integer) : TNetConnection;
  285. Function ConnectionExistsAndActive(ObjectPointer : TObject) : Boolean;
  286. Function ConnectionExists(ObjectPointer : TObject) : Boolean;
  287. Function ConnectionLock(Sender : TObject; ObjectPointer : TObject; MaxWaitMiliseconds : Cardinal) : Boolean;
  288. Procedure ConnectionUnlock(ObjectPointer : TObject);
  289. Function FindConnectionByClientRandomValue(Sender : TNetConnection) : TNetConnection;
  290. Procedure DiscoverServers;
  291. Procedure DisconnectClients;
  292. procedure OnReadingNewSafeboxProgressNotify(sender : TObject; const mesage : String; curPos, totalCount : Int64);
  293. Procedure GetNewBlockChainFromClient(Connection : TNetConnection; const why : String);
  294. Property NodeServersAddresses : TOrderedServerAddressListTS read FNodeServersAddresses;
  295. Property NetConnections : TPCThreadList<TNetConnection> read FNetConnections;
  296. Property NetStatistics : TNetStatistics read FNetStatistics;
  297. Property IsDiscoveringServers : Boolean read FIsDiscoveringServers;
  298. function IsGettingNewBlockChainFromClient(var status : String) : Boolean;
  299. Property MaxRemoteOperationBlock : TOperationBlock read FMaxRemoteOperationBlock;
  300. Property NodePrivateKey : TECPrivateKey read FNodePrivateKey;
  301. property OnConnectivityChanged : TNotifyManyEvent read FOnConnectivityChanged;
  302. Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
  303. Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
  304. Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
  305. Property OnReceivedHelloMessage : TNotifyEvent read FOnReceivedHelloMessage write FOnReceivedHelloMessage;
  306. Property OnStatisticsChanged : TNotifyEvent read FOnStatisticsChanged write FOnStatisticsChanged;
  307. property OnGetNewBlockchainFromClientDownloadNewSafebox : TGetNewBlockchainFromClientDownloadNewSafebox read FOnGetNewBlockchainFromClientDownloadNewSafebox write FOnGetNewBlockchainFromClientDownloadNewSafebox;
  308. procedure NotifyConnectivityChanged;
  309. Procedure NotifyNetConnectionUpdated;
  310. Procedure NotifyNodeServersUpdated;
  311. Procedure NotifyBlackListUpdated;
  312. Procedure NotifyReceivedHelloMessage;
  313. Procedure NotifyStatisticsChanged;
  314. Property NetConnectionsActive : Boolean read FNetConnectionsActive write SetNetConnectionsActive;
  315. Property NetworkAdjustedTime : TNetworkAdjustedTime read FNetworkAdjustedTime;
  316. Property MaxNodeServersAddressesBuffer : Integer read FMaxNodeServersAddressesBuffer write SetMaxNodeServersAddressesBuffer;
  317. Property OnProcessReservedAreaMessage : TProcessReservedAreaMessage read FOnProcessReservedAreaMessage write FOnProcessReservedAreaMessage;
  318. Property MinServersConnected : Integer read FMinServersConnected write SetMinServersConnected;
  319. Property MaxServersConnected : Integer read FMaxServersConnected write SetMaxServersConnected;
  320. Property IpInfos : TIpInfos read FIpInfos;
  321. Property MinFutureBlocksToDownloadNewSafebox : Integer read FMinFutureBlocksToDownloadNewSafebox write SetMinFutureBlocksToDownloadNewSafebox;
  322. End;
  323. { TNetConnection }
  324. TNetConnection = Class(TComponent)
  325. private
  326. FIsConnecting: Boolean;
  327. FTcpIpClient : TNetTcpIpClient;
  328. FRemoteOperationBlock : TOperationBlock;
  329. FRemoteAccumulatedWork : UInt64;
  330. FLastHelloTS : TTickCount;
  331. FLastDataReceivedTS : TTickCount;
  332. FLastDataSendedTS : TTickCount;
  333. FClientBufferRead : TStream;
  334. FNetLock : TPCCriticalSection;
  335. FIsWaitingForResponse : Boolean;
  336. FTimestampDiff : Integer;
  337. FIsMyselfServer : Boolean;
  338. FClientPublicKey : TAccountKey;
  339. FCreatedTime: TDateTime;
  340. FClientAppVersion: String;
  341. FDoFinalizeConnection : Boolean;
  342. FNetProtocolVersion: TNetProtocolVersion;
  343. FAlertedForNewProtocolAvailable : Boolean;
  344. FHasReceivedData : Boolean;
  345. FIsDownloadingBlocks : Boolean;
  346. FRandomWaitSecondsSendHello : Cardinal;
  347. FBufferLock : TPCCriticalSection;
  348. FBufferReceivedOperationsHash : TOrderedRawList;
  349. FBufferToSendOperations : TOperationsHashTree;
  350. FClientTimestampIp : String;
  351. function GetConnected: Boolean;
  352. procedure SetConnected(const Value: Boolean);
  353. procedure TcpClient_OnConnect(Sender: TObject);
  354. procedure TcpClient_OnDisconnect(Sender: TObject);
  355. procedure DoProcessBuffer;
  356. Procedure DoProcess_Hello(HeaderData : TNetHeaderData; DataBuffer: TStream);
  357. Procedure DoProcess_Message(HeaderData : TNetHeaderData; DataBuffer: TStream);
  358. Procedure DoProcess_GetBlocks_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  359. Procedure DoProcess_GetBlocks_Response(HeaderData : TNetHeaderData; DataBuffer: TStream);
  360. Procedure DoProcess_GetBlockchainOperations_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  361. Procedure DoProcess_GetOperationsBlock_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  362. Procedure DoProcess_NewBlock(HeaderData : TNetHeaderData; DataBuffer: TStream);
  363. Procedure DoProcess_AddOperations(HeaderData : TNetHeaderData; DataBuffer: TStream);
  364. Procedure DoProcess_GetSafeBox_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  365. Procedure DoProcess_GetPendingOperations_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  366. Procedure DoProcess_GetAccount_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  367. Procedure DoProcess_GetPubkeyAccounts_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
  368. Procedure DoProcess_GetPendingOperations;
  369. Procedure SetClient(Const Value : TNetTcpIpClient);
  370. Function ReadTcpClientBuffer(MaxWaitMiliseconds : Cardinal; var HeaderData : TNetHeaderData; BufferData : TStream) : Boolean;
  371. Procedure DisconnectInvalidClient(ItsMyself : Boolean; Const why : String);
  372. function GetClient: TNetTcpIpClient;
  373. protected
  374. Procedure Send(NetTranferType : TNetTransferType; operation, errorcode : Word; request_id : Integer; DataBuffer : TStream);
  375. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  376. Procedure SendError(NetTranferType : TNetTransferType; operation, request_id : Integer; error_code : Integer; const error_text : String);
  377. public
  378. Constructor Create(AOwner : TComponent); override;
  379. Destructor Destroy; override;
  380. Procedure DoSend(ANetTranferType: TNetTransferType; AOperation, AErrorcode: Word; ARequest_id: Integer; ADataBuffer: TStream);
  381. Function DoSendAndWaitForResponse(operation: Word; RequestId: Integer; SendDataBuffer, ReceiveDataBuffer: TStream; MaxWaitTime : Cardinal; var HeaderData : TNetHeaderData) : Boolean;
  382. Function ConnectTo(ServerIP: String; ServerPort:Word) : Boolean;
  383. Property Connected : Boolean read GetConnected write SetConnected;
  384. Property IsConnecting : Boolean read FIsConnecting;
  385. Function Send_Hello(NetTranferType : TNetTransferType; request_id : Integer) : Boolean;
  386. Function Send_NewBlockFound(Const NewBlock : TPCOperationsComp) : Boolean;
  387. Function Send_GetBlocks(StartAddress, quantity : Cardinal; var request_id : Cardinal) : Boolean;
  388. Function Send_AddOperations(Operations : TOperationsHashTree) : Boolean;
  389. Function Send_Message(Const TheMessage : String) : Boolean;
  390. Function AddOperationsToBufferForSend(Operations : TOperationsHashTree) : Integer;
  391. Property Client : TNetTcpIpClient read GetClient;
  392. Function ClientRemoteAddr : String;
  393. property TimestampDiff : Integer read FTimestampDiff;
  394. property RemoteOperationBlock : TOperationBlock read FRemoteOperationBlock;
  395. //
  396. Property NetProtocolVersion : TNetProtocolVersion read FNetProtocolVersion;
  397. //
  398. Property IsMyselfServer : Boolean read FIsMyselfServer;
  399. Property CreatedTime : TDateTime read FCreatedTime;
  400. Property ClientAppVersion : String read FClientAppVersion write FClientAppVersion;
  401. Procedure FinalizeConnection;
  402. End;
  403. TNetClient = Class;
  404. TNetClientThread = Class(TPCThread)
  405. private
  406. FNetClient : TNetClient;
  407. protected
  408. procedure BCExecute; override;
  409. public
  410. Constructor Create(NetClient : TNetClient; AOnTerminateThread : TNotifyEvent);
  411. End;
  412. TNetClient = Class(TNetConnection)
  413. private
  414. FNetClientThread : TNetClientThread;
  415. Procedure OnNetClientThreadTerminated(Sender : TObject);
  416. public
  417. Constructor Create(AOwner : TComponent); override;
  418. Destructor Destroy; override;
  419. End;
  420. TNetServerClient = Class(TNetConnection);
  421. { TNetServer }
  422. TNetServer = Class(TNetTcpIpServer)
  423. private
  424. protected
  425. Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); override;
  426. procedure SetActive(const Value: Boolean); override;
  427. procedure SetMaxConnections(AValue: Integer); override;
  428. public
  429. Constructor Create; override;
  430. End;
  431. TThreadDiscoverConnection = Class(TPCThread)
  432. FNodeServerAddress : TNodeServerAddress;
  433. protected
  434. procedure BCExecute; override;
  435. public
  436. Constructor Create(NodeServerAddress: TNodeServerAddress; NotifyOnTerminate : TNotifyEvent);
  437. End;
  438. { TThreadGetNewBlockChainFromClient }
  439. TThreadGetNewBlockChainFromClient = Class(TPCThread)
  440. protected
  441. procedure BCExecute; override;
  442. public
  443. Constructor Create;
  444. End;
  445. Const
  446. CT_TNodeServerAddress_NUL : TNodeServerAddress = (ip:'';port:0;last_connection:0;last_connection_by_server:0; last_connection_by_me:0; netConnection:nil;its_myself:false;last_attempt_to_connect:0;total_failed_attemps_to_connect:0;is_blacklisted:false;BlackListText:'');
  447. CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;ServersConnectionsWithResponse:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0;NodeServersListCount:0;NodeServersDeleted:0);
  448. implementation
  449. uses
  450. UConst, ULog, UNode, UTime, UPCEncryption, UChunk,
  451. UPCOperationsBlockValidator, UPCOperationsSignatureValidator;
  452. Const
  453. CT_NetTransferType : Array[TNetTransferType] of String = ('Unknown','Request','Response','Autosend');
  454. CT_NetHeaderData : TNetHeaderData = (header_type:ntp_unknown;protocol:(protocol_version:0;protocol_available:0);operation:0;request_id:0;buffer_data_length:0;is_error:false;error_code:0;error_text:'');
  455. { TOrderedServerAddressListTS }
  456. function TOrderedServerAddressListTS.CleanBlackList(forceCleanAll : Boolean) : Integer;
  457. Var P : PNodeServerAddress;
  458. i : Integer;
  459. begin
  460. CleanNodeServersList;
  461. // This procedure cleans old blacklisted IPs
  462. Result := 0;
  463. FCritical.Acquire;
  464. Try
  465. for i := FListByIp.Count - 1 downto 0 do begin
  466. P := FListByIp[i];
  467. // Is an old blacklisted IP? (More than 1 hour)
  468. If (P^.is_blacklisted) AND
  469. ((forceCleanAll) OR ((P^.last_connection+(CT_LAST_CONNECTION_MAX_MINUTES)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now))))) then begin
  470. if (AllowDeleteOnClean) then begin
  471. SecuredDeleteFromListByIp(i);
  472. end else begin
  473. P^.is_blacklisted:=False;
  474. end;
  475. inc(Result);
  476. end;
  477. end;
  478. Finally
  479. FCritical.Release;
  480. End;
  481. if (Result>0) then FNetData.NotifyBlackListUpdated;
  482. end;
  483. procedure TOrderedServerAddressListTS.CleanNodeServersList;
  484. var i : Integer;
  485. nsa : TNodeServerAddress;
  486. currunixtimestamp : Cardinal;
  487. begin
  488. If Not (FAllowDeleteOnClean) then Exit;
  489. currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  490. FCritical.Acquire;
  491. Try
  492. i := FListByIp.Count-1;
  493. while (i>=0) do begin
  494. nsa := PNodeServerAddress( FListByIp[i] )^;
  495. If (Not (nsa.is_blacklisted)) // Not blacklisted
  496. And ((nsa.netConnection = Nil) // No connection
  497. OR // Connected but a lot of time without data...
  498. ((Assigned(nsa.netConnection)) AND ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < currunixtimestamp )))
  499. And (
  500. (nsa.total_failed_attemps_to_connect>0)
  501. OR
  502. (
  503. // I've not connected CT_LAST_CONNECTION_MAX_MINUTES minutes before
  504. ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < (currunixtimestamp))
  505. And // Others have connected CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES minutes before
  506. ((nsa.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) < (currunixtimestamp))
  507. And
  508. ((nsa.last_connection>0) Or (nsa.last_connection_by_server>0))
  509. ))
  510. And (
  511. (nsa.last_connection_by_me=0)
  512. Or
  513. ((nsa.last_connection_by_me + 86400) < (currunixtimestamp)) // Not connected in 24 hours
  514. )
  515. then begin
  516. TLog.NewLog(ltdebug,ClassName,Format('Delete node server address: %s : %d last_connection:%d last_connection_by_server:%d total_failed_attemps:%d last_attempt_to_connect:%s ',
  517. [nsa.ip,nsa.port,nsa.last_connection,nsa.last_connection_by_server,nsa.total_failed_attemps_to_connect,FormatDateTime('dd/mm/yyyy hh:nn:ss',nsa.last_attempt_to_connect)]));
  518. SecuredDeleteFromListByIp(i);
  519. end;
  520. dec(i);
  521. end;
  522. finally
  523. FCritical.Release;
  524. end;
  525. end;
  526. procedure TOrderedServerAddressListTS.Clear;
  527. Var P : PNodeServerAddress;
  528. i : Integer;
  529. begin
  530. FCritical.Acquire;
  531. Try
  532. for i := 0 to FListByIp.Count - 1 do begin
  533. P := FListByIp[i];
  534. Dispose(P);
  535. end;
  536. inc(FNetData.FNetStatistics.NodeServersDeleted,FListByIp.count);
  537. FListByIp.Clear;
  538. FListByNetConnection.Clear;
  539. FNetData.FNetStatistics.NodeServersListCount := 0;
  540. finally
  541. FCritical.Release;
  542. end;
  543. end;
  544. function TOrderedServerAddressListTS.Count: Integer;
  545. begin
  546. FCritical.Acquire;
  547. try
  548. Result := FListByIp.Count;
  549. finally
  550. FCritical.Release;
  551. end;
  552. end;
  553. constructor TOrderedServerAddressListTS.Create(ANetData : TNetData);
  554. begin
  555. FNetData := ANetData;
  556. FCritical := TPCCriticalSection.Create(Classname);
  557. FListByIp := TList<Pointer>.Create;
  558. FListByNetConnection := TList<Pointer>.Create;
  559. FAllowDeleteOnClean := True;
  560. end;
  561. function TOrderedServerAddressListTS.DeleteNetConnection(netConnection: TNetConnection) : Boolean;
  562. Var i : Integer;
  563. begin
  564. FCritical.Acquire;
  565. Try
  566. If SecuredFindByNetConnection(netConnection,i) then begin
  567. PNodeServerAddress( FListByNetConnection[i] )^.netConnection := Nil;
  568. FListByNetConnection.Delete(i);
  569. Result := True;
  570. end else Result := False;
  571. Finally
  572. FCritical.Release;
  573. end;
  574. end;
  575. destructor TOrderedServerAddressListTS.Destroy;
  576. begin
  577. Clear;
  578. FreeAndNil(FCritical);
  579. FreeAndNil(FListByIp);
  580. FreeAndNil(FListByNetConnection);
  581. inherited Destroy;
  582. end;
  583. function TOrderedServerAddressListTS.GetNodeServerAddress(const ip: String; port: Word; CanAdd: Boolean; var nodeServerAddress: TNodeServerAddress): Boolean;
  584. Var i : Integer;
  585. P : PNodeServerAddress;
  586. begin
  587. FCritical.Acquire;
  588. Try
  589. if SecuredFindByIp(ip,port,i) then begin
  590. P := FListByIp.Items[i];
  591. nodeServerAddress := P^;
  592. Result := True;
  593. end else if CanAdd then begin
  594. New(P);
  595. P^ := CT_TNodeServerAddress_NUL;
  596. P^.ip := ip;
  597. P^.port := port;
  598. FListByIp.Insert(i,P);
  599. nodeServerAddress := P^;
  600. Result := True
  601. end else begin
  602. nodeServerAddress := CT_TNodeServerAddress_NUL;
  603. Result := False;
  604. end;
  605. Finally
  606. FCritical.Release;
  607. End;
  608. end;
  609. procedure TOrderedServerAddressListTS.GetNodeServersToConnnect(maxNodes: Integer; useArray : Boolean; var nsa: TNodeServerAddressArray);
  610. Procedure sw(l : TList<Pointer>);
  611. Var i,j,x,y : Integer;
  612. begin
  613. if l.Count<=1 then exit;
  614. j := Random(l.Count)*3;
  615. for i := 0 to j do begin
  616. x := Random(l.Count);
  617. y := Random(l.Count);
  618. if x<>y then l.Exchange(x,y);
  619. end;
  620. end;
  621. Function IsValid(Const ns : TNodeServerAddress) : Boolean;
  622. Begin
  623. Result := (Not Assigned(ns.netConnection)) AND (Not IsBlackListed(ns.ip)) AND (Not ns.its_myself) And
  624. ((ns.last_attempt_to_connect=0) Or ((ns.last_attempt_to_connect+EncodeTime(0,3,0,0)<now))) And
  625. ((ns.total_failed_attemps_to_connect<3) Or (ns.last_attempt_to_connect+EncodeTime(0,10,0,0)<now));
  626. End;
  627. Var i,j, iStart : Integer;
  628. P : PNodeServerAddress;
  629. l : TList<Pointer>;
  630. ns : TNodeServerAddress;
  631. begin
  632. FCritical.Acquire;
  633. Try
  634. l := TList<Pointer>.Create;
  635. Try
  636. if useArray then begin
  637. for i := 0 to High(nsa) do begin
  638. If GetNodeServerAddress(nsa[i].ip,nsa[i].port,true,ns) then begin
  639. if IsValid(ns) then begin
  640. new(P);
  641. P^ := ns;
  642. l.Add(P);
  643. end;
  644. end;
  645. end;
  646. SetLength(nsa,0);
  647. end else begin
  648. SetLength(nsa,0);
  649. if FListByIp.Count>0 then begin
  650. iStart := Random(FListByIp.Count);
  651. i := iStart;
  652. j := FListByIp.Count;
  653. while (l.Count<maxNodes) And (i<j) do begin
  654. P := FListByIp[i];
  655. If (Not Assigned(P.netConnection)) AND (Not IsBlackListed(P^.ip)) AND (Not P^.its_myself) And
  656. ((P^.last_attempt_to_connect=0) Or ((P^.last_attempt_to_connect+EncodeTime(0,3,0,0)<now))) And
  657. ((P^.total_failed_attemps_to_connect<3) Or (P^.last_attempt_to_connect+EncodeTime(0,10,0,0)<now)) then begin
  658. l.Add(P);
  659. end;
  660. // Second round
  661. inc(i);
  662. if (i>=j) and (iStart>0) then begin
  663. j := iStart;
  664. iStart := 0;
  665. i := 0;
  666. end;
  667. end;
  668. end;
  669. end;
  670. if (l.Count>0) then begin
  671. sw(l);
  672. if l.Count<maxNodes then setLength(nsa,l.Count)
  673. else setLength(nsa,maxNodes);
  674. for i := 0 to high(nsa) do begin
  675. nsa[i] := PNodeServerAddress(l[i])^;
  676. end;
  677. end;
  678. Finally
  679. if useArray then begin
  680. for i := 0 to l.Count - 1 do begin
  681. P := l[i];
  682. Dispose(P);
  683. end;
  684. end;
  685. l.Free;
  686. End;
  687. Finally
  688. FCritical.Release;
  689. end;
  690. end;
  691. function TOrderedServerAddressListTS.GetValidNodeServers(OnlyWhereIConnected: Boolean; Max: Integer): TNodeServerAddressArray;
  692. var i,j,iStart : Integer;
  693. nsa : TNodeServerAddress;
  694. currunixtimestamp : Cardinal;
  695. begin
  696. SetLength(Result,0);
  697. currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  698. CleanNodeServersList;
  699. // Save other node servers
  700. FCritical.Acquire;
  701. try
  702. If Max>0 then iStart := Random(FListByIp.Count)
  703. else iStart := 0;
  704. i := iStart;
  705. j := FListByIp.Count;
  706. while ((length(Result)<Max) Or (Max<=0)) And (i<j) do begin
  707. nsa := PNodeServerAddress( FListByIp[i] )^;
  708. if (Not IsBlackListed(nsa.ip))
  709. And
  710. ( // I've connected 1h before
  711. ((nsa.last_connection>0) And ((Assigned(nsa.netConnection)) Or ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) > (currunixtimestamp))))
  712. Or // Others have connected 3h before
  713. ((nsa.last_connection_by_server>0) And ((nsa.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) > (currunixtimestamp)))
  714. Or // Peer cache
  715. ((nsa.last_connection=0) And (nsa.last_connection_by_server=0))
  716. )
  717. And
  718. ( // Never tried to connect or successfully connected
  719. (nsa.total_failed_attemps_to_connect=0)
  720. )
  721. And
  722. ( (Not nsa.its_myself) Or (nsa.port=CT_NetServer_Port) )
  723. And
  724. (
  725. (Not OnlyWhereIConnected)
  726. Or
  727. (nsa.last_connection>0)
  728. )
  729. then begin
  730. SetLength(Result,length(Result)+1);
  731. Result[high(Result)] := nsa;
  732. end;
  733. // Second round
  734. inc(i);
  735. if (i>=j) and (iStart>0) then begin
  736. j := iStart;
  737. iStart := 0;
  738. i := 0;
  739. end;
  740. end;
  741. finally
  742. FCritical.Release;
  743. end;
  744. end;
  745. function TOrderedServerAddressListTS.IsBlackListed(const ip: String): Boolean;
  746. Var i : Integer;
  747. P : PNodeServerAddress;
  748. begin
  749. Result := false;
  750. FCritical.Acquire;
  751. Try
  752. SecuredFindByIp(ip,0,i);
  753. // Position will be the first by IP:
  754. while (i<FListByIp.Count) And (Not Result) do begin
  755. P := PNodeServerAddress(FListByIp[i]);
  756. if Not SameStr(P^.ip,ip) then exit;
  757. if P^.is_blacklisted then begin
  758. Result := Not P^.its_myself;
  759. end;
  760. inc(i);
  761. end;
  762. Finally
  763. FCritical.Release;
  764. End;
  765. end;
  766. function TOrderedServerAddressListTS.LockList: TList<Pointer>;
  767. begin
  768. FCritical.Acquire;
  769. Result := FListByIp;
  770. end;
  771. procedure TOrderedServerAddressListTS.SecuredDeleteFromListByIp(index: Integer);
  772. Var P : PNodeServerAddress;
  773. i2 : Integer;
  774. begin
  775. P := FListByIp.Items[index];
  776. if (Assigned(P^.netConnection)) then begin
  777. If SecuredFindByNetConnection(P^.netConnection,i2) then begin
  778. FListByNetConnection.Delete(i2);
  779. end else TLog.NewLog(ltError,ClassName,'DEV ERROR 20180201-1 NetConnection not found!');
  780. end;
  781. Dispose(P);
  782. FListByIp.Delete(index);
  783. dec(FNetData.FNetStatistics.NodeServersListCount);
  784. inc(FNetData.FNetStatistics.NodeServersDeleted);
  785. end;
  786. function TOrderedServerAddressListTS.SecuredFindByIp(const ip: String; port: Word; var Index: Integer): Boolean;
  787. var L, H, I, C: Integer;
  788. PN : PNodeServerAddress;
  789. begin
  790. Result := False;
  791. L := 0;
  792. H := FListByIp.Count - 1;
  793. while L <= H do
  794. begin
  795. I := (L + H) shr 1;
  796. PN := FListByIp.Items[I];
  797. C := CompareStr( PN.ip, ip );
  798. If (C=0) then begin
  799. C := PN.port-port;
  800. end;
  801. if C < 0 then L := I + 1 else
  802. begin
  803. H := I - 1;
  804. if C = 0 then
  805. begin
  806. Result := True;
  807. L := I;
  808. end;
  809. end;
  810. end;
  811. Index := L;
  812. end;
  813. function TOrderedServerAddressListTS.SecuredFindByNetConnection(const search: TNetConnection; var Index: Integer): Boolean;
  814. var L, H, I: Integer;
  815. PN : PNodeServerAddress;
  816. C : PtrInt;
  817. begin
  818. Result := False;
  819. L := 0;
  820. H := FListByNetConnection.Count - 1;
  821. while L <= H do
  822. begin
  823. I := (L + H) shr 1;
  824. PN := FListByNetConnection.Items[I];
  825. C := PtrInt(PN.netConnection) - PtrInt(search);
  826. if C < 0 then L := I + 1 else
  827. begin
  828. H := I - 1;
  829. if C = 0 then
  830. begin
  831. Result := True;
  832. L := I;
  833. end;
  834. end;
  835. end;
  836. Index := L;
  837. end;
  838. procedure TOrderedServerAddressListTS.SetNodeServerAddress(
  839. const nodeServerAddress: TNodeServerAddress);
  840. Var i : Integer;
  841. P : PNodeServerAddress;
  842. begin
  843. FCritical.Acquire;
  844. Try
  845. if SecuredFindByIp(nodeServerAddress.ip,nodeServerAddress.port,i) then begin
  846. P := FListByIp.Items[i];
  847. if (P^.netConnection<>nodeServerAddress.netConnection) then begin
  848. // Updated netConnection
  849. if Assigned(P^.netConnection) then begin
  850. // Delete old value
  851. if Not DeleteNetConnection(P^.netConnection) then TLog.NewLog(lterror,Classname,'DEV ERROR 20180205-1');
  852. end;
  853. end;
  854. P^ := nodeServerAddress;
  855. end else begin
  856. New(P);
  857. P^ := nodeServerAddress;
  858. FListByIp.Insert(i,P);
  859. Inc(FNetData.FNetStatistics.NodeServersListCount);
  860. TLog.NewLog(ltdebug,Classname,'Adding new server: '+NodeServerAddress.ip+':'+Inttostr(NodeServerAddress.port));
  861. end;
  862. if Assigned(nodeServerAddress.netConnection) then begin
  863. If Not SecuredFindByNetConnection(nodeServerAddress.netConnection,i) then begin
  864. FListByNetConnection.Insert(i,P);
  865. end;
  866. end;
  867. Finally
  868. FCritical.Release;
  869. end;
  870. end;
  871. procedure TOrderedServerAddressListTS.UnlockList;
  872. begin
  873. FCritical.Release;
  874. end;
  875. procedure TOrderedServerAddressListTS.UpdateNetConnection(netConnection: TNetConnection);
  876. Var i : Integer;
  877. begin
  878. FCritical.Acquire;
  879. Try
  880. If SecuredFindByNetConnection(netConnection,i) then begin
  881. PNodeServerAddress(FListByNetConnection[i])^.last_connection := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
  882. PNodeServerAddress(FListByNetConnection[i])^.total_failed_attemps_to_connect := 0;
  883. end;
  884. Finally
  885. FCritical.Release;
  886. End;
  887. end;
  888. { TNetData }
  889. Var _NetData : TNetData = nil;
  890. Type PNetRequestRegistered = ^TNetRequestRegistered;
  891. procedure TNetData.AddServer(NodeServerAddress: TNodeServerAddress);
  892. Var P : PNodeServerAddress;
  893. i : Integer;
  894. currunixtimestamp : Cardinal;
  895. nsa : TNodeServerAddress;
  896. begin
  897. if (trim(NodeServerAddress.ip)='')
  898. or (SameText(NodeServerAddress.ip,'localhost'))
  899. or (SameText('127.',NodeServerAddress.ip.Substring(0,4))) then Exit;
  900. if (NodeServerAddress.port<=0) then NodeServerAddress.port := CT_NetServer_Port
  901. else if (NodeServerAddress.port<>CT_NetServer_Port) then exit;
  902. // Protection against fill with invalid nodes
  903. currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  904. // If not connected CT_LAST_CONNECTION_MAX_MINUTES minutes ago...
  905. If (NodeServerAddress.last_connection_by_server=0) AND (NodeServerAddress.last_connection>0) AND ((NodeServerAddress.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < (currunixtimestamp)) then exit;
  906. // If not connected CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES minutes ago...
  907. If (NodeServerAddress.last_connection=0) AND (NodeServerAddress.last_connection_by_server>0) AND ((NodeServerAddress.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) < (currunixtimestamp)) then exit;
  908. If (NodeServerAddress.last_connection_by_server>currunixtimestamp) OR (NodeServerAddress.last_connection>currunixtimestamp) then exit;
  909. FNodeServersAddresses.GetNodeServerAddress(NodeServerAddress.ip,NodeServerAddress.port,True,nsa);
  910. if NodeServerAddress.last_connection>nsa.last_connection then nsa.last_connection := NodeServerAddress.last_connection;
  911. if NodeServerAddress.last_connection_by_server>nsa.last_connection_by_server then nsa.last_connection_by_server := NodeServerAddress.last_connection_by_server;
  912. if NodeServerAddress.last_attempt_to_connect>nsa.last_attempt_to_connect then nsa.last_attempt_to_connect := NodeServerAddress.last_attempt_to_connect;
  913. FNodeServersAddresses.SetNodeServerAddress(nsa);
  914. NotifyNodeServersUpdated;
  915. end;
  916. function TNetData.Bank: TPCBank;
  917. begin
  918. Result := TNode.Node.Bank;
  919. end;
  920. function TNetData.Connection(index: Integer): TNetConnection;
  921. Var l : TList<TNetConnection>;
  922. begin
  923. l := FNetConnections.LockList;
  924. try
  925. if (index>=0) And (index<l.Count) then Result := ( l[index] )
  926. else Result := Nil;
  927. finally
  928. FNetConnections.UnlockList;
  929. end;
  930. end;
  931. function TNetData.ConnectionExists(ObjectPointer: TObject): Boolean;
  932. var i : Integer;
  933. l : TList<TNetConnection>;
  934. begin
  935. Result := false;
  936. l := FNetConnections.LockList;
  937. try
  938. for i := 0 to l.Count - 1 do begin
  939. if TObject(l[i])=ObjectPointer then begin
  940. Result := true;
  941. exit;
  942. end;
  943. end;
  944. finally
  945. FNetConnections.UnlockList;
  946. end;
  947. end;
  948. function TNetData.ConnectionExistsAndActive(ObjectPointer: TObject): Boolean;
  949. var i : Integer;
  950. l : TList<TNetConnection>;
  951. begin
  952. Result := false;
  953. l := FNetConnections.LockList;
  954. try
  955. for i := 0 to l.Count - 1 do begin
  956. if TObject(l[i])=ObjectPointer then begin
  957. Result := (TNetConnection(ObjectPointer).Connected);
  958. exit;
  959. end;
  960. end;
  961. finally
  962. FNetConnections.UnlockList;
  963. end;
  964. end;
  965. function TNetData.ConnectionLock(Sender : TObject; ObjectPointer: TObject; MaxWaitMiliseconds : Cardinal) : Boolean;
  966. var i : Integer;
  967. l : TList<TNetConnection>;
  968. nc : TNetConnection;
  969. tc : TTickCount;
  970. begin
  971. Result := False; nc := Nil;
  972. tc := TPlatform.GetTickCount;
  973. if MaxWaitMiliseconds>60000 then MaxWaitMiliseconds := 60000;
  974. l := FNetConnections.LockList;
  975. try
  976. for i := 0 to l.Count - 1 do begin
  977. if (TObject(l[i])=ObjectPointer) then begin
  978. if (Not (TNetConnection(l[i]).FDoFinalizeConnection)) And (TNetConnection(l[i]).Connected) then begin
  979. nc := TNetConnection(l[i]);
  980. Break;
  981. end else Exit;
  982. end;
  983. end;
  984. finally
  985. FNetConnections.UnlockList;
  986. end;
  987. if Assigned(nc) then begin
  988. repeat
  989. if (nc.Connected) and Assigned(nc.FNetLock) then begin
  990. If nc.FNetLock.TryEnter then Result := True
  991. else Sleep(1);
  992. end else Exit;
  993. until (Result) Or (TPlatform.GetElapsedMilliseconds(tc)>MaxWaitMiliseconds);
  994. end;
  995. end;
  996. function TNetData.ConnectionsCount(CountOnlyNetClients : Boolean): Integer;
  997. var i : Integer;
  998. l : TList<TNetConnection>;
  999. begin
  1000. l := FNetConnections.LockList;
  1001. try
  1002. if CountOnlyNetClients then begin
  1003. Result := 0;
  1004. for i := 0 to l.Count - 1 do begin
  1005. if TObject(l[i]) is TNetClient then inc(Result);
  1006. end;
  1007. end else Result := l.Count;
  1008. finally
  1009. FNetConnections.UnlockList;
  1010. end;
  1011. end;
  1012. function TNetData.ConnectionsCountAll: Integer;
  1013. Var l : TList<TNetConnection>;
  1014. begin
  1015. l := FNetConnections.LockList;
  1016. try
  1017. Result := l.Count;
  1018. finally
  1019. FNetConnections.UnlockList;
  1020. end;
  1021. end;
  1022. function TNetData.ConnectionsCountClients: Integer;
  1023. Var l : TList<TNetConnection>; i : Integer;
  1024. begin
  1025. Result := 0;
  1026. l := FNetConnections.LockList;
  1027. try
  1028. for i := 0 to l.Count - 1 do begin
  1029. if TObject(l[i]) is TNetClient then inc(Result);
  1030. end;
  1031. finally
  1032. FNetConnections.UnlockList;
  1033. end;
  1034. end;
  1035. function TNetData.ConnectionsCountServerClients: Integer;
  1036. Var l : TList<TNetConnection>; i : Integer;
  1037. begin
  1038. Result := 0;
  1039. l := FNetConnections.LockList;
  1040. try
  1041. for i := 0 to l.Count - 1 do begin
  1042. if TObject(l[i]) is TNetServerClient then inc(Result);
  1043. end;
  1044. finally
  1045. FNetConnections.UnlockList;
  1046. end;
  1047. end;
  1048. procedure TNetData.ConnectionUnlock(ObjectPointer: TObject);
  1049. var i : Integer;
  1050. l : TList<TNetConnection>;
  1051. nc : TNetConnection;
  1052. begin
  1053. l := FNetConnections.LockList;
  1054. try
  1055. for i := 0 to l.Count - 1 do begin
  1056. if TObject(l[i])=ObjectPointer then begin
  1057. TNetConnection(l[i]).FNetLock.Release;
  1058. exit;
  1059. end;
  1060. end;
  1061. finally
  1062. FNetConnections.UnlockList;
  1063. end;
  1064. Try
  1065. nc := (ObjectPointer as TNetConnection);
  1066. if (not assigned(nc.FNetLock)) then raise Exception.Create('NetLock object not assigned');
  1067. nc.FNetLock.Release;
  1068. Except
  1069. on E:Exception do begin
  1070. TLog.NewLog(ltError,Classname,'Error unlocking Object '+IntToHex(PtrInt(ObjectPointer),8)+' Errors ('+E.ClassName+'): '+E.Message);
  1071. end;
  1072. End;
  1073. TLog.NewLog(ltDebug,ClassName,'Unlocked a NetLock object out of connections list');
  1074. end;
  1075. constructor TNetData.Create(AOwner: TComponent);
  1076. begin
  1077. inherited Create(AOwner);
  1078. FOnProcessReservedAreaMessage:=Nil;
  1079. TLog.NewLog(ltInfo,ClassName,'TNetData.Create');
  1080. FMaxConnections := CT_MaxClientsConnected;
  1081. FNetConnectionsActive := true;
  1082. SetLength(FFixedServers,0);
  1083. FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
  1084. FNetStatistics := CT_TNetStatistics_NUL;
  1085. FOnStatisticsChanged := Nil;
  1086. FOnNetConnectionsUpdated := Nil;
  1087. FOnNodeServersUpdated := Nil;
  1088. FOnBlackListUpdated := Nil;
  1089. FOnReceivedHelloMessage := Nil;
  1090. FOnGetNewBlockchainFromClientDownloadNewSafebox := Nil;
  1091. FIsDiscoveringServers := false;
  1092. FRegisteredRequests := TPCThreadList<Pointer>.Create('TNetData_RegisteredRequests');
  1093. FNodeServersAddresses := TOrderedServerAddressListTS.Create(Self);
  1094. FLastRequestId := 0;
  1095. FNetConnections := TPCThreadList<TNetConnection>.Create('TNetData_NetConnections');
  1096. FLockGettingNewBlockChainFromClient := TPCCriticalSection.Create('LockGettingNewBlockChainFromClient');
  1097. FNewBlockChainFromClientStatus := '';
  1098. FNodePrivateKey := TECPrivateKey.Create;
  1099. FNodePrivateKey.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
  1100. FThreadCheckConnections := TThreadCheckConnections.Create(Self);
  1101. FNetDataNotifyEventsThread := TNetDataNotifyEventsThread.Create(Self);
  1102. FNetClientsDestroyThread := TNetClientsDestroyThread.Create(Self);
  1103. FNetworkAdjustedTime := TNetworkAdjustedTime.Create;
  1104. FMaxNodeServersAddressesBuffer:=(CT_MAX_NODESERVERS_BUFFER DIV 2);
  1105. FMinServersConnected:=CT_MinServersConnected;
  1106. FMaxServersConnected:=CT_MaxServersConnected;
  1107. FIpInfos := TIpInfos.Create;
  1108. FIpInfos.MaxStatsLifetime := 60*60*4; // Max 4 hours
  1109. FIpInfos.MaxStatsCount := 100; // Max lasts 100 values
  1110. // By default, if our node is 7 days back vs highest blockchain detected, will not
  1111. // download blocks, instead will download directly new safebox state
  1112. MinFutureBlocksToDownloadNewSafebox := (86400 DIV CT_NewLineSecondsAvg) * {$IFDEF PRODUCTION}7{$ELSE}1{$ENDIF}; // Only 1 day for TESTNET, 7 for PRODUCTION
  1113. //
  1114. If Not Assigned(_NetData) then _NetData := Self;
  1115. end;
  1116. destructor TNetData.Destroy;
  1117. Var l : TList<TNetConnection>;
  1118. i : Integer;
  1119. tdc : TThreadDiscoverConnection;
  1120. begin
  1121. TLog.NewLog(ltInfo,ClassName,'TNetData.Destroy START');
  1122. FreeAndNil(FOnConnectivityChanged);
  1123. FOnGetNewBlockchainFromClientDownloadNewSafebox := Nil;
  1124. FOnStatisticsChanged := Nil;
  1125. FOnNetConnectionsUpdated := Nil;
  1126. FOnNodeServersUpdated := Nil;
  1127. FOnBlackListUpdated := Nil;
  1128. FOnReceivedHelloMessage := Nil;
  1129. // First destroy ThreadCheckConnections to prevent a call to "DiscoverServers"
  1130. TLog.NewLog(ltInfo,ClassName,'ThreadCheckConnections terminating...');
  1131. FThreadCheckConnections.Terminate;
  1132. FThreadCheckConnections.WaitFor;
  1133. FreeAndNil(FThreadCheckConnections);
  1134. // Now finish all DiscoverConnection threads
  1135. Repeat
  1136. tdc := TThreadDiscoverConnection( TPCThreadClass.GetThreadByClass(TThreadDiscoverConnection,nil) );
  1137. if Assigned(tdc) then begin
  1138. tdc.FreeOnTerminate := false;
  1139. tdc.Terminate;
  1140. tdc.WaitFor;
  1141. tdc.Free;
  1142. TLog.NewLog(ltInfo,ClassName,'TThreadDiscoverConnection finished');
  1143. end;
  1144. Until Not Assigned(tdc);
  1145. // Closing connections
  1146. l := FNetConnections.LockList;
  1147. Try
  1148. for i := 0 to l.Count - 1 do begin
  1149. TNetConnection(l[i]).Connected := false;
  1150. TNetConnection(l[i]).FinalizeConnection;
  1151. end;
  1152. Finally
  1153. FNetConnections.UnlockList;
  1154. End;
  1155. FNetClientsDestroyThread.WaitForTerminatedAllConnections;
  1156. FNetClientsDestroyThread.Terminate;
  1157. FNetClientsDestroyThread.WaitFor;
  1158. FreeAndNil(FNetClientsDestroyThread);
  1159. FreeAndNil(FNodeServersAddresses);
  1160. FreeAndNil(FNetConnections);
  1161. FreeAndNil(FNodePrivateKey);
  1162. FNetDataNotifyEventsThread.Terminate;
  1163. FNetDataNotifyEventsThread.WaitFor;
  1164. FreeAndNil(FNetDataNotifyEventsThread);
  1165. SetLength(FFixedServers,0);
  1166. FreeAndNil(FRegisteredRequests);
  1167. FreeAndNil(FNetworkAdjustedTime);
  1168. FreeAndNil(FIpInfos);
  1169. FreeAndNil(FLockGettingNewBlockChainFromClient);
  1170. inherited;
  1171. if (_NetData=Self) then _NetData := Nil;
  1172. TLog.NewLog(ltInfo,ClassName,'TNetData.Destroy END');
  1173. end;
  1174. procedure TNetData.DisconnectClients;
  1175. var i : Integer;
  1176. l : TList<TNetConnection>;
  1177. begin
  1178. l := FNetConnections.LockList;
  1179. Try
  1180. for i := l.Count - 1 downto 0 do begin
  1181. if (l[i] is TNetClient) then begin
  1182. TNetClient(l[i]).Connected := false;
  1183. TNetClient(l[i]).FinalizeConnection;
  1184. end;
  1185. end;
  1186. Finally
  1187. FNetConnections.UnlockList;
  1188. End;
  1189. end;
  1190. procedure TNetData.DiscoverFixedServersOnly(const FixedServers: TNodeServerAddressArray);
  1191. Var i : Integer;
  1192. begin
  1193. SetLength(FFixedServers,length(FixedServers));
  1194. for i := low(FixedServers) to high(FixedServers) do begin
  1195. FFixedServers[i] := FixedServers[i];
  1196. end;
  1197. for i := low(FixedServers) to high(FixedServers) do begin
  1198. AddServer(FixedServers[i]);
  1199. end;
  1200. end;
  1201. procedure TNetData.DiscoverServers;
  1202. Var P : PNodeServerAddress;
  1203. i,j,k : Integer;
  1204. tdc : TThreadDiscoverConnection;
  1205. canAdd : Boolean;
  1206. nsa : TNodeServerAddressArray;
  1207. begin
  1208. if Not FNetConnectionsActive then exit;
  1209. if TPCThread.ThreadClassFound(TThreadDiscoverConnection,nil)>=0 then begin
  1210. {$IFDEF HIGHLOG}TLog.NewLog(ltInfo,ClassName,'Already discovering servers...');{$ENDIF}
  1211. exit;
  1212. end;
  1213. FNodeServersAddresses.CleanBlackList(False);
  1214. If NetStatistics.ClientsConnections>0 then begin
  1215. j := FMinServersConnected - NetStatistics.ServersConnectionsWithResponse;
  1216. end else begin
  1217. j := FMaxServersConnected - NetStatistics.ServersConnectionsWithResponse;
  1218. end;
  1219. if j<=0 then exit;
  1220. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Discover servers start process searching up to '+inttostr(j)+' servers');{$ENDIF}
  1221. if (Length(FFixedServers)>0) then begin
  1222. nsa := FFixedServers;
  1223. FNodeServersAddresses.GetNodeServersToConnnect(j,true,nsa);
  1224. end else begin
  1225. SetLength(nsa,0);
  1226. FNodeServersAddresses.GetNodeServersToConnnect(j,false,nsa);
  1227. end;
  1228. if length(nsa)>0 then begin
  1229. TLog.NewLog(ltDebug,Classname,'Start discovering up to '+inttostr(length(nsa))+' servers... (max:'+inttostr(j)+')');
  1230. //
  1231. for i := 0 to high(nsa) do begin
  1232. FIsDiscoveringServers := true;
  1233. tdc := TThreadDiscoverConnection.Create(nsa[i],DiscoverServersTerminated);
  1234. end;
  1235. end;
  1236. end;
  1237. procedure TNetData.DiscoverServersTerminated(Sender: TObject);
  1238. begin
  1239. NotifyNodeServersUpdated;
  1240. if TPCThread.ThreadClassFound(TThreadDiscoverConnection,Nil)>=0 then exit;
  1241. FIsDiscoveringServers := false;
  1242. // If here, discover servers finished, so we can try to get/receive data
  1243. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,Format('Discovering servers finished. Now we have %d active connections and %d connections to other servers',
  1244. [ConnectionsCount(false),ConnectionsCount(true)]));{$ENDIF}
  1245. if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)>=0 then exit;
  1246. TThreadGetNewBlockChainFromClient.Create;
  1247. end;
  1248. procedure TNetData.DoProcessReservedAreaMessage(senderConnection : TNetConnection; const headerData: TNetHeaderData; receivedData: TStream; responseData: TStream);
  1249. begin
  1250. If Assigned(FOnProcessReservedAreaMessage) then begin
  1251. FOnProcessReservedAreaMessage(Self,senderConnection,headerData,receivedData,responseData);
  1252. end;
  1253. end;
  1254. class function TNetData.ExtractHeaderInfo(buffer : TStream; var HeaderData : TNetHeaderData; DataBuffer : TStream; var IsValidHeaderButNeedMoreData : Boolean) : Boolean;
  1255. Var lastp : Integer;
  1256. c : Cardinal;
  1257. w : Word;
  1258. begin
  1259. HeaderData := CT_NetHeaderData;
  1260. Result := false;
  1261. IsValidHeaderButNeedMoreData := false;
  1262. lastp := buffer.Position;
  1263. Try
  1264. if buffer.Size-buffer.Position < 22 then exit;
  1265. buffer.Read(c,4);
  1266. if (c<>CT_MagicNetIdentification) then exit;
  1267. buffer.Read(w,2);
  1268. case w of
  1269. CT_MagicRequest : HeaderData.header_type := ntp_request;
  1270. CT_MagicResponse : HeaderData.header_type := ntp_response;
  1271. CT_MagicAutoSend : HeaderData.header_type := ntp_autosend;
  1272. else
  1273. HeaderData.header_type := ntp_unknown;
  1274. exit;
  1275. end;
  1276. buffer.Read(HeaderData.operation,2);
  1277. buffer.Read(HeaderData.error_code,2);
  1278. buffer.Read(HeaderData.request_id,4);
  1279. buffer.Read(HeaderData.protocol.protocol_version,2);
  1280. buffer.Read(HeaderData.protocol.protocol_available,2);
  1281. buffer.Read(c,4);
  1282. HeaderData.buffer_data_length := c;
  1283. DataBuffer.Size := 0;
  1284. if (c>0) then begin
  1285. if buffer.Size - buffer.Position < c then begin
  1286. IsValidHeaderButNeedMoreData := true;
  1287. {$IFDEF HIGHLOG}
  1288. TLog.NewLog(ltdebug,className,Format('Need more data! Buffer size (%d) - position (%d) < %d - Header info: %s',
  1289. [buffer.Size,buffer.Position,c,HeaderDataToText(HeaderData)]));
  1290. {$ENDIF}
  1291. exit;
  1292. end;
  1293. DataBuffer.CopyFrom(buffer,c);
  1294. DataBuffer.Position := 0;
  1295. end;
  1296. //
  1297. if HeaderData.header_type=ntp_response then begin
  1298. HeaderData.is_error := HeaderData.error_code<>0;
  1299. if HeaderData.is_error then begin
  1300. TStreamOp.ReadString(DataBuffer,HeaderData.error_text);
  1301. end;
  1302. end else begin
  1303. HeaderData.is_error := HeaderData.error_code<>0;
  1304. if HeaderData.is_error then begin
  1305. TStreamOp.ReadString(DataBuffer,HeaderData.error_text);
  1306. end;
  1307. end;
  1308. if (HeaderData.is_error) then begin
  1309. TLog.NewLog(lterror,Classname,'Response with error ('+IntToHex(HeaderData.error_code,4)+'): '+HeaderData.error_text+' ...on '+
  1310. 'operation: '+OperationToText(HeaderData.operation)+' id: '+Inttostr(HeaderData.request_id));
  1311. end;
  1312. Result := true;
  1313. Finally
  1314. if Not Result then buffer.Position := lastp;
  1315. End;
  1316. end;
  1317. function TNetData.FindConnectionByClientRandomValue(Sender: TNetConnection): TNetConnection;
  1318. Var l : TList<TNetConnection>;
  1319. i : Integer;
  1320. begin
  1321. l := FNetConnections.LockList;
  1322. try
  1323. for i := 0 to L.Count - 1 do begin
  1324. Result := TNetConnection( l[i] );
  1325. If TAccountComp.EqualAccountKeys(Result.FClientPublicKey,Sender.FClientPublicKey) And (Sender<>Result) then exit;
  1326. end;
  1327. finally
  1328. FNetConnections.UnlockList;
  1329. end;
  1330. Result := Nil;
  1331. end;
  1332. function TNetData.GetConnection(index: Integer; var NetConnection : TNetConnection) : Boolean;
  1333. Var l : TList<TNetConnection>;
  1334. begin
  1335. Result := false; NetConnection := Nil;
  1336. l := FNetConnections.LockList;
  1337. try
  1338. if (index>=0) And (index<l.Count) then begin
  1339. NetConnection := TNetConnection( l[index] );
  1340. Result := true;
  1341. exit;
  1342. end;
  1343. finally
  1344. FNetConnections.UnlockList;
  1345. end;
  1346. end;
  1347. procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection;
  1348. const why: String);
  1349. Const CT_LogSender = 'GetNewBlockChainFromClient';
  1350. function Do_GetOperationsBlock(AssignToBank : TPCBank; block_start,block_end, MaxWaitMilliseconds : Cardinal; OnlyOperationBlock : Boolean; BlocksList : TList<TPCOperationsComp>) : Boolean;
  1351. Var SendData,ReceiveData : TMemoryStream;
  1352. headerdata : TNetHeaderData;
  1353. op : TPCOperationsComp;
  1354. request_id,opcount,i, last_n_block : Cardinal;
  1355. errors : String;
  1356. noperation : Integer;
  1357. begin
  1358. Result := false;
  1359. BlocksList.Clear;
  1360. // First receive operations from
  1361. SendData := TMemoryStream.Create;
  1362. ReceiveData := TMemoryStream.Create;
  1363. try
  1364. if OnlyOperationBlock then begin
  1365. noperation := CT_NetOp_GetBlockHeaders;
  1366. end else begin
  1367. noperation := CT_NetOp_GetBlocks;
  1368. end;
  1369. TLog.NewLog(ltdebug,CT_LogSender,Format('Sending %s from block %d to %d (Total: %d)',
  1370. [TNetData.OperationToText(noperation),block_start,block_end,block_end-block_start+1]));
  1371. SendData.Write(block_start,4);
  1372. SendData.Write(block_end,4);
  1373. request_id := TNetData.NetData.NewRequestId;
  1374. if Connection.DoSendAndWaitForResponse(noperation,request_id,SendData,ReceiveData,MaxWaitMilliseconds,headerdata) then begin
  1375. if HeaderData.is_error then exit;
  1376. if ReceiveData.Read(opcount,4)<4 then exit; // Error in data
  1377. i := 0; last_n_block := 0;
  1378. while (i<opcount) do begin
  1379. // decode data
  1380. op := TPCOperationsComp.Create(AssignToBank);
  1381. If op.LoadBlockFromStream(ReceiveData,errors) then begin
  1382. // Build 2.1.7 Protection for invalid block number
  1383. If ((i>0) And (last_n_block>=op.OperationBlock.block)) Or
  1384. ((Not OnlyOperationBlock) And
  1385. ( ((i=0) And (op.OperationBlock.block<>block_start))
  1386. Or
  1387. ((i>0) And (op.OperationBlock.block<>last_n_block+1)) ) ) then begin
  1388. Connection.DisconnectInvalidClient(false,Format('Invalid block sequence received last:%d received:%d',[last_n_block,op.OperationBlock.block]));
  1389. op.free;
  1390. break;
  1391. end else BlocksList.Add(op);
  1392. last_n_block := op.OperationBlock.block;
  1393. end else begin
  1394. Connection.DisconnectInvalidClient(false,Format('Error reading OperationBlock from received stream %d/%d: %s',[i+1,opcount,errors]));
  1395. op.free;
  1396. break;
  1397. end;
  1398. inc(i);
  1399. end;
  1400. Result := true;
  1401. end else begin
  1402. TLog.NewLog(lterror,CT_LogSender,Format('No received response after waiting %d request id %d operation %s',[MaxWaitMilliseconds,request_id,TNetData.OperationToText(noperation)]));
  1403. end;
  1404. finally
  1405. SendData.Free;
  1406. ReceiveData.free;
  1407. end;
  1408. end;
  1409. function Do_GetOperationBlock(block, MaxWaitMilliseconds : Cardinal; var OperationBlock : TOperationBlock) : Boolean;
  1410. Var BlocksList : TList<TPCOperationsComp>;
  1411. i : Integer;
  1412. begin
  1413. OperationBlock := CT_OperationBlock_NUL;
  1414. BlocksList := TList<TPCOperationsComp>.Create;
  1415. try
  1416. Result := Do_GetOperationsBlock(TNode.Node.Bank,block,block,MaxWaitMilliseconds,True,BlocksList);
  1417. // Build 2.1.7 - Included protection agains not good block received
  1418. if (Result) And (BlocksList.Count=1) then begin
  1419. OperationBlock := TPCOperationsComp(BlocksList[0]).OperationBlock;
  1420. If OperationBlock.block<>block then Result := False;
  1421. end else begin
  1422. Result := False;
  1423. end;
  1424. finally
  1425. for i := 0 to BlocksList.Count - 1 do TPCOperationsComp(BlocksList[i]).Free;
  1426. BlocksList.Free;
  1427. end;
  1428. end;
  1429. Function FindLastSameBlockByOperationsBlock(min,max : Cardinal; var OperationBlock : TOperationBlock) : Boolean;
  1430. var i : Integer;
  1431. ant_nblock : Int64;
  1432. auxBlock, sbBlock : TOperationBlock;
  1433. distinctmax,distinctmin : Cardinal;
  1434. BlocksList : TList<TPCOperationsComp>;
  1435. errors : String;
  1436. Begin
  1437. Result := false;
  1438. OperationBlock := CT_OperationBlock_NUL;
  1439. repeat
  1440. BlocksList := TList<TPCOperationsComp>.Create;
  1441. try
  1442. If Not Do_GetOperationsBlock(Nil,min,max,20000,true,BlocksList) then exit;
  1443. if (BlocksList.Count=0) then begin
  1444. Connection.DisconnectInvalidClient(false,'No received info for blocks from '+inttostr(min)+' to '+inttostr(max));
  1445. exit;
  1446. end;
  1447. distinctmin := min;
  1448. distinctmax := max;
  1449. ant_nblock := -1;
  1450. for i := 0 to BlocksList.Count - 1 do begin
  1451. auxBlock := TPCOperationsComp(BlocksList[i]).OperationBlock;
  1452. // Protection of invalid clients:
  1453. if (auxBlock.block<min) Or (auxBlock.block>max) Or (auxBlock.block=ant_nblock) then begin
  1454. Connection.DisconnectInvalidClient(false,'Invalid response... '+inttostr(min)+'<'+inttostr(auxBlock.block)+'<'+inttostr(max)+' ant:'+inttostr(ant_nblock));
  1455. exit;
  1456. end;
  1457. // New Build 2.1.7 - Check valid operationblock
  1458. If Not TPCSafeBox.IsValidOperationBlock(auxBlock,errors) then begin
  1459. Connection.DisconnectInvalidClient(false,'Received invalid operation block searching '+TPCOperationsComp.OperationBlockToText(auxBlock)+' errors: '+errors);
  1460. Exit;
  1461. end;
  1462. ant_nblock := auxBlock.block;
  1463. //
  1464. sbBlock := TNode.Node.Bank.SafeBox.Block(auxBlock.block).blockchainInfo;
  1465. if TPCOperationsComp.EqualsOperationBlock(sbBlock,auxBlock) then begin
  1466. distinctmin := auxBlock.block;
  1467. OperationBlock := auxBlock;
  1468. end else begin
  1469. if auxBlock.block<=distinctmax then
  1470. distinctmax := auxBlock.block-1;
  1471. end;
  1472. end;
  1473. min := distinctmin;
  1474. max := distinctmax;
  1475. finally
  1476. for i := 0 to BlocksList.Count - 1 do begin
  1477. TPCOperationsComp(BlocksList[i]).Free;
  1478. end;
  1479. BlocksList.Free;
  1480. end;
  1481. until (distinctmin=distinctmax);
  1482. Result := (OperationBlock.proof_of_work <> CT_OperationBlock_NUL.proof_of_work);
  1483. End;
  1484. procedure GetNewBank(start_block : Int64);
  1485. Var BlocksList : TList<TPCOperationsComp>;
  1486. i : Integer;
  1487. OpComp,OpExecute : TPCOperationsComp;
  1488. oldBlockchainOperations : TOperationsHashTree;
  1489. opsResume : TOperationsResumeList;
  1490. newBlock : TBlockAccount;
  1491. errors : String;
  1492. start,start_c : Cardinal;
  1493. finished : Boolean;
  1494. Bank : TPCBank;
  1495. ms : TMemoryStream;
  1496. IsAScam, IsUsingSnapshot : Boolean;
  1497. Begin
  1498. IsAScam := false;
  1499. TLog.NewLog(ltdebug,CT_LogSender,Format('GetNewBank(new_start_block:%d)',[start_block]));
  1500. Bank := TPCBank.Create(Nil);
  1501. try
  1502. Bank.StorageClass := TNode.Node.Bank.StorageClass;
  1503. Bank.Storage.Orphan := TNode.Node.Bank.Storage.Orphan;
  1504. Bank.Storage.ReadOnly := true;
  1505. Bank.Storage.CopyConfiguration(TNode.Node.Bank.Storage);
  1506. if start_block>=0 then begin
  1507. If (TNode.Node.Bank.SafeBox.HasSnapshotForBlock(start_block-1)) then begin
  1508. // Restore from a Snapshot (New on V3) instead of restore reading from File
  1509. Bank.SafeBox.SetToPrevious(TNode.Node.Bank.SafeBox,start_block-1);
  1510. Bank.UpdateValuesFromSafebox;
  1511. IsUsingSnapshot := True;
  1512. end else begin
  1513. // Restore a part from disk
  1514. Bank.DiskRestoreFromOperations(start_block-1);
  1515. Bank.Storage.SaveBank(True);
  1516. if (Bank.BlocksCount<start_block) then begin
  1517. TLog.NewLog(lterror,CT_LogSender,Format('No blockchain found start block %d, current %d',[start_block-1,Bank.BlocksCount]));
  1518. start_block := Bank.BlocksCount;
  1519. end;
  1520. IsUsingSnapshot := False;
  1521. end;
  1522. start := start_block;
  1523. end else begin
  1524. start := 0;
  1525. start_block := 0;
  1526. end;
  1527. start_c := start;
  1528. Bank.Storage.Orphan := FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now));
  1529. Bank.Storage.ReadOnly := false;
  1530. // Receive new blocks:
  1531. finished := false;
  1532. repeat
  1533. BlocksList := TList<TPCOperationsComp>.Create;
  1534. try
  1535. finished := NOT Do_GetOperationsBlock(Bank,start,start + 50,30000,false,BlocksList);
  1536. i := 0;
  1537. while (i<BlocksList.Count) And (Not finished) do begin
  1538. OpComp := TPCOperationsComp(BlocksList[i]);
  1539. ms := TMemoryStream.Create;
  1540. OpExecute := TPCOperationsComp.Create(Bank);
  1541. try
  1542. OpComp.SaveBlockToStream(false,ms);
  1543. ms.Position := 0;
  1544. If not OpExecute.LoadBlockFromStream(ms,errors) then begin
  1545. Connection.DisconnectInvalidClient(false,'Invalid block stream received for block '+IntToStr(Bank.BlocksCount)+' errors: '+errors );
  1546. finished := true;
  1547. IsAScam := true;
  1548. break;
  1549. end;
  1550. TNode.Node.MarkVerifiedECDSASignaturesFromMemPool(OpExecute); // Improvement speed v4.0.2
  1551. if Bank.AddNewBlockChainBlock(OpExecute,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlock,errors) then begin
  1552. inc(i);
  1553. end else begin
  1554. TLog.NewLog(lterror,CT_LogSender,'Error creating new bank with client Operations. Block:'+TPCOperationsComp.OperationBlockToText(OpExecute.OperationBlock)+' Error:'+errors);
  1555. // Add to blacklist !
  1556. Connection.DisconnectInvalidClient(false,'Invalid BlockChain on Block '+TPCOperationsComp.OperationBlockToText(OpExecute.OperationBlock)+' with errors:'+errors);
  1557. finished := true;
  1558. IsAScam := true;
  1559. break;
  1560. end;
  1561. finally
  1562. ms.Free;
  1563. OpExecute.Free;
  1564. end;
  1565. end;
  1566. finally
  1567. for i := 0 to BlocksList.Count - 1 do TPCOperationsComp(BlocksList[i]).Free;
  1568. BlocksList.Free;
  1569. end;
  1570. start := Bank.BlocksCount;
  1571. until (Bank.BlocksCount=Connection.FRemoteOperationBlock.block+1) Or (finished)
  1572. // Allow to do not download ALL new blockchain in a separate folder, only needed blocks!
  1573. Or (Bank.SafeBox.WorkSum > (TNode.Node.Bank.SafeBox.WorkSum + $FFFFFFFF) );
  1574. // New Build 1.5 more work vs more high
  1575. // work = SUM(target) of all previous blocks (Int64)
  1576. // -----------------------------
  1577. // Before of version 1.5 was: "if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then ..."
  1578. // Starting on version 1.5 is: "if Bank.WORK > MyBank.WORK then ..."
  1579. if Bank.SafeBox.WorkSum > TNode.Node.Bank.SafeBox.WorkSum then begin
  1580. oldBlockchainOperations := TOperationsHashTree.Create;
  1581. try
  1582. TNode.Node.DisableNewBlocks;
  1583. Try
  1584. // I'm an orphan blockchain...
  1585. TLog.NewLog(ltinfo,CT_LogSender,'New valid blockchain found. My block count='+inttostr(TNode.Node.Bank.BlocksCount)+' work: '+IntToStr(TNode.Node.Bank.SafeBox.WorkSum)+
  1586. ' found count='+inttostr(Bank.BlocksCount)+' work: '+IntToStr(Bank.SafeBox.WorkSum)+' starting at block '+inttostr(start_block));
  1587. if TNode.Node.Bank.BlocksCount>0 then begin
  1588. OpExecute := TPCOperationsComp.Create(Nil);
  1589. try
  1590. for start:=start_c to TNode.Node.Bank.BlocksCount-1 do begin
  1591. If TNode.Node.Bank.LoadOperations(OpExecute,start) then begin
  1592. if (OpExecute.Count>0) then begin
  1593. for i:=0 to OpExecute.Count-1 do begin
  1594. // TODO: NEED TO EXCLUDE OPERATIONS ALREADY INCLUDED IN BLOCKCHAIN?
  1595. oldBlockchainOperations.AddOperationToHashTree(OpExecute.Operation[i]);
  1596. end;
  1597. TLog.NewLog(ltInfo,CT_LogSender,'Recovered '+IntToStr(OpExecute.Count)+' operations from block '+IntToStr(start));
  1598. end;
  1599. end else begin
  1600. TLog.NewLog(ltError,CT_LogSender,'Fatal error: Cannot read block '+IntToStr(start));
  1601. end;
  1602. end;
  1603. finally
  1604. OpExecute.Free;
  1605. end;
  1606. end;
  1607. TNode.Node.Bank.Storage.MoveBlockChainBlocks(start_block,Inttostr(start_block)+'_'+FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now)),Nil);
  1608. Bank.Storage.MoveBlockChainBlocks(start_block,TNode.Node.Bank.Storage.Orphan,TNode.Node.Bank.Storage);
  1609. //
  1610. If IsUsingSnapshot then begin
  1611. TLog.NewLog(ltInfo,CT_LogSender,'Commiting new chain to Safebox');
  1612. Bank.SafeBox.CommitToPrevious;
  1613. TNode.Node.Bank.UpdateValuesFromSafebox; // BUG 2018-10-14 -> Must update TNode.Node.Bank instead of Bank, because FLastBlockCache must upgrade
  1614. {$IFDEF Check_Safebox_Names_Consistency}
  1615. If Not Check_Safebox_Names_Consistency(Bank.SafeBox,'Commited',errors) then begin
  1616. TLog.NewLog(lterror,CT_LogSender,'Fatal safebox consistency error getting bank at block '+IntTosTr(start_block)+' : '+errors);
  1617. Sleep(1000);
  1618. halt(0);
  1619. end;
  1620. {$ENDIF}
  1621. end else begin
  1622. TLog.NewLog(ltInfo,CT_LogSender,'Restoring modified Safebox from Disk');
  1623. TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
  1624. end;
  1625. Finally
  1626. TNode.Node.EnableNewBlocks;
  1627. End;
  1628. TNode.Node.NotifyBlocksChanged;
  1629. // Finally add new operations:
  1630. // Rescue old operations from old blockchain to new blockchain
  1631. If oldBlockchainOperations.OperationsCount>0 then begin
  1632. TLog.NewLog(ltInfo,CT_LogSender,Format('Executing %d operations from block %d to %d',
  1633. [oldBlockchainOperations.OperationsCount,start_c,TNode.Node.Bank.BlocksCount-1]));
  1634. opsResume := TOperationsResumeList.Create;
  1635. Try
  1636. // Re-add orphaned operations back into the pending pool.
  1637. // NIL is passed as senderConnection since localnode is considered
  1638. // the origin, and current sender needs these operations.
  1639. i := TNode.Node.AddOperations(NIL,oldBlockchainOperations,opsResume,errors);
  1640. TLog.NewLog(ltInfo,CT_LogSender,Format('Executed %d/%d operations. Returned errors: %s',[i,oldBlockchainOperations.OperationsCount,errors]));
  1641. finally
  1642. opsResume.Free;
  1643. end;
  1644. end else TLog.NewLog(ltInfo,CT_LogSender,Format('No operations from block %d to %d',[start_c,TNode.Node.Bank.BlocksCount-1]));
  1645. finally
  1646. oldBlockchainOperations.Free;
  1647. end;
  1648. end else begin
  1649. if (Not IsAScam) And (Connection.FRemoteAccumulatedWork > TNode.Node.Bank.SafeBox.WorkSum) then begin
  1650. // Possible scammer!
  1651. Connection.DisconnectInvalidClient(false,Format('Possible scammer! Says blocks:%d Work:%d - Obtained blocks:%d work:%d',
  1652. [Connection.FRemoteOperationBlock.block+1,Connection.FRemoteAccumulatedWork,
  1653. Bank.BlocksCount,Bank.SafeBox.WorkSum]));
  1654. end;
  1655. end;
  1656. finally
  1657. Bank.Free;
  1658. end;
  1659. End;
  1660. Function DownloadSafeBoxChunk(safebox_blockscount : Cardinal; Const sbh : TRawBytes; from_block, to_block : Cardinal; receivedDataUnzipped : TStream;
  1661. var safeBoxHeader : TPCSafeBoxHeader; var errors : String) : Boolean;
  1662. Var sendData,receiveData : TStream;
  1663. headerdata : TNetHeaderData;
  1664. request_id : Cardinal;
  1665. c : Cardinal;
  1666. Begin
  1667. Result := False;
  1668. sendData := TMemoryStream.Create;
  1669. receiveData := TMemoryStream.Create;
  1670. try
  1671. sendData.Write(safebox_blockscount,SizeOf(safebox_blockscount)); // 4 bytes for blockcount
  1672. TStreamOp.WriteAnsiString(SendData,sbh);
  1673. sendData.Write(from_block,SizeOf(from_block));
  1674. c := to_block;
  1675. if (c>=safebox_blockscount) then c := safebox_blockscount-1;
  1676. sendData.Write(c,SizeOf(c));
  1677. if (from_block>c) or (c>=safebox_blockscount) then begin
  1678. errors := 'ERROR DEV 20170727-1';
  1679. Exit;
  1680. end;
  1681. TLog.NewLog(ltDebug,CT_LogSender,Format('Call to GetSafeBox from blocks %d to %d of %d',[from_block,c,safebox_blockscount]));
  1682. request_id := TNetData.NetData.NewRequestId;
  1683. if Connection.DoSendAndWaitForResponse(CT_NetOp_GetSafeBox,request_id,sendData,receiveData,30000,headerdata) then begin
  1684. if HeaderData.is_error then exit;
  1685. receivedDataUnzipped.Size:=0;
  1686. If Not TPCChunk.LoadSafeBoxFromChunk(receiveData,receivedDataUnzipped,safeBoxHeader,errors) then begin
  1687. Connection.DisconnectInvalidClient(false,'Invalid received chunk: '+errors);
  1688. exit;
  1689. end;
  1690. If (Not (TBaseType.Equals(safeBoxHeader.safeBoxHash,sbh))) or (safeBoxHeader.startBlock<>from_block) or (safeBoxHeader.endBlock<>c) or
  1691. (safeBoxHeader.blocksCount<>safebox_blockscount) or (safeBoxHeader.protocol<CT_PROTOCOL_2) or
  1692. (safeBoxHeader.protocol>CT_BlockChain_Protocol_Available) then begin
  1693. errors := Format('Invalid received chunk based on call: Blockscount:%d %d - from:%d %d to %d %d - SafeboxHash:%s %s',
  1694. [safeBoxHeader.blocksCount,safebox_blockscount,safeBoxHeader.startBlock,from_block,safeBoxHeader.endBlock,c,
  1695. safeBoxHeader.safeBoxHash.ToHexaString,sbh.ToHexaString]);
  1696. Connection.DisconnectInvalidClient(false,'Invalid received chunk: '+errors);
  1697. exit;
  1698. end;
  1699. Result := True;
  1700. end else errors := 'No response on DownloadSafeBoxChunk';
  1701. finally
  1702. receiveData.Free;
  1703. SendData.Free;
  1704. end;
  1705. end;
  1706. Type TSafeBoxChunkData = Record
  1707. safeBoxHeader : TPCSafeBoxHeader;
  1708. chunkStream : TStream;
  1709. end;
  1710. Function DownloadSafeboxStream(safeboxStream : TStream; var safebox_last_operation_block : TOperationBlock) : Boolean;
  1711. var _blockcount, request_id : Cardinal;
  1712. chunks : Array of TSafeBoxChunkData;
  1713. receiveChunk, chunk1 : TStream;
  1714. safeBoxHeader : TPCSafeBoxHeader;
  1715. errors : String;
  1716. i : Integer;
  1717. Begin
  1718. Result := False;
  1719. safeboxStream.Size:=0;
  1720. safeboxStream.Position:=0;
  1721. // Will try to download penultimate saved safebox
  1722. _blockcount := ((Connection.FRemoteOperationBlock.block DIV CT_BankToDiskEveryNBlocks)-1) * CT_BankToDiskEveryNBlocks;
  1723. If not Do_GetOperationBlock(_blockcount,5000,safebox_last_operation_block) then begin
  1724. Connection.DisconnectInvalidClient(false,Format('Cannot obtain operation block %d for downloading safebox',[_blockcount]));
  1725. exit;
  1726. end;
  1727. // New Build 2.1.7 - Check valid operationblock
  1728. If Not TPCSafeBox.IsValidOperationBlock(safebox_last_operation_block,errors) then begin
  1729. Connection.DisconnectInvalidClient(false,'Invalid operation block at DownloadSafeBox '+TPCOperationsComp.OperationBlockToText(safebox_last_operation_block)+' errors: '+errors);
  1730. Exit;
  1731. end;
  1732. SetLength(chunks,0);
  1733. try
  1734. // Will obtain chunks of 10000 blocks each -> Note: Maximum is CT_MAX_SAFEBOXCHUNK_BLOCKS
  1735. for i:=0 to ((_blockcount-1) DIV 10000) do begin // Bug v3.0.1 and minors
  1736. FNewBlockChainFromClientStatus := Format('Receiving new safebox with %d blocks (step %d/%d) from %s',
  1737. [_blockcount,i+1,((_blockcount-1) DIV 10000)+1,Connection.ClientRemoteAddr]);
  1738. receiveChunk := TMemoryStream.Create;
  1739. if (Not DownloadSafeBoxChunk(_blockcount,safebox_last_operation_block.initial_safe_box_hash,(i*10000),((i+1)*10000)-1,receiveChunk,safeBoxHeader,errors)) then begin
  1740. receiveChunk.Free;
  1741. TLog.NewLog(ltError,CT_LogSender,errors);
  1742. Exit;
  1743. end;
  1744. SetLength(chunks,length(chunks)+1);
  1745. chunks[High(chunks)].safeBoxHeader := safeBoxHeader;
  1746. chunks[High(chunks)].chunkStream := receiveChunk;
  1747. end;
  1748. // Will concat safeboxs:
  1749. chunk1 := TMemoryStream.Create;
  1750. try
  1751. if (length(chunks)=1) then begin
  1752. safeboxStream.CopyFrom(chunks[0].chunkStream,0);
  1753. end else begin
  1754. chunk1.CopyFrom(chunks[0].chunkStream,0);
  1755. end;
  1756. for i:=1 to high(chunks) do begin
  1757. safeboxStream.Size:=0;
  1758. chunk1.Position:=0;
  1759. chunks[i].chunkStream.Position:=0;
  1760. If Not TPCSafeBox.ConcatSafeBoxStream(chunk1,chunks[i].chunkStream,safeboxStream,errors) then begin
  1761. TLog.NewLog(ltError,CT_LogSender,errors);
  1762. exit;
  1763. end;
  1764. chunk1.Size := 0;
  1765. chunk1.CopyFrom(safeboxStream,0);
  1766. end;
  1767. finally
  1768. chunk1.Free;
  1769. end;
  1770. finally
  1771. for i:=0 to high(chunks) do begin
  1772. chunks[i].chunkStream.Free;
  1773. end;
  1774. SetLength(chunks,0);
  1775. end;
  1776. Result := True;
  1777. End;
  1778. Function DownloadSafeBox(IsMyBlockchainValid : Boolean) : Boolean;
  1779. var receiveData : TStream;
  1780. op : TOperationBlock;
  1781. errors : String;
  1782. request_id : Cardinal;
  1783. Begin
  1784. Result := False;
  1785. receiveData := TMemoryStream.Create;
  1786. try
  1787. if Not DownloadSafeboxStream(receiveData,op) then Exit;
  1788. // Now receiveData is the ALL safebox
  1789. TNode.Node.DisableNewBlocks;
  1790. try
  1791. FNewBlockChainFromClientStatus := Format('Received new safebox with %d blocks from %s',[op.block+1,Connection.ClientRemoteAddr]);
  1792. receiveData.Position:=0;
  1793. If TNode.Node.Bank.LoadBankFromStream(receiveData,True,op.initial_safe_box_hash,TNode.Node.Bank.SafeBox,OnReadingNewSafeboxProgressNotify,errors) then begin
  1794. TLog.NewLog(ltInfo,ClassName,'Received new safebox!');
  1795. If Not IsMyBlockchainValid then begin
  1796. TNode.Node.Bank.Storage.EraseStorage;
  1797. end;
  1798. TNode.Node.Bank.Storage.SaveBank(False);
  1799. Connection.Send_GetBlocks(TNode.Node.Bank.BlocksCount,100,request_id);
  1800. Result := true;
  1801. end else begin
  1802. Connection.DisconnectInvalidClient(false,'Cannot load from stream! '+errors);
  1803. exit;
  1804. end;
  1805. finally
  1806. TNode.Node.EnableNewBlocks;
  1807. end;
  1808. finally
  1809. receiveData.Free;
  1810. end;
  1811. end;
  1812. procedure DownloadNewBlockchain(start_block : Int64; IsMyBlockChainOk : Boolean);
  1813. var safeboxStream : TMemoryStream;
  1814. newTmpBank : TPCBank;
  1815. safebox_last_operation_block : TOperationBlock;
  1816. newBlock : TBlockAccount;
  1817. opComp : TPCOperationsComp;
  1818. errors : String;
  1819. blocksList : TList<TPCOperationsComp>;
  1820. i : Integer;
  1821. rid : Cardinal;
  1822. download_new_safebox : Boolean;
  1823. begin
  1824. download_new_safebox := (FMinFutureBlocksToDownloadNewSafebox>0) And ((TNode.Node.Bank.BlocksCount + FMinFutureBlocksToDownloadNewSafebox) <= Connection.RemoteOperationBlock.block);
  1825. if Assigned(OnGetNewBlockchainFromClientDownloadNewSafebox) then begin
  1826. // Note: Will call to an event inside a thread, not main thread, be careful
  1827. OnGetNewBlockchainFromClientDownloadNewSafebox(Self,Connection,TNode.Node.Bank.BlocksCount,Connection.RemoteOperationBlock.block,download_new_safebox);
  1828. end;
  1829. if (download_new_safebox) then begin
  1830. TLog.NewLog(ltinfo,ClassName,Format('Will download new safebox. My blocks:%d Remote blocks:%d Equal Block:%d (MaxFutureBlocksToDownloadNewSafebox:%d)',[TNode.Node.Bank.BlocksCount,Connection.RemoteOperationBlock.block+1,start_block-1,MinFutureBlocksToDownloadNewSafebox]));
  1831. // Will try to download safebox
  1832. safeboxStream := TMemoryStream.Create;
  1833. Try
  1834. if Not DownloadSafeboxStream(safeboxStream,safebox_last_operation_block) then Exit;
  1835. safeboxStream.Position := 0;
  1836. newTmpBank := TPCBank.Create(Nil);
  1837. try
  1838. newTmpBank.StorageClass := TNode.Node.Bank.StorageClass;
  1839. newTmpBank.Storage.Orphan := TNode.Node.Bank.Storage.Orphan;
  1840. newTmpBank.Storage.ReadOnly := true;
  1841. newTmpBank.Storage.CopyConfiguration(TNode.Node.Bank.Storage);
  1842. newTmpBank.Storage.Orphan := FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now));
  1843. newTmpBank.Storage.ReadOnly := false;
  1844. if newTmpBank.LoadBankFromStream(safeboxStream,True,safebox_last_operation_block.initial_safe_box_hash,TNode.Node.Bank.SafeBox,OnReadingNewSafeboxProgressNotify,errors) then begin
  1845. TNode.Node.DisableNewBlocks;
  1846. try
  1847. TLog.NewLog(ltInfo,ClassName,'Received new safebox!');
  1848. newTmpBank.Storage.SaveBank(True); // Saving bank
  1849. // Receive at least 1 new block
  1850. blocksList := TList<TPCOperationsComp>.Create;
  1851. try
  1852. if Not Do_GetOperationsBlock(newTmpBank,safebox_last_operation_block.block,safebox_last_operation_block.block+10,20000,False,blocksList) then begin
  1853. TLog.NewLog(ltError,ClassName,Format('Cannot receive at least 1 new block:%d',[safebox_last_operation_block.block]));
  1854. Exit;
  1855. end;
  1856. for i:=0 to blocksList.Count-1 do begin
  1857. opComp := TPCOperationsComp( blocksList[i] );
  1858. if Not newTmpBank.AddNewBlockChainBlock(opComp,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlock,errors) then begin
  1859. TLog.NewLog(lterror,CT_LogSender,'Error adding new block with client Operations. Block:'+TPCOperationsComp.OperationBlockToText(opComp.OperationBlock)+' Error:'+errors);
  1860. // Add to blacklist !
  1861. Connection.DisconnectInvalidClient(false,'Invalid BlockChain on Block '+TPCOperationsComp.OperationBlockToText(opComp.OperationBlock)+' with errors:'+errors);
  1862. Exit;
  1863. end;
  1864. end;
  1865. finally
  1866. for i := 0 to blocksList.Count-1 do begin
  1867. TPCOperationsComp(blocksList[i]).Free;
  1868. end;
  1869. blocksList.Free;
  1870. end;
  1871. // We are ready to upgrade with newest safebox
  1872. // Delete blocks since start_block at current TNode
  1873. TNode.Node.Bank.Storage.MoveBlockChainBlocks(start_block,IntToStr(start_block)+'_'+FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now)),Nil);
  1874. TNode.Node.Bank.Storage.DeleteBlockChainBlocks(start_block);
  1875. newTmpBank.Storage.MoveBlockChainBlocks(safebox_last_operation_block.block,'',TNode.Node.Bank.Storage);
  1876. TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
  1877. Finally
  1878. TNode.Node.EnableNewBlocks;
  1879. End;
  1880. TNode.Node.NotifyBlocksChanged;
  1881. // High to new value:
  1882. Connection.Send_GetBlocks(TNode.Node.Bank.BlocksCount,100,rid);
  1883. end else begin
  1884. Connection.DisconnectInvalidClient(false,'Cannot load from stream! '+errors);
  1885. exit;
  1886. end;
  1887. finally
  1888. newTmpBank.Free;
  1889. end;
  1890. Finally
  1891. safeboxStream.Free;
  1892. End;
  1893. end else begin
  1894. if IsMyBlockChainOk then begin
  1895. Connection.Send_GetBlocks(start_block,1,rid);
  1896. end else begin
  1897. GetNewBank(start_block);
  1898. end;
  1899. end;
  1900. end;
  1901. var rid : Cardinal;
  1902. my_op, client_op : TOperationBlock;
  1903. errors : String;
  1904. begin
  1905. // Protection against discovering servers...
  1906. if FIsDiscoveringServers then begin
  1907. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,CT_LogSender,'Is discovering servers...');{$ENDIF}
  1908. exit;
  1909. end;
  1910. if (Not TNode.Node.UpdateBlockchain) then Exit;
  1911. if (Not Assigned(TNode.Node.Bank.StorageClass)) then Exit;
  1912. //
  1913. if Not FLockGettingNewBlockChainFromClient.TryEnter then begin
  1914. TLog.NewLog(ltdebug,CT_LogSender,'Is getting new blockchain from client...');
  1915. exit;
  1916. end;
  1917. Try
  1918. TLog.NewLog(ltdebug,CT_LogSender,'Starting receiving: '+why);
  1919. FNewBlockChainFromClientStatus := Format('Downloading block %d from %s',[Connection.RemoteOperationBlock.block,Connection.ClientRemoteAddr]);
  1920. FMaxRemoteOperationBlock := Connection.FRemoteOperationBlock;
  1921. if TNode.Node.Bank.BlocksCount=0 then begin
  1922. TLog.NewLog(ltdebug,CT_LogSender,'I have no blocks');
  1923. If Connection.FRemoteOperationBlock.protocol_version>=CT_PROTOCOL_2 then begin
  1924. DownloadSafeBox(False);
  1925. end else begin
  1926. Connection.Send_GetBlocks(0,10,rid);
  1927. end;
  1928. exit;
  1929. end;
  1930. TLog.NewLog(ltdebug,CT_LogSender,'Starting GetNewBlockChainFromClient at client:'+Connection.ClientRemoteAddr+
  1931. ' with OperationBlock:'+TPCOperationsComp.OperationBlockToText(Connection.FRemoteOperationBlock)+' (My block: '+TPCOperationsComp.OperationBlockToText(TNode.Node.Bank.LastOperationBlock)+')');
  1932. // NOTE: FRemoteOperationBlock.block >= TNode.Node.Bank.BlocksCount
  1933. // First capture same block than me (TNode.Node.Bank.BlocksCount-1) to check if i'm an orphan block...
  1934. my_op := TNode.Node.Bank.LastOperationBlock;
  1935. If Not Do_GetOperationBlock(my_op.block,5000,client_op) then begin
  1936. TLog.NewLog(lterror,CT_LogSender,'Cannot receive information about my block ('+inttostr(my_op.block)+')...');
  1937. // Disabled at Build 1.0.6 > Connection.DisconnectInvalidClient(false,'Cannot receive information about my block ('+inttostr(my_op.block)+')... Invalid client. Disconnecting');
  1938. Exit;
  1939. end;
  1940. // New Build 2.1.7 - Check valid operationblock
  1941. If Not TPCSafeBox.IsValidOperationBlock(client_op,errors) then begin
  1942. Connection.DisconnectInvalidClient(false,'Received invalid operation block '+TPCOperationsComp.OperationBlockToText(client_op)+' errors: '+errors);
  1943. Exit;
  1944. end;
  1945. if (NOT TPCOperationsComp.EqualsOperationBlock(my_op,client_op)) then begin
  1946. if (my_op.protocol_version > client_op.protocol_version) then begin // Version 4.0.2 protection against going back to previous protocol with highest blockchain
  1947. TPCOperationsComp.OperationBlockToText(my_op);
  1948. TLog.NewLog(lterror,CT_LogSender,Format('Detected an orphan highest blockchain in an old protocol. Detected: %s - My data: %s',[TPCOperationsComp.OperationBlockToText(client_op),TPCOperationsComp.OperationBlockToText(my_op)]));
  1949. Connection.DisconnectInvalidClient(false,'Detected an orphan highest blockchain in an old protocol');
  1950. Exit;
  1951. end;
  1952. TLog.NewLog(ltinfo,CT_LogSender,'My blockchain is not equal... received: '+TPCOperationsComp.OperationBlockToText(client_op)+' My: '+TPCOperationsComp.OperationBlockToText(my_op));
  1953. if Not FindLastSameBlockByOperationsBlock(0,client_op.block,client_op) then begin
  1954. Connection.DisconnectInvalidClient(false,'No found any base block to start process...');
  1955. Exit;
  1956. end else begin
  1957. // Move operations to orphan folder... (temporal... waiting for a confirmation)
  1958. if (TNode.Node.Bank.Storage.FirstBlock<client_op.block) then begin
  1959. TLog.NewLog(ltinfo,CT_LogSender,'Found base new block: '+TPCOperationsComp.OperationBlockToText(client_op));
  1960. DownloadNewBlockchain(client_op.block+1,False);
  1961. end else begin
  1962. TLog.NewLog(ltinfo,CT_LogSender,'Found base new block: '+TPCOperationsComp.OperationBlockToText(client_op)+' lower than saved:'+IntToStr(TNode.Node.Bank.Storage.FirstBlock));
  1963. DownloadSafeBox(False);
  1964. end;
  1965. end;
  1966. end else begin
  1967. TLog.NewLog(ltinfo,CT_LogSender,'My blockchain is ok! Need to download new blocks starting at '+inttostr(my_op.block+1));
  1968. // High to new value:
  1969. DownloadNewBlockchain(my_op.block+1,True);
  1970. end;
  1971. Finally
  1972. TLog.NewLog(ltdebug,CT_LogSender,'Finalizing');
  1973. FLockGettingNewBlockChainFromClient.Release;
  1974. end;
  1975. end;
  1976. class function TNetData.HeaderDataToText(const HeaderData: TNetHeaderData): String;
  1977. begin
  1978. Result := CT_NetTransferType[HeaderData.header_type]+' Operation:'+TNetData.OperationToText(HeaderData.operation);
  1979. if HeaderData.is_error then begin
  1980. Result := Result +' ERRCODE:'+Inttostr(HeaderData.error_code)+' ERROR:'+HeaderData.error_text;
  1981. end else begin
  1982. Result := Result +' ReqId:'+Inttostr(HeaderData.request_id)+' BufferSize:'+Inttostr(HeaderData.buffer_data_length);
  1983. end;
  1984. end;
  1985. procedure TNetData.IncStatistics(incActiveConnections, incClientsConnections,
  1986. incServersConnections,incServersConnectionsWithResponse: Integer; incBytesReceived, incBytesSend: Int64);
  1987. begin
  1988. // Multithread prevention
  1989. FNodeServersAddresses.FCritical.Acquire;
  1990. Try
  1991. FNetStatistics.ActiveConnections := FNetStatistics.ActiveConnections + incActiveConnections;
  1992. FNetStatistics.ClientsConnections := FNetStatistics.ClientsConnections + incClientsConnections;
  1993. FNetStatistics.ServersConnections := FNetStatistics.ServersConnections + incServersConnections;
  1994. FNetStatistics.ServersConnectionsWithResponse := FNetStatistics.ServersConnectionsWithResponse + incServersConnectionsWithResponse;
  1995. if (incActiveConnections>0) then FNetStatistics.TotalConnections := FNetStatistics.TotalConnections + incActiveConnections;
  1996. if (incClientsConnections>0) then FNetStatistics.TotalClientsConnections := FNetStatistics.TotalClientsConnections + incClientsConnections;
  1997. if (incServersConnections>0) then FNetStatistics.TotalServersConnections := FNetStatistics.TotalServersConnections + incServersConnections;
  1998. FNetStatistics.BytesReceived := FNetStatistics.BytesReceived + incBytesReceived;
  1999. FNetStatistics.BytesSend := FNetStatistics.BytesSend + incBytesSend;
  2000. Finally
  2001. FNodeServersAddresses.FCritical.Release;
  2002. End;
  2003. NotifyStatisticsChanged;
  2004. if (incBytesReceived<>0) Or (incBytesSend<>0) then begin
  2005. NotifyNetConnectionUpdated;
  2006. end;
  2007. end;
  2008. function TNetData.IsGettingNewBlockChainFromClient(var status: String): Boolean;
  2009. begin
  2010. if FLockGettingNewBlockChainFromClient.TryEnter then begin
  2011. try
  2012. Result := False;
  2013. status := '';
  2014. finally
  2015. FLockGettingNewBlockChainFromClient.Release;
  2016. end;
  2017. end else begin
  2018. status := FNewBlockChainFromClientStatus;
  2019. Result := True;
  2020. end;
  2021. end;
  2022. procedure TNetData.SetMaxNodeServersAddressesBuffer(AValue: Integer);
  2023. begin
  2024. if FMaxNodeServersAddressesBuffer=AValue then Exit;
  2025. if (AValue<CT_MIN_NODESERVERS_BUFFER) then FMaxNodeServersAddressesBuffer:=CT_MIN_NODESERVERS_BUFFER
  2026. else if (AValue>CT_MAX_NODESERVERS_BUFFER) then FMaxNodeServersAddressesBuffer:=CT_MAX_NODESERVERS_BUFFER
  2027. else FMaxNodeServersAddressesBuffer:=AValue;
  2028. end;
  2029. procedure TNetData.SetMaxServersConnected(AValue: Integer);
  2030. begin
  2031. if FMaxServersConnected=AValue then Exit;
  2032. if AValue<1 then FMaxServersConnected:=1
  2033. else FMaxServersConnected:=AValue;
  2034. if FMaxServersConnected<FMinServersConnected then FMinServersConnected:=FMaxServersConnected;
  2035. end;
  2036. procedure TNetData.SetMinFutureBlocksToDownloadNewSafebox(const Value: Integer);
  2037. begin
  2038. // Will allow a minimum of 200 future blocks fo enable download a new safebox
  2039. if (Value<=200) then FMinFutureBlocksToDownloadNewSafebox := 0
  2040. else FMinFutureBlocksToDownloadNewSafebox := Value;
  2041. end;
  2042. procedure TNetData.SetMinServersConnected(AValue: Integer);
  2043. begin
  2044. if FMinServersConnected=AValue then Exit;
  2045. if AValue<1 then FMinServersConnected:=1
  2046. else FMinServersConnected:=AValue;
  2047. if FMaxServersConnected<FMinServersConnected then FMaxServersConnected:=FMinServersConnected;
  2048. end;
  2049. class function TNetData.NetData: TNetData;
  2050. begin
  2051. if Not Assigned(_NetData) then begin
  2052. _NetData := TNetData.Create(nil);
  2053. end;
  2054. result := _NetData;
  2055. end;
  2056. class function TNetData.NetDataExists: Boolean;
  2057. begin
  2058. Result := Assigned(_NetData);
  2059. end;
  2060. function TNetData.NewRequestId: Cardinal;
  2061. begin
  2062. Inc(FLastRequestId);
  2063. Result := FLastRequestId;
  2064. end;
  2065. procedure TNetData.Notification(AComponent: TComponent; Operation: TOperation);
  2066. Var l : TList<TNetConnection>;
  2067. begin
  2068. inherited;
  2069. if (Operation=OpRemove) and Assigned(AComponent) and (AComponent is TNetConnection) then begin
  2070. if not (csDestroying in ComponentState) then begin
  2071. l := FNetConnections.LockList;
  2072. try
  2073. if l.Remove(TNetConnection(AComponent))>=0 then begin
  2074. NotifyNetConnectionUpdated;
  2075. end;
  2076. finally
  2077. FNetConnections.UnlockList;
  2078. end;
  2079. end;
  2080. end;
  2081. end;
  2082. procedure TNetData.NotifyBlackListUpdated;
  2083. begin
  2084. FNetDataNotifyEventsThread.FNotifyOnBlackListUpdated := true;
  2085. end;
  2086. procedure TNetData.NotifyConnectivityChanged;
  2087. begin
  2088. FOnConnectivityChanged.Invoke(Self);
  2089. end;
  2090. procedure TNetData.NotifyNetConnectionUpdated;
  2091. begin
  2092. FNetDataNotifyEventsThread.FNotifyOnNetConnectionsUpdated := true;
  2093. end;
  2094. procedure TNetData.NotifyNodeServersUpdated;
  2095. begin
  2096. FNetDataNotifyEventsThread.FNotifyOnNodeServersUpdated := true;
  2097. end;
  2098. procedure TNetData.NotifyReceivedHelloMessage;
  2099. begin
  2100. FNetDataNotifyEventsThread.FNotifyOnReceivedHelloMessage := true;
  2101. end;
  2102. procedure TNetData.NotifyStatisticsChanged;
  2103. begin
  2104. FNetDataNotifyEventsThread.FNotifyOnStatisticsChanged := true;
  2105. end;
  2106. procedure TNetData.OnReadingNewSafeboxProgressNotify(sender: TObject; const mesage: String; curPos, totalCount: Int64);
  2107. Var pct : String;
  2108. begin
  2109. if (totalCount>0) then pct := FormatFloat('0.00',curPos*100/totalCount)+'%' else pct := '';
  2110. FNewBlockChainFromClientStatus := Format('Checking new safebox: %s %s',[mesage,pct]);
  2111. end;
  2112. class function TNetData.OperationToText(operation: Word): String;
  2113. begin
  2114. case operation of
  2115. CT_NetOp_Hello : Result := 'HELLO';
  2116. CT_NetOp_Error : Result := 'ERROR';
  2117. CT_NetOp_GetBlocks : Result := 'GET_BLOCKS';
  2118. CT_NetOp_Message : Result := 'MESSAGE';
  2119. CT_NetOp_GetBlockHeaders : Result := 'GET_BLOCK_HEADERS';
  2120. CT_NetOp_NewBlock : Result := 'NEW_BLOCK';
  2121. CT_NetOp_NewBlock_Fast_Propagation : Result := 'NEW_BLOCK_FAST_PROPAGATION';
  2122. CT_NetOp_GetBlockchainOperations : Result := 'GET_BLOCKCHAIN_OPERATIONS';
  2123. CT_NetOp_AddOperations : Result := 'ADD_OPERATIONS';
  2124. CT_NetOp_GetSafeBox : Result := 'GET_SAFEBOX';
  2125. CT_NetOp_GetPendingOperations : Result := 'GET_PENDING_OPERATIONS';
  2126. CT_NetOp_GetAccount : Result := 'GET_ACCOUNT';
  2127. CT_NetOp_GetPubkeyAccounts : Result := 'GET_PUBKEY_ACCOUNTS';
  2128. else Result := 'UNKNOWN_OPERATION_'+Inttohex(operation,4);
  2129. end;
  2130. end;
  2131. function TNetData.PendingRequest(Sender: TNetConnection; var requests_data : String): Integer;
  2132. Var P : PNetRequestRegistered;
  2133. i : Integer;
  2134. l : TList<Pointer>;
  2135. begin
  2136. requests_data := '';
  2137. l := FRegisteredRequests.LockList;
  2138. Try
  2139. if Assigned(Sender) then begin
  2140. Result := 0;
  2141. for i := l.Count - 1 downto 0 do begin
  2142. if (PNetRequestRegistered(l[i])^.NetClient=Sender) then begin
  2143. requests_data := requests_data+'Op:'+OperationToText(PNetRequestRegistered(l[i])^.Operation)+' Id:'+Inttostr(PNetRequestRegistered(l[i])^.RequestId)+' - ';
  2144. inc(Result);
  2145. end;
  2146. end;
  2147. end else Result := l.Count;
  2148. Finally
  2149. FRegisteredRequests.UnlockList;
  2150. End;
  2151. end;
  2152. procedure TNetData.RegisterRequest(Sender: TNetConnection; operation: Word; request_id: Cardinal);
  2153. Var P : PNetRequestRegistered;
  2154. l : TList<Pointer>;
  2155. begin
  2156. l := FRegisteredRequests.LockList;
  2157. Try
  2158. New(P);
  2159. P^.NetClient := Sender;
  2160. P^.Operation := operation;
  2161. P^.RequestId := request_id;
  2162. P^.SendTime := Now;
  2163. l.Add(P);
  2164. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Registering request to '+Sender.ClientRemoteAddr+' Op:'+OperationToText(operation)+' Id:'+inttostr(request_id)+' Total pending:'+Inttostr(l.Count));{$ENDIF}
  2165. Finally
  2166. FRegisteredRequests.UnlockList;
  2167. End;
  2168. end;
  2169. procedure TNetData.SetNetConnectionsActive(const Value: Boolean);
  2170. begin
  2171. FNetConnectionsActive := Value;
  2172. NotifyConnectivityChanged;
  2173. if FNetConnectionsActive then DiscoverServers
  2174. else DisconnectClients;
  2175. end;
  2176. function TNetData.UnRegisterRequest(Sender: TNetConnection; operation: Word; request_id: Cardinal): Boolean;
  2177. Var P : PNetRequestRegistered;
  2178. i : Integer;
  2179. l : TList<Pointer>;
  2180. begin
  2181. Result := false;
  2182. l := FRegisteredRequests.LockList;
  2183. try
  2184. for i := l.Count - 1 downto 0 do begin
  2185. P := l[i];
  2186. if (P^.NetClient=Sender) And
  2187. ( ((Operation=P^.Operation) And (request_id = P^.RequestId))
  2188. Or
  2189. ((operation=0) And (request_id=0)) ) then begin
  2190. l.Delete(i);
  2191. Dispose(P);
  2192. Result := true;
  2193. {$IFDEF HIGHLOG}
  2194. if Assigned(Sender.FTcpIpClient) then begin
  2195. TLog.NewLog(ltdebug,Classname,'Unregistering request to '+Sender.ClientRemoteAddr+' Op:'+OperationToText(operation)+' Id:'+inttostr(request_id)+' Total pending:'+Inttostr(l.Count));
  2196. end else begin
  2197. TLog.NewLog(ltdebug,Classname,'Unregistering request to (NIL) Op:'+OperationToText(operation)+' Id:'+inttostr(request_id)+' Total pending:'+Inttostr(l.Count));
  2198. end;
  2199. {$ENDIF}
  2200. end;
  2201. end;
  2202. finally
  2203. FRegisteredRequests.UnlockList;
  2204. end;
  2205. end;
  2206. { TNetServer }
  2207. constructor TNetServer.Create;
  2208. begin
  2209. inherited;
  2210. MaxConnections := CT_MaxClientsConnected;
  2211. NetTcpIpClientClass := TBufferedNetTcpIpClient;
  2212. Port := CT_NetServer_Port;
  2213. end;
  2214. procedure TNetServer.OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient);
  2215. Var n : TNetServerClient;
  2216. DebugStep : String;
  2217. tc : TTickCount;
  2218. begin
  2219. DebugStep := '';
  2220. Try
  2221. if Not Client.Connected then exit;
  2222. // NOTE: I'm in a separate thread
  2223. // While in this function the ClientSocket connection will be active, when finishes the ClientSocket will be destroyed
  2224. TLog.NewLog(ltInfo,Classname,'Starting ClientSocket accept '+Client.ClientRemoteAddr);
  2225. n := TNetServerClient.Create(Nil);
  2226. Try
  2227. DebugStep := 'Assigning client';
  2228. n.SetClient(Client);
  2229. TNetData.NetData.IncStatistics(1,1,0,0,0,0);
  2230. TNetData.NetData.NodeServersAddresses.CleanBlackList(False);
  2231. DebugStep := 'Checking blacklisted';
  2232. if (TNetData.NetData.NodeServersAddresses.IsBlackListed(Client.RemoteHost)) then begin
  2233. // Invalid!
  2234. TLog.NewLog(ltinfo,Classname,'Refusing Blacklist ip: '+Client.ClientRemoteAddr);
  2235. n.SendError(ntp_autosend,CT_NetOp_Error, 0,CT_NetError_IPBlackListed,'Your IP is blacklisted:'+Client.ClientRemoteAddr);
  2236. // Wait some time before close connection
  2237. sleep(5000);
  2238. end else begin
  2239. DebugStep := 'Processing buffer and sleep...';
  2240. while (n.Connected) And (Active) do begin
  2241. n.DoProcessBuffer;
  2242. Sleep(10);
  2243. end;
  2244. end;
  2245. Finally
  2246. Try
  2247. TLog.NewLog(ltdebug,Classname,'Finalizing ServerAccept '+IntToHex(PtrInt(n),8)+' '+n.ClientRemoteAddr);
  2248. DebugStep := 'Disconnecting NetServerClient';
  2249. n.Connected := false;
  2250. tc := TPlatform.GetTickCount;
  2251. Repeat
  2252. sleep(10); // 1.5.4 -> To prevent that not client disconnected (and not called OnDisconnect), increase sleep time
  2253. Until (Not n.Connected) Or (tc + 5000 < TPlatform.GetTickCount);
  2254. sleep(5);
  2255. DebugStep := 'Assigning old client';
  2256. n.SetClient( NetTcpIpClientClass.Create(Nil) );
  2257. sleep(500); // Delay - Sleep time before destroying (1.5.3)
  2258. DebugStep := 'Freeing NetServerClient';
  2259. Finally
  2260. n.Free;
  2261. End;
  2262. End;
  2263. Except
  2264. On E:Exception do begin
  2265. TLog.NewLog(lterror,ClassName,'Exception processing client thread at step: '+DebugStep+' - ('+E.ClassName+') '+E.Message);
  2266. end;
  2267. End;
  2268. end;
  2269. procedure TNetServer.SetActive(const Value: Boolean);
  2270. begin
  2271. if Value then begin
  2272. TLog.NewLog(ltinfo,Classname,'Activating server on port '+IntToStr(Port));
  2273. end else begin
  2274. TLog.NewLog(ltinfo,Classname,'Closing server');
  2275. end;
  2276. inherited;
  2277. if Active then begin
  2278. // TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
  2279. end else if TNetData.NetDataExists then begin
  2280. TNetData.NetData.DisconnectClients;
  2281. end;
  2282. end;
  2283. procedure TNetServer.SetMaxConnections(AValue: Integer);
  2284. begin
  2285. inherited SetMaxConnections(AValue);
  2286. TNetData.NetData.FMaxConnections:=AValue;
  2287. end;
  2288. { TNetConnection }
  2289. function TNetConnection.AddOperationsToBufferForSend(Operations: TOperationsHashTree): Integer;
  2290. Var i : Integer;
  2291. begin
  2292. Result := 0;
  2293. try
  2294. FBufferLock.Acquire;
  2295. Try
  2296. for i := 0 to Operations.OperationsCount - 1 do begin
  2297. if FBufferReceivedOperationsHash.IndexOf(Operations.GetOperation(i).Sha256)<0 then begin
  2298. FBufferReceivedOperationsHash.Add(Operations.GetOperation(i).Sha256);
  2299. If FBufferToSendOperations.IndexOfOperation(Operations.GetOperation(i))<0 then begin
  2300. FBufferToSendOperations.AddOperationToHashTree(Operations.GetOperation(i));
  2301. Inc(Result);
  2302. end;
  2303. end;
  2304. end;
  2305. finally
  2306. FBufferLock.Release;
  2307. end;
  2308. Except
  2309. On E:Exception do begin
  2310. TLog.NewLog(ltError,ClassName,'Error at AddOperationsToBufferForSend ('+E.ClassName+'): '+E.Message);
  2311. Result := 0;
  2312. end;
  2313. end;
  2314. end;
  2315. function TNetConnection.ClientRemoteAddr: String;
  2316. begin
  2317. If Assigned(FTcpIpClient) then begin
  2318. Result := FtcpIpClient.ClientRemoteAddr
  2319. end else Result := 'NIL';
  2320. end;
  2321. function TNetConnection.ConnectTo(ServerIP: String; ServerPort: Word) : Boolean;
  2322. Var nsa : TNodeServerAddress;
  2323. i : Integer;
  2324. begin
  2325. If FIsConnecting then Exit;
  2326. Try
  2327. FIsConnecting:=True;
  2328. if Client.Connected then Client.Disconnect;
  2329. TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
  2330. Try
  2331. Client.RemoteHost := ServerIP;
  2332. if ServerPort<=0 then ServerPort := CT_NetServer_Port;
  2333. Client.RemotePort := ServerPort;
  2334. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Trying to connect to a server at: '+ClientRemoteAddr);{$ENDIF}
  2335. TNetData.NetData.NodeServersAddresses.GetNodeServerAddress(Client.RemoteHost,Client.RemotePort,true,nsa);
  2336. nsa.netConnection := Self;
  2337. TNetData.NetData.NodeServersAddresses.SetNodeServerAddress(nsa);
  2338. TNetData.NetData.NotifyNetConnectionUpdated;
  2339. Result := Client.Connect;
  2340. Finally
  2341. FNetLock.Release;
  2342. End;
  2343. if Result then begin
  2344. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Connected to a possible server at: '+ClientRemoteAddr);{$ENDIF}
  2345. TNetData.NetData.NodeServersAddresses.GetNodeServerAddress(Client.RemoteHost,Client.RemotePort,true,nsa);
  2346. nsa.netConnection := Self;
  2347. nsa.last_connection_by_me := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
  2348. TNetData.NetData.NodeServersAddresses.SetNodeServerAddress(nsa);
  2349. Result := Send_Hello(ntp_request,TNetData.NetData.NewRequestId);
  2350. end else begin
  2351. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Cannot connect to a server at: '+ClientRemoteAddr);{$ENDIF}
  2352. end;
  2353. finally
  2354. FIsConnecting:=False;
  2355. end;
  2356. end;
  2357. constructor TNetConnection.Create(AOwner: TComponent);
  2358. begin
  2359. inherited;
  2360. FIsConnecting:=False;
  2361. FIsDownloadingBlocks := false;
  2362. FHasReceivedData := false;
  2363. FNetProtocolVersion.protocol_version := 0; // 0 = unknown
  2364. FNetProtocolVersion.protocol_available := 0;
  2365. FAlertedForNewProtocolAvailable := false;
  2366. FDoFinalizeConnection := false;
  2367. FClientAppVersion := '';
  2368. FClientPublicKey := CT_TECDSA_Public_Nul;
  2369. FCreatedTime := Now;
  2370. FIsMyselfServer := false;
  2371. FTimestampDiff := 0;
  2372. FIsWaitingForResponse := false;
  2373. FClientBufferRead := TMemoryStream.Create;
  2374. FNetLock := TPCCriticalSection.Create('TNetConnection_NetLock');
  2375. FLastHelloTS := 0;
  2376. FLastDataReceivedTS := 0;
  2377. FLastDataSendedTS := 0;
  2378. FRandomWaitSecondsSendHello := (CT_NewLineSecondsAvg DIV 3) + Random(CT_NewLineSecondsAvg DIV 2);
  2379. FTcpIpClient := Nil;
  2380. FRemoteOperationBlock := CT_OperationBlock_NUL;
  2381. FRemoteAccumulatedWork := 0;
  2382. SetClient( TBufferedNetTcpIpClient.Create(Self) );
  2383. TNetData.NetData.FNetConnections.Add(Self);
  2384. TNetData.NetData.NotifyNetConnectionUpdated;
  2385. FBufferLock := TPCCriticalSection.Create('TNetConnection_BufferLock');
  2386. FBufferReceivedOperationsHash := TOrderedRawList.Create;
  2387. FBufferToSendOperations := TOperationsHashTree.Create;
  2388. FClientTimestampIp := '';
  2389. end;
  2390. destructor TNetConnection.Destroy;
  2391. begin
  2392. Try
  2393. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,ClassName,'Destroying '+Classname+' '+IntToHex(PtrInt(Self),8));{$ENDIF}
  2394. Connected := false;
  2395. Finally
  2396. TNetData.NetData.NodeServersAddresses.DeleteNetConnection(Self);
  2397. TNetData.NetData.FNetConnections.Remove(Self);
  2398. End;
  2399. TNetData.NetData.UnRegisterRequest(Self,0,0);
  2400. Try
  2401. TNetData.NetData.NotifyNetConnectionUpdated;
  2402. Finally
  2403. FreeAndNil(FNetLock);
  2404. FreeAndNil(FClientBufferRead);
  2405. FreeAndNil(FTcpIpClient);
  2406. FreeAndNil(FBufferLock);
  2407. FreeAndNil(FBufferReceivedOperationsHash);
  2408. FreeAndNil(FBufferToSendOperations);
  2409. inherited;
  2410. End;
  2411. end;
  2412. procedure TNetConnection.DisconnectInvalidClient(ItsMyself : Boolean; const why: String);
  2413. Var include_in_list : Boolean;
  2414. ns : TNodeServerAddress;
  2415. aux_s : String;
  2416. begin
  2417. FIsDownloadingBlocks := false;
  2418. if ItsMyself then begin
  2419. TLog.NewLog(ltInfo,Classname,'Disconecting myself '+ClientRemoteAddr+' > '+Why)
  2420. end else begin
  2421. TLog.NewLog(lterror,Classname,'Disconecting '+ClientRemoteAddr+' > '+Why);
  2422. end;
  2423. FIsMyselfServer := ItsMyself;
  2424. aux_s := Client.RemoteHost;
  2425. include_in_list := (Not SameText(aux_s,'localhost')) And (Not SameText('127.',aux_s.Substring(0,4)))
  2426. And (Not SameText('192.168.',aux_s.Substring(0,8)))
  2427. And (Not SameText('10.',aux_s.Substring(0,3)));
  2428. if include_in_list then begin
  2429. If TNetData.NetData.NodeServersAddresses.GetNodeServerAddress(Client.RemoteHost,Client.RemotePort,true,ns) then begin
  2430. ns.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  2431. ns.its_myself := ItsMyself;
  2432. ns.BlackListText := Why;
  2433. ns.is_blacklisted := true;
  2434. TNetData.NetData.NodeServersAddresses.SetNodeServerAddress(ns);
  2435. end;
  2436. end else if ItsMyself then begin
  2437. If TNetData.NetData.NodeServersAddresses.GetNodeServerAddress(Client.RemoteHost,Client.RemotePort,true,ns) then begin
  2438. ns.its_myself := ItsMyself;
  2439. TNetData.NetData.NodeServersAddresses.SetNodeServerAddress(ns);
  2440. end;
  2441. end;
  2442. TNetData.NetData.IpInfos.LogDisconnect(Client.RemoteHost,ClientRemoteAddr+' '+Why,ItsMyself);
  2443. Connected := False;
  2444. TNetData.NetData.NotifyBlackListUpdated;
  2445. TNetData.NetData.NotifyNodeServersUpdated;
  2446. end;
  2447. procedure TNetConnection.DoProcessBuffer;
  2448. Var HeaderData : TNetHeaderData;
  2449. ms : TMemoryStream;
  2450. ops : String;
  2451. iPending : Integer;
  2452. begin
  2453. if FDoFinalizeConnection then begin
  2454. if Connected then begin
  2455. TLog.NewLog(ltdebug,Classname,'Executing DoFinalizeConnection at client '+ClientRemoteAddr);
  2456. Connected := false;
  2457. end;
  2458. end;
  2459. if Not Connected then exit;
  2460. ms := TMemoryStream.Create;
  2461. try
  2462. if Not FIsWaitingForResponse then begin
  2463. DoSendAndWaitForResponse(0,0,Nil,ms,0,HeaderData);
  2464. end;
  2465. finally
  2466. ms.Free;
  2467. end;
  2468. If ((FLastDataReceivedTS>0) Or ( NOT (Self is TNetServerClient)))
  2469. and (TPlatform.GetElapsedMilliseconds(FLastHelloTS)>(1000*FRandomWaitSecondsSendHello)) then begin
  2470. iPending := TNetData.NetData.PendingRequest(Self,ops);
  2471. If iPending>=3 then begin
  2472. TLog.NewLog(ltDebug,Classname,'Pending requests without response... closing connection to '+ClientRemoteAddr+' > '+ops);
  2473. Connected := false;
  2474. end else begin
  2475. if iPending>0 then begin
  2476. TLog.NewLog(ltDebug,Classname,'Sending Hello to check connection to '+ClientRemoteAddr+' > '+ops);
  2477. end;
  2478. Send_Hello(ntp_request,TNetData.NetData.NewRequestId);
  2479. end;
  2480. end else if (Self is TNetServerClient) AND (FLastDataReceivedTS=0) And (FCreatedTime+EncodeTime(0,1,0,0)<Now) then begin
  2481. // Disconnecting client without data...
  2482. TLog.NewLog(ltDebug,Classname,'Disconnecting client without data '+ClientRemoteAddr);
  2483. Connected := false;
  2484. end;
  2485. end;
  2486. procedure TNetConnection.DoProcess_AddOperations(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2487. var c,i : Integer;
  2488. optype : Byte;
  2489. opclass : TPCOperationClass;
  2490. op : TPCOperation;
  2491. operations : TOperationsHashTree;
  2492. errors : String;
  2493. DoDisconnect : Boolean;
  2494. begin
  2495. DoDisconnect := true;
  2496. operations := TOperationsHashTree.Create;
  2497. try
  2498. if HeaderData.header_type<>ntp_autosend then begin
  2499. errors := 'Not autosend';
  2500. exit;
  2501. end;
  2502. if DataBuffer.Size<4 then begin
  2503. errors := 'Invalid databuffer size';
  2504. exit;
  2505. end;
  2506. DataBuffer.Read(c,4);
  2507. for i := 1 to c do begin
  2508. errors := 'Invalid operation '+inttostr(i)+'/'+inttostr(c);
  2509. if not DataBuffer.Read(optype,1)=1 then exit;
  2510. opclass := TPCOperationsComp.GetOperationClassByOpType(optype);
  2511. if Not Assigned(opclass) then exit;
  2512. op := opclass.Create;
  2513. Try
  2514. op.LoadFromNettransfer(DataBuffer);
  2515. operations.AddOperationToHashTree(op);
  2516. Finally
  2517. op.Free;
  2518. End;
  2519. end;
  2520. DoDisconnect := false;
  2521. finally
  2522. try
  2523. if DoDisconnect then begin
  2524. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  2525. end else begin
  2526. // Add to received buffer
  2527. FBufferLock.Acquire;
  2528. Try
  2529. for i := 0 to operations.OperationsCount - 1 do begin
  2530. op := operations.GetOperation(i);
  2531. FBufferReceivedOperationsHash.Add(op.Sha256);
  2532. c := FBufferToSendOperations.IndexOfOperation(op);
  2533. if (c>=0) then begin
  2534. FBufferToSendOperations.Delete(c);
  2535. end;
  2536. end;
  2537. Finally
  2538. FBufferLock.Release;
  2539. End;
  2540. TNode.Node.AddOperations(Self,operations,Nil,errors);
  2541. end;
  2542. finally
  2543. operations.Free;
  2544. end;
  2545. end;
  2546. end;
  2547. procedure TNetConnection.DoProcess_GetBlockchainOperations_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2548. {
  2549. As described on PIP-0015 this will return Operations stored in a specified Block of the Blockchain
  2550. Input:
  2551. operations_count : 4 bytes
  2552. foreach operations_count
  2553. BLOCK_OP_REF : 8 bytes -> BLOCK_OP_REF = (QWord(BlockNumber) SHL 32) BIT-OR QWord(OperationIndex)
  2554. Output:
  2555. operations_count : 4 bytes -> Must match input.operations_count
  2556. foreach operations_count
  2557. op_size : 4 bytes
  2558. op_data : (op_size) bytes
  2559. }
  2560. function GetBlock(bufferOperationsBlock : TList<TPCOperationsComp>; nBlock : Integer) : TPCOperationsComp;
  2561. var i : Integer;
  2562. begin
  2563. // Search at buffer:
  2564. i := 0; Result := Nil;
  2565. while (i<bufferOperationsBlock.Count) And (TPCOperationsComp( bufferOperationsBlock[i] ).OperationBlock.block <> nBlock) do inc(i);
  2566. if (i>=bufferOperationsBlock.Count) then begin
  2567. // Not found !
  2568. Result := TPCOperationsComp.Create(Nil);
  2569. if Not TNode.Node.Bank.LoadOperations(Result,nBlock) then FreeAndNil(Result)
  2570. else bufferOperationsBlock.Add(Result); // Memory leak on v4.0.0
  2571. end else Result := TPCOperationsComp( bufferOperationsBlock[i] );
  2572. end;
  2573. Var input_operations_count, cBlock, cBlockOpIndex, c : Cardinal;
  2574. block_op_ref : UInt64;
  2575. i : Integer;
  2576. bufferOperationsBlock : TList<TPCOperationsComp>;
  2577. opc : TPCOperationsComp;
  2578. outputBuffer : TStream;
  2579. opindexdata : TStream;
  2580. opsdata : TBytes;
  2581. errors : String;
  2582. DoDisconnect : Boolean;
  2583. begin
  2584. errors := 'Invalid GetBlockchainOperations_Request structure';
  2585. DoDisconnect := true;
  2586. outputBuffer := TMemoryStream.Create;
  2587. try
  2588. if HeaderData.header_type<>ntp_request then begin
  2589. errors := 'Not request';
  2590. Exit;
  2591. end;
  2592. if DataBuffer.Read(input_operations_count,SizeOf(input_operations_count))<>SizeOf(input_operations_count) then Exit;
  2593. if (input_operations_count>CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS) then begin
  2594. errors := Format('Inputs %d > %d',[input_operations_count,CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS]);
  2595. Exit;
  2596. end;
  2597. outputBuffer.Write(input_operations_count,SizeOf(input_operations_count));
  2598. bufferOperationsBlock := TList<TPCOperationsComp>.Create;
  2599. opindexdata := TStream.Create;
  2600. Try
  2601. for i := 1 to input_operations_count do begin
  2602. if DataBuffer.Read(block_op_ref,SizeOf(block_op_ref))<>SizeOf(block_op_ref) then begin
  2603. errors := Format('Cannot read enough data at pos %d/%d',[i,input_operations_count]);
  2604. Exit; // read 8 bytes
  2605. end;
  2606. cBlock := block_op_ref SHR 32;
  2607. cBlockOpIndex := Cardinal(block_op_ref AND ($00000000FFFFFFFF));
  2608. opc := GetBlock(bufferOperationsBlock, cBlock);
  2609. if Assigned(opc) then begin
  2610. if (cBlockOpIndex<opc.Count) then begin
  2611. opsdata := opc.Operation[cBlockOpIndex].GetOperationStreamData;
  2612. c := Length(opsdata);
  2613. outputBuffer.Write(c,SizeOf(c));
  2614. outputBuffer.WriteBuffer(opsdata[0],Length(opsdata)); // Fixed bug 4.0.0
  2615. SetLength(opsdata,0);
  2616. end else begin
  2617. // OpIndex not found on block -> Add NIL reference: data 0 size = No operation
  2618. c := 0;
  2619. outputBuffer.Write(c,SizeOf(c));
  2620. end;
  2621. end else begin
  2622. // Block operation not found -> Add NIL reference: data 0 size = No operation
  2623. c := 0;
  2624. outputBuffer.Write(c,SizeOf(c));
  2625. end;
  2626. end;
  2627. DoDisconnect := False;
  2628. // Send back
  2629. outputBuffer.Position := 0;
  2630. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,outputBuffer);
  2631. Finally
  2632. opindexdata.Free;
  2633. for i := 0 to bufferOperationsBlock.Count-1 do begin
  2634. TPCOperationsComp(bufferOperationsBlock[i]).Free;
  2635. end;
  2636. bufferOperationsBlock.Free;
  2637. End;
  2638. finally
  2639. outputBuffer.Free;
  2640. if DoDisconnect then begin
  2641. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  2642. end;
  2643. end;
  2644. end;
  2645. procedure TNetConnection.DoProcess_GetBlocks_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2646. Var b,b_start,b_end:Cardinal;
  2647. op : TPCOperationsComp;
  2648. db : TMemoryStream;
  2649. c : Cardinal;
  2650. errors : String;
  2651. DoDisconnect : Boolean;
  2652. posquantity : Int64;
  2653. begin
  2654. DoDisconnect := true;
  2655. try
  2656. if HeaderData.header_type<>ntp_request then begin
  2657. errors := 'Not request';
  2658. exit;
  2659. end;
  2660. // DataBuffer contains: from and to
  2661. errors := 'Invalid structure';
  2662. if (DataBuffer.Size-DataBuffer.Position<8) then begin
  2663. exit;
  2664. end;
  2665. DataBuffer.Read(b_start,4);
  2666. DataBuffer.Read(b_end,4);
  2667. if (b_start<0) Or (b_start>b_end) then begin
  2668. errors := 'Invalid structure start or end: '+Inttostr(b_start)+' '+Inttostr(b_end);
  2669. exit;
  2670. end;
  2671. if (b_end>=TNetData.NetData.Bank.BlocksCount) then begin
  2672. errors := Format('b_end:%d >= current block:%d b_start:%d',[b_end,TNetData.NetData.Bank.BlocksCount,b_start]);
  2673. b_end := TNetData.NetData.Bank.BlocksCount-1;
  2674. if (b_start>b_end) then begin
  2675. // No data:
  2676. db := TMemoryStream.Create;
  2677. try
  2678. c := 0;
  2679. db.Write(c,4);
  2680. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,db);
  2681. Exit;
  2682. finally
  2683. db.Free;
  2684. end;
  2685. end;
  2686. end;
  2687. DoDisconnect := false;
  2688. db := TMemoryStream.Create;
  2689. try
  2690. op := TPCOperationsComp.Create(TNetData.NetData.bank);
  2691. try
  2692. c := b_end - b_start + 1;
  2693. posquantity := db.position;
  2694. db.Write(c,4);
  2695. c := 0;
  2696. b := b_start;
  2697. for b := b_start to b_end do begin
  2698. inc(c);
  2699. If TNetData.NetData.bank.LoadOperations(op,b) then begin
  2700. op.SaveBlockToStream(false,db);
  2701. end else begin
  2702. SendError(ntp_response,HeaderData.operation,HeaderData.request_id,CT_NetError_InternalServerError,'Operations of block:'+inttostr(b)+' not found');
  2703. exit;
  2704. end;
  2705. // Build 1.0.5 To prevent high data over net in response (Max 2 Mb of data)
  2706. if (db.size>(1024*1024*2)) then begin
  2707. // Stop
  2708. db.position := posquantity;
  2709. db.Write(c,4);
  2710. // BUG of Build 1.0.5 !!! Need to break bucle OH MY GOD!
  2711. db.Position := db.Size;
  2712. break;
  2713. end;
  2714. end;
  2715. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,db);
  2716. finally
  2717. op.Free;
  2718. end;
  2719. finally
  2720. db.Free;
  2721. end;
  2722. TLog.NewLog(ltdebug,Classname,'Sending operations from block '+inttostr(b_start)+' to '+inttostr(b_end));
  2723. finally
  2724. if DoDisconnect then begin
  2725. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  2726. end;
  2727. end;
  2728. end;
  2729. procedure TNetConnection.DoProcess_GetBlocks_Response(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2730. var LTmpOp : TPCOperationsComp;
  2731. LOpCountCardinal,c : Cardinal;
  2732. LOpCount : Integer;
  2733. i : Integer;
  2734. newBlockAccount : TBlockAccount;
  2735. errors : String;
  2736. DoDisconnect : Boolean;
  2737. LBlocks : TList<TPCOperationsComp>;
  2738. LSafeboxTransaction : TPCSafeBoxTransaction;
  2739. begin
  2740. DoDisconnect := true;
  2741. try
  2742. if HeaderData.header_type<>ntp_response then begin
  2743. errors := 'Not response';
  2744. exit;
  2745. end;
  2746. If HeaderData.is_error then begin
  2747. DoDisconnect := false;
  2748. exit; //
  2749. end;
  2750. // DataBuffer contains: from and to
  2751. errors := 'Invalid structure';
  2752. LBlocks := TList<TPCOperationsComp>.Create;
  2753. Try
  2754. if DataBuffer.Size-DataBuffer.Position<4 then begin
  2755. DisconnectInvalidClient(false,'DoProcess_GetBlocks_Response invalid format: '+errors);
  2756. exit;
  2757. end;
  2758. DataBuffer.Read(LOpCountCardinal,4);
  2759. LOpCount := LOpCountCardinal;
  2760. DoDisconnect :=false;
  2761. for i := 0 to LOpCount-1 do begin
  2762. LTmpOp := TPCOperationsComp.Create(nil);
  2763. try
  2764. LTmpOp.bank := TNode.Node.Bank;
  2765. if Not LTmpOp.LoadBlockFromStream(DataBuffer,errors) then begin
  2766. errors := 'Error decoding block '+inttostr(i+1)+'/'+inttostr(LOpCount)+' Errors:'+errors;
  2767. DoDisconnect := true;
  2768. Exit;
  2769. end;
  2770. if (LTmpOp.OperationBlock.block=TNode.Node.Bank.BlocksCount+i) then begin
  2771. TNode.Node.MarkVerifiedECDSASignaturesFromMemPool(LTmpOp); // Improvement speed v4.0.2
  2772. LBlocks.Add(LTmpOp);
  2773. LTmpOp := Nil;
  2774. end else Break;
  2775. finally
  2776. FreeAndNil(LTmpOp);
  2777. end;
  2778. end;
  2779. TPCOperationsBlockValidator.MultiThreadValidateOperationsBlock(LBlocks);
  2780. LSafeboxTransaction := TPCSafeBoxTransaction.Create(TNode.Node.Bank.SafeBox);
  2781. try
  2782. TPCOperationsSignatureValidator.MultiThreadPreValidateSignatures(LSafeboxTransaction,LBlocks,Nil);
  2783. finally
  2784. LSafeboxTransaction.Free;
  2785. end;
  2786. for i := 0 to LBlocks.Count-1 do begin
  2787. if (LBlocks[i].OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
  2788. if (TNode.Node.Bank.AddNewBlockChainBlock(LBlocks[i],TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock, newBlockAccount,errors)) then begin
  2789. // Ok, one more!
  2790. end else begin
  2791. // Is not a valid entry????
  2792. // Perhaps an orphan blockchain: Me or Client!
  2793. TLog.NewLog(ltinfo,Classname,'Distinct operation block found! My:'+
  2794. TPCOperationsComp.OperationBlockToText(TNode.Node.Bank.SafeBox.Block(TNode.Node.Bank.BlocksCount-1).blockchainInfo)+
  2795. ' remote:'+TPCOperationsComp.OperationBlockToText(LBlocks[i].OperationBlock)+' Errors: '+errors);
  2796. end;
  2797. end else begin
  2798. // Receiving an unexpected operationblock
  2799. TLog.NewLog(lterror,classname,'Received a distinct block, finalizing: '+TPCOperationsComp.OperationBlockToText(LBlocks[i].OperationBlock)+' (My block: '+TPCOperationsComp.OperationBlockToText(TNode.Node.Bank.LastOperationBlock)+')' );
  2800. FIsDownloadingBlocks := false;
  2801. exit;
  2802. end;
  2803. sleep(1);
  2804. end;
  2805. FIsDownloadingBlocks := false;
  2806. if ((LOpCount>0) And (FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount)) then begin
  2807. Send_GetBlocks(TNode.Node.Bank.BlocksCount,100,c);
  2808. end else begin
  2809. // No more blocks to download, download Pending operations
  2810. DoProcess_GetPendingOperations;
  2811. end;
  2812. TNode.Node.NotifyBlocksChanged;
  2813. Finally
  2814. for i := 0 to LBlocks.Count-1 do begin
  2815. LBlocks[i].Free;
  2816. end;
  2817. LBlocks.Free;
  2818. End;
  2819. Finally
  2820. if DoDisconnect then begin
  2821. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  2822. end;
  2823. end;
  2824. end;
  2825. procedure TNetConnection.DoProcess_GetOperationsBlock_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2826. Const CT_Max_Positions = 10;
  2827. Var inc_b,b,b_start,b_end, total_b:Cardinal;
  2828. db,msops : TMemoryStream;
  2829. errors, blocksstr : String;
  2830. DoDisconnect : Boolean;
  2831. ob : TOperationBlock;
  2832. begin
  2833. blocksstr := '';
  2834. DoDisconnect := true;
  2835. try
  2836. if HeaderData.header_type<>ntp_request then begin
  2837. errors := 'Not request';
  2838. exit;
  2839. end;
  2840. errors := 'Invalid structure';
  2841. if (DataBuffer.Size-DataBuffer.Position<8) then begin
  2842. exit;
  2843. end;
  2844. DataBuffer.Read(b_start,4);
  2845. DataBuffer.Read(b_end,4);
  2846. if (b_start<0) Or (b_start>b_end) then begin
  2847. errors := 'Invalid start ('+Inttostr(b_start)+') or end ('+Inttostr(b_end)+') of count ('+Inttostr(TNode.Node.Bank.BlocksCount)+')';
  2848. exit;
  2849. end;
  2850. DoDisconnect := false;
  2851. if (b_start>=TNode.Node.Bank.BlocksCount) then begin
  2852. SendError(ntp_response,HeaderData.operation,HeaderData.request_id,CT_NetError_NotFound,Format('Block %d not found',[b_start]));
  2853. Exit;
  2854. end;
  2855. if (b_end>=TNode.Node.Bank.BlocksCount) then b_end := TNode.Node.Bank.BlocksCount-1;
  2856. inc_b := ((b_end - b_start) DIV CT_Max_Positions)+1;
  2857. msops := TMemoryStream.Create;
  2858. try
  2859. b := b_start;
  2860. total_b := 0;
  2861. repeat
  2862. ob := TNode.Node.Bank.SafeBox.Block(b).blockchainInfo;
  2863. If TPCOperationsComp.SaveOperationBlockToStream(ob,msops) then begin
  2864. blocksstr := blocksstr + inttostr(b)+',';
  2865. b := b + inc_b;
  2866. inc(total_b);
  2867. end else begin
  2868. errors := 'ERROR DEV 20170522-1 block:'+inttostr(b);
  2869. SendError(ntp_response,HeaderData.operation,HeaderData.request_id,CT_NetError_InternalServerError,errors);
  2870. exit;
  2871. end;
  2872. until (b > b_end);
  2873. db := TMemoryStream.Create;
  2874. try
  2875. db.Write(total_b,4);
  2876. db.WriteBuffer(msops.Memory^,msops.Size);
  2877. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,db);
  2878. finally
  2879. db.Free;
  2880. end;
  2881. finally
  2882. msops.Free;
  2883. end;
  2884. TLog.NewLog(ltdebug,Classname,'Sending '+inttostr(total_b)+' operations block from block '+inttostr(b_start)+' to '+inttostr(b_end)+' '+blocksstr);
  2885. finally
  2886. if DoDisconnect then begin
  2887. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  2888. end;
  2889. end;
  2890. end;
  2891. procedure TNetConnection.DoProcess_GetSafeBox_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2892. Var _blockcount : Cardinal;
  2893. _safeboxHash : TRawBytes;
  2894. _from,_to : Cardinal;
  2895. sbStream : TStream;
  2896. responseStream : TStream;
  2897. antPos : Int64;
  2898. sbHeader : TPCSafeBoxHeader;
  2899. errors : String;
  2900. begin
  2901. {
  2902. This call is used to obtain a chunk of the safebox
  2903. Request:
  2904. BlockCount (4 bytes) - The safebox checkpoint
  2905. SafeboxHash (TRawBytes) - The safeboxhash of that checkpoint
  2906. StartPos (4 bytes) - The start index (0..BlockCount-1)
  2907. EndPos (4 bytes) - The final index (0..BlockCount-1)
  2908. If valid info:
  2909. - If available will return a LZIP chunk of safebox
  2910. - If not available (requesting for an old safebox) will retun not available
  2911. If not valid will disconnect
  2912. }
  2913. DataBuffer.Read(_blockcount,SizeOf(_blockcount));
  2914. TStreamOp.ReadAnsiString(DataBuffer,_safeboxHash);
  2915. DataBuffer.Read(_from,SizeOf(_from));
  2916. DataBuffer.Read(_to,SizeOf(_to));
  2917. // Protections:
  2918. if (_from>_to) Or (_from + CT_MAX_SAFEBOXCHUNK_BLOCKS <= _to) then begin
  2919. DisconnectInvalidClient(False,Format('Invalid GetSafebox values on request. From:%d to:%d',[_from,_to]));
  2920. Exit;
  2921. end;
  2922. //
  2923. sbStream := TNode.Node.Bank.Storage.CreateSafeBoxStream(_blockcount);
  2924. try
  2925. responseStream := TMemoryStream.Create;
  2926. try
  2927. If Not Assigned(sbStream) then begin
  2928. SendError(ntp_response,HeaderData.operation,CT_NetError_SafeboxNotFound,HeaderData.request_id,Format('Safebox for block %d not found',[_blockcount]));
  2929. exit;
  2930. end;
  2931. antPos := sbStream.Position;
  2932. TPCSafeBox.LoadSafeBoxStreamHeader(sbStream,sbHeader);
  2933. If Not TBaseType.Equals(sbHeader.safeBoxHash,_safeboxHash) then begin
  2934. DisconnectInvalidClient(false,Format('Invalid safeboxhash on GetSafeBox request (Real:%s > Requested:%s)',[TCrypto.ToHexaString(sbHeader.safeBoxHash),TCrypto.ToHexaString(_safeboxHash)]));
  2935. exit;
  2936. end;
  2937. // Response:
  2938. sbStream.Position:=antPos;
  2939. If not TPCChunk.SaveSafeBoxChunkFromSafeBox(sbStream,responseStream,_from,_to,errors) then begin
  2940. TLog.NewLog(ltError,Classname,'Error saving chunk: '+errors);
  2941. exit;
  2942. end;
  2943. // Sending
  2944. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,responseStream);
  2945. TLog.NewLog(ltInfo,ClassName,Format('Sending Safebox(%d) chunk[%d..%d] to %s Bytes:%d',[_blockcount,_from,_to,ClientRemoteAddr,responseStream.Size]));
  2946. finally
  2947. responseStream.Free;
  2948. end;
  2949. finally
  2950. FreeAndNil(sbStream);
  2951. end;
  2952. end;
  2953. procedure TNetConnection.DoProcess_GetPendingOperations_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  2954. var responseStream : TMemoryStream;
  2955. i,start,max : Integer;
  2956. b : Byte;
  2957. c : Cardinal;
  2958. DoDisconnect : Boolean;
  2959. errors : String;
  2960. opht : TOperationsHashTree;
  2961. LLockedMempool : TPCOperationsComp;
  2962. begin
  2963. {
  2964. This call is used to obtain pending operations not included in blockchain
  2965. Request:
  2966. - Request type (1 byte) - Values
  2967. - Value 1:
  2968. Returns Count
  2969. - Value 2:
  2970. - start (4 bytes)
  2971. - max (4 bytes)
  2972. Returns Pending operations (from start to start+max) in a TOperationsHashTree Stream
  2973. }
  2974. errors := '';
  2975. DoDisconnect := true;
  2976. responseStream := TMemoryStream.Create;
  2977. try
  2978. if HeaderData.header_type<>ntp_request then begin
  2979. errors := 'Not request';
  2980. exit;
  2981. end;
  2982. DataBuffer.Read(b,1);
  2983. if (b=1) then begin
  2984. // Return count
  2985. c := TNode.Node.MempoolOperationsCount;
  2986. responseStream.Write(c,SizeOf(c));
  2987. end else if (b=2) then begin
  2988. // Return from start to start+max
  2989. DataBuffer.Read(c,SizeOf(c)); // Start 4 bytes
  2990. start:=c;
  2991. DataBuffer.Read(c,SizeOf(c)); // max 4 bytes
  2992. max:=c;
  2993. //
  2994. if (start<0) Or (max<0) then begin
  2995. errors := 'Invalid start/max value';
  2996. Exit;
  2997. end;
  2998. opht := TOperationsHashTree.Create;
  2999. Try
  3000. LLockedMempool := TNode.Node.LockMempoolRead;
  3001. Try
  3002. if (start >= LLockedMempool.Count) Or (max=0) then begin
  3003. end else begin
  3004. if (start + max >= LLockedMempool.Count) then max := LLockedMempool.Count - start;
  3005. for i:=start to (start + max -1) do begin
  3006. opht.AddOperationToHashTree(LLockedMempool.OperationsHashTree.GetOperation(i));
  3007. end;
  3008. end;
  3009. finally
  3010. TNode.Node.UnlockMempoolRead;
  3011. end;
  3012. opht.SaveOperationsHashTreeToStream(responseStream,False);
  3013. Finally
  3014. opht.Free;
  3015. End;
  3016. end else begin
  3017. errors := 'Invalid call type '+inttostr(b);
  3018. Exit;
  3019. end;
  3020. DoDisconnect:=False;
  3021. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,responseStream);
  3022. finally
  3023. responseStream.Free;
  3024. if DoDisconnect then begin
  3025. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  3026. end;
  3027. end;
  3028. end;
  3029. procedure TNetConnection.DoProcess_GetPendingOperations;
  3030. Var dataSend, dataReceived : TMemoryStream;
  3031. request_id, cStart, cMax, cTotal, cTotalByOther, cReceived, cAddedOperations : Cardinal;
  3032. b : Byte;
  3033. headerData : TNetHeaderData;
  3034. opht : TOperationsHashTree;
  3035. errors : String;
  3036. i : Integer;
  3037. begin
  3038. {$IFDEF PRODUCTION}
  3039. If FNetProtocolVersion.protocol_available<=6 then Exit; // Note: GetPendingOperations started on protocol_available=7
  3040. {$ENDIF}
  3041. request_id := 0;
  3042. cAddedOperations := 0;
  3043. if Not Connected then exit;
  3044. // First receive operations from
  3045. dataSend := TMemoryStream.Create;
  3046. dataReceived := TMemoryStream.Create;
  3047. try
  3048. b := 1;
  3049. dataSend.Write(b,1);
  3050. request_id := TNetData.NetData.NewRequestId;
  3051. If Not DoSendAndWaitForResponse(CT_NetOp_GetPendingOperations,request_id,dataSend,dataReceived,20000,headerData) then begin
  3052. Exit;
  3053. end;
  3054. dataReceived.Position:=0;
  3055. cTotalByOther := 0;
  3056. If (dataReceived.Read(cTotalByOther,SizeOf(cTotal))<SizeOf(cTotal)) then begin
  3057. DisconnectInvalidClient(False,'Invalid data returned on GetPendingOperations');
  3058. Exit;
  3059. end;
  3060. cTotal := cTotalByOther;
  3061. if (cTotal>5000) then begin
  3062. // Limiting max pending operations to 5000
  3063. cTotal := 5000;
  3064. end;
  3065. cReceived:=0;
  3066. cStart := 0;
  3067. While (Connected) And (cReceived<cTotal) do begin
  3068. dataSend.Clear;
  3069. dataReceived.Clear;
  3070. b := 2;
  3071. dataSend.Write(b,1);
  3072. dataSend.Write(cStart,SizeOf(cStart));
  3073. cMax := 1000; // Limiting in 1000 by round
  3074. dataSend.Write(cMax,SizeOf(cMax));
  3075. request_id := TNetData.NetData.NewRequestId;
  3076. If Not DoSendAndWaitForResponse(CT_NetOp_GetPendingOperations,request_id,dataSend,dataReceived,50000,headerData) then begin
  3077. Exit;
  3078. end;
  3079. dataReceived.Position:=0;
  3080. //
  3081. opht := TOperationsHashTree.Create;
  3082. try
  3083. If Not opht.LoadOperationsHashTreeFromStream(dataReceived,False,0,Nil,errors) then begin
  3084. DisconnectInvalidClient(False,'Invalid operations hash tree stream: '+errors);
  3085. Exit;
  3086. end;
  3087. If (opht.OperationsCount>0) then begin
  3088. inc(cReceived,opht.OperationsCount);
  3089. i := TNode.Node.AddOperations(Self,opht,Nil,errors);
  3090. inc(cAddedOperations,i);
  3091. end else Break; // No more
  3092. inc(cStart,opht.OperationsCount);
  3093. finally
  3094. opht.Free;
  3095. end;
  3096. end;
  3097. TLog.NewLog(ltInfo,Classname,Format('Processed GetPendingOperations to %s obtaining %d (available %d) operations and added %d to Node',
  3098. [Self.ClientRemoteAddr,cTotal,cTotalByOther,cAddedOperations]));
  3099. finally
  3100. dataSend.Free;
  3101. dataReceived.Free;
  3102. end;
  3103. end;
  3104. procedure TNetConnection.DoProcess_GetPubkeyAccounts_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  3105. Const CT_Max_Accounts_per_call = 1000;
  3106. var responseStream, accountsStream : TMemoryStream;
  3107. start,max,iPubKey : Integer;
  3108. c, nAccounts : Cardinal;
  3109. acc : TAccount;
  3110. DoDisconnect : Boolean;
  3111. errors : String;
  3112. pubKey : TAccountKey;
  3113. sbakl : TOrderedAccountKeysList;
  3114. ocl : TOrderedCardinalList;
  3115. begin
  3116. {
  3117. This call is used to obtain Accounts used by a Public key
  3118. - Also will return current node block number
  3119. - If a returned data has updated_block value = (current block+1) that means that Account is currently affected by a pending operation in the pending operations
  3120. Request fields
  3121. - Public key
  3122. - start position
  3123. - max
  3124. Returns:
  3125. - current block number (4 bytes): Note, if an account has updated_block > current block means that has been updated and is in pending state
  3126. - count (4 bytes)
  3127. - for 1 to count: TAccountComp.SaveAccountToAStream
  3128. }
  3129. errors := '';
  3130. DoDisconnect := True;
  3131. responseStream := TMemoryStream.Create;
  3132. accountsStream := TMemoryStream.Create;
  3133. try
  3134. // Response first 4 bytes are current block number
  3135. c := TNode.Node.Bank.BlocksCount-1;
  3136. responseStream.Write(c,SizeOf(c));
  3137. //
  3138. if HeaderData.header_type<>ntp_request then begin
  3139. errors := 'Not request';
  3140. Exit;
  3141. end;
  3142. if TStreamOp.ReadAccountKey(DataBuffer,pubKey)<0 then begin
  3143. errors := 'Invalid public key';
  3144. Exit;
  3145. end;
  3146. DataBuffer.Read(c,SizeOf(c));
  3147. start:=c;
  3148. DataBuffer.Read(c,SizeOf(c));
  3149. max:=c;
  3150. If max>CT_Max_Accounts_per_call then max := CT_Max_Accounts_per_call;
  3151. if (start<0) Or (max<0) then begin
  3152. errors := 'Invalid start/max value';
  3153. Exit;
  3154. end;
  3155. //
  3156. nAccounts := 0;
  3157. sbakl := TNode.Node.Bank.SafeBox.OrderedAccountKeysList;
  3158. if Assigned(sbakl) then begin
  3159. iPubKey := sbakl.IndexOfAccountKey(pubKey);
  3160. if (iPubKey>=0) then begin
  3161. ocl := sbakl.AccountKeyList[iPubKey];
  3162. while (start<ocl.Count) And (max>0) do begin
  3163. acc := TNode.Node.GetMempoolAccount(ocl.Get(start));
  3164. TAccountComp.SaveAccountToAStream(accountsStream,acc);
  3165. inc(nAccounts);
  3166. inc(start);
  3167. dec(max);
  3168. end;
  3169. end;
  3170. // Save & send
  3171. responseStream.Write(nAccounts,SizeOf(nAccounts)); // nAccounts = 4 bytes
  3172. responseStream.CopyFrom(accountsStream,0); // Copy all
  3173. DoDisconnect := False;
  3174. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,responseStream);
  3175. end else begin
  3176. DoDisconnect := False;
  3177. SendError(ntp_response,HeaderData.operation,HeaderData.request_id,CT_NetError_NotAvailable,'No OrderedAccountKeysList available');
  3178. end;
  3179. finally
  3180. responseStream.Free;
  3181. accountsStream.Free;
  3182. if DoDisconnect then begin
  3183. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  3184. end;
  3185. end;
  3186. end;
  3187. procedure TNetConnection.DoProcess_GetAccount_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
  3188. Const CT_Max_Accounts_per_call = 1000;
  3189. var responseStream : TMemoryStream;
  3190. i,start,max : Integer;
  3191. b : Byte;
  3192. c : Cardinal;
  3193. acc : TAccount;
  3194. DoDisconnect : Boolean;
  3195. errors : String;
  3196. begin
  3197. {
  3198. This call is used to obtain an Account data
  3199. - Also will return current node block number
  3200. - If a returned data has updated_block value = (current block+1) that means that Account is currently affected by a pending operation in the pending operations
  3201. Request:
  3202. Request type (1 byte) - Values
  3203. - Value 1: Single account
  3204. - Value 2: From account start to start+max LIMITED AT MAX 1000
  3205. - Value 3: Multiple accounts LIMITED AT MAX 1000
  3206. On 1:
  3207. - account (4 bytes)
  3208. On 2:
  3209. - start (4 bytes)
  3210. - max (4 bytes)
  3211. On 3:
  3212. - count (4 bytes)
  3213. - for 1 to count read account (4 bytes)
  3214. Returns:
  3215. - current block number (4 bytes): Note, if an account has updated_block > current block means that has been updated and is in pending state
  3216. - count (4 bytes)
  3217. - for 1 to count: TAccountComp.SaveAccountToAStream
  3218. }
  3219. errors := '';
  3220. DoDisconnect := true;
  3221. responseStream := TMemoryStream.Create;
  3222. try
  3223. // Response first 4 bytes are current block number
  3224. c := TNode.Node.Bank.BlocksCount-1;
  3225. responseStream.Write(c,SizeOf(c));
  3226. //
  3227. if HeaderData.header_type<>ntp_request then begin
  3228. errors := 'Not request';
  3229. exit;
  3230. end;
  3231. if (DataBuffer.Size-DataBuffer.Position<5) then begin
  3232. errors := 'Invalid structure';
  3233. exit;
  3234. end;
  3235. DataBuffer.Read(b,1);
  3236. if (b in [1,2]) then begin
  3237. if (b=1) then begin
  3238. DataBuffer.Read(c,SizeOf(c));
  3239. start:=c;
  3240. max:=1; // Bug 3.0.1 (was c instead of fixed 1)
  3241. end else begin
  3242. DataBuffer.Read(c,SizeOf(c));
  3243. start:=c;
  3244. DataBuffer.Read(c,SizeOf(c));
  3245. max:=c;
  3246. end;
  3247. If max>CT_Max_Accounts_per_call then max := CT_Max_Accounts_per_call;
  3248. if (start<0) Or (max<0) then begin
  3249. errors := 'Invalid start/max value';
  3250. Exit;
  3251. end;
  3252. if (start >= TNode.Node.Bank.AccountsCount) Or (max=0) then begin
  3253. c := 0;
  3254. responseStream.Write(c,SizeOf(c));
  3255. end else begin
  3256. if (start + max >= TNode.Node.Bank.AccountsCount) then max := TNode.Node.Bank.AccountsCount - start;
  3257. c := max;
  3258. responseStream.Write(c,SizeOf(c));
  3259. for i:=start to (start + max -1) do begin
  3260. acc := TNode.Node.GetMempoolAccount(i);
  3261. TAccountComp.SaveAccountToAStream(responseStream,acc);
  3262. end;
  3263. end;
  3264. end else if (b=3) then begin
  3265. DataBuffer.Read(c,SizeOf(c));
  3266. if (c>CT_Max_Accounts_per_call) then c := CT_Max_Accounts_per_call;
  3267. responseStream.Write(c,SizeOf(c));
  3268. max := c;
  3269. for i:=1 to max do begin
  3270. DataBuffer.Read(c,SizeOf(c));
  3271. if (c>=0) And (c<TNode.Node.Bank.AccountsCount) then begin
  3272. acc := TNode.Node.GetMempoolAccount(c);
  3273. TAccountComp.SaveAccountToAStream(responseStream,acc);
  3274. end else begin
  3275. errors := 'Invalid account number '+Inttostr(c);
  3276. Exit;
  3277. end;
  3278. end;
  3279. end else begin
  3280. errors := 'Invalid call type '+inttostr(b);
  3281. Exit;
  3282. end;
  3283. DoDisconnect:=False;
  3284. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,responseStream);
  3285. finally
  3286. responseStream.Free;
  3287. if DoDisconnect then begin
  3288. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  3289. end;
  3290. end;
  3291. end;
  3292. procedure TNetConnection.DoProcess_Hello(HeaderData: TNetHeaderData; DataBuffer: TStream);
  3293. var op, myLastOp : TPCOperationsComp;
  3294. errors : String;
  3295. connection_has_a_server : Word;
  3296. i,c : Integer;
  3297. nsa : TNodeServerAddress;
  3298. rid : Cardinal;
  3299. connection_ts : Cardinal;
  3300. Duplicate : TNetConnection;
  3301. RawAccountKey : TRawBytes;
  3302. other_version : String;
  3303. isFirstHello : Boolean;
  3304. lastTimestampDiff : Integer;
  3305. Begin
  3306. FRemoteAccumulatedWork := 0;
  3307. op := TPCOperationsComp.Create(Nil);
  3308. try
  3309. DataBuffer.Position:=0;
  3310. if DataBuffer.Read(connection_has_a_server,2)<2 then begin
  3311. DisconnectInvalidClient(false,'Invalid data on buffer: '+TNetData.HeaderDataToText(HeaderData));
  3312. exit;
  3313. end;
  3314. If TStreamOp.ReadAnsiString(DataBuffer,RawAccountKey)<0 then begin
  3315. DisconnectInvalidClient(false,'Invalid data on buffer. No Public key: '+TNetData.HeaderDataToText(HeaderData));
  3316. exit;
  3317. end;
  3318. FClientPublicKey := TAccountComp.RawString2Accountkey(RawAccountKey);
  3319. If Not TAccountComp.IsValidAccountKey(FClientPublicKey,errors) then begin
  3320. DisconnectInvalidClient(false,'Invalid Public key: '+TNetData.HeaderDataToText(HeaderData)+' errors: '+errors);
  3321. exit;
  3322. end;
  3323. if DataBuffer.Read(connection_ts,4)<4 then begin
  3324. DisconnectInvalidClient(false,'Invalid data on buffer. No TS: '+TNetData.HeaderDataToText(HeaderData));
  3325. exit;
  3326. end;
  3327. lastTimestampDiff := FTimestampDiff;
  3328. FTimestampDiff := Integer( Int64(connection_ts) - Int64(TNetData.NetData.NetworkAdjustedTime.GetAdjustedTime) );
  3329. If FClientTimestampIp='' then begin
  3330. isFirstHello := True;
  3331. FClientTimestampIp := FTcpIpClient.RemoteHost;
  3332. TNetData.NetData.NetworkAdjustedTime.AddNewIp(FClientTimestampIp,connection_ts);
  3333. if (Abs(TNetData.NetData.NetworkAdjustedTime.TimeOffset)>CT_MaxFutureBlockTimestampOffset) then begin
  3334. TNode.Node.NotifyNetClientMessage(Nil,'The detected network time is different from this system time in '+
  3335. IntToStr(TNetData.NetData.NetworkAdjustedTime.TimeOffset)+' seconds! Please check your local time/timezone');
  3336. end;
  3337. if (Abs(FTimestampDiff) > CT_MaxFutureBlockTimestampOffset) then begin
  3338. TLog.NewLog(ltDebug,ClassName,'Detected a node ('+ClientRemoteAddr+') with incorrect timestamp: '+IntToStr(connection_ts)+' offset '+IntToStr(FTimestampDiff) );
  3339. end;
  3340. end else begin
  3341. isFirstHello := False;
  3342. TNetData.NetData.NetworkAdjustedTime.UpdateIp(FClientTimestampIp,connection_ts);
  3343. end;
  3344. If (Abs(lastTimestampDiff) > CT_MaxFutureBlockTimestampOffset) And (Abs(FTimestampDiff) <= CT_MaxFutureBlockTimestampOffset) then begin
  3345. TLog.NewLog(ltDebug,ClassName,'Corrected timestamp for node ('+ClientRemoteAddr+') old offset: '+IntToStr(lastTimestampDiff)+' current offset '+IntToStr(FTimestampDiff) );
  3346. end;
  3347. if (connection_has_a_server>0) And (Not SameText(Client.RemoteHost,'localhost')) And (Not SameText('127.',Client.RemoteHost.Substring(0,4)))
  3348. And (Not SameText('192.168.',Client.RemoteHost.Substring(0,8)))
  3349. And (Not SameText('10.',Client.RemoteHost.Substring(0,3)))
  3350. And (Not TAccountComp.EqualAccountKeys(FClientPublicKey,TNetData.NetData.FNodePrivateKey.PublicKey)) then begin
  3351. nsa := CT_TNodeServerAddress_NUL;
  3352. nsa.ip := Client.RemoteHost;
  3353. nsa.port := connection_has_a_server;
  3354. nsa.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  3355. TNetData.NetData.AddServer(nsa);
  3356. end;
  3357. if op.LoadBlockFromStream(DataBuffer,errors) then begin
  3358. FRemoteOperationBlock := op.OperationBlock;
  3359. if (DataBuffer.Size-DataBuffer.Position>=4) then begin
  3360. DataBuffer.Read(c,4);
  3361. for i := 1 to c do begin
  3362. nsa := CT_TNodeServerAddress_NUL;
  3363. TStreamOp.ReadString(DataBuffer,nsa.ip);
  3364. DataBuffer.Read(nsa.port,2);
  3365. DataBuffer.Read(nsa.last_connection_by_server,4);
  3366. If (nsa.last_connection_by_server>0) And (i<=CT_MAX_NODESERVERS_ON_HELLO) then // Protect massive data
  3367. TNetData.NetData.AddServer(nsa);
  3368. end;
  3369. if TStreamOp.ReadString(DataBuffer,other_version)>=0 then begin
  3370. // Captures version
  3371. ClientAppVersion := other_version;
  3372. if (DataBuffer.Size-DataBuffer.Position>=SizeOf(FRemoteAccumulatedWork)) then begin
  3373. DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
  3374. TLog.NewLog(ltdebug,ClassName,'Received HELLO with height: '+inttostr(op.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+ ' Remote block: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
  3375. end;
  3376. end;
  3377. //
  3378. if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) Or
  3379. ((FRemoteAccumulatedWork=0) And (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block)) then begin
  3380. TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
  3381. if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)<0 then begin
  3382. TThreadGetNewBlockChainFromClient.Create;
  3383. end;
  3384. end;
  3385. end;
  3386. FLastHelloTS:=TPlatform.GetTickCount;
  3387. FRandomWaitSecondsSendHello := (CT_NewLineSecondsAvg DIV 3) + Random(CT_NewLineSecondsAvg DIV 2);
  3388. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Hello received: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));{$ENDIF}
  3389. if (HeaderData.header_type in [ntp_request,ntp_response]) then begin
  3390. // Response:
  3391. if (HeaderData.header_type=ntp_request) then begin
  3392. Send_Hello(ntp_response,HeaderData.request_id);
  3393. end;
  3394. // Protection of invalid timestamp when is a new incoming connection due to wait time
  3395. if (isFirstHello) And (Self is TNetServerClient) and (HeaderData.header_type=ntp_request) and (Abs(FTimestampDiff) > CT_MaxFutureBlockTimestampOffset) then begin
  3396. TLog.NewLog(ltDebug,ClassName,'Sending HELLO again to ('+ClientRemoteAddr+') in order to check invalid current Timestamp offset: '+IntToStr(FTimestampDiff) );
  3397. Send_Hello(ntp_request,TNetData.NetData.NewRequestId);
  3398. end;
  3399. if (TAccountComp.EqualAccountKeys(FClientPublicKey,TNetData.NetData.FNodePrivateKey.PublicKey)) then begin
  3400. DisconnectInvalidClient(true,'MySelf disconnecting...');
  3401. exit;
  3402. end;
  3403. Duplicate := TNetData.NetData.FindConnectionByClientRandomValue(Self);
  3404. if (Duplicate<>Nil) And (Duplicate.Connected) then begin
  3405. DisconnectInvalidClient(true,'Duplicate connection with '+Duplicate.ClientRemoteAddr);
  3406. exit;
  3407. end;
  3408. TNetData.NetData.NotifyReceivedHelloMessage;
  3409. end else begin
  3410. DisconnectInvalidClient(false,'Invalid header type > '+TNetData.HeaderDataToText(HeaderData));
  3411. end;
  3412. //
  3413. If (isFirstHello) And (HeaderData.header_type = ntp_response) then begin
  3414. DoProcess_GetPendingOperations;
  3415. end;
  3416. end else begin
  3417. TLog.NewLog(lterror,Classname,'Error decoding operations of HELLO: '+errors);
  3418. DisconnectInvalidClient(false,'Error decoding operations of HELLO: '+errors);
  3419. end;
  3420. finally
  3421. op.Free;
  3422. end;
  3423. end;
  3424. procedure TNetConnection.DoProcess_Message(HeaderData: TNetHeaderData; DataBuffer: TStream);
  3425. Var errors : String;
  3426. decrypted,messagecrypted : TRawBytes;
  3427. DoDisconnect : boolean;
  3428. begin
  3429. errors := '';
  3430. DoDisconnect := true;
  3431. try
  3432. if HeaderData.header_type<>ntp_autosend then begin
  3433. errors := 'Not autosend';
  3434. exit;
  3435. end;
  3436. If TStreamOp.ReadAnsiString(DataBuffer,messagecrypted)<0 then begin
  3437. errors := 'Invalid message data';
  3438. exit;
  3439. end;
  3440. if not TPCEncryption.DoPascalCoinECIESDecrypt(TNetData.NetData.NodePrivateKey.PrivateKey,messagecrypted,decrypted) then begin
  3441. errors := 'Error on decrypting message';
  3442. exit;
  3443. end;
  3444. DoDisconnect := false;
  3445. if TCrypto.IsHumanReadable(decrypted) then
  3446. TLog.NewLog(ltinfo,Classname,'Received new message from '+ClientRemoteAddr+' Message ('+inttostr(length(decrypted))+' bytes): '+decrypted.ToPrintable)
  3447. else
  3448. TLog.NewLog(ltinfo,Classname,'Received new message from '+ClientRemoteAddr+' Message ('+inttostr(length(decrypted))+' bytes) in hexadecimal: '+decrypted.ToHexaString);
  3449. Try
  3450. TNode.Node.NotifyNetClientMessage(Self,decrypted.ToString);
  3451. Except
  3452. On E:Exception do begin
  3453. TLog.NewLog(lterror,Classname,'Error processing received message. '+E.ClassName+' '+E.Message);
  3454. end;
  3455. end;
  3456. finally
  3457. if DoDisconnect then begin
  3458. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  3459. end;
  3460. end;
  3461. end;
  3462. procedure TNetConnection.DoProcess_NewBlock(HeaderData: TNetHeaderData; DataBuffer: TStream);
  3463. Type
  3464. TNewFastPropagationBlockOperation = Record
  3465. opReference : TOpReference;
  3466. opStreamData : TBytes;
  3467. end;
  3468. TNewFastPropagationBlockOperationsArray = Array of TNewFastPropagationBlockOperation;
  3469. var operationsComp : TPCOperationsComp;
  3470. DoDisconnect : Boolean;
  3471. errors : String;
  3472. function ProcessNewFastBlockPropagation : Boolean;
  3473. var nfpboarr : TNewFastPropagationBlockOperationsArray;
  3474. oprefcount, notFoundOpReferencesCount, c : Cardinal;
  3475. i,iNodeOpReference : Integer;
  3476. sendStream, receiveStream : TStream;
  3477. block_op_ref : UInt64;
  3478. headerData : TNetHeaderData;
  3479. auxOp : TPCOperation;
  3480. tc : TTickCount;
  3481. original_OperationBlock : TOperationBlock;
  3482. LLockedMempool : TPCOperationsComp;
  3483. begin
  3484. Result := False;
  3485. DoDisconnect := True;
  3486. original_OperationBlock := operationsComp.OperationBlock;
  3487. errors := 'Invalid structure data in ProcessNewFastBlockPropagation';
  3488. tc := TPlatform.GetTickCount;
  3489. SetLength(nfpboarr,0);
  3490. try
  3491. if DataBuffer.Read(oprefcount,SizeOf(oprefcount))<>SizeOf(oprefcount) then Exit;
  3492. if DataBuffer.Size - DataBuffer.Position < (oprefcount * SizeOf(TOpReference)) then Exit;
  3493. SetLength(nfpboarr,oprefcount);
  3494. if (oprefcount>0) then begin
  3495. for i := 0 to Integer(Integer(oprefcount)-1) do begin
  3496. if DataBuffer.Read(nfpboarr[i].opReference,SizeOf(TOpReference))<>SizeOf(TOpReference) then Exit;
  3497. SetLength(nfpboarr[i].opStreamData,0);
  3498. end;
  3499. end;
  3500. DoDisconnect := False;
  3501. notFoundOpReferencesCount := 0;
  3502. if (oprefcount>0) then begin
  3503. // Try TNode locking process
  3504. If Not TNode.Node.TryLockNode(3000) then Exit; // Cannot lock...
  3505. Try
  3506. if (operationsComp.OperationBlock.block<>TNode.Node.Bank.BlocksCount) then Exit; // Meanwhile other threads have added it
  3507. // Fill not included operations:
  3508. LLockedMempool := TNode.Node.LockMempoolRead;
  3509. try
  3510. for i:=0 to High(nfpboarr) do begin
  3511. iNodeOpReference := LLockedMempool.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
  3512. if iNodeOpReference>=0 then begin
  3513. nfpboarr[i].opStreamData := LLockedMempool.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
  3514. end else begin
  3515. inc(notFoundOpReferencesCount);
  3516. end;
  3517. end;
  3518. finally
  3519. TNode.Node.UnlockMempoolRead;
  3520. end;
  3521. Finally
  3522. TNode.Node.UnlockNode;
  3523. End;
  3524. end;
  3525. if (notFoundOpReferencesCount>CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS) then begin
  3526. // A lot of operations pending! Calling GetBlocks
  3527. TLog.NewLog(ltdebug,ClassName,Format('Too many pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
  3528. Exit;
  3529. end else if (notFoundOpReferencesCount>0) then begin
  3530. // Must obtain not found calling CT_NetOp_GetBlockchainOperations
  3531. TLog.NewLog(ltdebug,ClassName,Format('Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
  3532. sendStream := TMemoryStream.Create;
  3533. receiveStream := TMemoryStream.Create;
  3534. Try
  3535. sendStream.Write(notFoundOpReferencesCount,SizeOf(notFoundOpReferencesCount)); // 4 bytes for count
  3536. for i:=0 to High(nfpboarr) do begin
  3537. if Length(nfpboarr[i].opStreamData)=0 then begin
  3538. // Need this!
  3539. block_op_ref := UInt64(UInt64(operationsComp.OperationBlock.block) SHL 32) + i;
  3540. sendStream.Write(block_op_ref,SizeOf(block_op_ref)); // 8 bytes for Block_op_ref
  3541. end;
  3542. end;
  3543. // Send & wait
  3544. if Not DoSendAndWaitForResponse(CT_NetOp_GetBlockchainOperations,TNetData.NetData.NewRequestId,sendStream,receiveStream,5000,headerData) then begin
  3545. TLog.NewLog(ltdebug,ClassName,Format('Not received Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
  3546. Exit;
  3547. end;
  3548. DoDisconnect := True; // If bad received data... then DoDisconnect
  3549. if (headerData.is_error) then Exit;
  3550. receiveStream.Position := 0;
  3551. receiveStream.Read(c,SizeOf(c));
  3552. if (c<>notFoundOpReferencesCount) then Exit; // Error!
  3553. // Process Response
  3554. for i:=0 to High(nfpboarr) do begin
  3555. if Length(nfpboarr[i].opStreamData)=0 then begin
  3556. // Read it from response:
  3557. if receiveStream.Read(c,SizeOf(c)) <> SizeOf(c) then Exit;
  3558. if receiveStream.Size - receiveStream.Position < c then Exit; // Not enough received data
  3559. SetLength(nfpboarr[i].opStreamData,c);
  3560. receiveStream.ReadBuffer(nfpboarr[i].opStreamData[0],c); // Fixed bug 4.0.0
  3561. end;
  3562. end;
  3563. DoDisconnect := False;
  3564. finally
  3565. sendStream.Free;
  3566. receiveStream.Free;
  3567. end;
  3568. end;
  3569. // Now we have nfpboarr with full data
  3570. for i := 0 to High(nfpboarr) do begin
  3571. auxOp := TPCOperation.GetOperationFromStreamData( nfpboarr[i].opStreamData );
  3572. if not Assigned(auxOp) then begin
  3573. errors := Format('Op index not available (%d/%d) OpReference:%d size:%d',[i,High(nfpboarr),nfpboarr[i].opReference,Length(nfpboarr[i].opStreamData)]);
  3574. Exit;
  3575. end else begin
  3576. if Not operationsComp.AddOperation(False,auxOp,errors) then Exit;
  3577. auxOp.Free;
  3578. end;
  3579. end;
  3580. // Finished
  3581. if (notFoundOpReferencesCount > 0) then begin
  3582. TLog.NewLog(ltdebug,ClassName,Format('Processed NewFastBlockPropagation with Pending operations (%d of %d) in Fast propagation block %d for %d miliseconds',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block,TPlatform.GetElapsedMilliseconds(tc)]));
  3583. end;
  3584. // Check that operationsComp.operationBlock is equal to received
  3585. If Not TAccountComp.EqualOperationBlocks(operationsComp.OperationBlock,original_OperationBlock) then begin
  3586. // This can happen when a OpReference in my MEMPOOL is different to an OpReference in the miner, causing different OperationsHash value
  3587. // This means a possible double spend found
  3588. TLog.NewLog(lterror,ClassName,Format('Constructed a distinct FAST PROPAGATION block with my mempool operations. Received: %s Constructed: %s',
  3589. [TPCOperationsComp.OperationBlockToText(original_OperationBlock),TPCOperationsComp.OperationBlockToText(operationsComp.OperationBlock)]));
  3590. if Not TPCSafeBox.IsValidOperationBlock(original_OperationBlock,errors) then begin
  3591. // This means a scammer!
  3592. DoDisconnect := True;
  3593. end;
  3594. Exit;
  3595. end;
  3596. finally
  3597. // Clean memory
  3598. for i := 0 to High(nfpboarr) do begin
  3599. SetLength(nfpboarr[i].opStreamData,0);
  3600. end;
  3601. SetLength(nfpboarr,0);
  3602. end;
  3603. DoDisconnect := False;
  3604. Result := True;
  3605. end;
  3606. var bacc : TBlockAccount;
  3607. c : Cardinal;
  3608. begin
  3609. errors := '';
  3610. DoDisconnect := true;
  3611. try
  3612. if HeaderData.header_type<>ntp_autosend then begin
  3613. errors := 'Not autosend';
  3614. exit;
  3615. end;
  3616. operationsComp := TPCOperationsComp.Create(nil);
  3617. try
  3618. operationsComp.bank := TNode.Node.Bank;
  3619. if Not operationsComp.LoadBlockFromStream(DataBuffer,errors) then begin
  3620. errors := 'Error decoding new account: '+errors;
  3621. exit;
  3622. end else begin
  3623. DoDisconnect := false;
  3624. DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
  3625. if operationsComp.IsOnlyOperationBlock then begin
  3626. TLog.NewLog(ltdebug,ClassName,'Received NEW FAST PROPAGATION BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
  3627. end else begin
  3628. TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
  3629. end;
  3630. FRemoteOperationBlock := operationsComp.OperationBlock;
  3631. if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
  3632. if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
  3633. // New block candidate:
  3634. if (operationsComp.IsOnlyOperationBlock) then begin
  3635. // Received a FAST PROPAGATION BLOCK as described at PIP-0015
  3636. // Fill operations reference:
  3637. If Not ProcessNewFastBlockPropagation then begin
  3638. if DoDisconnect then Exit
  3639. else begin
  3640. Send_GetBlocks(operationsComp.OperationBlock.block,1,c);
  3641. Exit;
  3642. end;
  3643. end;
  3644. end;
  3645. If Not TNode.Node.AddNewBlockChain(Self,operationsComp,bacc,errors) then begin
  3646. // Check valid header, if not, scammer... Disconnect
  3647. if Not TPCSafeBox.IsValidOperationBlock(operationsComp.OperationBlock,errors) then begin
  3648. DoDisconnect := True;
  3649. Exit;
  3650. end;
  3651. // Really is a new block? (Check it)
  3652. if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
  3653. // Received a new invalid block... perhaps I'm an orphan blockchain
  3654. TNetData.NetData.GetNewBlockChainFromClient(Self,'Higher Work with same block height. I''m a orphan blockchain candidate');
  3655. end;
  3656. end;
  3657. end else begin
  3658. // Received a new higher work
  3659. TNetData.NetData.GetNewBlockChainFromClient(Self,Format('Higher Work and distinct blocks count. Need to download BlocksCount:%d my BlocksCount:%d',[operationsComp.OperationBlock.block+1,TNode.Node.Bank.BlocksCount]));
  3660. end;
  3661. end;
  3662. end;
  3663. finally
  3664. operationsComp.Free;
  3665. end;
  3666. finally
  3667. if DoDisconnect then begin
  3668. DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
  3669. end;
  3670. end;
  3671. end;
  3672. procedure TNetConnection.DoSend(ANetTranferType: TNetTransferType; AOperation, AErrorcode: Word; ARequest_id: Integer; ADataBuffer: TStream);
  3673. begin
  3674. Send(ANetTranferType, AOperation, AErrorcode, ARequest_id, ADataBuffer);
  3675. end;
  3676. function TNetConnection.DoSendAndWaitForResponse(operation: Word;
  3677. RequestId: Integer; SendDataBuffer, ReceiveDataBuffer: TStream;
  3678. MaxWaitTime: Cardinal; var HeaderData: TNetHeaderData): Boolean;
  3679. var tc : TTickCount;
  3680. was_waiting_for_response : Boolean;
  3681. iDebugStep : Integer;
  3682. reservedResponse : TMemoryStream;
  3683. begin
  3684. iDebugStep := 0;
  3685. Try
  3686. Result := false;
  3687. HeaderData := CT_NetHeaderData;
  3688. If FIsWaitingForResponse then begin
  3689. TLog.NewLog(ltdebug,Classname,'Is waiting for response ...');
  3690. exit;
  3691. end;
  3692. iDebugStep := 100;
  3693. If Not Assigned(FTcpIpClient) then exit;
  3694. if Not Client.Connected then exit;
  3695. iDebugStep := 110;
  3696. tc := TPlatform.GetTickCount;
  3697. If TPCThread.TryProtectEnterCriticalSection(Self,MaxWaitTime,FNetLock) then begin
  3698. Try
  3699. iDebugStep := 120;
  3700. was_waiting_for_response := RequestId>0;
  3701. try
  3702. if was_waiting_for_response then begin
  3703. iDebugStep := 200;
  3704. FIsWaitingForResponse := true;
  3705. Send(ntp_request,operation,0,RequestId,SendDataBuffer);
  3706. end;
  3707. iDebugStep := 300;
  3708. Repeat
  3709. iDebugStep := 400;
  3710. if (MaxWaitTime > TPlatform.GetTickCount - tc) then MaxWaitTime := MaxWaitTime - (TPlatform.GetTickCount - tc)
  3711. else MaxWaitTime := 1;
  3712. If (MaxWaitTime>60000) then MaxWaitTime:=60000;
  3713. tc := TPlatform.GetTickCount;
  3714. if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
  3715. iDebugStep := 500;
  3716. TNetData.NetData.NodeServersAddresses.UpdateNetConnection(Self);
  3717. iDebugStep := 800;
  3718. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Received '+CT_NetTransferType[HeaderData.header_type]+' operation:'+TNetData.OperationToText(HeaderData.operation)+' id:'+Inttostr(HeaderData.request_id)+' Buffer size:'+Inttostr(HeaderData.buffer_data_length) );{$ENDIF}
  3719. if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
  3720. Result := true;
  3721. end else begin
  3722. iDebugStep := 1000;
  3723. case HeaderData.operation of
  3724. CT_NetOp_Hello : Begin
  3725. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3726. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(CT_NewLineSecondsAvg * 2,20,20000))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3727. else begin
  3728. iDebugStep := 1100;
  3729. DoProcess_Hello(HeaderData,ReceiveDataBuffer);
  3730. end;
  3731. End;
  3732. CT_NetOp_Message : Begin
  3733. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3734. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(60,20,20000))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3735. else DoProcess_Message(HeaderData,ReceiveDataBuffer);
  3736. End;
  3737. CT_NetOp_GetBlocks : Begin
  3738. if HeaderData.header_type=ntp_request then begin
  3739. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3740. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(300,100,0),TLimitLifetime.Create(10,5,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3741. else DoProcess_GetBlocks_Request(HeaderData,ReceiveDataBuffer)
  3742. end else if HeaderData.header_type=ntp_response then begin
  3743. DoProcess_GetBlocks_Response(HeaderData,ReceiveDataBuffer);
  3744. end else DisconnectInvalidClient(false,'Not resquest or response: '+TNetData.HeaderDataToText(HeaderData));
  3745. End;
  3746. CT_NetOp_GetBlockHeaders : Begin
  3747. if HeaderData.header_type=ntp_request then begin
  3748. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3749. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(30,30,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3750. else DoProcess_GetOperationsBlock_Request(HeaderData,ReceiveDataBuffer)
  3751. end else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
  3752. End;
  3753. CT_NetOp_NewBlock, CT_NetOp_NewBlock_Fast_Propagation : Begin
  3754. DoProcess_NewBlock(HeaderData,ReceiveDataBuffer);
  3755. End;
  3756. CT_NetOp_GetBlockchainOperations : Begin
  3757. if HeaderData.header_type=ntp_request then begin
  3758. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3759. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(60,10,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3760. else DoProcess_GetBlockchainOperations_Request(HeaderData,ReceiveDataBuffer)
  3761. end else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
  3762. End;
  3763. CT_NetOp_AddOperations : Begin
  3764. DoProcess_AddOperations(HeaderData,ReceiveDataBuffer);
  3765. End;
  3766. CT_NetOp_GetSafeBox : Begin
  3767. if HeaderData.header_type=ntp_request then begin
  3768. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3769. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(1200,100,0),TLimitLifetime.Create(10,40,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3770. else DoProcess_GetSafeBox_Request(HeaderData,ReceiveDataBuffer)
  3771. end else DisconnectInvalidClient(false,'Received '+TNetData.HeaderDataToText(HeaderData));
  3772. end;
  3773. CT_NetOp_GetPendingOperations : Begin
  3774. if (HeaderData.header_type=ntp_request) then begin
  3775. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3776. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(300,100,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3777. else DoProcess_GetPendingOperations_Request(HeaderData,ReceiveDataBuffer)
  3778. end else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
  3779. end;
  3780. CT_NetOp_GetAccount : Begin
  3781. if (HeaderData.header_type=ntp_request) then begin
  3782. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3783. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(10,60,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3784. else DoProcess_GetAccount_Request(HeaderData,ReceiveDataBuffer)
  3785. end else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
  3786. end;
  3787. CT_NetOp_GetPubkeyAccounts : Begin
  3788. if (HeaderData.header_type=ntp_request) then begin
  3789. if TNetData.NetData.IpInfos.ReachesLimits(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length,
  3790. TArray<TLimitLifetime>.Create(TLimitLifetime.Create(10,50,0))) then DisconnectInvalidClient(False,Format('Reached limit %s',[TNetData.OperationToText(HeaderData.operation)]))
  3791. else DoProcess_GetPubkeyAccounts_Request(HeaderData,ReceiveDataBuffer)
  3792. end else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
  3793. End;
  3794. CT_NetOp_Reserved_Start..CT_NetOp_Reserved_End : Begin
  3795. // This will allow to do nothing if not implemented
  3796. reservedResponse := TMemoryStream.Create;
  3797. Try
  3798. TNetData.NetData.DoProcessReservedAreaMessage(Self,HeaderData,ReceiveDataBuffer,reservedResponse);
  3799. if (HeaderData.header_type=ntp_request) then begin
  3800. if (reservedResponse.Size>0) then begin
  3801. Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,reservedResponse);
  3802. end else begin
  3803. // If is a request, and DoProcessReservedAreaMessage didn't filled reservedResponse, will response with ERRORCODE_NOT_IMPLEMENTED
  3804. Send(ntp_response,HeaderData.operation, CT_NetOp_ERRORCODE_NOT_IMPLEMENTED ,HeaderData.request_id,Nil);
  3805. end;
  3806. end;
  3807. finally
  3808. reservedResponse.Free;
  3809. end;
  3810. end
  3811. else
  3812. DisconnectInvalidClient(false,'Invalid operation: '+TNetData.HeaderDataToText(HeaderData));
  3813. end;
  3814. end;
  3815. end else sleep(1);
  3816. iDebugStep := 900;
  3817. Until (Result) Or (TPlatform.GetTickCount>(MaxWaitTime+tc)) Or (Not Connected) Or (FDoFinalizeConnection);
  3818. finally
  3819. if was_waiting_for_response then FIsWaitingForResponse := false;
  3820. end;
  3821. iDebugStep := 990;
  3822. Finally
  3823. FNetLock.Release;
  3824. End;
  3825. end;
  3826. Except
  3827. On E:Exception do begin
  3828. E.Message := E.Message+' DoSendAndWaitForResponse step '+Inttostr(iDebugStep)+' Header.operation:'+Inttostr(HeaderData.operation);
  3829. Raise;
  3830. end;
  3831. End;
  3832. end;
  3833. procedure TNetConnection.FinalizeConnection;
  3834. begin
  3835. If FDoFinalizeConnection then exit;
  3836. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,ClassName,'Executing FinalizeConnection to '+ClientRemoteAddr);{$ENDIF}
  3837. FDoFinalizeConnection := true;
  3838. end;
  3839. function TNetConnection.GetClient: TNetTcpIpClient;
  3840. begin
  3841. if Not Assigned(FTcpIpClient) then begin
  3842. TLog.NewLog(ltError,Classname,'TcpIpClient=NIL');
  3843. raise Exception.Create('TcpIpClient=NIL');
  3844. end;
  3845. Result := FTcpIpClient;
  3846. end;
  3847. function TNetConnection.GetConnected: Boolean;
  3848. begin
  3849. Result := Assigned(FTcpIpClient) And (FTcpIpClient.Connected);
  3850. end;
  3851. procedure TNetConnection.Notification(AComponent: TComponent; Operation: TOperation);
  3852. begin
  3853. inherited;
  3854. if (Operation=opRemove) And (AComponent = FTcpIpClient) then begin
  3855. FTcpIpClient := Nil;
  3856. end;
  3857. end;
  3858. function TNetConnection.ReadTcpClientBuffer(MaxWaitMiliseconds: Cardinal; var HeaderData: TNetHeaderData; BufferData: TStream): Boolean;
  3859. var
  3860. auxstream : TMemoryStream;
  3861. tc : TTickCount;
  3862. last_bytes_read, t_bytes_read : Int64;
  3863. //
  3864. IsValidHeaderButNeedMoreData : Boolean;
  3865. deletedBytes : Int64;
  3866. begin
  3867. t_bytes_read := 0;
  3868. Result := false;
  3869. HeaderData := CT_NetHeaderData;
  3870. BufferData.Size := 0;
  3871. TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
  3872. try
  3873. tc := TPlatform.GetTickCount;
  3874. repeat
  3875. If not Connected then exit;
  3876. if Not Client.Connected then exit;
  3877. last_bytes_read := 0;
  3878. FClientBufferRead.Position := 0;
  3879. Result := TNetData.ExtractHeaderInfo(FClientBufferRead,HeaderData,BufferData,IsValidHeaderButNeedMoreData);
  3880. if Result then begin
  3881. FNetProtocolVersion := HeaderData.protocol;
  3882. // Build 1.0.4 accepts net protocol 1 and 2
  3883. if HeaderData.protocol.protocol_version>CT_NetProtocol_Available then begin
  3884. TNode.Node.NotifyNetClientMessage(Nil,
  3885. 'Detected a higher Net protocol version at '+
  3886. ClientRemoteAddr+' (v '+inttostr(HeaderData.protocol.protocol_version)+' '+inttostr(HeaderData.protocol.protocol_available)+') '+
  3887. '... check that your version is Ok! Visit official download website for possible updates: https://sourceforge.net/projects/pascalcoin/');
  3888. DisconnectInvalidClient(false,Format('Invalid Net protocol version found: %d available: %d',[HeaderData.protocol.protocol_version,HeaderData.protocol.protocol_available]));
  3889. Result := false;
  3890. exit;
  3891. end else begin
  3892. if (FNetProtocolVersion.protocol_available>CT_NetProtocol_Available) And (Not FAlertedForNewProtocolAvailable) then begin
  3893. FAlertedForNewProtocolAvailable := true;
  3894. TNode.Node.NotifyNetClientMessage(Nil,
  3895. 'Detected a new Net protocol version at '+
  3896. ClientRemoteAddr+' (v '+inttostr(HeaderData.protocol.protocol_version)+' '+inttostr(HeaderData.protocol.protocol_available)+') '+
  3897. '... Visit official download website for possible updates: https://sourceforge.net/projects/pascalcoin/');
  3898. end;
  3899. // Remove data from buffer and save only data not processed (higher than stream.position)
  3900. auxstream := TMemoryStream.Create;
  3901. try
  3902. if FClientBufferRead.Position<FClientBufferRead.Size then begin
  3903. auxstream.CopyFrom(FClientBufferRead,FClientBufferRead.Size-FClientBufferRead.Position);
  3904. end;
  3905. FClientBufferRead.Size := 0;
  3906. FClientBufferRead.CopyFrom(auxstream,0);
  3907. finally
  3908. auxstream.Free;
  3909. end;
  3910. end;
  3911. end else begin
  3912. sleep(1);
  3913. if Not Client.WaitForData(100) then begin
  3914. exit;
  3915. end;
  3916. auxstream := (Client as TBufferedNetTcpIpClient).ReadBufferLock;
  3917. try
  3918. last_bytes_read := auxstream.size;
  3919. if last_bytes_read>0 then begin
  3920. FLastDataReceivedTS := TPlatform.GetTickCount;
  3921. FClientBufferRead.Position := FClientBufferRead.size; // Go to the end
  3922. auxstream.Position := 0;
  3923. FClientBufferRead.CopyFrom(auxstream,last_bytes_read);
  3924. FClientBufferRead.Position := 0;
  3925. auxstream.Size := 0;
  3926. inc(t_bytes_read,last_bytes_read);
  3927. end;
  3928. finally
  3929. (Client as TBufferedNetTcpIpClient).ReadBufferUnlock;
  3930. end;
  3931. end;
  3932. until (Result) Or ((TPlatform.GetTickCount > (tc+MaxWaitMiliseconds)) And (last_bytes_read=0));
  3933. finally
  3934. Try
  3935. if (Connected) then begin
  3936. if (Not Result) And (FClientBufferRead.Size>0) And (Not IsValidHeaderButNeedMoreData) then begin
  3937. deletedBytes := FClientBufferRead.Size;
  3938. TLog.NewLog(lterror,ClassName,Format('Deleting %d bytes from TcpClient buffer of %s after max %d miliseconds. Elapsed: %d',
  3939. [deletedBytes, Client.ClientRemoteAddr,MaxWaitMiliseconds,TPlatform.GetTickCount-tc]));
  3940. FClientBufferRead.Size:=0;
  3941. DisconnectInvalidClient(false,'Invalid data received in buffer ('+inttostr(deletedBytes)+' bytes)');
  3942. end else if (IsValidHeaderButNeedMoreData) then begin
  3943. if (t_bytes_read>0) then begin
  3944. TLog.NewLog(ltDebug,ClassName,Format('Not enough data received - Received %d bytes from TcpClient buffer of %s after max %d miliseconds. Elapsed: %d - HeaderData: %s',
  3945. [FClientBufferRead.Size, Client.ClientRemoteAddr,MaxWaitMiliseconds,TPlatform.GetTickCount-tc,TNetData.HeaderDataToText(HeaderData)]));
  3946. end else if (TPlatform.GetElapsedMilliseconds(FLastDataReceivedTS)>60000) then begin
  3947. TLog.NewLog(lterror,ClassName,Format('Closing connection to %s due not received expected data. Received:%d Expected:%d ElapsedMilis:%d',
  3948. [Client.ClientRemoteAddr,FClientBufferRead.Size,HeaderData.buffer_data_length,TPlatform.GetElapsedMilliseconds(FLastDataReceivedTS)]));
  3949. Connected:=False;
  3950. end;
  3951. end;
  3952. end;
  3953. Finally
  3954. FNetLock.Release;
  3955. End;
  3956. end;
  3957. if t_bytes_read>0 then begin
  3958. if Not FHasReceivedData then begin
  3959. FHasReceivedData := true;
  3960. if (Self is TNetClient) then
  3961. TNetData.NetData.IncStatistics(0,0,0,1,t_bytes_read,0)
  3962. else TNetData.NetData.IncStatistics(0,0,0,0,t_bytes_read,0);
  3963. end else begin
  3964. TNetData.NetData.IncStatistics(0,0,0,0,t_bytes_read,0);
  3965. end;
  3966. end;
  3967. if (Result) And (HeaderData.header_type=ntp_response) then begin
  3968. TNetData.NetData.UnRegisterRequest(Self,HeaderData.operation,HeaderData.request_id);
  3969. end;
  3970. // Update stats... only if not response (because we don't need to know/store stats for responses in general). This is minimal memory use
  3971. if (Result) And (HeaderData.header_type<>ntp_response) then begin
  3972. TNetData.NetData.IpInfos.UpdateIpInfo(Client.RemoteHost,CT_NetTransferType[HeaderData.header_type],TNetData.OperationToText(HeaderData.operation),HeaderData.buffer_data_length);
  3973. end;
  3974. end;
  3975. procedure TNetConnection.Send(NetTranferType: TNetTransferType; operation, errorcode: Word; request_id: Integer; DataBuffer: TStream);
  3976. Var l : Cardinal;
  3977. w : Word;
  3978. Buffer : TStream;
  3979. {$IFDEF HIGHLOG}
  3980. s : String;
  3981. {$ENDIF}
  3982. begin
  3983. Buffer := TMemoryStream.Create;
  3984. try
  3985. l := CT_MagicNetIdentification;
  3986. Buffer.Write(l,4);
  3987. case NetTranferType of
  3988. ntp_request: begin
  3989. w := CT_MagicRequest;
  3990. Buffer.Write(w,2);
  3991. Buffer.Write(operation,2);
  3992. w := 0;
  3993. Buffer.Write(w,2);
  3994. Buffer.Write(request_id,4);
  3995. end;
  3996. ntp_response: begin
  3997. w := CT_MagicResponse;
  3998. Buffer.Write(w,2);
  3999. Buffer.Write(operation,2);
  4000. Buffer.Write(errorcode,2);
  4001. Buffer.Write(request_id,4);
  4002. end;
  4003. ntp_autosend: begin
  4004. w := CT_MagicAutoSend;
  4005. Buffer.Write(w,2);
  4006. Buffer.Write(operation,2);
  4007. w := errorcode;
  4008. Buffer.Write(w,2);
  4009. l := 0;
  4010. Buffer.Write(l,4);
  4011. end
  4012. else
  4013. raise Exception.Create('Invalid encoding');
  4014. end;
  4015. l := CT_NetProtocol_Version;
  4016. Buffer.Write(l,2);
  4017. l := CT_NetProtocol_Available;
  4018. Buffer.Write(l,2);
  4019. if Assigned(DataBuffer) then begin
  4020. l := DataBuffer.Size;
  4021. Buffer.Write(l,4);
  4022. DataBuffer.Position := 0;
  4023. Buffer.CopyFrom(DataBuffer,DataBuffer.Size);
  4024. {$IFDEF HIGHLOG}s := '(Data:'+inttostr(DataBuffer.Size)+'b) ';{$ENDIF}
  4025. end else begin
  4026. l := 0;
  4027. Buffer.Write(l,4);
  4028. {$IFDEF HIGHLOG}s := '';{$ENDIF}
  4029. end;
  4030. Buffer.Position := 0;
  4031. TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
  4032. Try
  4033. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Sending: '+CT_NetTransferType[NetTranferType]+' operation:'+
  4034. TNetData.OperationToText(operation)+' id:'+Inttostr(request_id)+' errorcode:'+InttoStr(errorcode)+
  4035. ' Size:'+InttoStr(Buffer.Size)+'b '+s+'to '+
  4036. ClientRemoteAddr);{$ENDIF}
  4037. (Client as TBufferedNetTcpIpClient).WriteBufferToSend(Buffer);
  4038. FLastDataSendedTS := TPlatform.GetTickCount;
  4039. Finally
  4040. FNetLock.Release;
  4041. End;
  4042. TNetData.NetData.IncStatistics(0,0,0,0,0,Buffer.Size);
  4043. finally
  4044. Buffer.Free;
  4045. end;
  4046. end;
  4047. procedure TNetConnection.SendError(NetTranferType: TNetTransferType; operation,
  4048. request_id: Integer; error_code: Integer; const error_text: String);
  4049. var buffer : TStream;
  4050. begin
  4051. buffer := TMemoryStream.Create;
  4052. Try
  4053. TStreamOp.WriteAnsiString(buffer,TEncoding.ASCII.GetBytes(error_text));
  4054. Send(NetTranferType,operation,error_code,request_id,buffer);
  4055. Finally
  4056. buffer.Free;
  4057. End;
  4058. end;
  4059. function TNetConnection.Send_AddOperations(Operations : TOperationsHashTree) : Boolean;
  4060. Var data : TMemoryStream;
  4061. c1, request_id : Cardinal;
  4062. i, nOpsToSend : Integer;
  4063. optype : Byte;
  4064. begin
  4065. Result := false;
  4066. if Not Connected then exit;
  4067. FNetLock.Acquire;
  4068. try
  4069. nOpsToSend := 0;
  4070. FBufferLock.Acquire;
  4071. Try
  4072. If Assigned(Operations) then begin
  4073. for i := 0 to Operations.OperationsCount - 1 do begin
  4074. if FBufferReceivedOperationsHash.IndexOf(Operations.GetOperation(i).Sha256)<0 then begin
  4075. FBufferReceivedOperationsHash.Add(Operations.GetOperation(i).Sha256);
  4076. If FBufferToSendOperations.IndexOfOperation(Operations.GetOperation(i))<0 then begin
  4077. FBufferToSendOperations.AddOperationToHashTree(Operations.GetOperation(i));
  4078. end;
  4079. end;
  4080. end;
  4081. nOpsToSend := Operations.OperationsCount;
  4082. end;
  4083. if FBufferToSendOperations.OperationsCount>0 then begin
  4084. TLog.NewLog(ltdebug,ClassName,Format('Sending %d Operations to %s (inProc:%d, Received:%d)',[FBufferToSendOperations.OperationsCount,ClientRemoteAddr,nOpsToSend,FBufferReceivedOperationsHash.Count]));
  4085. data := TMemoryStream.Create;
  4086. try
  4087. request_id := TNetData.NetData.NewRequestId;
  4088. c1 := FBufferToSendOperations.OperationsCount;
  4089. data.Write(c1,4);
  4090. for i := 0 to FBufferToSendOperations.OperationsCount-1 do begin
  4091. optype := FBufferToSendOperations.GetOperation(i).OpType;
  4092. data.Write(optype,1);
  4093. FBufferToSendOperations.GetOperation(i).SaveToNettransfer(data);
  4094. end;
  4095. Send(ntp_autosend,CT_NetOp_AddOperations,0,request_id,data);
  4096. FBufferToSendOperations.ClearHastThree;
  4097. finally
  4098. data.Free;
  4099. end;
  4100. end{$IFDEF HIGHLOG} else TLog.NewLog(ltdebug,ClassName,Format('Not sending any operations to %s (inProc:%d, Received:%d, Sent:%d)',[ClientRemoteAddr,nOpsToSend,FBufferReceivedOperationsHash.Count,FBufferToSendOperations.OperationsCount])){$ENDIF};
  4101. finally
  4102. FBufferLock.Release;
  4103. end;
  4104. finally
  4105. FNetLock.Release;
  4106. end;
  4107. Result := Connected;
  4108. end;
  4109. function TNetConnection.Send_GetBlocks(StartAddress, quantity : Cardinal; var request_id : Cardinal) : Boolean;
  4110. Var data : TMemoryStream;
  4111. c1,c2 : Cardinal;
  4112. begin
  4113. Result := false;
  4114. request_id := 0;
  4115. if (FRemoteOperationBlock.block<TNetData.NetData.Bank.BlocksCount) Or (FRemoteOperationBlock.block=0) then exit;
  4116. if Not Connected then exit;
  4117. // First receive operations from
  4118. data := TMemoryStream.Create;
  4119. try
  4120. if TNetData.NetData.Bank.BlocksCount=0 then c1:=0
  4121. else c1:=StartAddress;
  4122. if (quantity=0) then begin
  4123. if FRemoteOperationBlock.block>0 then c2 := FRemoteOperationBlock.block
  4124. else c2 := c1+100;
  4125. end else c2 := c1+quantity-1;
  4126. // Build 1.0.5 BUG - Always query for ONLY 1 if Build is lower or equal to 1.0.5
  4127. if ((FClientAppVersion='') Or ( (length(FClientAppVersion)=5) And (FClientAppVersion<='1.0.5') )) then begin
  4128. c2 := c1;
  4129. end;
  4130. data.Write(c1,4);
  4131. data.Write(c2,4);
  4132. request_id := TNetData.NetData.NewRequestId;
  4133. TNetData.NetData.RegisterRequest(Self,CT_NetOp_GetBlocks,request_id);
  4134. TLog.NewLog(ltdebug,ClassName,Format('Send GET BLOCKS start:%d quantity:%d (from:%d to %d)',[StartAddress,quantity,StartAddress,quantity+StartAddress]));
  4135. FIsDownloadingBlocks := quantity>1;
  4136. Send(ntp_request,CT_NetOp_GetBlocks,0,request_id,data);
  4137. Result := Connected;
  4138. finally
  4139. data.Free;
  4140. end;
  4141. end;
  4142. function TNetConnection.Send_Hello(NetTranferType : TNetTransferType; request_id : Integer) : Boolean;
  4143. { HELLO command:
  4144. - Operation stream
  4145. - My Active server port (0 if no active). (2 bytes)
  4146. - A Random Longint (4 bytes) to check if its myself connection to my server socket
  4147. - My Unix Timestamp (4 bytes)
  4148. - Registered node servers count
  4149. (For each)
  4150. - ip (string)
  4151. - port (2 bytes)
  4152. - last_connection UTS (4 bytes)
  4153. - My Server port (2 bytes)
  4154. - If this is a response:
  4155. - If remote operation block is lower than me:
  4156. - Send My Operation Stream in the same block thant requester
  4157. }
  4158. var data : TStream;
  4159. i : Integer;
  4160. nsa : TNodeServerAddress;
  4161. nsarr : TNodeServerAddressArray;
  4162. w : Word;
  4163. currunixtimestamp : Cardinal;
  4164. begin
  4165. Result := false;
  4166. if Not Connected then exit;
  4167. // Send Hello command:
  4168. data := TMemoryStream.Create;
  4169. try
  4170. if NetTranferType=ntp_request then begin
  4171. TNetData.NetData.RegisterRequest(Self,CT_NetOp_Hello,request_id);
  4172. end;
  4173. If TNode.Node.NetServer.Active then
  4174. w := TNode.Node.NetServer.Port
  4175. else w := 0;
  4176. // Save active server port (2 bytes). 0 = No active server port
  4177. data.Write(w,2);
  4178. // Save My connection public key
  4179. TStreamOp.WriteAnsiString(data,TAccountComp.AccountKey2RawString(TNetData.NetData.FNodePrivateKey.PublicKey));
  4180. // Save my Unix timestamp (4 bytes)
  4181. currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  4182. data.Write(currunixtimestamp,4);
  4183. // Save last operations block
  4184. TPCOperationsComp.SaveOperationBlockToStream(TNode.Node.Bank.LastOperationBlock,data);
  4185. nsarr := TNetData.NetData.NodeServersAddresses.GetValidNodeServers(true,CT_MAX_NODESERVERS_ON_HELLO);
  4186. i := length(nsarr);
  4187. data.Write(i,4);
  4188. for i := 0 to High(nsarr) do begin
  4189. nsa := nsarr[i];
  4190. TStreamOp.WriteAnsiString(data,TEncoding.ASCII.GetBytes(nsa.ip));
  4191. data.Write(nsa.port,2);
  4192. data.Write(nsa.last_connection,4);
  4193. end;
  4194. // Send client version
  4195. TStreamOp.WriteAnsiString(data,TEncoding.ASCII.GetBytes(TNode.NodeVersion));
  4196. // Build 1.5 send accumulated work
  4197. data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
  4198. //
  4199. Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
  4200. Result := Client.Connected;
  4201. FLastHelloTS := TPlatform.GetTickCount;
  4202. finally
  4203. data.Free;
  4204. end;
  4205. end;
  4206. function TNetConnection.Send_Message(const TheMessage: String): Boolean;
  4207. Var data : TStream;
  4208. cyp : TRawBytes;
  4209. begin
  4210. Result := false;
  4211. if Not Connected then exit;
  4212. data := TMemoryStream.Create;
  4213. Try
  4214. // Cypher message:
  4215. TPCEncryption.DoPascalCoinECIESEncrypt(FClientPublicKey,TEncoding.ASCII.GetBytes(TheMessage),cyp);
  4216. TStreamOp.WriteAnsiString(data,cyp);
  4217. Send(ntp_autosend,CT_NetOp_Message,0,0,data);
  4218. Result := true;
  4219. Finally
  4220. data.Free;
  4221. End;
  4222. end;
  4223. function TNetConnection.Send_NewBlockFound(const NewBlock: TPCOperationsComp): Boolean;
  4224. var data : TStream;
  4225. request_id : Integer;
  4226. netOp : Word;
  4227. c : Cardinal;
  4228. i : Integer;
  4229. opRef : TOpReference;
  4230. begin
  4231. Result := false;
  4232. if Not Connected then exit;
  4233. FNetLock.Acquire;
  4234. Try
  4235. // Clear buffers
  4236. FBufferLock.Acquire;
  4237. Try
  4238. FBufferReceivedOperationsHash.Clear;
  4239. FBufferToSendOperations.ClearHastThree;
  4240. finally
  4241. FBufferLock.Release;
  4242. end;
  4243. // Checking if operationblock is the same to prevent double messaging...
  4244. If (TPCOperationsComp.EqualsOperationBlock(FRemoteOperationBlock,NewBlock.OperationBlock)) then begin
  4245. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,ClassName,'This connection has the same block, does not need to send');{$ENDIF}
  4246. exit;
  4247. end;
  4248. if (TNode.Node.Bank.BlocksCount<>NewBlock.OperationBlock.block+1) then begin
  4249. TLog.NewLog(ltDebug,ClassName,'The block number '+IntToStr(NewBlock.OperationBlock.block)+' is not equal to current blocks stored in bank ('+IntToStr(TNode.Node.Bank.BlocksCount)+'), finalizing');
  4250. exit;
  4251. end;
  4252. data := TMemoryStream.Create;
  4253. try
  4254. request_id := TNetData.NetData.NewRequestId;
  4255. // Will send a FAST PROPAGATION BLOCK as described at PIP-0015
  4256. netOp := CT_NetOp_NewBlock_Fast_Propagation;
  4257. NewBlock.SaveBlockToStream(netOp = CT_NetOp_NewBlock_Fast_Propagation,data); // Will save all only if not FAST PROPAGATION
  4258. data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
  4259. if (netOp = CT_NetOp_NewBlock_Fast_Propagation) then begin
  4260. // Fill with OpReference data:
  4261. c := NewBlock.OperationsHashTree.OperationsCount;
  4262. data.Write(c,SizeOf(c));
  4263. if (c>0) then begin
  4264. for i := 0 to (Integer(c)-1) do begin
  4265. opRef := NewBlock.Operation[i].GetOpReference;
  4266. data.Write(opRef,SizeOf(opRef));
  4267. end;
  4268. end;
  4269. end;
  4270. Send(ntp_autosend,netOp,0,request_id,data);
  4271. finally
  4272. data.Free;
  4273. end;
  4274. Finally
  4275. FNetLock.Release;
  4276. End;
  4277. Result := Connected;
  4278. end;
  4279. procedure TNetConnection.SetClient(const Value: TNetTcpIpClient);
  4280. Var old : TNetTcpIpClient;
  4281. begin
  4282. if FTcpIpClient<>Value then begin
  4283. if Assigned(FTcpIpClient) then begin
  4284. FTcpIpClient.OnConnect := Nil;
  4285. FTcpIpClient.OnDisconnect := Nil;
  4286. FTcpIpClient.RemoveFreeNotification(Self);
  4287. end;
  4288. TNetData.NetData.UnRegisterRequest(Self,0,0);
  4289. old := FTcpIpClient;
  4290. FTcpIpClient := Value;
  4291. if Assigned(old) then begin
  4292. if old.Owner=Self then begin
  4293. old.Free;
  4294. end;
  4295. end;
  4296. end;
  4297. if Assigned(FTcpIpClient) then begin
  4298. FTcpIpClient.FreeNotification(Self);
  4299. FTcpIpClient.OnConnect := TcpClient_OnConnect;
  4300. FTcpIpClient.OnDisconnect := TcpClient_OnDisconnect;
  4301. end;
  4302. TNetData.NetData.NotifyNetConnectionUpdated;
  4303. end;
  4304. procedure TNetConnection.SetConnected(const Value: Boolean);
  4305. begin
  4306. if (Value = GetConnected) then exit;
  4307. if Value then ConnectTo(Client.RemoteHost,Client.RemotePort)
  4308. else begin
  4309. FinalizeConnection;
  4310. Client.Disconnect;
  4311. end;
  4312. end;
  4313. procedure TNetConnection.TcpClient_OnConnect(Sender: TObject);
  4314. begin
  4315. TNetData.NetData.IncStatistics(1,0,1,0,0,0);
  4316. TLog.NewLog(ltdebug,Classname,'Connected to a server '+ClientRemoteAddr);
  4317. TNetData.NetData.NotifyNetConnectionUpdated;
  4318. end;
  4319. procedure TNetConnection.TcpClient_OnDisconnect(Sender: TObject);
  4320. begin
  4321. if self is TNetServerClient then TNetData.NetData.IncStatistics(-1,-1,0,0,0,0)
  4322. else begin
  4323. if FHasReceivedData then TNetData.NetData.IncStatistics(-1,0,-1,-1,0,0)
  4324. else TNetData.NetData.IncStatistics(-1,0,-1,0,0,0);
  4325. end;
  4326. TLog.NewLog(ltInfo,Classname,'Disconnected from '+ClientRemoteAddr);
  4327. TNetData.NetData.NotifyNetConnectionUpdated;
  4328. if (FClientTimestampIp<>'') then begin
  4329. TNetData.NetData.NetworkAdjustedTime.RemoveIp(FClientTimestampIp);
  4330. end;
  4331. end;
  4332. { TNetClientThread }
  4333. procedure TNetClientThread.BCExecute;
  4334. begin
  4335. while (Not Terminated) do begin
  4336. If FNetClient.Connected then begin
  4337. FNetClient.DoProcessBuffer;
  4338. end;
  4339. Sleep(1);
  4340. end;
  4341. end;
  4342. constructor TNetClientThread.Create(NetClient: TNetClient; AOnTerminateThread : TNotifyEvent);
  4343. begin
  4344. FNetClient := NetClient;
  4345. inherited Create(false);
  4346. OnTerminate := AOnTerminateThread;
  4347. end;
  4348. { TNetClient }
  4349. constructor TNetClient.Create(AOwner: TComponent);
  4350. begin
  4351. inherited;
  4352. FNetClientThread := TNetClientThread.Create(Self,OnNetClientThreadTerminated);
  4353. FNetClientThread.FreeOnTerminate := false;
  4354. end;
  4355. destructor TNetClient.Destroy;
  4356. begin
  4357. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Starting TNetClient.Destroy');{$ENDIF}
  4358. FNetClientThread.OnTerminate := Nil;
  4359. if Not FNetClientThread.Terminated then begin
  4360. FNetClientThread.Terminate;
  4361. FNetClientThread.WaitFor;
  4362. end;
  4363. FreeAndNil(FNetClientThread);
  4364. inherited;
  4365. end;
  4366. procedure TNetClient.OnNetClientThreadTerminated(Sender: TObject);
  4367. begin
  4368. // Close connection
  4369. if TNetData.NetData.ConnectionExistsAndActive(Self) then begin
  4370. Connected := false;
  4371. end;
  4372. end;
  4373. { TThreadDiscoverConnection }
  4374. procedure TThreadDiscoverConnection.BCExecute;
  4375. Var NC : TNetClient;
  4376. ok : Boolean;
  4377. ns : TNodeServerAddress;
  4378. begin
  4379. Repeat // Face to face conflict when 2 nodes connecting together
  4380. Sleep(Random(1000));
  4381. until (Terminated) Or (Random(5)=0);
  4382. if Terminated then exit;
  4383. {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Starting discovery of connection '+FNodeServerAddress.ip+':'+InttoStr(FNodeServerAddress.port));{$ENDIF}
  4384. DebugStep := 'Locking list';
  4385. // Register attempt
  4386. If TNetData.NetData.NodeServersAddresses.GetNodeServerAddress(FNodeServerAddress.ip,FNodeServerAddress.port,true,ns) then begin
  4387. ns.last_attempt_to_connect := Now;
  4388. inc(ns.total_failed_attemps_to_connect);
  4389. TNetData.NetData.NodeServersAddresses.SetNodeServerAddress(ns);
  4390. end;
  4391. DebugStep := 'Synchronizing notify';
  4392. if Terminated then exit;
  4393. TNetData.NetData.NotifyNodeServersUpdated;
  4394. // Try to connect
  4395. ok := false;
  4396. DebugStep := 'Trying to connect';
  4397. if Terminated then exit;
  4398. NC := TNetClient.Create(Nil);
  4399. Try
  4400. DebugStep := 'Connecting';
  4401. If NC.ConnectTo(FNodeServerAddress.ip,FNodeServerAddress.port) then begin
  4402. if Terminated then exit;
  4403. Sleep(500);
  4404. DebugStep := 'Is connected now?';
  4405. if Terminated then exit;
  4406. ok :=NC.Connected;
  4407. end;
  4408. if Terminated then exit;
  4409. Finally
  4410. if (not ok) And (Not Terminated) then begin
  4411. DebugStep := 'Destroying non connected';
  4412. NC.FinalizeConnection;
  4413. end;
  4414. End;
  4415. DebugStep := 'Synchronizing notify final';
  4416. if Terminated then exit;
  4417. TNetData.NetData.NotifyNodeServersUpdated;
  4418. end;
  4419. constructor TThreadDiscoverConnection.Create(NodeServerAddress: TNodeServerAddress; NotifyOnTerminate : TNotifyEvent);
  4420. begin
  4421. FNodeServerAddress := NodeServerAddress;
  4422. inherited Create(true);
  4423. OnTerminate := NotifyOnTerminate;
  4424. FreeOnTerminate := true;
  4425. Suspended := false;
  4426. end;
  4427. { TThreadCheckConnections }
  4428. procedure TThreadCheckConnections.BCExecute;
  4429. Var l : TList<TNetConnection>;
  4430. i, nactive,ndeleted,nserverclients : Integer;
  4431. netconn : TNetConnection;
  4432. netserverclientstop : TNetServerClient;
  4433. newstats : TNetStatistics;
  4434. begin
  4435. FLastCheckTS := TPlatform.GetTickCount;
  4436. while (Not Terminated) do begin
  4437. if ((TPlatform.GetTickCount>(FLastCheckTS+1000)) AND (Not FNetData.FIsDiscoveringServers)) then begin
  4438. nactive := 0;
  4439. ndeleted := 0;
  4440. nserverclients := 0;
  4441. netserverclientstop := Nil;
  4442. FLastCheckTS := TPlatform.GetTickCount;
  4443. If (FNetData.FNetConnections.TryLockList(100,l)) then begin
  4444. try
  4445. newstats := CT_TNetStatistics_NUL;
  4446. for i := l.Count-1 downto 0 do begin
  4447. netconn := TNetConnection(l.Items[i]);
  4448. if (netconn is TNetClient) then begin
  4449. if (netconn.Connected) then begin
  4450. inc(newstats.ServersConnections);
  4451. if (netconn.FHasReceivedData) then inc(newstats.ServersConnectionsWithResponse);
  4452. end;
  4453. if (Not TNetClient(netconn).Connected) And (netconn.CreatedTime+EncodeTime(0,0,5,0)<now) then begin
  4454. // Free this!
  4455. TNetClient(netconn).FinalizeConnection;
  4456. inc(ndeleted);
  4457. end else inc(nactive);
  4458. end else if (netconn is TNetServerClient) then begin
  4459. if (netconn.Connected) then begin
  4460. inc(newstats.ClientsConnections);
  4461. end;
  4462. inc(nserverclients);
  4463. if (Not netconn.FDoFinalizeConnection) then begin
  4464. // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
  4465. if not assigned(netserverclientstop) then begin
  4466. netserverclientstop := TNetServerClient(netconn);
  4467. end else if (netconn.CreatedTime<netserverclientstop.CreatedTime) then begin
  4468. netserverclientstop := TNetServerClient(netconn);
  4469. end;
  4470. end;
  4471. end;
  4472. end;
  4473. // Update stats:
  4474. FNetData.FNetStatistics.ActiveConnections := newstats.ClientsConnections + newstats.ServersConnections;
  4475. FNetData.FNetStatistics.ClientsConnections := newstats.ClientsConnections;
  4476. FNetData.FNetStatistics.ServersConnections := newstats.ServersConnections;
  4477. FNetData.FNetStatistics.ServersConnectionsWithResponse := newstats.ServersConnectionsWithResponse;
  4478. // Must stop clients?
  4479. if (nserverclients>FNetData.MaxServersConnected) And // This is to ensure there are more serverclients than clients
  4480. ((nserverclients + nactive + ndeleted)>=FNetData.FMaxConnections) And (Assigned(netserverclientstop)) then begin
  4481. TLog.NewLog(ltinfo,Classname,Format('Sending FinalizeConnection to NodeConnection %s created on %s (working time %s) - NetServerClients:%d Servers_active:%d Servers_deleted:%d',
  4482. [netserverclientstop.Client.ClientRemoteAddr,FormatDateTime('hh:nn:ss',netserverclientstop.CreatedTime),
  4483. FormatDateTime('hh:nn:ss',Now - netserverclientstop.CreatedTime),
  4484. nserverclients,nactive,ndeleted]));
  4485. netserverclientstop.FinalizeConnection;
  4486. end;
  4487. finally
  4488. FNetData.FNetConnections.UnlockList;
  4489. end;
  4490. if (nactive<=FNetData.MaxServersConnected) And (Not Terminated) then begin
  4491. // Discover
  4492. FNetData.DiscoverServers;
  4493. end;
  4494. end;
  4495. end;
  4496. sleep(100);
  4497. end;
  4498. end;
  4499. constructor TThreadCheckConnections.Create(NetData: TNetData);
  4500. begin
  4501. FNetData := NetData;
  4502. inherited Create(false);
  4503. end;
  4504. { TThreadGetNewBlockChainFromClient }
  4505. procedure TThreadGetNewBlockChainFromClient.BCExecute;
  4506. Var i,j : Integer;
  4507. maxWork : UInt64;
  4508. candidates : TList<TNetConnection>;
  4509. lop : TOperationBlock;
  4510. nc : TNetConnection;
  4511. begin
  4512. if Not TNode.Node.UpdateBlockchain then Exit;
  4513. // Search better candidates:
  4514. candidates := TList<TNetConnection>.Create;
  4515. try
  4516. lop := CT_OperationBlock_NUL;
  4517. TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
  4518. // First round: Find by most work
  4519. maxWork := 0;
  4520. j := TNetData.NetData.ConnectionsCountAll;
  4521. nc := Nil;
  4522. for i := 0 to j - 1 do begin
  4523. if TNetData.NetData.GetConnection(i,nc) then begin
  4524. if (nc.FRemoteAccumulatedWork>maxWork) And (nc.FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
  4525. maxWork := nc.FRemoteAccumulatedWork;
  4526. end;
  4527. // Preventing downloading
  4528. if nc.FIsDownloadingBlocks then exit;
  4529. end;
  4530. end;
  4531. if (maxWork>0) then begin
  4532. for i := 0 to j - 1 do begin
  4533. If TNetData.NetData.GetConnection(i,nc) then begin
  4534. if (nc.FRemoteAccumulatedWork>=maxWork) then begin
  4535. candidates.Add(nc);
  4536. lop := nc.FRemoteOperationBlock;
  4537. end;
  4538. end;
  4539. end;
  4540. end;
  4541. // Second round: Find by most height
  4542. if candidates.Count=0 then begin
  4543. for i := 0 to j - 1 do begin
  4544. if (TNetData.NetData.GetConnection(i,nc)) then begin
  4545. if (nc.FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
  4546. (nc.FRemoteOperationBlock.block>=lop.block) then begin
  4547. lop := nc.FRemoteOperationBlock;
  4548. end;
  4549. end;
  4550. end;
  4551. if (lop.block>0) then begin
  4552. for i := 0 to j - 1 do begin
  4553. If (TNetData.NetData.GetConnection(i,nc)) then begin
  4554. if (nc.FRemoteOperationBlock.block>=lop.block) then begin
  4555. candidates.Add(nc);
  4556. end;
  4557. end;
  4558. end;
  4559. end;
  4560. end;
  4561. TNetData.NetData.FMaxRemoteOperationBlock := lop;
  4562. if (candidates.Count>0) then begin
  4563. // Random a candidate
  4564. i := 0;
  4565. if (candidates.Count>1) then i := Random(candidates.Count); // i = 0..count-1
  4566. nc := TNetConnection(candidates[i]);
  4567. TNetData.NetData.GetNewBlockChainFromClient(nc,Format('Candidate block: %d sum: %d',[nc.FRemoteOperationBlock.block,nc.FRemoteAccumulatedWork]));
  4568. end;
  4569. finally
  4570. candidates.Free;
  4571. end;
  4572. end;
  4573. constructor TThreadGetNewBlockChainFromClient.Create;
  4574. begin
  4575. Inherited Create(True);
  4576. FreeOnTerminate := true;
  4577. Suspended := false;
  4578. end;
  4579. { TNetDataNotifyEventsThread }
  4580. procedure TNetDataNotifyEventsThread.BCExecute;
  4581. begin
  4582. while (not Terminated) do begin
  4583. if (FNotifyOnReceivedHelloMessage) Or
  4584. (FNotifyOnStatisticsChanged) Or
  4585. (FNotifyOnNetConnectionsUpdated) Or
  4586. (FNotifyOnNodeServersUpdated) Or
  4587. (FNotifyOnBlackListUpdated) then begin
  4588. Synchronize(SynchronizedNotify);
  4589. end;
  4590. Sleep(10);
  4591. end;
  4592. end;
  4593. constructor TNetDataNotifyEventsThread.Create(ANetData: TNetData);
  4594. begin
  4595. FNetData := ANetData;
  4596. FNotifyOnReceivedHelloMessage := false;
  4597. FNotifyOnStatisticsChanged := false;
  4598. FNotifyOnNetConnectionsUpdated := false;
  4599. FNotifyOnNodeServersUpdated := false;
  4600. FNotifyOnBlackListUpdated := false;
  4601. inherited Create(false);
  4602. end;
  4603. procedure TNetDataNotifyEventsThread.SynchronizedNotify;
  4604. begin
  4605. if Terminated then exit;
  4606. if Not Assigned(FNetData) then exit;
  4607. if FNotifyOnReceivedHelloMessage then begin
  4608. FNotifyOnReceivedHelloMessage := false;
  4609. If Assigned(FNetData.FOnReceivedHelloMessage) then FNetData.FOnReceivedHelloMessage(FNetData);
  4610. end;
  4611. if FNotifyOnStatisticsChanged then begin
  4612. FNotifyOnStatisticsChanged := false;
  4613. If Assigned(FNetData.FOnStatisticsChanged) then FNetData.FOnStatisticsChanged(FNetData);
  4614. end;
  4615. if FNotifyOnNetConnectionsUpdated then begin
  4616. FNotifyOnNetConnectionsUpdated := false;
  4617. If Assigned(FNetData.FOnNetConnectionsUpdated) then FNetData.FOnNetConnectionsUpdated(FNetData);
  4618. end;
  4619. if FNotifyOnNodeServersUpdated then begin
  4620. FNotifyOnNodeServersUpdated := false;
  4621. If Assigned(FNetData.FOnNodeServersUpdated) then FNetData.FOnNodeServersUpdated(FNetData);
  4622. end;
  4623. if FNotifyOnBlackListUpdated then begin
  4624. FNotifyOnBlackListUpdated := false;
  4625. If Assigned(FNetData.FOnBlackListUpdated) then FNetData.FOnBlackListUpdated(FNetData);
  4626. end;
  4627. end;
  4628. { TNetClientsDestroyThread }
  4629. procedure TNetClientsDestroyThread.BCExecute;
  4630. Var l,l_to_del : TList<TNetConnection>;
  4631. i : Integer;
  4632. LNetConnection : TNetConnection;
  4633. begin
  4634. l_to_del := TList<TNetConnection>.Create;
  4635. Try
  4636. while not Terminated do begin
  4637. l_to_del.Clear;
  4638. l := FNetData.NetConnections.LockList;
  4639. try
  4640. FTerminatedAllConnections := l.Count=0;
  4641. for i := 0 to l.Count-1 do begin
  4642. If (TObject(l[i]) is TNetClient) And (not TNetConnection(l[i]).Connected)
  4643. And (TNetConnection(l[i]).FDoFinalizeConnection)
  4644. And (Not TNetConnection(l[i]).IsConnecting) then begin
  4645. l_to_del.Add(l[i]);
  4646. end;
  4647. end;
  4648. finally
  4649. FNetData.NetConnections.UnlockList;
  4650. end;
  4651. sleep(500); // Delay - Sleep time before destroying (1.5.3)
  4652. if l_to_del.Count>0 then begin
  4653. TLog.NewLog(ltDebug,ClassName,'Destroying NetClients: '+inttostr(l_to_del.Count));
  4654. for i := 0 to l_to_del.Count - 1 do begin
  4655. Try
  4656. LNetConnection := l_to_del[i];
  4657. DebugStep := 'Destroying NetClient '+LNetConnection.ClientRemoteAddr;
  4658. {$IFDEF AUTOREFCOUNT}
  4659. { On Delphi mobile, the Free method is not called. We need this
  4660. manual calls to remove this connection from TNetData lists}
  4661. TNetData.NetData.NodeServersAddresses.DeleteNetConnection(LNetConnection);
  4662. TNetData.NetData.FNetConnections.Remove(LNetConnection);
  4663. TNetData.NetData.UnRegisterRequest(LNetConnection,0,0);
  4664. {$ENDIF}
  4665. LNetConnection.Free;
  4666. Except
  4667. On E:Exception do begin
  4668. TLog.NewLog(ltError,ClassName,'Exception destroying TNetConnection '+IntToHex(PtrInt(l_to_del[i]),8)+': ('+E.ClassName+') '+E.Message );
  4669. end;
  4670. End;
  4671. end;
  4672. end;
  4673. Sleep(100);
  4674. end;
  4675. Finally
  4676. l_to_del.Free;
  4677. end;
  4678. end;
  4679. constructor TNetClientsDestroyThread.Create(NetData: TNetData);
  4680. begin
  4681. FNetData:=NetData;
  4682. FTerminatedAllConnections := true;
  4683. Inherited Create(false);
  4684. end;
  4685. procedure TNetClientsDestroyThread.WaitForTerminatedAllConnections;
  4686. var LTC : TTickCount;
  4687. begin
  4688. LTC := TPlatform.GetTickCount;
  4689. while (Not FTerminatedAllConnections) do begin
  4690. if TPlatform.GetElapsedMilliseconds(LTC)>1000 then begin
  4691. LTC := TPlatform.GetTickCount;
  4692. TLog.NewLog(ltdebug,ClassName,'Waiting all connections terminated');
  4693. end;
  4694. Sleep(50);
  4695. end;
  4696. end;
  4697. { TNetworkAdjustedTime }
  4698. Type TNetworkAdjustedTimeReg = Record
  4699. clientIp : String; // Client IP allows only 1 connection per IP (not using port)
  4700. timeOffset : Integer;
  4701. counter : Integer; // To prevent a time attack from a single IP with multiple connections, only 1 will be used for calc NAT
  4702. End;
  4703. PNetworkAdjustedTimeReg = ^TNetworkAdjustedTimeReg;
  4704. procedure TNetworkAdjustedTime.AddNewIp(const clientIp: String; clientTimestamp : Cardinal);
  4705. Var l : TList<Pointer>;
  4706. i : Integer;
  4707. P : PNetworkAdjustedTimeReg;
  4708. begin
  4709. l := FTimesList.LockList;
  4710. try
  4711. i := IndexOfClientIp(l,clientIp);
  4712. if i<0 then begin
  4713. New(P);
  4714. P^.clientIp := clientIp;
  4715. P^.counter := 0;
  4716. l.Add(P);
  4717. end else begin
  4718. P := l[i];
  4719. end;
  4720. P^.timeOffset := clientTimestamp - UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  4721. inc(P^.counter);
  4722. inc(FTotalCounter);
  4723. UpdateMedian(l);
  4724. TLog.NewLog(ltDebug,ClassName,Format('AddNewIp (%s,%d) - Total:%d/%d Offset:%d',[clientIp,clientTimestamp,l.Count,FTotalCounter,FTimeOffset]));
  4725. finally
  4726. FTimesList.UnlockList;
  4727. end;
  4728. end;
  4729. constructor TNetworkAdjustedTime.Create;
  4730. begin
  4731. FTimesList := TPCThreadList<Pointer>.Create('TNetworkAdjustedTime_TimesList');
  4732. FTimeOffset := 0;
  4733. FTotalCounter := 0;
  4734. end;
  4735. destructor TNetworkAdjustedTime.Destroy;
  4736. Var P : PNetworkAdjustedTimeReg;
  4737. i : Integer;
  4738. l : TList<Pointer>;
  4739. begin
  4740. l := FTimesList.LockList;
  4741. try
  4742. for i := 0 to l.Count - 1 do begin
  4743. P := l[i];
  4744. Dispose(P);
  4745. end;
  4746. l.Clear;
  4747. finally
  4748. FTimesList.UnlockList;
  4749. end;
  4750. FreeAndNil(FTimesList);
  4751. inherited;
  4752. end;
  4753. function TNetworkAdjustedTime.GetAdjustedTime: Cardinal;
  4754. begin
  4755. Result := UnivDateTimeToUnix(DateTime2UnivDateTime(now)) + FTimeOffset;
  4756. end;
  4757. function TNetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock: Cardinal;
  4758. var l : TList<Pointer>;
  4759. begin
  4760. l := FTimesList.LockList;
  4761. try
  4762. Result := (GetAdjustedTime + CT_MaxFutureBlockTimestampOffset);
  4763. finally
  4764. FTimesList.UnlockList;
  4765. end;
  4766. end;
  4767. function TNetworkAdjustedTime.IndexOfClientIp(list: TList<Pointer>; const clientIp: String): Integer;
  4768. begin
  4769. for Result := 0 to list.Count - 1 do begin
  4770. if SameStr(PNetworkAdjustedTimeReg(list[result])^.clientIp,clientIp) then exit;
  4771. end;
  4772. Result := -1;
  4773. end;
  4774. procedure TNetworkAdjustedTime.RemoveIp(const clientIp: String);
  4775. Var l : TList<Pointer>;
  4776. i : Integer;
  4777. P : PNetworkAdjustedTimeReg;
  4778. begin
  4779. l := FTimesList.LockList;
  4780. try
  4781. i := IndexOfClientIp(l,clientIp);
  4782. if (i>=0) then begin
  4783. P := l[i];
  4784. Dec(P^.counter);
  4785. if (P^.counter<=0) then begin
  4786. l.Delete(i);
  4787. Dispose(P);
  4788. end;
  4789. Dec(FTotalCounter);
  4790. end;
  4791. UpdateMedian(l);
  4792. if (i>=0) then
  4793. TLog.NewLog(ltDebug,ClassName,Format('RemoveIp (%s) - Total:%d/%d Offset:%d',[clientIp,l.Count,FTotalCounter,FTimeOffset]))
  4794. else TLog.NewLog(ltError,ClassName,Format('RemoveIp not found (%s) - Total:%d/%d Offset:%d',[clientIp,l.Count,FTotalCounter,FTimeOffset]))
  4795. finally
  4796. FTimesList.UnlockList;
  4797. end;
  4798. end;
  4799. procedure TNetworkAdjustedTime.UpdateIp(const clientIp: String; clientTimestamp: Cardinal);
  4800. Var l : TList<Pointer>;
  4801. i : Integer;
  4802. P : PNetworkAdjustedTimeReg;
  4803. lastOffset : Integer;
  4804. begin
  4805. l := FTimesList.LockList;
  4806. try
  4807. i := IndexOfClientIp(l,clientIp);
  4808. if i<0 then begin
  4809. TLog.NewLog(ltError,ClassName,Format('UpdateIP (%s,%d) not found',[clientIp,clientTimestamp]));
  4810. exit;
  4811. end else begin
  4812. P := l[i];
  4813. end;
  4814. lastOffset := P^.timeOffset;
  4815. P^.timeOffset := clientTimestamp - UnivDateTimeToUnix(DateTime2UnivDateTime(now));
  4816. if (lastOffset<>P^.timeOffset) then begin
  4817. UpdateMedian(l);
  4818. {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,ClassName,Format('UpdateIp (%s,%d) - Total:%d/%d Offset:%d',[clientIp,clientTimestamp,l.Count,FTotalCounter,FTimeOffset]));{$ENDIF}
  4819. end;
  4820. finally
  4821. FTimesList.UnlockList;
  4822. end;
  4823. end;
  4824. {$IFDEF FPC}
  4825. type
  4826. TPNetworkAdjustedTimeReg = class(TInterfacedObject, IComparer<Pointer>)
  4827. public
  4828. function Compare(constref ALeft, ARight: Pointer): Integer;
  4829. end;
  4830. { TPNetworkAdjustedTimeReg }
  4831. function TPNetworkAdjustedTimeReg.Compare(constref ALeft, ARight: Pointer): Integer;
  4832. begin
  4833. Result := PNetworkAdjustedTimeReg(ALeft)^.timeOffset - PNetworkAdjustedTimeReg(ARight)^.timeOffset;
  4834. end;
  4835. {$ENDIF}
  4836. procedure TNetworkAdjustedTime.UpdateMedian(list : TList<Pointer>);
  4837. Var last : Integer;
  4838. i : Integer;
  4839. s : String;
  4840. {$IFNDEF FPC}
  4841. LComparison : TComparison<Pointer>;
  4842. {$ELSE}
  4843. LComparer : TPNetworkAdjustedTimeReg;
  4844. {$ENDIF}
  4845. begin
  4846. last := FTimeOffset;
  4847. {$IFDEF FPC}
  4848. LComparer := TPNetworkAdjustedTimeReg.Create;
  4849. try
  4850. list.Sort(LComparer);
  4851. finally
  4852. LComparer.Free;
  4853. end;
  4854. {$ELSE}
  4855. LComparison :=
  4856. function(const Left, Right: Pointer): Integer
  4857. begin
  4858. Result := PNetworkAdjustedTimeReg(Left)^.timeOffset - PNetworkAdjustedTimeReg(Right)^.timeOffset;
  4859. end;
  4860. List.Sort(TComparer<Pointer>.Construct(LComparison));
  4861. {$ENDIF}
  4862. if list.Count<CT_MinNodesToCalcNAT then begin
  4863. FTimeOffset := 0;
  4864. end else if ((list.Count MOD 2)=0) then begin
  4865. FTimeOffset := (PNetworkAdjustedTimeReg(list[(list.Count DIV 2)-1])^.timeOffset + PNetworkAdjustedTimeReg(list[(list.Count DIV 2)])^.timeOffset) DIV 2;
  4866. end else begin
  4867. FTimeOffset := PNetworkAdjustedTimeReg(list[list.Count DIV 2])^.timeOffset;
  4868. end;
  4869. if (last<>FTimeOffset) then begin
  4870. s := '';
  4871. for i := 0 to list.Count - 1 do begin
  4872. s := s + ',' + IntToStr(PNetworkAdjustedTimeReg(list[i])^.timeOffset);
  4873. end;
  4874. TLog.NewLog(ltdebug,ClassName,
  4875. Format('Updated NAT median offset. My offset is now %d (before %d) based on %d/%d connections %s',[FTimeOffset,last,list.Count,FTotalCounter,s]));
  4876. end;
  4877. end;
  4878. initialization
  4879. _NetData := Nil;
  4880. finalization
  4881. FreeAndNil(_NetData);
  4882. end.