UNetProtocol.pas 189 KB

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