Добро попладне, на сите! Долго време се занимавам со развој на Backend, а во последните неколку години пишувам се повеќе различни блокчејн проекти (Solidity на EVM). Нуркањето во блокчејн не ми беше лесно, а мојот заден мозок се расипа неколку пати, па решив да го споделам моето мислење за преминувањето кон развој на блокчејн.
Одрекување: сè што е опишано подолу е чисто мое мислење. Може да грешам, а и редовно грешам :))
Блокчејн е многу кул технологија што може да го придвижи нашиот свет напред. Но, сега за сега, многу луѓе го користат за да купат-продадат-измамат-измамат-зголемат. Јас нема и не планирам да го сметам крипто како предност.
Да, многу различни видеа и објави велат: „Еве, таков и таков крипто може да расте сега, а таков и таков крипто падна. Момци, да инвестираме, да купиме...“ Нема да ви кажам ништо за тоа.
Ќе кажам само едно - треба да избегнувате крипто за заработка. Ако сте програмер, подобро е да се обидете да заработите како програмер и да не се вклучите во инвестиции. И ако навистина сакате да инвестирате, не навлегувајте во крипто.
Вреди да се започне со важна забелешка. Блокчејн не е криптовалута. Блокчејн е технологијата на која е изградена криптовалутата, а криптовалутата да се нарекува блокчејн е исто како да се нарекува целата развојна индустрија Javascript . Да, се чини дека JavaScript е посебен случај за развој, но кога се дискутира за развој, не мислиме на JavaScript. Иако некои луѓе мислат само JavaScript...
Првото нешто што ми паѓа на ум се парите. Програмерите на блокчејн се платени доста добро. Јас лично имам отворено вакви работни места. Јас лично одговорив на такви слободни работни места, каде што можете да добиете повеќе од ист развивач на заднина за истото време поминато дневно на работа. Програмерите на блокчејн вредат злато во стартапи базирани на блокчејн. Особено добар развивач на блокчејн!
Невозможно е да се стане добар развивач на заднина, без да се отфрли или поправи. Можеби јас сум само губитник и учам само преку негативни искуства, но тоа е теоријата што ја имам:
Не можете да разменувате искуство со неуспех, но искуството на неуспех ви овозможува да сфатите дека имате искуство. Тешко е да се стане добар развивач на блокчејн без губење пари:
Сликата погоре го покажува првиот авион на браќата Рајт во светот, кој лета прилично лошо. Но, леташе, и во своето време, односот на просечниот човек кон авионите беше отприлика вака:
И сега, авиоиндустријата е прекрасен дел од нашите животи, поврзувајќи ги луѓето ширум планетата во рок од неколку часа. Логистиката сега е на ниво за кое браќата Рајт не сонувале! Целиот свет живее поинаку поради авионите.
Јас би го рекол истото за блокчејн сега - скапо е и незгодно и нејасно зошто. Додека не бев потопен во развојот на блокчејн, ми изгледаше како нешто бескорисно за мамење инвеститори (=хрчаци). Но, ако го погледнете од другата страна, можно е да се складираат какви било факти на децентрализиран начин без можност за манипулација. „Без можност за манипулација“ е важен детал.
Но, за жал, асоцијациите со зборот „блокчејн“ се прилично досадни и монотони:
Ако фрлиме сноп хартиени пари во шпоретот, шпоретот добро ќе изгори, а парите дури и ќе даваат топлина некое време. Но, тоа е апсурдно.
Така е и со блокчејнот. Да се користи само за пари и крипто е лошо, но другото сè уште не фаќа корени...
Еден од главните двигатели на развојот на секој производ се парите. Ако има нешто од кое може да се заработат добри и моќни пари, тогаш ова „нешто“ активно ќе се развива. И затоа, досега, финансиските проекти базирани на блокчејн навистина се засноваат на правење пари за некој да заработи пари и губење пари за некој друг.
Која е разликата помеѓу централизирана и децентрализирана услуга? Да почнеме со централизиран систем. Тука сме јас и некој друг, и решивме да користиме услуга меѓу нас, како банка или друг провајдер, за да го олесниме трансферот.
Да замислиме дека имаме банка, која е централизирана услуга. Ја командувам оваа банка: „Ве молиме префрлете 100 долари на оваа личност“. Банката евидентира дека јас имам 100 долари помалку, а некој друг има 100 долари повеќе.
Но, што е проблемот со централизираната услуга? Зад оваа централизирана услуга стои сопственик, нели? Обично, некои големи компании, холдинзи, не е важно; во нашиот случај нека биде една личност. Овој човек може да каже: „Ајде да го направиме ова. Алекс нека испрати 100 долари, но никој нема да ги добие овие 100 долари. Ми требаат повеќе“.
Централизираните услуги имаат свои сопственици. Проблемот е што сопственикот може да носи негативни одлуки, одземајќи пари. И не може да се работи само за „земање пари за себе“. На пример, можете да напишете „Имаме 100.500 долари во банка“ и да се надевате дека сите штедачи нема да тргнат по тие пари... како што се случи со SVB и другите банки кои умреа.
Биткоинот е измислен за да се децентрализира управувањето со парите.
Децентрализирана услуга е изградена на мрежа од јазли каде што секој јазол складира и пренесува информации. Едноставно кажано, јазлите се договорија кои информации се сметаат за точни, а што не и како ги складираме.
Можеме да направиме аналогија со соба - едно лице ги извикува информациите што сака другите да ги задржат. Потоа, сите во собата работат со информациите што ги зачувале по викањето.
На пример, блокчејн може да складира и пренесува пораки или информации за трансфери на пари. Учесниците во мрежата ги проверуваат информациите пред да ги снимаат.
Во аналогијата на собата, викам: „Префрлам 100 долари на Сем“. Сите бележат дека јас имам 100 долари помалку, а Сем има 100 долари повеќе. Ако наеднаш, пред трансферот имам помалку од 100 долари, никој нема да ја снима трансакцијата.
Во blockchain, можете да креирате паметни договори на јазикот Solidity (во случај на blockchain на EVM). Паметниот договор е програма што работи на блокчејн мрежата. Може да содржи механизми за валидација, справување со грешки и други функции.
Повторно, во случајот со просторијата каде што извикуваме команди, паметен договор е што на секој учесник во просторијата однапред му го давам програмскиот код: како да реагира на моите команди, што да провери и што да зачува. И тогаш викам: „Изврши ја програмата со овие параметри“. Потоа, сите ги следат упатствата. Пример за едноставен, паметен договор е складирање на информации со функции за додавање и примање податоци. Кодот на договорот се компајлира во бајт код и се предава на учесниците во блокчејнот за извршување.
Како се справуваме со конкретните барања што ќе бидат испратени до овој паметен договор? Ако нацртаме аналогија со задниот дел, тоа е услуга која може да ги обработува барањата POST и GET. POST складира информации. GET here ги враќа информациите што сме ги зачувале. Ова е обично како е структуриран секој заден дел.
За време на мојот развој на заднината, многу се навикнав на аранжманот дека API, базата на податоци и сè што е поврзано со складирање и обработка на податоци се случува на моја страна. И јас веќе, како зад ѕид, обезбедувам интерфејс за корисникот да работи со овие податоци според однапред подготвено сценарио.
На пример, корисникот 1 доаѓа и зачувува содржина (објава, на пример) преку методот POST. Потоа, корисникот 2 доаѓа и ја презема оваа содржина користејќи го методот GET. Корисниците не знаат каде и како лежи - задниот дел е црна кутија за нив.
И тука доаѓаме до еден многу важен дел од блокчејнот. Да се вратиме на нашите примери на јазли или луѓе кои стојат во соба. Да речеме, користејќи аналогија со задниот дел, секој пат го имаме следново: фрлам метод „ДОДАЈ“ во блокчејнот, а потоа секој локално го повикува методот и потоа може да земе информации од нивната копија на блокчејнот.
Значи, имаме еден куп различни копии во мрежата од кои јазлите земаат информации. Проблемот со блокчејн е тоа што мора да плаќаме вистински пари за секоја операција за пишување. Ова го плаќа мрежната валута, која може да се купи со вистински пари (или да се минира, но тоа не е она за што зборуваме денес).
Ако ги споредиме blockchain и backend, сликата е следна:
На пример, Telegram има централизирана база на податоци. Секогаш можеме да пристапиме до него бесплатно и да ги преземаме нашите пораки, фотографии, видеа итн. Но, ако серверите на Telegram ненадејно паднат, не можеме да пристапиме до него.
Мора да платиме за виртуелната машина EVM да изврши некои команди за паметни договори, вклучително и пишување информации во блокчејнот. Врши некои пресметки, собира нешто, се множи, множи, множи и на крајот, се појавува нов артефакт во складиштето на блокчејн, кој се ажурира на сите јазли кои учествуваат во блокчејнот.
Секој учесник во мрежата може да изврши целосен јазол со стотици гигабајти блокчејн податоци и да работи со него локално. Можете исто така да користите лесна верзија на јазолот, која нема да го складира целиот блокчејн, но можете да пристапите до целосните јазли во мрежата и да ги вратите потребните информации преку него.
Идејата е дека секој запис во блокчејнот е блок кој содржи куп трансакции во кои се случуваат промени во состојбата на блокчејнот. Секој последователен блок зависи од претходниот во синџирот заснован на алгоритми за хеширање.
Во принцип, тоа е основно, но вреди да се има на ум - мора да платите за секое кивање доколку се променат податоците. Патем, распоредувањето на договор е исто така рекорд во блокчејнот и не е евтин!
Во светот на задниот дел, навикнат сум на приближно следниот животен циклус на развој на функции:
Односно, навикнати сме да работиме на овој начин, а тоа се случува бесплатно. Иако условно бесплатно, затоа што плаќаме за серверите. Што е со блокчејн?
Во случај на блокчејн, треба да го напишеме новиот код на нашата „апликација“ (паметен договор) во блокчејнот. Како што напишав погоре, треба да платиме за секоја плоча. Пред да направиме трансакција со нашиот паметен договор, треба да направиме трансакција со поставувањето на паметниот договор.
Потоа, клиентот/серверот за услуги ќе контактира со кој било од јазлите за да прима или зачува информации во договорот.
Треба да се известат огромен број јазли - „момци, еве го бајтекодот на договорот чии алгоритми треба да се направат за моите трансакции“. Неопходно е да бидете сигурни дека истиот код се појавува на сите јазли што го учат блокчејнот и тој ќе биде извршен на ист начин, без разлика кој го повикува и без разлика како се нарекува. Механиката ќе биде иста и непроменлива. Понатаму, не постои начин паметниот договор некако да се промени за да работи поинаку на кој било од јазлите.
Подолу е пример за трансакција каде што депонирав договор во мрежата на ETH пред многу одамна.
Тоа беше тест договор кој никогаш не бил користен во реалноста. Платив 200 долари во ЕТХ за неговото распоредување. Односно, сè уште немавме направено ништо со овој договор - ниту едно барање, туку веќе беа потрошени 200 долари. Сè уште сум тажен кога се сеќавам на ова погрешно распоредување на погрешен договор...
Ајде да зборуваме за складирање податоци. Сите ние сме навикнати да имаме PostgreSQL , MySQL , MongoDB , Redis и други услуги на задниот дел што ни овозможуваат практично да работиме со податоци. Во случај на блокчејн, нема ништо слично дури и блиску.
Во блокчејн, складирањето се имплементира како променливи во класа на други јазици. Тоа е, само клучни вредности или низи. Нема релациски табели со пригодни врски итн. Само - пишете на променлива и бидете среќни.
Во моментов, не знам на друг начин да се организира складирање во блокчејн. Па, можеби ситуацијата веќе е променета; можеби кога го читате ова, постои таков начин - пишете во коментарите.
На пример, ако сакаме да складираме не само во низа? И ние сакаме да складираме информации по клуч - постои мапирање за тоа.
Знакот за долар е нацртан со причина - мрежната комисија ќе се зема за секој сет.
Во овој блок ќе разговарам за работи кои ме изненадија или налутија. Има многу повеќе отколку што се во овој документ, но јас ќе ги споделам првите работи што први ме погодија во мојата пракса.
Важно е да се забележи дека повеќето „болки“ се разбирливи поради некоја логична причина. Но, тоа не ги поништува болките за мојот заден мозок.
На пример, јас сум навикнат на фактот дека лесно можеме да поминеме низ сите елементи на било што. Не е важно дали е низа или објект или мапа. Во Solidity, за таа цел, ќе треба посебно да складираме низа од сите клучеви и потоа, доколку е потребно, да ги поминеме сите и да извадиме елементи од мапата за секој клуч. Па, ние исто така трошиме гас за дополнително пишување на оваа низа клучеви и нејзината иницијализација.
Не можеме да ги добиеме ниту сите практични работи за сортирање на клучеви.
Непријатна е и состојбата со сечата. Навикнат сум на дебагирање преку дебагерот во развојната средина, но тука треба да заборавите дури и на нормалното логирање.
Во Typescript, јас сум навикнат само да пишувам console.log(a)
и веднаш да го добивам излезот во конзолата. Во Solidity, постои console.log
, кој работи само кога работи во локалната околина за развој на hardhat . И, она што е одлично е што откако ќе го поделам она што ми треба, морам да ги избришам сите овие логови пред да се распореди договорот бидејќи во спротивно, договорот тежи повеќе и чини повеќе за распоредување, а воопшто нема да работи на прод. .
На крајот излегува дека кога го водиме проектот веќе во битка, сакаме да видиме што не е во ред, не можеме да видиме што тргнало наопаку. Но, можеме да видиме што тргна како што треба. Постои систем на настани во рамките на паметните договори. Еве еден пример: да речеме дека сакаме да имаме настан каде што е додадена нова ставка под овој индекс со оваа вредност.
Овој настан го нарекуваме во методот set
и можеме да ги видиме дневниците само кога тој е успешно извршен. Ако нешто тргна наопаку, сте имале повеќе повици до договори или имавме пад на трансакцијата, тогаш дневниците не се зачувуваат ниту затоа што информациите во блокчејнот се враќаат назад.
Да претпоставиме дека користите синџир од неколку паметни договори. Имате во првиот договор наречени некои настани, потоа се нарекува вториот договор, кој нарекува други настани, а потоа паѓа се што беше наречено во вториот договор. Сè ќе биде целосно избришано еднаш засекогаш.
Мора да бидеме многу внимателни кога сакаме да евидентираме што се случува внатре во блокчејнот и да имаме на ум дека нормалното логирање, на кое сме навикнати, едноставно не ни е достапно овде.
Друга непријатна работа е што не можеме да добиеме информации од нашите трансакции во функција за запишување. Ако направиме трансакција што пишува нешто на блокчејнот (т.е. платена трансакција), return
нема да даде ништо на нашата услуга што се интегрира со паметниот договор. Ова враќање работи само во рамките на самиот паметен договор или во view
(бесплатни) функции.
На пример, би сакале кога додаваме нова вредност на нашиот блокчејн, можеби ќе сакаме да ја дознаеме големината на складирањето по зачувувањето (слика од екранот погоре). Односно, само преку настани можеме да дознаеме што точно е додадено. И за да го направиме тоа, треба да ги повлечеме настаните што беа активирани во рамките на таа трансакција.
Овде имаше изненадување за мене - невозможно е нормално да се работи со жици. Блокчејнот не е создаден за жици. Да преминеме на примерите.
Кодот подолу ќе работи без никакви проблеми.
И овој код повеќе нема да работи:
Одамна сум навикнат да работам нормално со жици, да менувам знаци во жици, да сечам низи, да ги спојувам - сето ова не е достапно надвор од кутијата. Исто така, нема можност да се прикаже должината на низата. Тоа е, овој код нема да компајлира:
Ако навистина ви треба должината на низата, можете да ја претворите во бајти и потоа да го броите бројот на бајти. Но, проблемот е што некои специјални знаци не се претвораат во бајти 1v1. А некои едноставно не се конвертираат и трансакцијата може да се сруши.
Може да завршите со пишување паметен договор кој се справува со жици и тестови на нормални жици. Потоа, ќе пристигне низа што нема да се обработи и сè ќе се сруши или должината на низата ќе се брои погрешно поради специјални знаци.
Заклучокот за жиците е едноставен: не работете со жици и не потпирајте се на жици во договорот. Ако е важно да се зачуваат низи, тогаш зачувајте бајти и потпирајте се на бајти и конвертирате низи во бајти на самата услуга.
Следната сложеност, која е продолжување на главната карактеристика на блокчејнот, е изолацијата. Сите податоци што се наоѓаат на блокчејнот се или родени во блокчејнот или се пренесуваат до него однадвор. Но, самиот блокчејн никогаш не може да затропа на надворешниот свет - само други паметни договори.
Проблемот е што сите команди за паметни договори се извршуваат кај секој учесник во мрежата. И не можете да му верувате на надворешен извор, бидејќи не можете да бидете сигурни дека истите информации ќе бидат примени на секој јазол. Ќе се случи секој јазол да има различна верзија на блокчејнот со различни податоци и блокчејнот да пропадне.
А тривијалната задача „да ја извади моменталната температура надвор“ станува нешто невозможно. Иако времето не ни треба секогаш, некои податоци (како девизниот курс или моменталната состојба на некој надворешен систем) се од суштинско значење. Решението лежи во следниот пристап:
Излегува дека е толку долг ланец. Тагата на приказната е што парите се земаат на мое прво барање на формуларот „оди по мене на такво барање“ и на второто барање, што веќе го прави серверот што го извршил барањето.
На пример, ни се потребни 50 илјади гас за секој чекор. Ја започнуваме трансакцијата, ставаме 50 илјади ГАС ЛИМИТ и мислиме дека ќе бидеме добро. Но, на пример, механиката за зачувување на новото време се менува - сега, кога температурата е над 10 степени, треба да префрлиме пари на еден од учесниците. Логиката се проширува и сега ќе бидат потребни, на пример, 80 илјади гас по трансакција.
На крајот, веќе на втората трансакција, целиот синџир пропаѓа поради недостаток на гас за трансакцијата. Таквата „зеленчук“ околу надворешни повици ги прави ваквите проекти покомплицирани. Најверојатно, ако имате цврста врска со надворешниот свет, не треба да избирате блокчејн за вашиот проект.
Исто така, не постои нормална случајност што не може да се предодреди. Оваа случајност ја обезбедуваат и различни провајдери „како што е“ - само случајна вредност редовно се запишува во паметниот договор. Но, опасно е да се верува на такво нешто за реални финансиски проекти.
Посебно внимание заслужува фактот дека вредноста на променливата block.timestamp
е поставена од рударот на блокови. Се разбира, тешко е да се замисли дека рударот однапред ќе знае дека тој го минира блокот и може да го замени времето. Сепак, постои хипотетичка можност. Оваа опасност е релевантна во контекст на 15 секунди, а ако се потпреме на минути и големи временски интервали, нема таков проблем.
Не планирам многу да зборувам за безбедноста. Но, ќе нагласам важен аспект: сè во блокчејнот е видливо за секого. Единственото нешто што е недостапно за другите е вашиот приватен клуч. Кодот за паметни договори е објавен на отворено со цел да помине ревизии и за да можат корисниците на паметни договори да му веруваат.
Процедурата за ревизија значи дека компанијата е ангажирана да го погледне кодот за паметен договор и да потврди дека конкретниот договор е објавен под оваа адреса. Прашањето за безбедноста на договорот е проверено и го прави она што го декларираат програмерите. Следно, компанијата за ревизија објавува информации како „овој договор е потврден од нас - може да му се верува“ на својата веб-страница.
Но, дури и ако кодот на договорот не е наведен, може лесно да се декомпајлира. На пример, следниот код има непроменлива променлива - таа едноставно се заменува насекаде со константа во кодот подолу.
По распоредувањето на овој договор и отворањето преку декомпајлерот, го гледаме следново:
Тоа е, веднаш ја добиваме оваа вредност на променливата.
Навикнат сум да можам да бидам смирен во задниот дел, а вредноста на приватните променливи за читање без пристап до меморијата ќе биде проблематична. Овде е исто - едноставно секој има пристап до „меморија“.
Променливата amount
ја нарековме приватна. Распоредете го паметниот договор и потоа повлечете ја неговата вредност со едноставен фрагмент од код:
На тој начин можете да извлечете што било. Затоа, не размислувајте да складирате нешто чувствително во паметниот договор!
Во основа е невозможно да ги вратите вашите промени. Паметниот договор се доделува еднаш, и ништо не може да се промени. Ќе остане на блокчејнот до крајот на времето, а потоа малку.
Затоа треба да напишете сè правилно и добро одеднаш. Не можам да го сторам тоа, па набрзина дојдов до интересен решение - Договори за надградба . Нивната механика работи на следниов начин.
Објавена е првата верзија на договорот (Договор V1).
Објавен е договор за прокси и тој ја има следната задача: да ги проследи сите барања 1v1 до договорот V1 или да користи сопствено складирање и да користи само логика од целниот договор.
Понатаму, корисникот комуницира со договорот за прокси на ист начин како и со главниот.
Доколку е неопходно да се ажурира договорот, администраторот го распоредува Договорот V2 и, преку администраторскиот договор, му кажува на прокси-договорот дека имплементацијата сега е на адресата на Договорот V2.
Следно, корисникот исто така комуницира со прокси, а механиката од Contract V2 е веќе извршена.
Следно, корисникот исто така комуницира со прокси, а механиката на Договорот V2 е веќе извршена.
Овој механизам има голем број ограничувања и трикови. На пример, променливите од претходната верзија не можат да се променат во новата верзија на договорот. Ако променливата повеќе не е потребна, таа сепак мора да се остави и да се депопулира во новиот договор.
Се разбира, ова решение и многу други веќе имаат готови решенија. Главниот снабдувач на овие случувања е OpenZeppelin . Така, за среќа, нема потреба повторно да се измисли тркалото.
Договор за надградба:
Паметните договори што може да се надградат се одлична причина да не бидете предмет на ревизија. Светот на блокчејн е изграден на доверба. Сега, паметниот договор може да има чесна и отворена механика, но подоцна, сопственикот на паметниот договор ќе ја префрли имплементацијата на таков каде што ќе ги земе сите пари.