UNetProtocol.pas 200 KB

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