በቴሌግራም ክፍት አውታረመረብ (ቶን) ውስጥ ብልህ ውል እንዴት እንደሚፃፍ እና እንደሚታተም

በቶን ውስጥ ብልጥ ውል እንዴት እንደሚፃፍ እና እንደሚታተም

ይህ ጽሑፍ ስለ ምንድን ነው?

በጽሁፉ ውስጥ በመጀመሪያው (ከሁለት) የቴሌግራም የብሎክቼይን ውድድር ውስጥ እንዴት እንደተሳተፍኩ እና ሽልማት እንዳልወሰድኩ እና ወደ እርሳት ውስጥ እንዳይገባ እና ምናልባትም እንደሚረዳኝ በአንድ ጽሑፍ ውስጥ ልምዴን ለመመዝገብ ወሰንኩ ። አንድ ሰው.

አብስትራክት ኮድ መጻፍ ስለማልፈልግ ነገር ግን የሚሰራ ነገር ለመስራት፣ ለጽሁፉ ለፈጣን ሎተሪ ብልጥ ውል ጻፍኩኝ እና መካከለኛ ማከማቻ ሳይጠቀም የስማርት ኮንትራት መረጃን በቀጥታ ከ ቶን የሚያሳይ ድር ጣቢያ ጻፍኩ።

ጽሑፉ በ ቶን ውስጥ የመጀመሪያውን ዘመናዊ ውል ለመሥራት ለሚፈልጉ ሰዎች ጠቃሚ ይሆናል, ነገር ግን የት መጀመር እንዳለባቸው አያውቁም.

ሎተሪውን እንደ ምሳሌ በመጠቀም አካባቢን ከመጫን ወደ ስማርት ኮንትራት ማተም፣ ከሱ ጋር መስተጋብር እና መረጃ ለመቀበል እና ለማተም ድረ-ገጽ በመጻፍ እሄዳለሁ።

ስለ ውድድር ተሳትፎ

ባለፈው ጥቅምት፣ ቴሌግራም ከአዳዲስ ቋንቋዎች ጋር የብሎክቼይን ውድድርን አስታውቋል Fift и FunC. ከአምስቱ የታቀዱ ዘመናዊ ኮንትራቶች ውስጥ ማንኛውንም ከመጻፍ መምረጥ አስፈላጊ ነበር. ወደፊት ምንም መጻፍ ባይኖርብኝም የተለየ ነገር ብሠራ፣ ቋንቋ ብማርና አንድ ነገር ብሠራ ጥሩ መስሎኝ ነበር። በተጨማሪም, ርዕሱ ያለማቋረጥ በከንፈሮች ላይ ነው.

ብልጥ ኮንትራቶችን የማዘጋጀት ልምድ አልነበረኝም ማለት ተገቢ ነው።

እስከ መጨረሻው ድረስ ለመሳተፍ እቅድ ነበረኝ እና ከዚያ የግምገማ ጽሁፍ ለመጻፍ አስቤ ነበር, ነገር ግን በመጀመሪያው ላይ ወዲያውኑ አልተሳካልኝም. አይ ቦርሳ ጽፏል ባለ ብዙ ፊርማ በርቶ FunC እና በአጠቃላይ ሠርቷል. መሰረት አድርጌ ወሰድኩት በ Solidity ላይ ብልጥ ውል.

በዚያን ጊዜ፣ ይህ በእርግጠኝነት ቢያንስ የተወሰነ የሽልማት ቦታ ለመውሰድ በቂ ነው ብዬ አስቤ ነበር። በዚህ ምክንያት ከ40 ተሳታፊዎች ውስጥ 60 ያህሉ ተሸላሚ ሆነዋል እኔም ከእነሱ መካከል አልነበርኩም። በአጠቃላይ, በዚህ ውስጥ ምንም ስህተት የለበትም, ግን አንድ ነገር አስጨንቆኝ. ውጤቱ በሚገለጽበት ጊዜ ለኮንትራቴ የፈተና ግምገማ አልተካሄደም ነበር, በቻት ውስጥ ያሉ ተሳታፊዎች ሌላ ሰው ከሌለ ሌላ ሰው ካለ ጠየቅኳቸው, ምንም አልነበሩም.

ለመልእክቶቼ ትኩረት በመስጠት ይመስላል ከሁለት ቀናት በኋላ ዳኞቹ አስተያየት አወጡ እና አሁንም በዳኝነት ጊዜ የእኔን ብልጥ ውል በአጋጣሚ አምልጠው እንደሆነ ወይም በቀላሉ አስተያየት አያስፈልገውም ብለው በማሰብ አሁንም አልገባኝም። በገጹ ላይ አንድ ጥያቄ ብጠይቅም መልስ አላገኘሁም። ምንም እንኳን ማን እንደፈረደ ሚስጥር ባይሆንም, የግል መልዕክቶችን መጻፍ እንደማያስፈልግ ቆጠርኩ.

በመረዳት ላይ ብዙ ጊዜ አሳልፏል, ስለዚህ አንድ ጽሑፍ ለመጻፍ ተወሰነ. ገና ብዙ መረጃ ስለሌለ, ይህ ጽሑፍ ፍላጎት ላለው ሁሉ ጊዜን ለመቆጠብ ይረዳል.

በቶን ውስጥ የስማርት ኮንትራቶች ጽንሰ-ሀሳብ

ማንኛውንም ነገር ከመጻፍዎ በፊት, ይህንን ነገር ከየትኛው ወገን እንደሚቀርቡ ማወቅ ያስፈልግዎታል. ስለዚህ, አሁን ስርዓቱ ምን ክፍሎች እንዳሉ እነግርዎታለሁ. የበለጠ በትክክል ፣ ቢያንስ አንድ ዓይነት የሥራ ውል ለመፃፍ ምን ክፍሎች ማወቅ ያስፈልግዎታል።

ዘመናዊ ኮንትራት በመጻፍ እና በመሥራት ላይ እናተኩራለን TON Virtual Machine (TVM), Fift и FunC, ስለዚህ ጽሑፉ እንደ መደበኛ ፕሮግራም እድገት መግለጫ ነው. መድረኩ ራሱ እንዴት እንደሚሰራ እዚህ ላይ አናተኩርም።

በአጠቃላይ እንዴት እንደሚሰራ TVM እና ቋንቋ Fift ጥሩ ኦፊሴላዊ ሰነዶች አሉ. በውድድሩ ላይ ስሳተፍ እና አሁን ያለውን ውል እየፃፍኩ ብዙ ጊዜ ወደ እሷ ዞርኩ።

ብልጥ ኮንትራቶች የሚጻፉበት ዋና ቋንቋ ነው። FunC. በአሁኑ ጊዜ ምንም ሰነድ የለም, ስለዚህ አንድ ነገር ለመጻፍ ከኦፊሴላዊው የመረጃ ማጠራቀሚያ እና የቋንቋው አተገባበር ምሳሌዎችን ማጥናት ያስፈልግዎታል, በተጨማሪም ካለፉት ሁለት የስማርት ኮንትራቶች ምሳሌዎችን መመልከት ይችላሉ. ውድድሮች. በአንቀጹ መጨረሻ ላይ አገናኞች.

አስቀድመን ብልጥ ውል ጽፈናል እንበል FunC, ከዚያ በኋላ ኮዱን ወደ Fift assembler እንሰበስባለን.

የተጠናቀረው ስማርት ውል ለመታተም ይቀራል። ይህንን ለማድረግ አንድ ተግባር መፃፍ ያስፈልግዎታል Fift, ይህም ዘመናዊ የኮንትራት ኮድ እና አንዳንድ ሌሎች መለኪያዎችን እንደ ግብአት የሚወስድ ሲሆን ውጤቱም ቅጥያው ያለው ፋይል ይሆናል .boc (ማለትም "የሴሎች ቦርሳ" ማለት ነው), እና, እንዴት እንደምንጽፈው, የግል ቁልፍ እና አድራሻ, ይህም በስማርት ኮንትራት ኮድ ላይ የተመሰረተ ነው. እስካሁን ያልታተመ የስማርት ኮንትራት አድራሻ ግራም መላክ ይችላሉ።

በ TON የተቀበለው ዘመናዊ ውል ለማተም .boc ፋይሉ የብርሃን ደንበኛን በመጠቀም ወደ blockchain መላክ አለበት (ከዚህ በታች ባለው ተጨማሪ)። ነገር ግን ከማተምዎ በፊት ግራም ወደተፈጠረው አድራሻ ማስተላለፍ ያስፈልግዎታል, አለበለዚያ ዘመናዊው ኮንትራት አይታተምም. ከህትመቱ በኋላ ከስማርት ኮንትራቱ ጋር ከውጭ መልዕክቶችን በመላክ (ለምሳሌ የብርሃን ደንበኛን በመጠቀም) ወይም ከውስጥ (ለምሳሌ አንድ ብልጥ ኮንትራት በቶን ውስጥ ሌላ መልእክት ይልካል) ጋር መስተጋብር መፍጠር ይችላሉ።

ኮዱ እንዴት እንደሚታተም ከተረዳን በኋላ ቀላል ይሆናል። ምን መጻፍ እንደምንፈልግ እና ፕሮግራማችን እንዴት እንደሚሰራ በትክክል እናውቃለን። እና በሚጽፉበት ጊዜ, ይህ አሁን ባለው ዘመናዊ ኮንትራቶች ውስጥ እንዴት እንደሚተገበር እንፈልጋለን, ወይም የአተገባበሩን ኮድ እንመለከታለን Fift и FunC በኦፊሴላዊው ማከማቻ ውስጥ, ወይም ኦፊሴላዊ ሰነዶችን ይመልከቱ.

ብዙ ጊዜ ሁሉም የውድድር ተሳታፊዎች እና የቴሌግራም ሰራተኞች በተሰበሰቡበት የቴሌግራም ቻት ላይ ቁልፍ ቃላትን እፈልግ ነበር እናም በውድድሩ ወቅት ሁሉም ሰው እዚያው ተሰብስበው ስለ Fift እና FunC መወያየት ጀመሩ። በአንቀጹ መጨረሻ ላይ አገናኝ.

ከቲዎሪ ወደ ልምምድ የምንሸጋገርበት ጊዜ ነው።

ከ TON ጋር ለመስራት አካባቢን ማዘጋጀት

በ MacOS ላይ ባለው መጣጥፍ ውስጥ የሚብራራውን ሁሉንም ነገር አደረግሁ እና በንጹህ ኡቡንቱ 18.04 LTS በ Docker ላይ ሁለቴ አረጋግጫለሁ።

ማድረግ ያለብዎት የመጀመሪያው ነገር ማውረድ እና መጫን ነው lite-client ወደ ቶን ጥያቄዎችን መላክ የሚችሉበት.

በኦፊሴላዊው ድርጣቢያ ላይ ያሉት መመሪያዎች የመጫን ሂደቱን በዝርዝር እና በግልፅ ይገልፃሉ እና አንዳንድ ዝርዝሮችን ይተዋል ። እዚህ መመሪያዎቹን እንከተላለን, የጎደሉትን ጥገኞች በመንገድ ላይ ይጫኑ. እያንዳንዱን ፕሮጄክት ራሴ አላጠናቀርኩም እና ከኦፊሴላዊው የኡቡንቱ ማከማቻ ጫን (በማክኦኤስ የተጠቀምኩት) brew).

apt -y install git 
apt -y install wget 
apt -y install cmake 
apt -y install g++ 
apt -y install zlib1g-dev 
apt -y install libssl-dev 

አንዴ ሁሉም ጥገኛዎች ከተጫኑ መጫን ይችላሉ lite-client, Fift, FunC.

በመጀመሪያ ፣ የቶን ማከማቻውን ከጥገኛዎቹ ጋር እናዘጋዋለን። ለመመቻቸት, ሁሉንም ነገር በአቃፊ ውስጥ እናደርጋለን ~/TON.

cd ~/TON
git clone https://github.com/ton-blockchain/ton.git
cd ./ton
git submodule update --init --recursive

ማከማቻው አተገባበርንም ያከማቻል Fift и FunC.

አሁን ፕሮጀክቱን ለመሰብሰብ ዝግጁ ነን. የማጠራቀሚያው ኮድ ወደ አቃፊ ተዘግቷል። ~/TON/ton. በ ~/TON አቃፊ ይፍጠሩ build እና ፕሮጀክቱን በውስጡ ይሰብስቡ.

mkdir ~/TON/build 
cd ~/TON/build
cmake ../ton

ብልጥ ውል ስለምንጽፍ ብቻ ሳይሆን ያስፈልገናል lite-clientግን Fift с FunC, ስለዚህ ሁሉንም ነገር እናጠናቅቅ. ፈጣን ሂደት አይደለም, ስለዚህ እየጠበቅን ነው.

cmake --build . --target lite-client
cmake --build . --target fift
cmake --build . --target func

በመቀጠል ስለ መስቀለኛ መንገድ መረጃ የያዘውን የውቅር ፋይል ያውርዱ lite-client ይገናኛል.

wget https://test.ton.org/ton-lite-client-test1.config.json

ለ TON የመጀመሪያ ጥያቄዎችን በማቅረብ ላይ

አሁን እንሩጥ lite-client.

cd ~/TON/build
./lite-client/lite-client -C ton-lite-client-test1.config.json

ግንባታው የተሳካ ከሆነ ከተጀመረ በኋላ የብርሃን ደንበኛው ከመስቀያው ጋር ያለው ግንኙነት ምዝግብ ማስታወሻ ያያሉ።

[ 1][t 2][1582054822.963129282][lite-client.h:201][!testnode]   conn ready
[ 2][t 2][1582054823.085654020][lite-client.cpp:277][!testnode] server version is 1.1, capabilities 7
[ 3][t 2][1582054823.085725069][lite-client.cpp:286][!testnode] server time is 1582054823 (delta 0)
...

ትዕዛዙን ማሄድ ይችላሉ help እና የትኞቹ ትዕዛዞች እንዳሉ ይመልከቱ.

help

በዚህ ጽሑፍ ውስጥ የምንጠቀምባቸውን ትዕዛዞች እንዘርዝር.

list of available commands:
last    Get last block and state info from server
sendfile <filename> Load a serialized message from <filename> and send it to server
getaccount <addr> [<block-id-ext>]  Loads the most recent state of specified account; <addr> is in [<workchain>:]<hex-or-base64-addr> format
runmethod <addr> [<block-id-ext>] <method-id> <params>...   Runs GET method <method-id> of account <addr> with specified parameters

last получает последний созданный блок с сервера. 

sendfile <filename> отправляет в TON файл с сообщением, именно с помощью этой команды публикуется смарт-контракт и запрсосы к нему. 

getaccount <addr> загружает текущее состояние смарт-контракта с указанным адресом. 

runmethod <addr> [<block-id-ext>] <method-id> <params>  запускает get-методы смартконтракта. 

አሁን ኮንትራቱን ራሱ ለመጻፍ ዝግጁ ነን.

ትግበራ

ሐሳብ

ከላይ እንደጻፍኩት የምንጽፈው ብልጥ ውል ሎተሪ ነው።

ከዚህም በላይ ይህ ቲኬት ገዝተህ አንድ ሰዓት፣ ቀን ወይም ወር መጠበቅ ያለብህ ሎተሪ ሳይሆን ተጠቃሚው ወደ ውሉ አድራሻ የሚሸጋገርበት ቅጽበታዊ ነው። N ግራም, እና ወዲያውኑ መልሶ ያገኛል 2 * N ግራም ወይም ማጣት. 40% አካባቢ የማሸነፍ እድላችንን እናደርጋለን። ለክፍያ በቂ ግራሞች ከሌሉ, ግብይቱን እንደ መሙላት እንቆጥራለን.

ከዚህም በላይ ውርርድ በእውነተኛ ጊዜ እና ምቹ በሆነ መልኩ መታየት አስፈላጊ ነው, ይህም ተጠቃሚው ያሸነፈ ወይም የተሸነፈ እንደሆነ ወዲያውኑ እንዲረዳው. ስለዚህ, ውርርዶችን እና ውጤቶችን በቀጥታ ከ ቶን የሚያሳይ ድህረ ገጽ መስራት ያስፈልግዎታል.

ብልጥ ኮንትራት መጻፍ

ለምቾት ሲባል የFunCን ኮድ አጉልቻለሁ፤ ተሰኪው በ Visual Studio Code ፍለጋ ውስጥ ሊገኝ እና ሊጭን ይችላል፤ በድንገት የሆነ ነገር ማከል ከፈለጉ ፕለጊኑን በይፋ እንዲገኝ አድርጌዋለሁ። እንዲሁም፣ አንድ ሰው ከዚህ ቀደም ከFift ጋር አብሮ ለመስራት ተሰኪ ሠርቷል፣ እሱን መጫን እና በቪኤስሲ ውስጥ ማግኘት ይችላሉ።

ወዲያውኑ መካከለኛ ውጤቶችን የምንፈጽምበት ማከማቻ እንፍጠር.

ህይወታችንን ለማቅለል፣ ስማርት ኮንትራት እንፅፋለን እና እስኪዘጋጅ ድረስ በአገር ውስጥ እንፈትሻለን። ከዚያ በኋላ ብቻ በቶን ውስጥ እናተምነው።

ብልጥ ኮንትራቱ ሊደረስባቸው የሚችሉ ሁለት ውጫዊ ዘዴዎች አሉት. አንደኛ, recv_external() ይህ ተግባር የሚፈጸመው የኮንትራቱ ጥያቄ ከውጭው ዓለም ሲመጣ ማለትም ከቶን ሳይሆን እኛ ራሳችን መልእክት አምጥተን በሊተ-ደንበኛ በኩል ስንልክ ነው። ሁለተኛ, recv_internal() ይህ በቶን በራሱ ውስጥ ማንኛውም ውል የእኛን ይመለከታል። በሁለቱም ሁኔታዎች መለኪያዎችን ወደ ተግባሩ ማለፍ ይችላሉ.

ከታተመ በሚሰራ ቀላል ምሳሌ እንጀምር, ነገር ግን በውስጡ ምንም ተግባራዊ ጭነት የለም.

() recv_internal(slice in_msg) impure {
    ;; TODO: implementation 
}

() recv_external(slice in_msg) impure {
    ;; TODO: implementation  
}

እዚህ ምን እንደሆነ ማብራራት ያስፈልገናል slice. በ TON Blockchain ውስጥ የተከማቹ ሁሉም መረጃዎች ስብስብ ናቸው። TVM cell ወይም በቀላሉ cellበእንደዚህ ዓይነት ሕዋስ ውስጥ እስከ 1023 ቢት ዳታ እና እስከ 4 አገናኞችን ወደ ሌሎች ህዋሶች ማከማቸት ይችላሉ።

TVM cell slice ወይም slice ይህ የነባሩ አካል ነው። cell እሱን ለመተንተን ጥቅም ላይ ይውላል, በኋላ ላይ ግልጽ ይሆናል. ለእኛ ዋናው ነገር ማስተላለፍ መቻላችን ነው slice እና እንደ የመልዕክቱ አይነት ውሂቡን ወደ ውስጥ ያስኬዱ recv_external() ወይም recv_internal().

impure - ተግባሩ ዘመናዊ የኮንትራት ውሂብን እንደሚቀይር የሚያመለክት ቁልፍ ቃል።

የኮንትራቱን ኮድ ወደ ውስጥ እናስቀምጥ lottery-code.fc እና ማጠናቀር.

~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc 

የባንዲራዎች ትርጉም ትዕዛዙን በመጠቀም ሊታይ ይችላል

~/TON/build/crypto/func -help

የ Fift assembler ኮድ አዘጋጅተናል lottery-compiled.fif:

// lottery-compiled.fif

"Asm.fif" include
// automatically generated from `/Users/rajymbekkapisev/TON/ton/crypto/smartcont/stdlib.fc` `./lottery-code.fc` 
PROGRAM{
  DECLPROC recv_internal
  DECLPROC recv_external
  recv_internal PROC:<{
    //  in_msg
    DROP    // 
  }>
  recv_external PROC:<{
    //  in_msg
    DROP    // 
  }>
}END>c

በአካባቢው ሊጀመር ይችላል, ለዚህም አከባቢን እናዘጋጃለን.

የመጀመሪያው መስመር እንደሚገናኝ ልብ ይበሉ Asm.fif፣ ይህ በ Fift for the Fift assembler የተጻፈ ኮድ ነው።

ስማርት ኮንትራቱን በአገር ውስጥ መሮጥ እና መሞከር ስለምንፈልግ ፋይል እንፈጥራለን lottery-test-suite.fif እና በውስጡ ያለውን የመጨረሻውን መስመር በመተካት የተሰበሰበውን ኮድ እዚያ ይቅዱ, ይህም ዘመናዊውን የኮንትራት ኮድ በቋሚነት ይጽፋል codeከዚያ ወደ ቨርቹዋል ማሽን ለማስተላለፍ፡-

"TonUtil.fif" include
"Asm.fif" include

PROGRAM{
  DECLPROC recv_internal
  DECLPROC recv_external
  recv_internal PROC:<{
    //  in_msg
    DROP    // 
  }>
  recv_external PROC:<{
    //  in_msg
    DROP    // 
  }>
}END>s constant code

እስካሁን ግልፅ ይመስላል፣ አሁን ቲቪኤምን ለመክፈት የምንጠቀምበትን ኮድ ወደ ተመሳሳይ ፋይል እንጨምር።

0 tuple 0x076ef1ea , // magic
0 , 0 , // actions msg_sents
1570998536 , // unix_time
1 , 1 , 3 , // block_lt, trans_lt, rand_seed
0 tuple 100000000000000 , dictnew , , // remaining balance
0 , dictnew , // contract_address, global_config
1 tuple // wrap to another tuple
constant c7

0 constant recv_internal // to run recv_internal() 
-1 constant recv_external // to invoke recv_external()

В c7 እኛ አውድ እንመዘግባለን, ማለትም, የቲቪኤም (ወይም የአውታረ መረብ ሁኔታ) የሚጀመርበትን ውሂብ. በውድድሩ ወቅት እንኳን ከገንቢዎቹ አንዱ እንዴት መፍጠር እንደሚቻል አሳይቷል። c7 እና እኔ ገለበጥኩ. በዚህ ጽሑፍ ውስጥ መለወጥ ሊያስፈልገን ይችላል rand_seed የዘፈቀደ ቁጥር ማመንጨት በእሱ ላይ የተመሰረተ ስለሆነ እና ካልተቀየረ, ተመሳሳይ ቁጥር በየጊዜው ይመለሳል.

recv_internal и recv_external ቋሚዎች ከ0 እና -1 እሴቶች ጋር በስማርት ኮንትራት ውስጥ ያሉትን ተዛማጅ ተግባራት ለመጥራት ሃላፊነት አለባቸው።

አሁን ለ ባዶ ስማርት ኮንትራታችን የመጀመሪያውን ፈተና ለመፍጠር ተዘጋጅተናል። ግልፅ ለማድረግ፣ አሁን ሁሉንም ፈተናዎች ወደ ተመሳሳይ ፋይል እንጨምራለን። lottery-test-suite.fif.

ተለዋዋጭ እንፍጠር storage እና በውስጡ ባዶ ጻፍ cellይህ ብልጥ የኮንትራት ማከማቻ ይሆናል።

message ከውጭ ወደ ብልጥ ግንኙነት የምናስተላልፈው መልእክት ይህ ነው። ለአሁኑም ባዶ እናደርገዋለን።

variable storage 
<b b> storage ! 

variable message 
<b b> message ! 

ቋሚዎችን እና ተለዋዋጭዎችን ካዘጋጀን በኋላ, ትዕዛዙን በመጠቀም TVM እንጀምራለን runvmctx እና የተፈጠሩትን መለኪያዎች ወደ ግብአት ያስተላልፉ.

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx 

መጨረሻ ላይ እንሳካለን ልክ እንደዚህ መካከለኛ ኮድ ለ Fift.

አሁን የተገኘውን ኮድ ማስኬድ እንችላለን.

export FIFTPATH=~/TON/ton/crypto/fift/lib // выполняем один раз для удобства 
~/TON/build/crypto/fift -s lottery-test-suite.fif 

ፕሮግራሙ ያለ ስህተቶች መሮጥ አለበት እና በውጤቱ ውስጥ የማስፈጸሚያ ምዝግብ ማስታወሻውን እናያለን-

execute SETCP 0
execute DICTPUSHCONST 19 (xC_,1)
execute DICTIGETJMPZ
execute DROP
execute implicit RET
[ 3][t 0][1582281699.325381279][vm.cpp:479]     steps: 5 gas: used=304, max=9223372036854775807, limit=9223372036854775807, credit=0

በጣም ጥሩ፣ የስማርት ኮንትራቱን የመጀመሪያ የስራ ስሪት ጽፈናል።

አሁን ተግባራዊነትን ማከል አለብን. በመጀመሪያ ከውጪው ዓለም የሚመጡ መልዕክቶችን እናስተናግድ recv_external()

ገንቢው ራሱ ውሉ ሊቀበለው የሚችለውን የመልዕክት ቅርጸት ይመርጣል.

ግን አብዛኛውን ጊዜ

  • በመጀመሪያ ውላችንን ከውጪው አለም ለመጠበቅ እና የውሉ ባለቤት ብቻ የውጭ መልእክት እንዲልክለት ለማድረግ እንፈልጋለን።
  • በሁለተኛ ደረጃ ትክክለኛ መልእክት ወደ ቶን ስንልክ ይህ በትክክል አንድ ጊዜ እንዲሆን እንፈልጋለን እና ተመሳሳይ መልእክት ስንልክ ስማርት ኮንትራቱ ውድቅ ያደርገዋል።

ስለዚህ እያንዳንዱ ውል ማለት ይቻላል እነዚህን ሁለት ችግሮች ይፈታል፣ ውላችን የውጭ መልዕክቶችን ስለሚቀበል እኛም ልንጠነቀቅበት ይገባል።

በተቃራኒው ቅደም ተከተል እናደርገዋለን. በመጀመሪያ ችግሩን በመድገም እንፍታው፤ ውሉ አስቀድሞ እንደዚህ አይነት መልእክት ደርሶት ከሆነ ለሁለተኛ ጊዜ አያስፈጽመውም። እና ከዚያ የተወሰኑ የሰዎች ክበብ ብቻ ወደ ብልጥ ኮንትራቱ መልእክት እንዲልክ ችግሩን እንፈታዋለን።

በተባዙ መልዕክቶች ችግሩን ለመፍታት የተለያዩ መንገዶች አሉ። እንዴት እንደምናደርገው እነሆ። በዘመናዊው ኮንትራት ውስጥ የተቀበሉትን መልእክቶች ቆጣሪ ከመጀመሪያው እሴት 0 ጋር እናስጀምራለን ። በእያንዳንዱ መልእክት ወደ ብልጥ ኮንትራት ፣ የአሁኑን ቆጣሪ እሴት እንጨምራለን ። በመልእክቱ ውስጥ ያለው የቆጣሪ እሴት በስማርት ኮንትራት ውስጥ ካለው ዋጋ ጋር የማይመሳሰል ከሆነ እኛ አናስኬደውም ፣ ከሰራ እኛ እናሰራው እና በስማርት ኮንትራት ውስጥ ያለውን ቆጣሪ በ 1 እንጨምራለን ።

ወደዚህ እንመለስ lottery-test-suite.fif እና በእሱ ላይ ሁለተኛ ፈተና ጨምር. የተሳሳተ ቁጥር ከላክን, ኮዱ የተለየ ነገር መጣል አለበት. ለምሳሌ የኮንትራቱ ዳታ 166 ያስቀምጥ እና 165 እንልካለን።

<b 166 32 u, b> storage !
<b 165 32 u, b> message !

message @ 
recv_external 
code 
storage @ 
c7 
runvmctx

drop 
exit_code ! 
."Exit code " exit_code @ . cr 
exit_code @ 33 - abort"Test #2 Not passed"

እንጀምር።

 ~/TON/build/crypto/fift -s lottery-test-suite.fif 

እና ፈተናው በስህተት መፈጸሙን እናያለን.

[ 1][t 0][1582283084.210902214][words.cpp:3046] lottery-test-suite.fif:67: abort": Test #2 Not passed
[ 1][t 0][1582283084.210941076][fift-main.cpp:196]      Error interpreting file `lottery-test-suite.fif`: error interpreting included file `lottery-test-suite.fif` : lottery-test-suite.fif:67: abort": Test #2 Not passed

በዚህ ደረጃ lottery-test-suite.fif መምሰል አለበት። ማያያዣ.

አሁን የቆጣሪ አመክንዮ ወደ ብልጥ ኮንትራት እንጨምር lottery-code.fc.

() recv_internal(slice in_msg) impure {
    ;; TODO: implementation 
}

() recv_external(slice in_msg) impure {
    if (slice_empty?(in_msg)) {
        return (); 
    }
    int msg_seqno = in_msg~load_uint(32);
    var ds = begin_parse(get_data());
    int stored_seqno = ds~load_uint(32);
    throw_unless(33, msg_seqno == stored_seqno);
}

В slice in_msg የምንልከው መልእክት ነው።

እኛ የምናደርገው የመጀመሪያው ነገር መልእክቱ ውሂብ እንደያዘ ማረጋገጥ ነው, ካልሆነ, በቀላሉ እንወጣለን.

በመቀጠል መልእክቱን እንመረምራለን. in_msg~load_uint(32) ቁጥሩን 165, 32-ቢት ይጭናል unsigned int ከተላለፈው መልእክት.

በመቀጠል ከስማርት ኮንትራት ማከማቻ 32 ቢት እንጭናለን። የተጫነው ቁጥር ካለፈው ቁጥር ጋር እንደሚዛመድ እናረጋግጣለን፤ ካልሆነ ግን የተለየ ነገር እንጥላለን። በእኛ ሁኔታ፣ ያለተዛማጅ ስለምናልፍ፣ የተለየ ነገር መጣል አለበት።

አሁን እናጠናቅቅ።

~/TON/build/crypto/func -APSR -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc 

የተገኘውን ኮድ ወደዚህ ይቅዱ lottery-test-suite.fifየመጨረሻውን መስመር ለመተካት አለመዘንጋት.

ፈተናው እንዳለፈ እናረጋግጣለን።

~/TON/build/crypto/fift -s lottery-test-suite.fif

እዚህ ጋ አሁን ካለው ውጤት ጋር ተጓዳኝ ቁርጠኝነትን ማየት ይችላሉ።

የተሰበሰበውን የስማርት ኮንትራት ኮድ ያለማቋረጥ ወደ ፋይል ከሙከራዎች ጋር መቅዳት የማይመች መሆኑን ልብ ይበሉ ፣ስለዚህ ኮዱን ወደ ቋሚ የሚፅፍልን ስክሪፕት እንፅፍልን እና በቀላሉ የተቀናበረውን ኮድ ከፈተናዎቻችን ጋር እናገናኘዋለን። "include".

በፕሮጀክት አቃፊ ውስጥ ፋይል ይፍጠሩ build.sh ከሚከተለው ይዘት ጋር.

#!/bin/bash

~/TON/build/crypto/func -SPA -R -o lottery-compiled.fif ~/TON/ton/crypto/smartcont/stdlib.fc ./lottery-code.fc

ተፈፃሚ እንዲሆን እናድርገው።

chmod +x ./build.sh

አሁን ኮንትራቱን ለማጠናቀር የእኛን ስክሪፕት ብቻ ያሂዱ። ነገር ግን ከዚህ በተጨማሪ, ወደ ቋሚነት መጻፍ ያስፈልገናል code. ስለዚህ አዲስ ፋይል እንፈጥራለን lotter-compiled-for-test.fif, በፋይሉ ውስጥ የምናካትተው lottery-test-suite.fif.

የሸርተቴ ኮድን ወደ sh እንጨምር፣ ይህም በቀላሉ የተጠናቀረውን ፋይል ወደ ውስጥ ያባዛዋል። lotter-compiled-for-test.fif እና በውስጡ የመጨረሻውን መስመር ይለውጡ.

# copy and change for test 
cp lottery-compiled.fif lottery-compiled-for-test.fif
sed '$d' lottery-compiled-for-test.fif > test.fif
rm lottery-compiled-for-test.fif
mv test.fif lottery-compiled-for-test.fif
echo -n "}END>s constant code" >> lottery-compiled-for-test.fif

አሁን፣ ለመፈተሽ፣ የተገኘውን ስክሪፕት እናካሂድ እና ፋይል ይፈጠራል። lottery-compiled-for-test.fif, በእኛ ውስጥ የምናካትተው lottery-test-suite.fif

В lottery-test-suite.fif የኮንትራቱን ኮድ ሰርዝ እና መስመሩን ጨምር "lottery-compiled-for-test.fif" include.

ማለፉን ለማረጋገጥ ፈተናዎችን እናካሂዳለን።

~/TON/build/crypto/fift -s lottery-test-suite.fif

በጣም ጥሩ፣ አሁን የፈተናዎችን ጅምር በራስ ሰር ለመስራት፣ ፋይል እንፍጠር test.shበመጀመሪያ የሚያስፈጽም build.sh, እና ከዚያ ፈተናዎችን ያሂዱ.

touch test.sh
chmod +x test.sh

ወደ ውስጥ እንጽፋለን

./build.sh 

echo "nCompilation completedn"

export FIFTPATH=~/TON/ton/crypto/fift/lib
~/TON/build/crypto/fift -s lottery-test-suite.fif

እንስራው test.sh እና ፈተናዎቹ መስራታቸውን ለማረጋገጥ ያሂዱት።

chmod +x ./test.sh
./test.sh

ኮንትራቱ ማጠናቀሩን እና ፈተናዎቹ መፈጸማቸውን እናረጋግጣለን።

በጣም ጥሩ፣ አሁን በጅምር ላይ test.sh ፈተናዎቹ ይጠናቀቃሉ እና ወዲያውኑ ይሰራሉ። ሊንኩ እዚህ አለ። መፈጸም.

እሺ፣ ከመቀጠላችን በፊት፣ ለመመቸት አንድ ተጨማሪ ነገር እናድርግ።

ማህደር እንፍጠር build የተቀዳውን ውል እና ክሎኑን ወደ ቋሚ የተጻፈውን የምናከማችበት lottery-compiled.fif, lottery-compiled-for-test.fif. እንዲሁም ማህደር እንፍጠር test የሙከራ ፋይሉ የት ነው የሚቀመጠው? lottery-test-suite.fif እና ሌሎች ደጋፊ ፋይሎች። ተዛማጅ ለውጦች አገናኝ.

ዘመናዊ ኮንትራቱን ማዘጋጀቱን እንቀጥል።

በመቀጠል መልእክቱ እንደደረሰ እና ትክክለኛውን ቁጥር ስንልክ ቆጣሪው በመደብሩ ውስጥ መዘመንን የሚያረጋግጥ ሙከራ መደረግ አለበት። ግን በኋላ እናደርጋለን.

አሁን ምን ዓይነት የውሂብ መዋቅር እና ምን ውሂብ በዘመናዊ ኮንትራት ውስጥ መቀመጥ እንዳለበት እናስብ.

ያከማቻልን ሁሉንም ነገር እገልጻለሁ።

`seqno` 32-х битное целое положительное число счетчик. 

`pubkey` 256-ти битное целое положительное число публичный ключ, с помощью которого, мы будем проверять подпись отправленного извне сообщения, о чем ниже. 

`order_seqno` 32-х битное целое положительное число хранит счетчик количества ставок. 

`number_of_wins` 32-х битное целое положительное число хранит  количество побед. 

`incoming_amount` тип данных Gram (первые 4 бита отвечает за длину), хранит общее количество грамов, которые были отправлены на контртакт. 

`outgoing_amount` общее количество грамов, которое было отправлено победителям. 

`owner_wc` номер воркчейна, 32-х битное (в некоторых местах написано, что 8-ми битное) целое число. В данный момент всего два -1 и 0. 

`owner_account_id` 256-ти битное целое положительное число, адрес контракта в текущем воркчейне. 

`orders` переменная типа словарь, хранит последние двадцать ставок. 

በመቀጠል ሁለት ተግባራትን መጻፍ ያስፈልግዎታል. የመጀመሪያውን እንጥራ pack_state(), ይህም ለቀጣይ ቁጠባ በዘመናዊ የኮንትራት ማከማቻ ውስጥ ውሂቡን ያጠቃልላል. ሁለተኛውን እንጥራ unpack_state() አንብቦ ውሂብ ከማከማቻ ይመለሳል።

_ pack_state(int seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) inline_ref {
    return begin_cell()
            .store_uint(seqno, 32)
            .store_uint(pubkey, 256)
            .store_uint(order_seqno, 32)
            .store_uint(number_of_wins, 32)
            .store_grams(incoming_amount)
            .store_grams(outgoing_amount)
            .store_int(owner_wc, 32)
            .store_uint(owner_account_id, 256)
            .store_dict(orders)
            .end_cell();
}

_ unpack_state() inline_ref {
    var ds = begin_parse(get_data());
    var unpacked = (ds~load_uint(32), ds~load_uint(256), ds~load_uint(32), ds~load_uint(32), ds~load_grams(), ds~load_grams(), ds~load_int(32), ds~load_uint(256), ds~load_dict());
    ds.end_parse();
    return unpacked;
}

እነዚህን ሁለት ተግባራት ወደ ብልጥ ኮንትራቱ መጀመሪያ እንጨምራለን. ይሳካለታል ልክ እንደዚህ መካከለኛ ውጤት.

ውሂብን ለማስቀመጥ አብሮ የተሰራውን ተግባር መደወል ያስፈልግዎታል set_data() እና ከ ውሂብ ይጽፋል pack_state() በስማርት ኮንትራት ማከማቻ ውስጥ።

cell packed_state = pack_state(arg_1, .., arg_n); 
set_data(packed_state);

አሁን መረጃን ለመጻፍ እና ለማንበብ ምቹ ተግባራት ስላለን, መቀጠል እንችላለን.

ከውጭ የሚመጣው መልእክት በውሉ ባለቤት (ወይም የግል ቁልፉን የሚጠቀም ሌላ ተጠቃሚ) የተፈረመ መሆኑን ማረጋገጥ አለብን።

ዘመናዊ ኮንትራት ስናተም በማከማቻ ውስጥ በምንፈልገው ውሂብ ማስጀመር እንችላለን፣ ይህም ለወደፊት ጥቅም ላይ ይውላል። መጪው መልእክት በተዛማጅ የግል ቁልፍ የተፈረመ መሆኑን ለማረጋገጥ የአደባባይ ቁልፍን እዚያ እንቀዳለን።

ከመቀጠልዎ በፊት የግል ቁልፍ እንፍጠር እና እንፃፍ test/keys/owner.pk. ይህንን ለማድረግ Fiftን በይነተገናኝ ሁነታ እናስጀምር እና አራት ትዕዛዞችን እናስፈጽም.

`newkeypair` генерация публичного и приватного ключа и запись их в стек. 

`drop` удаления из стека верхнего элемента (в данном случае публичный ключ)  

`.s` просто посмотреть что лежит в стеке в данный момент 

`"owner.pk" B>file` запись приватного ключа в файл с именем `owner.pk`. 

`bye` завершает работу с Fift. 

ማህደር እንፍጠር keys በአቃፊው ውስጥ test እና እዚያ የግል ቁልፉን ይፃፉ.

mkdir test/keys
cd test/keys
~/TON/build/crypto/fift -i 
newkeypair
 ok
.s 
BYTES:128DB222CEB6CF5722021C3F21D4DF391CE6D5F70C874097E28D06FCE9FD6917 BYTES:DD0A81AAF5C07AAAA0C7772BB274E494E93BB0123AA1B29ECE7D42AE45184128 
drop 
 ok
"owner.pk" B>file
 ok
bye

አሁን ባለው አቃፊ ውስጥ አንድ ፋይል እናያለን owner.pk.

የወል ቁልፉን ከቁልል እናስወግደዋለን እና ሲያስፈልግ ከግል ልናገኘው እንችላለን።

አሁን የፊርማ ማረጋገጫ መፃፍ አለብን። በፈተናው እንጀምር። በመጀመሪያ ተግባሩን በመጠቀም ከፋይሉ ውስጥ ያለውን የግል ቁልፍ እናነባለን file>B እና ወደ ተለዋዋጭ ይፃፉ owner_private_key, ከዚያም ተግባሩን በመጠቀም priv>pub የግል ቁልፉን ወደ ይፋዊ ቁልፍ ይለውጡ እና ውጤቱን ይፃፉ owner_public_key.

variable owner_private_key
variable owner_public_key 

"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !

ሁለቱንም ቁልፎች እንፈልጋለን.

የስማርት ኮንትራት ማከማቻውን በዘፈቀደ ውሂብ እናስጀምረዋለን በተግባሩ ውስጥ በተመሳሳይ ቅደም ተከተል pack_state()እና በተለዋዋጭ ውስጥ ይፃፉ storage.

variable owner_private_key
variable owner_public_key 
variable orders
variable owner_wc
variable owner_account_id

"./keys/owner.pk" file>B owner_private_key !
owner_private_key @ priv>pub owner_public_key !
dictnew orders !
0 owner_wc !
0 owner_account_id !

<b 0 32 u, owner_public_key @ B, 0 32 u, 0 32 u, 0 Gram, 0 Gram, owner_wc @ 32 i, owner_account_id @ 256 u,  orders @ dict, b> storage !

በመቀጠል, የተፈረመ መልእክት እንጽፋለን, ፊርማውን እና የቆጣሪውን ዋጋ ብቻ ይይዛል.

በመጀመሪያ ማስተላለፍ የምንፈልገውን ውሂብ እንፈጥራለን ከዚያም በግል ቁልፍ እንፈርማለን እና በመጨረሻም የተፈረመ መልእክት እናመነጫለን.

variable message_to_sign
variable message_to_send
variable signature
<b 0 32 u, b> message_to_sign !
message_to_sign @ hashu owner_private_key @ ed25519_sign_uint signature !
<b signature @ B, 0 32 u, b> <s  message_to_send !  

በውጤቱም, ወደ ስማርት ኮንትራት የምንልከው መልእክት በተለዋዋጭ ውስጥ ተመዝግቧል message_to_send, ስለ ተግባራት hashu, ed25519_sign_uint ማንበብ ትችላለህ በአምስቱ ሰነዶች ውስጥ.

እና ፈተናውን ለማካሄድ እንደገና እንጠራዋለን.

message_to_send @ 
recv_external 
code 
storage @
c7
runvmctx

እዚህ አለ ከሙከራዎች ጋር ያለው ፋይል በዚህ ደረጃ ይህን መምሰል አለበት።

ፈተናውን እናካሂድና አይሳካም ስለዚህ ስማርት ኮንትራቱን በመቀየር የዚህ ፎርማት መልእክት ተቀብሎ ፊርማውን እንዲያረጋግጥ እንለውጣለን።

በመጀመሪያ, ከመልዕክቱ ውስጥ 512 ቢት ፊርማዎችን እንቆጥራለን እና ወደ ተለዋዋጭ እንጽፋለን, ከዚያም የቆጣሪው ተለዋዋጭ 32 ቢት እንቆጥራለን.

ከስማርት ኮንትራት ማከማቻ መረጃ የማንበብ ተግባር ስላለን እንጠቀማለን።

በመቀጠል የተላለፈውን ቆጣሪ ከማከማቻው ጋር በማጣራት እና ፊርማውን ማረጋገጥ ነው. የሆነ ነገር የማይዛመድ ከሆነ ፣ ከዚያ ከተገቢው ኮድ ጋር ልዩ ሁኔታን እንጥላለን።

var signature = in_msg~load_bits(512);
var message = in_msg;
int msg_seqno = message~load_uint(32);
(int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, check_signature(slice_hash(in_msg), signature, pubkey));

አግባብነት ያለው ቁርጠኝነት እዚሁ.

ፈተናዎቹን እናካሂድ እና ሁለተኛው ፈተና እንዳልተሳካ እንይ። በሁለት ምክንያቶች በመልዕክቱ ውስጥ በቂ ቢት የለም እና በማከማቻው ውስጥ በቂ ቢት የለም, ስለዚህ ሲተነተን ኮዱ ይበላሻል. በምንልክ መልእክት ላይ ፊርማ ማከል እና ማከማቻውን ከመጨረሻው ሙከራ መቅዳት አለብን።

በሁለተኛው ፈተና የመልእክት ፊርማ እንጨምራለን እና ዘመናዊ የኮንትራት ማከማቻውን እንለውጣለን። እዚህ አለ ከፈተናዎች ጋር ያለው ፋይል በአሁኑ ጊዜ ይመስላል።

በሌላ ሰው የግል ቁልፍ የተፈረመ መልእክት የምንልክበትን አራተኛ ፈተና እንፃፍ። ሌላ የግል ቁልፍ እንፍጠር እና ወደ ፋይል እናስቀምጠው not-owner.pk. በዚህ የግል ቁልፍ መልእክቱን እንፈርማለን። ፈተናዎቹን እናካሂድ እና ሁሉም ፈተናዎች ማለፋቸውን እናረጋግጥ። ቁርጠኝነት በዚህ ወቅት.

አሁን በመጨረሻ ወደ ስማርት ኮንትራት አመክንዮ መተግበር መሄድ እንችላለን።
В recv_external() ሁለት አይነት መልዕክቶችን እንቀበላለን።

ኮንትራታችን የተጫዋቾቹን ኪሳራ ስለሚያከማች ይህ ገንዘብ ለሎተሪው ፈጣሪ መተላለፍ አለበት። ኮንትራቱ ሲፈጠር የሎተሪ ፈጣሪው የኪስ ቦርሳ አድራሻ በማከማቻ ውስጥ ይመዘገባል.

እንደዚያ ከሆነ፣ የተሸናፊዎችን ግራም የምንልክበትን አድራሻ የመቀየር ችሎታ ያስፈልገናል። ከሎተሪው ወደ ባለቤቱ አድራሻ ግራም መላክ መቻል አለብን።

ከመጀመሪያው እንጀምር። በመጀመሪያ መልእክቱን ከላኩ በኋላ ስማርት ኮንትራቱ አዲሱን አድራሻ በማከማቻው ውስጥ እንዳስቀመጠው የሚያረጋግጥ ፈተና እንፃፍ። እባክዎን በመልእክቱ ውስጥ ከቆጣሪው እና ከአዲሱ አድራሻ በተጨማሪ እኛ እንደምናስተላልፍ ልብ ይበሉ action ባለ 7-ቢት ኢንቲጀር አሉታዊ ያልሆነ ቁጥር, በእሱ ላይ በመመስረት, በስማርት ኮንትራቱ ውስጥ መልእክቱን እንዴት እንደሚሰራ እንመርጣለን.

<b 0 32 u, 1 @ 7 u, new_owner_wc @  32 i, new_owner_account_id @ 256 u, b> message_to_sign !

በፈተናው ውስጥ እንዴት የስማርት ኮንትራት ማከማቻ ከሴሪያላይዝድ እንደተደረገ ማየት ይችላሉ። storage በአምስተኛው. ተለዋዋጮችን ማጥፋት በ Fift ሰነድ ውስጥ ተገልጿል.

ቁርኝት አገናኝ ከተጨመረው ሊጥ ጋር.

ፈተናውን እናካሂድና አለመሳካቱን እናረጋግጥ። አሁን የሎተሪውን ባለቤት አድራሻ ለመቀየር አመክንዮ እንጨምር።

በዘመናዊው ውል ውስጥ መተንተን እንቀጥላለን message፣ አንብብ action. ሁለት እንደሚኖረን እናስታውስህ actionአድራሻ ቀይር እና ግራም ላክ።

ከዚያም የኮንትራቱን ባለቤት አዲሱን አድራሻ እናነባለን እና በማከማቻ ውስጥ እናስቀምጠዋለን.
ፈተናዎቹን እናካሂዳለን እና ሶስተኛው ፈተና አለመሳካቱን እናያለን. ኮንትራቱ አሁን በሙከራው ውስጥ የጎደሉትን ከመልእክቱ 7 ቢት በመለየቱ ይወድቃል። ወደ መልእክቱ የማይኖር ያክሉ action. ፈተናዎቹን እናካሂድ እና ሁሉም ነገር እንዳለፈ እንይ። እዚህ ለለውጦች መሰጠት. በጣም ጥሩ.

አሁን የተገለጸውን የግራሞች ቁጥር ቀደም ሲል ወደተቀመጠው አድራሻ ለመላክ አመክንዮውን እንፃፍ.

መጀመሪያ ፈተና እንፃፍ። ሁለት ሙከራዎችን እንጽፋለን, አንድ በቂ ሚዛን በማይኖርበት ጊዜ, ሁለተኛው ሁሉም ነገር በተሳካ ሁኔታ ማለፍ ሲኖርበት. ፈተናዎች ሊታዩ ይችላሉ በዚህ ቁርጠኝነት ውስጥ.

አሁን ኮዱን እንጨምር። በመጀመሪያ, ሁለት ረዳት ዘዴዎችን እንጻፍ. የመጀመሪያው የማግኛ ዘዴ የስማርት ኮንትራት የአሁኑን ሚዛን ማወቅ ነው።

int balance() inline_ref method_id {
    return get_balance().pair_first();
}

እና ሁለተኛው ግራም ወደ ሌላ ዘመናዊ ውል ለመላክ ነው. ይህንን ዘዴ ከሌላ ዘመናዊ ኮንትራት ሙሉ በሙሉ ገልብጫለሁ.

() send_grams(int wc, int addr, int grams) impure {
    ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
    cell msg = begin_cell()
    ;;  .store_uint(0, 1) ;; 0 <= format indicator int_msg_info$0 
    ;;  .store_uint(1, 1) ;; 1 <= ihr disabled
    ;;  .store_uint(1, 1) ;; 1 <= bounce = true
    ;;  .store_uint(0, 1) ;; 0 <= bounced = false
    ;;  .store_uint(4, 5)  ;; 00100 <= address flags, anycast = false, 8-bit workchain
        .store_uint (196, 9)
        .store_int(wc, 8)
        .store_uint(addr, 256)
        .store_grams(grams)
        .store_uint(0, 107) ;; 106 zeroes +  0 as an indicator that there is no cell with the data.
        .end_cell(); 
    send_raw_message(msg, 3); ;; mode, 2 for ignoring errors, 1 for sender pays fees, 64 for returning inbound message value
}

እነዚህን ሁለት ዘዴዎች ወደ ብልጥ ኮንትራት እንጨምር እና አመክንዮውን እንፃፍ። በመጀመሪያ ከመልእክቱ ውስጥ የግራሞችን ብዛት እናነባለን. በመቀጠል ሚዛኑን እንፈትሻለን, በቂ ካልሆነ የተለየ ነገር እንጥላለን. ሁሉም ነገር ደህና ከሆነ, ከዚያም ግራሞቹን ወደተቀመጠው አድራሻ እንልካለን እና ቆጣሪውን እናዘምነዋለን.

int amount_to_send = message~load_grams();
throw_if(36, amount_to_send + 500000000 > balance());
accept_message();
send_grams(owner_wc, owner_account_id, amount_to_send);
set_data(pack_state(stored_seqno + 1, pubkey, order_seqno, number_of_wins, incoming_amount, outgoing_amount, owner_wc, owner_account_id, orders));

እዚህ አለ በአሁኑ ጊዜ ብልጥ ኮንትራት ይመስላል። ፈተናዎቹን እናካሂድ እና ማለፋቸውን እናረጋግጥ።

በነገራችን ላይ ለተቀነባበረ መልእክት ሁል ጊዜ ከስማርት ኮንትራት ኮሚሽን ይቀነሳል። ብልጥ የኮንትራት መልእክቶች ጥያቄውን እንዲፈጽሙ ፣ ከመሠረታዊ ቼኮች በኋላ መደወል ያስፈልግዎታል accept_message().

አሁን ወደ ውስጣዊ መልዕክቶች እንሂድ። እንደውም ግራሞችን ብቻ ተቀብለን ተጫዋቹ ቢያሸንፍ እና ከተሸነፈ ሶስተኛውን ለባለቤቱ እንልካለን።

በመጀመሪያ አንድ ቀላል ፈተና እንፃፍ። ይህንን ለማድረግ ግራም ወደ ስማርት ኮንትራት የምንልክበት የስማርት ኮንትራት የሙከራ አድራሻ እንፈልጋለን።

የስማርት ኮንትራቱ አድራሻ ሁለት ቁጥሮችን የያዘ ባለ 32-ቢት ኢንቲጀር ለስራ ሰንሰለት ኃላፊነት ያለው እና 256-ቢት አሉታዊ ያልሆነ የኢንቲጀር ልዩ መለያ ቁጥር በዚህ የስራ ሰንሰለት ውስጥ። ለምሳሌ, -1 እና 12345, ይህ በፋይል ውስጥ የምናስቀምጠው አድራሻ ነው.

አድራሻውን የማስቀመጥ ተግባሩን ገልብጫለሁ። TonUtil.fif.

// ( wc addr fname -- )  Save address to file in 36-byte format
{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-address

ተግባሩ እንዴት እንደሚሰራ እንመልከት, ይህ Fift እንዴት እንደሚሰራ መረዳትን ይሰጣል. በይነተገናኝ ሁነታ Fiftን አስጀምር።

~/TON/build/crypto/fift -i 

በመጀመሪያ -1, 12345 እና የወደፊቱን ፋይል ስም "sender.addr" ወደ ቁልል እንገፋለን:

-1 12345 "sender.addr" 

ቀጣዩ ደረጃ ተግባሩን ማከናወን ነው -rot, ይህም ቁልል አናት ላይ ልዩ የሆነ ዘመናዊ የኮንትራት ቁጥር እንዲኖረው በሚያስችል መንገድ ይቀይራል:

"sender.addr" -1 12345

256 u>B ባለ 256-ቢት አሉታዊ ያልሆነ ኢንቲጀር ወደ ባይት ይለውጣል።

"sender.addr" -1 BYTES:0000000000000000000000000000000000000000000000000000000000003039

swap የቁልል ሁለቱን ዋና አካላት ይለዋወጣል።

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 -1

32 i>B ባለ 32-ቢት ኢንቲጀር ወደ ባይት ይቀይራል።

"sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039 BYTES:FFFFFFFF

B+ ሁለት ተከታታይ ባይት ያገናኛል።

 "sender.addr" BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF

እንደገና swap.

BYTES:0000000000000000000000000000000000000000000000000000000000003039FFFFFFFF "sender.addr" 

እና በመጨረሻም ባይት በፋይሉ ላይ ተጽፏል B>file. ከዚህ በኋላ የእኛ ቁልል ባዶ ነው። እናቆማለን Fift. አሁን ባለው አቃፊ ውስጥ ፋይል ተፈጥሯል። sender.addr. ፋይሉን ወደ ተፈጠረ ማህደር እናንቀሳቅሰው test/addresses/.

ግራም ወደ ብልጥ ውል የሚልክ ቀላል ፈተና እንፃፍ። ቁርጠኝነት እነሆ.

አሁን የሎተሪውን አመክንዮ እንመልከት።

እኛ የምናደርገው የመጀመሪያው ነገር መልእክቱን ማረጋገጥ ነው bounced ወይም ከሆነ አይደለም bounced, ከዚያም ችላ እንላለን. bounced አንዳንድ ስህተት ከተፈጠረ ኮንትራቱ ግራም ይመለሳል ማለት ነው. ስህተት በድንገት ቢከሰት ግራም አንመልስም።

እንፈትሻለን, ሚዛኑ ከግማሽ ግራም ያነሰ ከሆነ, በቀላሉ መልእክቱን እንቀበላለን እና ችላ እንላለን.

በመቀጠል መልእክቱ የመጣበትን የስማርት ኮንትራት አድራሻ እንተነተነዋለን።

መረጃውን ከማጠራቀሚያው ውስጥ እናነባለን እና ከዚያ ከሃያ በላይ ካሉ የቆዩ መወራቶችን ከታሪክ እንሰርዛለን። ለመመቻቸት, ሶስት ተጨማሪ ተግባራትን ጻፍኩ pack_order(), unpack_order(), remove_old_orders().

በመቀጠል ፣ ሚዛኑ ለክፍያው በቂ ካልሆነ እናያለን ፣ ከዚያ ይህ ውርርድ እንዳልሆነ እናስባለን ፣ ግን መሙላት እና መሙላትን በ ውስጥ እናስቀምጠዋለን። orders.

ከዚያ በመጨረሻ የስማርት ኮንትራቱ ይዘት።

በመጀመሪያ ተጫዋቹ ከተሸነፈ በውርርድ ታሪክ ውስጥ እናስቀምጠዋለን እና መጠኑ ከ 3 ግራም በላይ ከሆነ 1/3 ለብልጥ ኮንትራቱ ባለቤት እንልካለን።

ተጫዋቹ ካሸነፈ, ከዚያም በእጥፍ መጠን ወደ ተጫዋቹ አድራሻ እንልካለን እና ከዚያም በታሪክ ውስጥ ስለ ውርርድ መረጃ እናስቀምጠዋለን.

() recv_internal(int order_amount, cell in_msg_cell, slice in_msg) impure {
    var cs = in_msg_cell.begin_parse();
    int flags = cs~load_uint(4);  ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
    if (flags & 1) { ;; ignore bounced
        return ();
    }
    if (order_amount < 500000000) { ;; just receive grams without changing state 
        return ();
    }
    slice src_addr_slice = cs~load_msg_addr();
    (int src_wc, int src_addr) = parse_std_addr(src_addr_slice);
    (int stored_seqno, int pubkey, int order_seqno, int number_of_wins, int incoming_amount, int outgoing_amount, int owner_wc, int owner_account_id, cell orders) = unpack_state();
    orders = remove_old_orders(orders, order_seqno);
    if (balance() < 2 * order_amount + 500000000) { ;; not enough grams to pay the bet back, so this is re-fill
        builder order = pack_order(order_seqno, 1, now(), order_amount, src_wc, src_addr);
        orders~udict_set_builder(32, order_seqno, order);
        set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
        return ();
    }
    if (rand(10) >= 4) {
        builder order = pack_order(order_seqno, 3, now(), order_amount, src_wc, src_addr);
        orders~udict_set_builder(32, order_seqno, order);
        set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins, incoming_amount + order_amount, outgoing_amount, owner_wc, owner_account_id, orders));
        if (order_amount > 3000000000) {
            send_grams(owner_wc, owner_account_id, order_amount / 3);
        }
        return ();
    }
    send_grams(src_wc, src_addr, 2 * order_amount);
    builder order = pack_order(order_seqno, 2, now(), order_amount, src_wc, src_addr);
    orders~udict_set_builder(32, order_seqno, order);
    set_data(pack_state(stored_seqno, pubkey, order_seqno + 1, number_of_wins + 1, incoming_amount, outgoing_amount + 2 * order_amount, owner_wc, owner_account_id, orders));
}

ያ ብቻ ነው። ተጓዳኝ ቃል ኪዳን.

አሁን የቀረው ሁሉ ቀላል ነው, ስለ ኮንትራቱ ሁኔታ ከውጭው ዓለም መረጃ ለማግኘት እንድንችል የማግኘት ዘዴዎችን እንፍጠር (በእውነቱ, መረጃውን ከዘመናዊ የኮንትራት ማከማቻቸው ያንብቡ).

ዘዴዎችን እንጨምር. ስለ ብልጥ ኮንትራት መረጃ እንዴት እንደሚቀበል ከዚህ በታች እንጽፋለን.

እንዲሁም ብልጥ ውል ሲያትሙ የሚከሰተውን የመጀመሪያውን ጥያቄ የሚያስኬድ ኮድ ማከል ረሳሁ። ተጓዳኝ ቃል ኪዳን. እና ተጨማሪ ተስተካክሏል ከገንዘቡ 1/3 ቱን ወደ ባለቤት መለያ በመላክ ስህተት።

ቀጣዩ ደረጃ ዘመናዊ ኮንትራቱን ማተም ነው. ማህደር እንፍጠር requests.

የሕትመት ኮዱን እንደ መሠረት አድርጌ ወሰድኩት simple-wallet-code.fc የት ማግኘት ይችላል በኦፊሴላዊው ማከማቻ ውስጥ.

ትኩረት ሊሰጠው የሚገባ ነገር. ዘመናዊ የኮንትራት ማከማቻ እና የግቤት መልእክት እናመነጫለን። ከዚህ በኋላ የስማርት ኮንትራቱ አድራሻ ይፈጠራል, ማለትም አድራሻው በቶን ውስጥ ከመታተሙ በፊት እንኳን ይታወቃል. በመቀጠል ፣ ብዙ ግራም ወደዚህ አድራሻ መላክ ያስፈልግዎታል ፣ እና ከዚያ በኋላ ብቻ ከስማርት ኮንትራቱ ጋር ፋይል መላክ ያስፈልግዎታል ፣ ምክንያቱም አውታረ መረቡ ብልጥ ኮንትራቱን እና በውስጡ ያሉትን ስራዎች ለማከማቸት ኮሚሽን ስለሚወስድ (ስማርት የሚያከማቹ እና የሚፈጽሙ አረጋጋጮች) ውሎች)። ኮዱ እዚህ ሊታይ ይችላል.

በመቀጠል የህትመት ኮዱን እናስፈጽማለን እና እናገኛለን lottery-query.boc ብልጥ የኮንትራት ፋይል እና አድራሻ።

~/TON/build/crypto/fift -s requests/new-lottery.fif 0

የተፈጠሩትን ፋይሎች ማስቀመጥዎን አይርሱ፡- lottery-query.boc, lottery.addr, lottery.pk.

ከሌሎች ነገሮች በተጨማሪ, በአፈፃፀም ምዝግብ ማስታወሻዎች ውስጥ የስማርት ኮንትራቱን አድራሻ እንመለከታለን.

new wallet address = 0:044910149dbeaf8eadbb2b28722e7d6a2dc6e264ec2f1d9bebd6fb209079bc2a 
(Saving address to file lottery.addr)
Non-bounceable address (for init): 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd
Bounceable address (for later access): kQAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8KpFY

ለመዝናናት ያህል፣ ለቶን ጥያቄ እናቅርብ

$ ./lite-client/lite-client -C ton-lite-client-test1.config.json 
getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

እና በዚህ አድራሻ ያለው መለያ ባዶ መሆኑን እናያለን።

account state is empty

ወደ አድራሻው እንልካለን። 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 ግራም እና ከጥቂት ሰከንዶች በኋላ ተመሳሳይ ትዕዛዝ እንፈጽማለን. እኔ እጠቀማለሁ ግራም ለመላክ ኦፊሴላዊ የኪስ ቦርሳ, እና አንድ ሰው ከቻት ለሙከራ ግራም መጠየቅ ይችላሉ, ይህም በአንቀጹ መጨረሻ ላይ ስለማወራው.

> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

ያልታወቀ ይመስላል (state:account_uninit) ተመሳሳዩ አድራሻ ያለው ብልጥ ውል እና የ 1 ናኖግራም ሚዛን።

account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:0 address:x044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:1)
      bits:(var_uint len:1 value:103)
      public_cells:(var_uint len:0 value:0)) last_paid:1583257959
    due_payment:nothing)
  storage:(account_storage last_trans_lt:3825478000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:2000000000))
      other:(extra_currencies
        dict:hme_empty))
    state:account_uninit))
x{C00044910149DBEAF8EADBB2B28722E7D6A2DC6E264EC2F1D9BEBD6FB209079BC2A20259C2F2F4CB3800000DEAC10776091DCD650004_}
last transaction lt = 3825478000001 hash = B043616AE016682699477FFF01E6E903878CDFD6846042BA1BFC64775E7AC6C4
account balance is 2000000000ng

አሁን ብልጥ ኮንትራቱን እናተም። ሊት-ደንበኛን እንጀምር እና እንፈጽም።

> sendfile lottery-query.boc
[ 1][t 2][1583008371.631410122][lite-client.cpp:966][!testnode] sending query from file lottery-query.boc
[ 3][t 1][1583008371.828550100][lite-client.cpp:976][!query]    external message status is 1 

ውሉ እንደታተመ እንፈትሽ።

> last
> getaccount 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd

ከሌሎች ነገሮች በተጨማሪ እናገኛለን.

  storage:(account_storage last_trans_lt:3825499000002
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:4 value:1987150999))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active

ያንን እናያለን account_active.

ከለውጦች ጋር ተጓዳኝ ቃል ኪዳን እዚሁ.

አሁን ከስማርት ኮንትራቱ ጋር ለመገናኘት ጥያቄዎችን እንፍጠር።

ይበልጥ በትክክል ፣ አድራሻውን ለመቀየር የመጀመሪያውን እንተወዋለን እንደ ገለልተኛ ሥራ ፣ እና ሁለተኛውን ግራም ወደ የባለቤቱ አድራሻ ለመላክ እንሰራለን። እንደ እውነቱ ከሆነ, ግራም ለመላክ በፈተና ውስጥ እንደነበረው ተመሳሳይ ነገር ማድረግ አለብን.

ይህ እኛ ወደ ብልጥ ኮንትራት የምንልክ መልእክት ነው, የት msg_seqno 165, action ለመላክ 2 እና 9.5 ግራም.

<b 165 32 u, 2 7 u, 9500000000 Gram, b>

መልእክቱን በግል ቁልፍዎ መፈረምዎን አይርሱ lottery.pkብልጥ ኮንትራቱን ሲፈጥሩ ቀደም ብሎ የተፈጠረ. ተጓዳኝ ቁርጠኝነት እነሆ.

የማግኛ ዘዴዎችን በመጠቀም ከዘመናዊ ኮንትራት መረጃ መቀበል

አሁን እንዴት ስማርት ኮንትራት ማግኘት እንደሚቻል እንይ።

አስጀምር lite-client እና እኛ የጻፍናቸው ዘዴዎችን ያሂዱ።

$ ./lite-client/lite-client -C ton-lite-client-test1.config.json
> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd balance
arguments:  [ 104128 ] 
result:  [ 64633878952 ] 
...

В result ተግባሩ የሚመለሰውን እሴት ይዟል balance() ከብልጥ ኮንትራታችን.
ለብዙ ተጨማሪ ዘዴዎች ተመሳሳይ ነገር እናደርጋለን.

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_seqno
...
arguments:  [ 77871 ] 
result:  [ 1 ] 

የእርስዎን ውርርድ ታሪክ እንጠይቅ።

> runmethod 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd get_orders
...
arguments:  [ 67442 ] 
result:  [ ([0 1 1583258284 10000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [1 3 1583258347 4000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308] [2 1 1583259901 50000000000 0 74649920601963823558742197308127565167945016780694342660493511643532213172308]) ] 

ቀላል ደንበኛን እንጠቀማለን እና በጣቢያው ላይ ስላለው ዘመናዊ ኮንትራት መረጃን ለማሳየት ዘዴዎችን እናገኛለን።

በድር ጣቢያው ላይ የስማርት ኮንትራት ውሂብን በማሳየት ላይ

መረጃውን ከስማርት ኮንትራቱ ምቹ በሆነ መንገድ ለማሳየት በፓይዘን ውስጥ ቀላል ድር ጣቢያ ጻፍኩ ። እዚህ ላይ በዝርዝር አልቆይም እና ጣቢያውን አሳትመዋለሁ በአንድ ቃል ኪዳን.

የ TON ጥያቄዎች የሚቀርቡት ከ Python በ እገዛ lite-client. ለምቾት ሲባል ጣቢያው በዶከር ታሽጎ በGoogle ክላውድ ላይ ታትሟል። አገናኝ.

እንሞክር

አሁን ለመሙላት እዚያ ግራም ለመላክ እንሞክር ቦርሳ. 40 ግራም እንልካለን. እና ለግልጽነት ሁለት ውርርዶችን እናድርግ። ጣቢያው የውርርድ ታሪክን፣ አሁን ያለውን የአሸናፊነት መቶኛ እና ሌሎች ጠቃሚ መረጃዎችን እንደሚያሳይ አይተናል።

እናያለንየመጀመሪያውን አሸነፍን, ሁለተኛውን ተሸንፈናል.

ከቃል በኋላ

ጽሑፉ ከጠበቅኩት በላይ ረዘም ያለ ሆኖ ተገኝቷል፣ ምናልባት አጠር ያለ ሊሆን ይችላል ወይም ምናልባት ስለ ቶን ምንም ለማያውቅ እና ቀላል ያልሆነ ስማርት ኮንትራት መጻፍ እና ማተም ለሚፈልግ ሰው የመግባባት ችሎታ ሊኖረው ይችላል። ነው። ምናልባት አንዳንድ ነገሮች በቀላሉ ሊብራሩ ይችሉ ይሆናል።

ምናልባት አንዳንድ የአተገባበሩ ገጽታዎች ይበልጥ በተቀላጠፈ እና በሚያምር ሁኔታ ሊከናወኑ ይችሉ ነበር, ነገር ግን ጽሑፉን ለማዘጋጀት የበለጠ ጊዜ ይወስድ ነበር. እንዲሁም የሆነ ቦታ ስህተት ሰርቼ ወይም የሆነ ነገር እንዳልገባኝ ሊሆን ይችላል, ስለዚህ አንድ ከባድ ነገር እያደረጉ ከሆነ, በ TON ኮድ ኦፊሴላዊ ሰነድ ወይም ኦፊሴላዊ ማከማቻ ላይ መተማመን አለብዎት.

ቶን ራሱ ገና በንቃት የዕድገት ደረጃ ላይ ስለሆነ በዚህ ጽሑፍ ውስጥ ያሉትን ማናቸውንም እርምጃዎች የሚጥሱ ለውጦች ሊከሰቱ እንደሚችሉ ልብ ሊባል ይገባል (በምጽፍበት ጊዜ የተከሰተው ፣ ቀድሞውኑ ተስተካክሏል) ፣ ግን አጠቃላይ አቀራረብ ሊለወጥ የማይችል.

ስለ ቶን የወደፊት ሁኔታ አልናገርም. ምናልባት መድረኩ ትልቅ ነገር ይሆናል እና እሱን ለማጥናት ጊዜ እናጠፋለን እና አሁን በምርቶቻችን ውስጥ አንድ ቦታ እንሞላለን።

ከ ‹TON› የበለጠ የተጠቃሚዎች ተመልካች ያለው ሊብራ ከፌስቡክም አለ። ስለ ሊብራ ምንም የማውቀው ነገር የለም፣ በፎረሙ ስንገመግም ከቶን ማህበረሰብ የበለጠ ብዙ እንቅስቃሴ አለ። ምንም እንኳን የቶን ገንቢዎች እና ማህበረሰቦች እንደ ከመሬት በታች ያሉ ቢሆኑም ጥሩ ነው።

ማጣቀሻዎች

  1. በቶን ላይ ኦፊሴላዊ ሰነዶች፡- https://test.ton.org
  2. ኦፊሴላዊ የቶን ማከማቻ፡- https://github.com/ton-blockchain/ton
  3. ለተለያዩ መድረኮች ይፋዊ የኪስ ቦርሳ፡- https://wallet.ton.org
  4. የስማርት ኮንትራት ማከማቻ ከዚህ አንቀጽ፡- https://github.com/raiym/astonished
  5. ወደ ዘመናዊ የኮንትራት ድር ጣቢያ አገናኝ፡ https://ton-lottery.appspot.com
  6. የVisual Studio Code ለFunC የማራዘሚያ ማከማቻ፡ https://github.com/raiym/func-visual-studio-plugin
  7. በቴሌግራም ስለ ቶን ይወያዩ፣ ይህም በመነሻ ደረጃ ለማወቅ የረዳው። ለቶን የሆነ ነገር የፃፉ ሁሉ እዚያ አሉ ብባል ስህተት አይሆንም ብዬ አስባለሁ። እዚያም ለሙከራ ግራም መጠየቅ ይችላሉ. https://t.me/tondev_ru
  8. ጠቃሚ መረጃ ያገኘሁበት ስለ ቶን ሌላ ውይይት፡- https://t.me/TONgramDev
  9. የውድድሩ የመጀመሪያ ደረጃ፡- https://contest.com/blockchain
  10. የውድድሩ ሁለተኛ ደረጃ፡- https://contest.com/blockchain-2

ምንጭ: hab.com

አስተያየት ያክሉ