เปลี่ยน FunC ให้เป็น FunCtional ด้วย Haskell: Serokell ชนะการแข่งขัน Telegram Blockchain ได้อย่างไร

คุณคงเคยได้ยินว่าโทรเลข กำลังจะเปิดตัวแพลตฟอร์ม Ton blockchain. แต่คุณอาจพลาดข่าวคราวของ Telegram เมื่อไม่นานมานี้ ประกาศการแข่งขัน สำหรับการดำเนินการสัญญาอัจฉริยะตั้งแต่หนึ่งสัญญาขึ้นไปสำหรับแพลตฟอร์มนี้

ทีม Serokell ซึ่งมีประสบการณ์มากมายในการพัฒนาโครงการบล็อกเชนขนาดใหญ่ไม่สามารถยืนหยัดได้ เราได้มอบหมายพนักงานห้าคนเข้าร่วมการแข่งขัน และสองสัปดาห์ต่อมาพวกเขาก็ได้ที่หนึ่งภายใต้ชื่อเล่นแบบสุ่ม (ใน) สุดเก๋อย่าง Sexy Chameleon ในบทความนี้ ฉันจะพูดถึงว่าพวกเขาทำได้อย่างไร เราหวังว่าในอีกสิบนาทีข้างหน้าคุณจะได้อ่านเรื่องราวที่น่าสนใจเป็นอย่างน้อยและอย่างน้อยที่สุดคุณจะพบสิ่งที่มีประโยชน์ซึ่งคุณสามารถนำไปใช้ในงานของคุณได้

แต่ขอเริ่มต้นด้วยบริบทเล็กน้อย

การแข่งขันและเงื่อนไข

ดังนั้นงานหลักของผู้เข้าร่วมคือการดำเนินการตามสัญญาอัจฉริยะที่เสนอตั้งแต่หนึ่งรายการขึ้นไป ตลอดจนจัดทำข้อเสนอเพื่อปรับปรุงระบบนิเวศ TON การแข่งขันเริ่มตั้งแต่วันที่ 24 กันยายนถึง 15 ตุลาคม และประกาศผลในวันที่ 15 พฤศจิกายนเท่านั้น ค่อนข้างนานเมื่อพิจารณาว่าในช่วงเวลานี้ Telegram สามารถจัดการและประกาศผลการแข่งขันเกี่ยวกับการออกแบบและพัฒนาแอปพลิเคชันใน C ++ เพื่อทดสอบและประเมินคุณภาพการโทร VoIP ใน Telegram

เราเลือกสัญญาอัจฉริยะสองฉบับจากรายการที่เสนอโดยผู้จัดงาน สำหรับหนึ่งในนั้น เราใช้เครื่องมือที่เผยแพร่กับ TON และเครื่องมือที่สองถูกนำมาใช้ในภาษาใหม่ที่พัฒนาโดยวิศวกรของเราสำหรับ TON โดยเฉพาะและสร้างไว้ใน Haskell

การเลือกภาษาการเขียนโปรแกรมเชิงฟังก์ชันไม่ใช่เรื่องบังเอิญ ในตัวเรา บล็อกขององค์กร เรามักจะพูดถึงว่าทำไมเราถึงคิดว่าความซับซ้อนของภาษาที่ใช้งานได้นั้นเป็นการพูดเกินจริงอย่างมากและทำไมเราถึงชอบภาษาเหล่านี้มากกว่าภาษาเชิงวัตถุ โดยวิธีการนี้ก็ยังประกอบด้วย ต้นฉบับของบทความนี้.

ทำไมเราถึงตัดสินใจเข้าร่วม?

กล่าวโดยสรุป เนื่องจากความเชี่ยวชาญของเราเป็นโครงการที่ไม่ได้มาตรฐานและซับซ้อนซึ่งต้องใช้ทักษะพิเศษและมักจะมีคุณค่าทางวิทยาศาสตร์ต่อชุมชนไอที เราสนับสนุนการพัฒนาโอเพ่นซอร์สอย่างยิ่งและมีส่วนร่วมในการเผยแพร่ให้แพร่หลาย และยังร่วมมือกับมหาวิทยาลัยชั้นนำของรัสเซียในสาขาวิทยาการคอมพิวเตอร์และคณิตศาสตร์

งานที่น่าสนใจของการแข่งขันและการมีส่วนร่วมในโครงการ Telegram อันเป็นที่รักของเรานั้นเป็นแรงจูงใจที่ดีเยี่ยมในตัวมันเอง แต่เงินรางวัลก็กลายเป็นแรงจูงใจเพิ่มเติม 🙂

การวิจัยบล็อกเชน TON

เราติดตามการพัฒนาใหม่ๆ ในบล็อกเชน ปัญญาประดิษฐ์ และการเรียนรู้ของเครื่องจักรอย่างใกล้ชิด และพยายามที่จะไม่พลาดการเผยแพร่ที่สำคัญเพียงครั้งเดียวในแต่ละด้านที่เราทำงาน ดังนั้นเมื่อเริ่มการแข่งขันทีมของเราก็คุ้นเคยกับไอเดียจาก กระดาษสีขาวของตัน. อย่างไรก็ตาม ก่อนที่จะเริ่มทำงานกับ TON เราไม่ได้วิเคราะห์เอกสารทางเทคนิคและซอร์สโค้ดจริงของแพลตฟอร์ม ดังนั้นขั้นตอนแรกจึงค่อนข้างชัดเจน - การศึกษาเอกสารอย่างเป็นทางการเกี่ยวกับ เว็บไซต์ และ ที่เก็บโครงการ.

เมื่อการแข่งขันเริ่มต้น รหัสก็ถูกเผยแพร่ไปแล้ว ดังนั้น เพื่อเป็นการประหยัดเวลา เราจึงตัดสินใจหาคำแนะนำหรือบทสรุปที่เขียนโดย โดยผู้ใช้. น่าเสียดายที่สิ่งนี้ไม่ได้ให้ผลลัพธ์ใด ๆ นอกเหนือจากคำแนะนำในการประกอบแพลตฟอร์มบน Ubuntu แล้ว เราไม่พบวัสดุอื่นใด

เอกสารประกอบได้รับการค้นคว้ามาอย่างดี แต่อ่านยากในบางพื้นที่ บ่อยครั้งเราต้องกลับไปยังจุดหนึ่งและเปลี่ยนจากคำอธิบายระดับสูงของแนวคิดเชิงนามธรรมไปเป็นรายละเอียดการนำไปปฏิบัติระดับต่ำ

มันจะง่ายกว่านี้ถ้าข้อกำหนดไม่มีคำอธิบายโดยละเอียดของการนำไปปฏิบัติเลย ข้อมูลเกี่ยวกับวิธีที่เครื่องเสมือนเป็นตัวแทนสแต็กมีแนวโน้มที่จะเบี่ยงเบนความสนใจของนักพัฒนาในการสร้างสัญญาอัจฉริยะสำหรับแพลตฟอร์ม TON มากกว่าที่จะช่วยเหลือพวกเขา

ห้าม: รวบรวมโครงการเข้าด้วยกัน

ที่ Serokell เราเป็นแฟนตัวยง ไม่มีอะไร. เรารวบรวมโครงการของเรากับพวกเขาและปรับใช้โดยใช้ นิกซ์โอปส์และติดตั้งบนเซิร์ฟเวอร์ทั้งหมดของเรา Nix OS. ด้วยเหตุนี้ บิลด์ทั้งหมดของเราจึงสามารถทำซ้ำได้และทำงานได้บนระบบปฏิบัติการใดๆ ที่สามารถติดตั้ง Nix ได้

ดังนั้นเราจึงเริ่มต้นด้วยการสร้าง ห้ามซ้อนทับด้วยนิพจน์สำหรับการประกอบ TON. ด้วยความช่วยเหลือนี้ การคอมไพล์ TON จึงง่ายที่สุด:

$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && make

โปรดทราบว่าคุณไม่จำเป็นต้องติดตั้งการขึ้นต่อกันใดๆ Nix จะทำทุกอย่างให้คุณอย่างน่าอัศจรรย์ ไม่ว่าคุณจะใช้ NixOS, Ubuntu หรือ macOS

การเขียนโปรแกรมสำหรับ TON

รหัสสัญญาอัจฉริยะในเครือข่าย TON ทำงานบน TON Virtual Machine (TVM) TVM มีความซับซ้อนมากกว่าเครื่องเสมือนอื่นๆ ส่วนใหญ่ และมีฟังก์ชันที่น่าสนใจมาก เช่น สามารถทำงานได้ ความต่อเนื่อง и เชื่อมโยงไปยังข้อมูล.

นอกจากนี้ ทีมจาก TON ยังได้สร้างภาษาการเขียนโปรแกรมใหม่สามภาษา:

ห้า เป็นภาษาโปรแกรมสแต็กสากลที่มีลักษณะคล้าย ออกมา. ความสามารถพิเศษของเขาคือความสามารถในการโต้ตอบกับ TVM

ฟันซี เป็นภาษาโปรแกรมสัญญาอัจฉริยะที่มีลักษณะคล้ายกับ C และรวบรวมเป็นภาษาอื่น - Fift Assembler

ผู้ประกอบคนที่ห้า — ห้าไลบรารีสำหรับสร้างโค้ดปฏิบัติการแบบไบนารีสำหรับ TVM Fifth Assembler ไม่มีคอมไพเลอร์ นี้ ภาษาเฉพาะโดเมนแบบฝัง (eDSL).

การแข่งขันของเราทำงาน

ในที่สุดก็ถึงเวลาดูผลลัพธ์ของความพยายามของเรา

ช่องทางการชำระเงินแบบอะซิงโครนัส

ช่องทางการชำระเงินเป็นสัญญาอัจฉริยะที่อนุญาตให้ผู้ใช้สองคนส่งการชำระเงินนอกบล็อคเชน เป็นผลให้คุณไม่เพียงประหยัดเงิน (ไม่มีค่าคอมมิชชัน) แต่ยังประหยัดเวลาด้วย (คุณไม่ต้องรอบล็อกถัดไปที่จะดำเนินการ) การชำระเงินอาจมีเพียงเล็กน้อยตามต้องการและบ่อยเท่าที่ต้องการ ในกรณีนี้ คู่สัญญาไม่จำเป็นต้องเชื่อใจซึ่งกันและกัน เนื่องจากความเป็นธรรมของการชำระหนี้ขั้นสุดท้ายรับประกันโดยสัญญาอัจฉริยะ

เราพบวิธีแก้ไขปัญหาที่ค่อนข้างง่าย ทั้งสองฝ่ายสามารถแลกเปลี่ยนข้อความที่ลงนาม โดยแต่ละฝ่ายจะมีตัวเลขสองตัว ซึ่งเป็นจำนวนเงินที่แต่ละฝ่ายชำระเต็มจำนวน ตัวเลขสองตัวนี้ทำงานเหมือนกัน นาฬิกาเวกเตอร์ ในระบบกระจายแบบดั้งเดิมและกำหนดลำดับ "เกิดขึ้นก่อน" ในธุรกรรม การใช้ข้อมูลนี้จะทำให้สัญญาสามารถแก้ไขข้อขัดแย้งที่อาจเกิดขึ้นได้

อันที่จริง ตัวเลขตัวเดียวก็เพียงพอที่จะนำแนวคิดนี้ไปใช้ แต่เราทิ้งทั้งสองไว้เพราะวิธีนี้เราสามารถสร้างอินเทอร์เฟซผู้ใช้ที่สะดวกยิ่งขึ้นได้ นอกจากนี้เรายังตัดสินใจรวมจำนวนเงินที่ชำระไว้ในแต่ละข้อความด้วย หากไม่มีข้อความดังกล่าว หากข้อความสูญหายด้วยเหตุผลบางประการ แม้ว่าจำนวนเงินทั้งหมดและการคำนวณขั้นสุดท้ายจะถูกต้อง แต่ผู้ใช้อาจไม่สังเกตเห็นการสูญเสีย

เพื่อทดสอบแนวคิดของเรา เรามองหาตัวอย่างของการใช้โปรโตคอลช่องทางการชำระเงินที่เรียบง่ายและรัดกุม น่าแปลกที่เราพบเพียงสองรายการเท่านั้น:

  1. ลักษณะ วิธีการที่คล้ายกัน เฉพาะในกรณีของช่องทางเดียวเท่านั้น
  2. บทช่วยสอนซึ่งอธิบายแนวคิดเดียวกันกับของเรา แต่ไม่ได้อธิบายรายละเอียดที่สำคัญมากมาย เช่น ความถูกต้องทั่วไป และขั้นตอนการแก้ไขข้อขัดแย้ง

เห็นได้ชัดว่าเป็นการเหมาะสมที่จะอธิบายโปรโตคอลของเราโดยละเอียด โดยให้ความสำคัญกับความถูกต้องเป็นพิเศษ หลังจากทำซ้ำหลายครั้ง ข้อมูลจำเพาะก็พร้อม และตอนนี้คุณก็ทำได้เช่นกัน มองที่เธอ.

เราใช้สัญญาใน FunC และเราเขียนยูทิลิตี้บรรทัดคำสั่งสำหรับการโต้ตอบกับสัญญาของเราทั้งหมดใน Fift ตามที่ผู้จัดงานแนะนำ เราสามารถเลือกภาษาอื่นสำหรับ CLI ของเราได้ แต่เราสนใจที่จะลองใช้ Fit เพื่อดูว่ามันทำงานอย่างไรในทางปฏิบัติ

พูดตามตรงหลังจากทำงานกับ Fift เราไม่เห็นเหตุผลที่น่าสนใจใด ๆ ที่จะเลือกใช้ภาษานี้มากกว่าภาษายอดนิยมและใช้งานอย่างแข็งขันด้วยเครื่องมือและห้องสมุดที่พัฒนาขึ้น การเขียนโปรแกรมในภาษาแบบสแต็กนั้นค่อนข้างไม่เป็นที่พอใจเนื่องจากคุณต้องนึกถึงสิ่งที่อยู่ในสแต็กอย่างต่อเนื่องและคอมไพเลอร์ไม่ได้ช่วยในเรื่องนี้

ดังนั้นตามความเห็นของเรา เหตุผลเดียวสำหรับการมีอยู่ของ Fift คือบทบาทของมันในฐานะภาษาโฮสต์สำหรับ Fift Assembler แต่จะดีกว่าไหมถ้าฝัง TVM แอสเซมเบลอร์เป็นภาษาที่มีอยู่ แทนที่จะสร้างภาษาใหม่ขึ้นมาเพื่อจุดประสงค์หลักเพียงอย่างเดียวนี้

TVM Haskell eDSL

ตอนนี้ถึงเวลาพูดคุยเกี่ยวกับสัญญาอันชาญฉลาดฉบับที่สองของเราแล้ว เราตัดสินใจที่จะพัฒนากระเป๋าเงินแบบหลายลายเซ็น แต่การเขียนสัญญาอัจฉริยะอีกฉบับใน FunC คงจะน่าเบื่อเกินไป เราต้องการเพิ่มรสชาติ และนั่นคือภาษาแอสเซมบลีของเราเองสำหรับ TVM

เช่นเดียวกับ Fift Assembler ภาษาใหม่ของเราถูกฝังไว้ แต่เราเลือก Haskell เป็นโฮสต์แทนที่จะเป็น Fift ทำให้เราใช้ประโยชน์จากระบบประเภทขั้นสูงได้อย่างเต็มที่ เมื่อทำงานกับสัญญาอัจฉริยะ ซึ่งต้นทุนของข้อผิดพลาดเล็กๆ น้อยๆ อาจสูงมาก ในความคิดของเรา การพิมพ์แบบคงที่ถือเป็นข้อได้เปรียบที่ยิ่งใหญ่

เพื่อแสดงให้เห็นว่าแอสเซมเบลอร์ TVM มีลักษณะอย่างไรที่ฝังอยู่ใน Haskell เราได้ติดตั้งกระเป๋าเงินมาตรฐานไว้ ต่อไปนี้เป็นบางสิ่งที่ควรคำนึงถึง:

  • สัญญานี้ประกอบด้วยหนึ่งฟังก์ชัน แต่คุณสามารถใช้ได้มากเท่าที่คุณต้องการ เมื่อคุณกำหนดฟังก์ชันใหม่ในภาษาโฮสต์ (เช่น Haskell) eDSL ของเราจะช่วยให้คุณสามารถเลือกได้ว่าต้องการให้กลายเป็นกิจวัตรแยกต่างหากใน TVM หรือเพียงแทรกในบรรทัด ณ จุดที่มีการโทร
  • เช่นเดียวกับ Haskell ฟังก์ชันมีประเภทที่ได้รับการตรวจสอบ ณ เวลาคอมไพล์ ใน eDSL ของเรา ประเภทอินพุตของฟังก์ชันคือประเภทของสแต็กที่ฟังก์ชันคาดหวัง และประเภทผลลัพธ์คือประเภทของสแต็กที่จะสร้างขึ้นหลังจากการเรียก
  • รหัสมีคำอธิบายประกอบ stacktypeอธิบายประเภทสแต็กที่คาดหวังที่จุดเรียก ในสัญญากระเป๋าเงินต้นฉบับ สิ่งเหล่านี้เป็นเพียงความคิดเห็น แต่ใน eDSL ของเรา จริงๆ แล้วสิ่งเหล่านี้เป็นส่วนหนึ่งของโค้ดและได้รับการตรวจสอบ ณ เวลาคอมไพล์ สามารถใช้เป็นเอกสารหรือคำสั่งที่ช่วยให้นักพัฒนาค้นหาปัญหาได้หากโค้ดเปลี่ยนแปลงและประเภทสแต็กเปลี่ยนไป แน่นอนว่าคำอธิบายประกอบดังกล่าวจะไม่ส่งผลกระทบต่อประสิทธิภาพรันไทม์ เนื่องจากไม่มีการสร้างโค้ด TVM สำหรับหมายเหตุเหล่านั้น
  • นี่ยังคงเป็นต้นแบบที่เขียนขึ้นภายในสองสัปดาห์ ดังนั้นจึงยังมีงานอีกมากที่ต้องทำในโครงการนี้ ตัวอย่างเช่น อินสแตนซ์ทั้งหมดของคลาสที่คุณเห็นในโค้ดด้านล่างควรถูกสร้างขึ้นโดยอัตโนมัติ

นี่คือลักษณะการใช้งาน Multisig Wallet บน eDSL ของเรา:

main :: IO ()
main = putText $ pretty $ declProgram procedures methods
  where
    procedures =
      [ ("recv_external", decl recvExternal)
      , ("recv_internal", decl recvInternal)
      ]
    methods =
      [ ("seqno", declMethod getSeqno)
      ]

data Storage = Storage
  { sCnt :: Word32
  , sPubKey :: PublicKey
  }

instance DecodeSlice Storage where
  type DecodeSliceFields Storage = [PublicKey, Word32]
  decodeFromSliceImpl = do
    decodeFromSliceImpl @Word32
    decodeFromSliceImpl @PublicKey

instance EncodeBuilder Storage where
  encodeToBuilder = do
    encodeToBuilder @Word32
    encodeToBuilder @PublicKey

data WalletError
  = SeqNoMismatch
  | SignatureMismatch
  deriving (Eq, Ord, Show, Generic)

instance Exception WalletError

instance Enum WalletError where
  toEnum 33 = SeqNoMismatch
  toEnum 34 = SignatureMismatch
  toEnum _ = error "Uknown MultiSigError id"

  fromEnum SeqNoMismatch = 33
  fromEnum SignatureMismatch = 34

recvInternal :: '[Slice] :-> '[]
recvInternal = drop

recvExternal :: '[Slice] :-> '[]
recvExternal = do
  decodeFromSlice @Signature
  dup
  preloadFromSlice @Word32
  stacktype @[Word32, Slice, Signature]
  -- cnt cs sign

  pushRoot
  decodeFromCell @Storage
  stacktype @[PublicKey, Word32, Word32, Slice, Signature]
  -- pk cnt' cnt cs sign

  xcpu @1 @2
  stacktype @[Word32, Word32, PublicKey, Word32, Slice, Signature]
  -- cnt cnt' pk cnt cs sign

  equalInt >> throwIfNot SeqNoMismatch

  push @2
  sliceHash
  stacktype @[Hash Slice, PublicKey, Word32, Slice, Signature]
  -- hash pk cnt cs sign

  xc2pu @0 @4 @4
  stacktype @[PublicKey, Signature, Hash Slice, Word32, Slice, PublicKey]
  -- pubk sign hash cnt cs pubk

  chkSignU
  stacktype @[Bool, Word32, Slice, PublicKey]
  -- ? cnt cs pubk

  throwIfNot SignatureMismatch
  accept

  swap
  decodeFromSlice @Word32
  nip

  dup
  srefs @Word8

  pushInt 0
  if IsEq
  then ignore
  else do
    decodeFromSlice @Word8
    decodeFromSlice @(Cell MessageObject)
    stacktype @[Slice, Cell MessageObject, Word8, Word32, PublicKey]
    xchg @2
    sendRawMsg
    stacktype @[Slice, Word32, PublicKey]

  endS
  inc

  encodeToCell @Storage
  popRoot

getSeqno :: '[] :-> '[Word32]
getSeqno = do
  pushRoot
  cToS
  preloadFromSlice @Word32

สามารถดูซอร์สโค้ดฉบับสมบูรณ์ของ eDSL และสัญญากระเป๋าเงินหลายลายเซ็นได้ที่ พื้นที่เก็บข้อมูลนี้ และอื่น ๆ บอกอย่างละเอียด เกี่ยวกับภาษาในตัว Georgy Agapov เพื่อนร่วมงานของเรา

สรุปผลการแข่งขันและ TON

งานของเราใช้เวลาทั้งหมด 380 ชั่วโมง (รวมถึงการทำความคุ้นเคยกับเอกสาร การประชุม และการพัฒนาจริง) นักพัฒนาห้ารายเข้าร่วมในโครงการแข่งขัน ได้แก่ CTO หัวหน้าทีม ผู้เชี่ยวชาญด้านแพลตฟอร์มบล็อกเชน และนักพัฒนาซอฟต์แวร์ Haskell

เราพบทรัพยากรที่จะเข้าร่วมในการแข่งขันได้โดยไม่ยาก เนื่องจากจิตวิญญาณของแฮ็กกาธอน การทำงานเป็นทีมอย่างใกล้ชิด และความต้องการที่จะดื่มด่ำไปกับเทคโนโลยีใหม่ ๆ อย่างรวดเร็วนั้นน่าตื่นเต้นอยู่เสมอ การนอนไม่หลับหลายคืนเพื่อให้ได้ผลลัพธ์สูงสุดในสภาวะที่มีทรัพยากรจำกัดจะได้รับการชดเชยด้วยประสบการณ์อันล้ำค่าและความทรงจำที่ยอดเยี่ยม นอกจากนี้ การทำงานดังกล่าวถือเป็นการทดสอบกระบวนการของบริษัทที่ดีเสมอ เนื่องจากเป็นเรื่องยากมากที่จะบรรลุผลลัพธ์ที่ดีอย่างแท้จริงโดยปราศจากปฏิสัมพันธ์ภายในที่ดี

นอกเหนือจากเนื้อเพลง: เราประทับใจกับปริมาณงานของทีม TON พวกเขาสามารถสร้างระบบการทำงานที่ซับซ้อน สวยงาม และที่สำคัญที่สุดได้ TON ได้พิสูจน์ตัวเองแล้วว่าเป็นแพลตฟอร์มที่มีศักยภาพสูง อย่างไรก็ตาม เพื่อให้ระบบนิเวศนี้พัฒนาขึ้น จำเป็นต้องดำเนินการอีกมาก ทั้งในแง่ของการใช้งานในโครงการบล็อคเชน และในแง่ของการปรับปรุงเครื่องมือการพัฒนา ตอนนี้เราภูมิใจที่ได้เป็นส่วนหนึ่งของกระบวนการนี้

หากหลังจากอ่านบทความนี้แล้ว หากคุณยังคงมีคำถามหรือมีแนวคิดเกี่ยวกับวิธีใช้ TON เพื่อแก้ไขปัญหาของคุณ เขียนถึงเรา — เรายินดีที่จะแบ่งปันประสบการณ์ของเรา

ที่มา: will.com

เพิ่มความคิดเห็น