UNetProtocol.pas 210 KB

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