Πιθανότατα έχετε ακούσει αυτό το Telegram . Αλλά μπορεί να χάσατε τα νέα ότι πριν από λίγο καιρό το Telegram για την υλοποίηση ενός ή περισσότερων έξυπνων συμβολαίων για αυτήν την πλατφόρμα.
Η ομάδα Serokell, με μεγάλη εμπειρία στην ανάπτυξη μεγάλων έργων blockchain, δεν μπορούσε να σταθεί στην άκρη. Αναθέσαμε πέντε υπαλλήλους στον διαγωνισμό και δύο εβδομάδες αργότερα κατέλαβαν την πρώτη θέση σε αυτόν με το (μη) μέτριο τυχαίο ψευδώνυμο Sexy Chameleon. Σε αυτό το άρθρο θα μιλήσω για το πώς το έκαναν. Ελπίζουμε στα επόμενα δέκα λεπτά να διαβάσετε τουλάχιστον μια ενδιαφέρουσα ιστορία και το πολύ να βρείτε κάτι χρήσιμο σε αυτήν που μπορείτε να εφαρμόσετε στη δουλειά σας.
Ας ξεκινήσουμε όμως με ένα μικρό πλαίσιο.
Ο ανταγωνισμός και οι προϋποθέσεις του
Έτσι, τα κύρια καθήκοντα των συμμετεχόντων ήταν η υλοποίηση ενός ή περισσοτέρων από τα προτεινόμενα έξυπνα συμβόλαια, καθώς και η υποβολή προτάσεων για τη βελτίωση του οικοσυστήματος TON. Ο διαγωνισμός διήρκεσε από τις 24 Σεπτεμβρίου έως τις 15 Οκτωβρίου και τα αποτελέσματα ανακοινώθηκαν μόλις στις 15 Νοεμβρίου. Αρκετά καιρό, λαμβάνοντας υπόψη ότι σε αυτό το διάστημα η Telegram κατάφερε να πραγματοποιήσει και να ανακοινώσει τα αποτελέσματα διαγωνισμών για το σχεδιασμό και την ανάπτυξη εφαρμογών σε C++ για δοκιμή και αξιολόγηση της ποιότητας των κλήσεων VoIP στο Telegram.
Επιλέξαμε δύο έξυπνα συμβόλαια από τη λίστα που πρότειναν οι διοργανωτές. Για ένα από αυτά, χρησιμοποιήσαμε εργαλεία που διανεμήθηκαν με TON και το δεύτερο εφαρμόστηκε σε μια νέα γλώσσα που αναπτύχθηκε από τους μηχανικούς μας ειδικά για το TON και ενσωματώθηκε στο Haskell.
Η επιλογή μιας λειτουργικής γλώσσας προγραμματισμού δεν είναι τυχαία. Στο δικό μας Συχνά μιλάμε για το γιατί πιστεύουμε ότι η πολυπλοκότητα των λειτουργικών γλωσσών είναι τεράστια υπερβολή και γιατί γενικά τις προτιμούμε από τις αντικειμενοστρεφείς. Παρεμπιπτόντως, περιέχει επίσης .
Γιατί αποφασίσαμε να συμμετάσχουμε;
Εν ολίγοις, επειδή η εξειδίκευσή μας είναι μη τυποποιημένα και πολύπλοκα έργα που απαιτούν ειδικές δεξιότητες και συχνά έχουν επιστημονική αξία για την κοινότητα της πληροφορικής. Υποστηρίζουμε σθεναρά την ανάπτυξη ανοιχτού κώδικα και ασχολούμαστε με τη διάδοσή του, και επίσης συνεργαζόμαστε με κορυφαία ρωσικά πανεπιστήμια στον τομέα της επιστήμης των υπολογιστών και των μαθηματικών.
Τα ενδιαφέροντα καθήκοντα του διαγωνισμού και η συμμετοχή στο αγαπημένο μας έργο Telegram ήταν από μόνα τους ένα εξαιρετικό κίνητρο, αλλά το χρηματικό έπαθλο έγινε ένα επιπλέον κίνητρο. 🙂
Έρευνα blockchain TON
Παρακολουθούμε στενά τις νέες εξελίξεις στο blockchain, την τεχνητή νοημοσύνη και τη μηχανική μάθηση και προσπαθούμε να μην χάσουμε ούτε μία σημαντική κυκλοφορία σε κάθε έναν από τους τομείς στους οποίους εργαζόμαστε. Ως εκ τούτου, από τη στιγμή που ξεκίνησε ο διαγωνισμός, η ομάδα μας ήταν ήδη εξοικειωμένη με τις ιδέες από . Ωστόσο, πριν ξεκινήσουμε τη δουλειά με την TON, δεν αναλύσαμε την τεχνική τεκμηρίωση και τον πραγματικό πηγαίο κώδικα της πλατφόρμας, επομένως το πρώτο βήμα ήταν αρκετά προφανές - μια διεξοδική μελέτη της επίσημης τεκμηρίωσης για και .
Μέχρι να ξεκινήσει ο διαγωνισμός, ο κώδικας είχε ήδη δημοσιευτεί, οπότε για να εξοικονομήσουμε χρόνο, αποφασίσαμε να αναζητήσουμε έναν οδηγό ή περίληψη γραμμένη από από τους χρήστες. Δυστυχώς, αυτό δεν έδωσε κανένα αποτέλεσμα - εκτός από οδηγίες για τη συναρμολόγηση της πλατφόρμας στο Ubuntu, δεν βρήκαμε άλλα υλικά.
Η ίδια η τεκμηρίωση ήταν καλά ερευνημένη, αλλά ήταν δύσκολο να διαβαστεί σε ορισμένες περιοχές. Αρκετά συχνά έπρεπε να επιστρέψουμε σε ορισμένα σημεία και να μεταβούμε από υψηλού επιπέδου περιγραφές αφηρημένων ιδεών σε λεπτομέρειες υλοποίησης χαμηλού επιπέδου.
Θα ήταν ευκολότερο εάν η προδιαγραφή δεν περιελάμβανε καθόλου λεπτομερή περιγραφή της υλοποίησης. Οι πληροφορίες σχετικά με το πώς μια εικονική μηχανή αντιπροσωπεύει τη στοίβα της είναι πιο πιθανό να αποσπάσουν την προσοχή των προγραμματιστών που δημιουργούν έξυπνα συμβόλαια για την πλατφόρμα TON παρά να τους βοηθήσουν.
Nix: συναρμολόγηση του έργου
Στο Serokell είμαστε μεγάλοι θαυμαστές . Συλλέγουμε τα έργα μας με αυτό και τα αναπτύσσουμε χρησιμοποιώντας , και εγκατεστημένο σε όλους τους διακομιστές μας . Χάρη σε αυτό, όλες οι εκδόσεις μας είναι αναπαραγώγιμες και λειτουργούν σε οποιοδήποτε λειτουργικό σύστημα στο οποίο μπορεί να εγκατασταθεί το Nix.
Ξεκινήσαμε λοιπόν δημιουργώντας . Με τη βοήθειά του, η μεταγλώττιση του 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 (TVM). Το TVM είναι πιο περίπλοκο από τις περισσότερες άλλες εικονικές μηχανές και έχει πολύ ενδιαφέρουσα λειτουργικότητα, για παράδειγμα, μπορεί να λειτουργήσει συνέχειες и συνδέσμους προς δεδομένα.
Επιπλέον, τα παιδιά από το TON δημιούργησαν τρεις νέες γλώσσες προγραμματισμού:
Πέντε είναι μια καθολική γλώσσα προγραμματισμού στοίβας που μοιάζει με . Η σούπερ ικανότητά του είναι η ικανότητα αλληλεπίδρασης με το TVM.
FunC είναι μια γλώσσα προγραμματισμού έξυπνης σύμβασης που είναι παρόμοια με και μεταγλωττίζεται σε άλλη γλώσσα - Fift Assembler.
Πέμπτος Συναρμολογητής — Πέντε βιβλιοθήκη για τη δημιουργία δυαδικού εκτελέσιμου κώδικα για TVM. Το Fifth Assembler δεν έχει μεταγλωττιστή. Αυτό .
Ο διαγωνισμός μας λειτουργεί
Επιτέλους, ήρθε η ώρα να δούμε τα αποτελέσματα των προσπαθειών μας.
Ασύγχρονο κανάλι πληρωμής
Το κανάλι πληρωμής είναι ένα έξυπνο συμβόλαιο που επιτρέπει σε δύο χρήστες να στέλνουν πληρωμές εκτός του blockchain. Ως αποτέλεσμα, εξοικονομείτε όχι μόνο χρήματα (δεν υπάρχει προμήθεια), αλλά και χρόνο (δεν χρειάζεται να περιμένετε για την επεξεργασία του επόμενου μπλοκ). Οι πληρωμές μπορεί να είναι τόσο μικρές όσο επιθυμείτε και όσο συχνά απαιτείται. Σε αυτή την περίπτωση, τα μέρη δεν χρειάζεται να εμπιστεύονται το ένα το άλλο, αφού η δικαιοσύνη της τελικής διευθέτησης διασφαλίζεται από το έξυπνο συμβόλαιο.
Βρήκαμε μια αρκετά απλή λύση στο πρόβλημα. Δύο μέρη μπορούν να ανταλλάξουν υπογεγραμμένα μηνύματα, το καθένα από τα οποία περιέχει δύο αριθμούς—το πλήρες ποσό που καταβάλλεται από κάθε μέρος. Αυτοί οι δύο αριθμοί λειτουργούν όπως στα παραδοσιακά κατανεμημένα συστήματα και να ορίσετε την εντολή "συνέβη πριν" στις συναλλαγές. Χρησιμοποιώντας αυτά τα δεδομένα, η σύμβαση θα είναι σε θέση να επιλύσει οποιαδήποτε πιθανή σύγκρουση.
Στην πραγματικότητα, ένας αριθμός αρκεί για να υλοποιηθεί αυτή η ιδέα, αλλά αφήσαμε και τα δύο γιατί έτσι θα μπορούσαμε να φτιάξουμε ένα πιο βολικό περιβάλλον χρήστη. Επιπλέον, αποφασίσαμε να συμπεριλάβουμε το ποσό πληρωμής σε κάθε μήνυμα. Χωρίς αυτό, εάν το μήνυμα χαθεί για κάποιο λόγο, τότε, αν και όλα τα ποσά και ο τελικός υπολογισμός θα είναι σωστά, ο χρήστης μπορεί να μην παρατηρήσει την απώλεια.
Για να δοκιμάσουμε την ιδέα μας, αναζητήσαμε παραδείγματα χρήσης ενός τόσο απλού και συνοπτικού πρωτοκόλλου καναλιού πληρωμής. Παραδόξως, βρήκαμε μόνο δύο:
- παρόμοια προσέγγιση, μόνο για την περίπτωση ενός μονοκατευθυντικού καναλιού.
- , που περιγράφει την ίδια ιδέα με τη δική μας, χωρίς όμως να εξηγεί πολλές σημαντικές λεπτομέρειες, όπως τη γενική ορθότητα και τις διαδικασίες επίλυσης συγκρούσεων.
Έγινε σαφές ότι έχει νόημα να περιγράψουμε λεπτομερώς το πρωτόκολλό μας, δίνοντας ιδιαίτερη προσοχή στην ορθότητά του. Μετά από αρκετές επαναλήψεις, η προδιαγραφή ήταν έτοιμη και τώρα μπορείτε και εσείς. .
Υλοποιήσαμε τη σύμβαση στο FunC και γράψαμε το βοηθητικό πρόγραμμα γραμμής εντολών για αλληλεπίδραση με το συμβόλαιό μας εξ ολοκλήρου στο Fift, όπως προτείνεται από τους διοργανωτές. Θα μπορούσαμε να έχουμε επιλέξει οποιαδήποτε άλλη γλώσσα για το CLI μας, αλλά μας ενδιέφερε να δοκιμάσουμε το Fit για να δούμε την απόδοση του στην πράξη.
Για να είμαστε ειλικρινείς, μετά τη συνεργασία με το Fift, δεν είδαμε κανέναν επιτακτικό λόγο για να προτιμήσουμε αυτήν τη γλώσσα από δημοφιλείς και ενεργά χρησιμοποιούμενες γλώσσες με ανεπτυγμένα εργαλεία και βιβλιοθήκες. Ο προγραμματισμός σε μια γλώσσα που βασίζεται σε στοίβα είναι αρκετά δυσάρεστος, αφού πρέπει να κρατάτε συνεχώς στο μυαλό σας ό,τι υπάρχει στη στοίβα και ο μεταγλωττιστής δεν βοηθά σε αυτό.
Επομένως, κατά τη γνώμη μας, η μόνη δικαιολογία για την ύπαρξη του Fift είναι ο ρόλος του ως γλώσσα υποδοχής για τον Fift Assembler. Αλλά δεν θα ήταν καλύτερο να ενσωματώσετε το assembler TVM σε κάποια υπάρχουσα γλώσσα, αντί να εφεύρετε μια νέα για αυτόν τον ουσιαστικά μοναδικό σκοπό;
TVM Haskell eDSL
Τώρα ήρθε η ώρα να μιλήσουμε για το δεύτερο έξυπνο συμβόλαιό μας. Αποφασίσαμε να αναπτύξουμε ένα πορτοφόλι πολλαπλών υπογραφών, αλλά η σύνταξη ενός άλλου έξυπνου συμβολαίου στο FunC θα ήταν πολύ βαρετή. Θέλαμε να προσθέσουμε λίγη γεύση και αυτή ήταν η δική μας γλώσσα συναρμολόγησης για το TVM.
Όπως το Fift Assembler, η νέα μας γλώσσα είναι ενσωματωμένη, αλλά επιλέξαμε το Haskell ως κεντρικό υπολογιστή αντί για το Fift, επιτρέποντάς μας να εκμεταλλευτούμε πλήρως το σύστημα προηγμένου τύπου του. Όταν εργάζεστε με έξυπνα συμβόλαια, όπου το κόστος ακόμη και ενός μικρού σφάλματος μπορεί να είναι πολύ υψηλό, η στατική πληκτρολόγηση, κατά τη γνώμη μας, είναι ένα μεγάλο πλεονέκτημα.
Για να δείξουμε πώς μοιάζει ο συναρμολογητής TVM ενσωματωμένος στο Haskell, εφαρμόσαμε ένα τυπικό πορτοφόλι σε αυτό. Εδώ είναι μερικά πράγματα που πρέπει να προσέξετε:
- Αυτό το συμβόλαιο αποτελείται από μία λειτουργία, αλλά μπορείτε να χρησιμοποιήσετε όσες θέλετε. Όταν ορίζετε μια νέα συνάρτηση στη γλώσσα υποδοχής (δηλαδή Haskell), το eDSL σας επιτρέπει να επιλέξετε εάν θέλετε να γίνει ξεχωριστή ρουτίνα στο TVM ή απλώς να ενσωματωθεί στο σημείο κλήσης.
- Όπως και η Haskell, οι συναρτήσεις έχουν τύπους που ελέγχονται κατά το χρόνο μεταγλώττισης. Στο eDSL μας, ο τύπος εισόδου μιας συνάρτησης είναι ο τύπος στοίβας που αναμένει η συνάρτηση και ο τύπος αποτελέσματος είναι ο τύπος στοίβας που θα παραχθεί μετά την κλήση.
- Ο κώδικας έχει σχολιασμούς
stacktype, περιγράφοντας τον αναμενόμενο τύπο στοίβας στο σημείο κλήσης. Στο αρχικό συμβόλαιο πορτοφολιού αυτά ήταν απλώς σχόλια, αλλά στο eDSL μας αποτελούν στην πραγματικότητα μέρος του κώδικα και ελέγχονται κατά τη στιγμή της μεταγλώττισης. Μπορούν να χρησιμεύσουν ως τεκμηρίωση ή δηλώσεις που βοηθούν τον προγραμματιστή να βρει το πρόβλημα εάν αλλάξει ο κώδικας και αλλάξει ο τύπος στοίβας. Φυσικά, τέτοιοι σχολιασμοί δεν επηρεάζουν την απόδοση χρόνου εκτέλεσης, καθώς δεν δημιουργείται κώδικας TVM για αυτούς. - Αυτό είναι ακόμα ένα πρωτότυπο που γράφτηκε σε δύο εβδομάδες, επομένως υπάρχει ακόμη πολλή δουλειά που πρέπει να γίνει για το έργο. Για παράδειγμα, όλες οι παρουσίες των κλάσεων που βλέπετε στον παρακάτω κώδικα θα πρέπει να δημιουργούνται αυτόματα.
Έτσι φαίνεται η υλοποίηση ενός πορτοφολιού multisig στο 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.
Συμπεράσματα για τον διαγωνισμό και τον ΤΟΝ
Συνολικά, η εργασία μας διήρκεσε 380 ώρες (συμπεριλαμβανομένης της εξοικείωσης με την τεκμηρίωση, τις συναντήσεις και την πραγματική ανάπτυξη). Πέντε προγραμματιστές συμμετείχαν στο διαγωνισμό: CTO, επικεφαλής ομάδας, ειδικοί πλατφόρμας blockchain και προγραμματιστές λογισμικού Haskell.
Βρήκαμε πόρους για να συμμετάσχουμε στον διαγωνισμό χωρίς δυσκολία, καθώς το πνεύμα ενός hackathon, η στενή ομαδική εργασία και η ανάγκη να βυθιστούμε γρήγορα σε πτυχές των νέων τεχνολογιών είναι πάντα συναρπαστικά. Αρκετές άγρυπνες νύχτες για την επίτευξη των μέγιστων αποτελεσμάτων σε συνθήκες περιορισμένων πόρων αντισταθμίζονται από ανεκτίμητη εμπειρία και εξαιρετικές αναμνήσεις. Επιπλέον, η εργασία σε τέτοιες εργασίες είναι πάντα μια καλή δοκιμή των διαδικασιών της εταιρείας, καθώς είναι εξαιρετικά δύσκολο να επιτευχθούν πραγματικά αξιοπρεπή αποτελέσματα χωρίς εσωτερική αλληλεπίδραση που λειτουργεί σωστά.
Εκτός από τους στίχους: εντυπωσιαστήκαμε από τον όγκο της δουλειάς που έκανε η ομάδα TON. Κατάφεραν να φτιάξουν ένα σύνθετο, όμορφο και το πιο σημαντικό, λειτουργικό σύστημα. Η TON έχει αποδείξει ότι είναι μια πλατφόρμα με μεγάλες δυνατότητες. Ωστόσο, για να αναπτυχθεί αυτό το οικοσύστημα, πρέπει να γίνουν πολύ περισσότερα, τόσο ως προς τη χρήση του σε έργα blockchain όσο και ως προς τη βελτίωση των εργαλείων ανάπτυξης. Είμαστε περήφανοι που τώρα είμαστε μέρος αυτής της διαδικασίας.
Εάν μετά την ανάγνωση αυτού του άρθρου εξακολουθείτε να έχετε ερωτήσεις ή έχετε ιδέες για το πώς να χρησιμοποιήσετε το TON για να λύσετε τα προβλήματά σας, — Θα χαρούμε να μοιραστούμε την εμπειρία μας.
Πηγή: www.habr.com
