Βέλτιστες πρακτικές στερεότητας για έξυπνη ασφάλεια συμβολαίων

blog 1ΕιδήσειςΑναπτυσσόμενοιΕξέτασηΕπεξήγηση BlockchainΕκδηλώσεις και ΣυνέδριαΠατήστεΕνημερωτικά δελτία

Contents

Εγγραφείτε στο newsletter μας.

Διεύθυνση ηλεκτρονικού ταχυδρομείου

Σεβόμαστε το απόρρητό σας

HomeBlogBlockchain Ανάπτυξη

Βέλτιστες πρακτικές στερεότητας για έξυπνη ασφάλεια συμβολαίων

Από την παρακολούθηση έως τις παραμέτρους της χρονικής σήμανσης, ακολουθούν μερικές επαγγελματικές συμβουλές για να διασφαλιστεί ότι τα έξυπνα συμβόλαια Ethereum είναι ενισχυμένα. από ConsenSys 21 Αυγούστου 2020 Δημοσιεύτηκε στις 21 Αυγούστου 2020

ήρωας βέλτιστων πρακτικών αλληλεγγύης

Με την ConsenSys Diligence, η ομάδα εμπειρογνωμόνων ασφαλείας blockchain.

Εάν έχετε πάρει το μυαλό της έξυπνης ασφάλειας συμβολαίου και παίρνετε μια λαβή για τις ιδιοσυγκρασίες της EVM, ήρθε η ώρα να λάβετε υπόψη ορισμένα μοτίβα ασφαλείας που αφορούν τη γλώσσα προγραμματισμού Solidity. Σε αυτό το ενημερωτικό δελτίο, θα επικεντρωθούμε σε ασφαλείς αναπτυξιακές προτάσεις για τη Στερεότητα που μπορεί επίσης να είναι χρήσιμες για την ανάπτυξη έξυπνων συμβάσεων σε άλλες γλώσσες. 

Εντάξει, ας περάσουμε.

Χρησιμοποιήστε το assert (), απαιτείται (), επαναφέρετε () σωστά

Η ευκολία λειτουργεί διεκδικώ και απαιτώ μπορεί να χρησιμοποιηθεί για τον έλεγχο των συνθηκών και την εξαίρεση εάν δεν πληρούται η συνθήκη.

ο διεκδικώ Η συνάρτηση πρέπει να χρησιμοποιείται μόνο για τον έλεγχο εσωτερικών σφαλμάτων και για τον έλεγχο των αμετάβλητων.

ο απαιτώ Η συνάρτηση πρέπει να χρησιμοποιείται για να διασφαλίζει έγκυρες συνθήκες, όπως εισόδους, ή τηρούνται οι μεταβλητές κατάστασης σύμβασης ή για την επικύρωση των τιμών επιστροφής από κλήσεις σε εξωτερικές συμβάσεις. 

Ακολουθώντας αυτό το παράδειγμα, επιτρέπεται στα επίσημα εργαλεία ανάλυσης να επαληθεύσουν ότι δεν είναι δυνατή η επίτευξη του μη έγκυρου opcode: που σημαίνει ότι δεν παραβιάζονται αναλλοίωτα στον κώδικα και ότι ο κώδικας επαληθεύεται επίσημα.

σταθερότητα πραγμάτων ^ 0,5,0; σύμβαση Sharer {function sendHalf (διεύθυνση πληρωτέας προσθήκης) δημόσιες πληρωτέες επιστροφές (υπόλοιπο uint) {απαιτείται (msg.value% 2 == 0, "Απαιτείται ομοιόμορφη τιμή."); // Το Require () μπορεί να έχει μια προαιρετική συμβολοσειρά μηνύματος uint balanceBeforeTransfer = address (this) .balance; (bool επιτυχία,) = addr.call.value (msg.value / 2) (""); απαιτούν (επιτυχία)? // Εφόσον επιστρέψαμε εάν η μεταφορά απέτυχε, δεν θα έπρεπε να υπάρχει κανένας τρόπος για να έχουμε ακόμα τα μισά χρήματα. assert (διεύθυνση (αυτό) .balance == balanceBeforeTransfer – msg.value / 2); // χρησιμοποιείται για εσωτερικό σφάλμα ελέγχου διεύθυνσης επιστροφής (αυτό). ισορροπία; }} Γλώσσα κώδικα: JavaScript (javascript)


Βλέπω SWC-110 & SWC-123

Χρησιμοποιήστε τροποποιητές μόνο για ελέγχους

Ο κωδικός μέσα σε έναν τροποποιητή εκτελείται συνήθως πριν από το σώμα της λειτουργίας, οπότε τυχόν αλλαγές κατάστασης ή εξωτερικές κλήσεις θα παραβιάζουν το Έλεγχοι-Εφέ-Αλληλεπιδράσεις πρότυπο. Επιπλέον, αυτές οι δηλώσεις ενδέχεται επίσης να παραμένουν απαρατήρητες από τον προγραμματιστή, καθώς ο κωδικός για τροποποιητή ενδέχεται να απέχει πολύ από τη δήλωση συνάρτησης. Για παράδειγμα, μια εξωτερική κλήση στον τροποποιητή μπορεί να οδηγήσει στην επίθεση επανεισόδου:

Μητρώο σύμβασης {κάτοχος διεύθυνσης · function isVoter (address _addr) εξωτερικές επιστροφές (bool) {// Code}} συμβόλαιο Εκλογή {Μητρώο μητρώου; τροποποιητής isEligible (διεύθυνση _addr) {απαιτείται (registry.isVoter (_addr)); _; } function vote () isEligible (msg.sender) public {// Code}} Γλώσσα κώδικα: JavaScript (javascript)

Σε αυτήν την περίπτωση, η σύμβαση μητρώου μπορεί να κάνει μια επίθεση επανάληψης καλώντας το Election.vote () μέσα στο isVoter ().

Σημείωση: Χρήση τροποποιητές για να αντικαταστήσετε διπλούς ελέγχους συνθηκών σε πολλές συναρτήσεις, όπως το isOwner (), διαφορετικά η χρήση απαιτεί ή επαναφέρετε μέσα στη συνάρτηση. Αυτό καθιστά τον έξυπνο κωδικό σύμβασης πιο ευανάγνωστο και ευκολότερο στον έλεγχο.

Προσοχή στρογγυλοποίηση με ακέραιο διαχωρισμό

Όλη η ακέραια διαίρεση στρογγυλοποιείται προς τον πλησιέστερο ακέραιο. Εάν χρειάζεστε περισσότερη ακρίβεια, σκεφτείτε να χρησιμοποιήσετε έναν πολλαπλασιαστή ή αποθηκεύστε τον αριθμητή και τον παρονομαστή.

(Στο μέλλον, η Στερεότητα θα έχει σταθερό σημείο πληκτρολογήστε, κάτι που θα το κάνει πιο εύκολο.)

// bad uint x = 5/2; // Το αποτέλεσμα είναι 2, όλοι οι ακέραιοι διαιρέτες γυρίζουν ΚΑΤΩ στην πλησιέστερη ακέραια γλώσσα Κωδικός: JavaScript (javascript)

Η χρήση ενός πολλαπλασιαστή αποτρέπει την στρογγυλοποίηση προς τα κάτω, αυτός ο πολλαπλασιαστής πρέπει να ληφθεί υπόψη κατά την εργασία με το x στο μέλλον:

// καλός πολλαπλασιαστής uint = 10; uint x = (5 * πολλαπλασιαστής) / 2; Γλώσσα κώδικα: JavaScript (javascript)

Η αποθήκευση του αριθμητή και του παρονομαστή σημαίνει ότι μπορείτε να υπολογίσετε το αποτέλεσμα του αριθμητή / παρονομαστή εκτός αλυσίδας:

// καλός αριθμητής uint = 5; uint denominator = 2; Γλώσσα κώδικα: JavaScript (javascript)

Να γνωρίζετε τις ανταλλαγές μεταξύ αφηρημένες συμβάσεις και διεπαφές

Τόσο οι διεπαφές όσο και οι αφηρημένες συμβάσεις παρέχουν μια προσαρμόσιμη και επαναχρησιμοποιήσιμη προσέγγιση για έξυπνες συμβάσεις. Οι διεπαφές, οι οποίες εισήχθησαν στο Solidity 0.4.11, είναι παρόμοιες με αφηρημένες συμβάσεις, αλλά δεν μπορούν να εφαρμοστούν λειτουργίες. Οι διασυνδέσεις έχουν επίσης περιορισμούς όπως η μη πρόσβαση σε χώρο αποθήκευσης ή η κληρονομικότητά τους από άλλες διεπαφές που καθιστούν γενικά πιο αφηρημένες τις συμβάσεις. Αν και, οι διασυνδέσεις είναι σίγουρα χρήσιμες για το σχεδιασμό συμβάσεων πριν από την εφαρμογή. Επιπλέον, είναι σημαντικό να θυμάστε ότι εάν ένα συμβόλαιο κληρονομεί από ένα αφηρημένο συμβόλαιο, πρέπει να εφαρμόσει όλες τις μη υλοποιημένες λειτουργίες μέσω παρακάμπτοντας ή θα είναι επίσης αφηρημένο.

Εναλλακτικές λειτουργίες

Διατηρήστε απλές τις εναλλακτικές λειτουργίες

Εναλλακτικές λειτουργίες καλούνται όταν ένα συμβόλαιο αποστέλλεται ένα μήνυμα χωρίς ορίσματα (ή όταν δεν αντιστοιχεί σε λειτουργία) και έχει πρόσβαση μόνο σε 2.300 αέριο όταν καλείται από .send () ή .transfer (). Εάν θέλετε να μπορείτε να λαμβάνετε το Ether από το .send () ή το .transfer (), το μεγαλύτερο μέρος που μπορείτε να κάνετε σε μια εναλλακτική λειτουργία είναι να καταγράψετε ένα συμβάν. Χρησιμοποιήστε μια σωστή λειτουργία εάν απαιτείται υπολογισμός περισσότερου αερίου.

// bad function () πληρωτέο {υπόλοιπα [msg.sender] + = msg.value; } // καλή λειτουργία κατάθεσης () πληρωτέα εξωτερικά {υπόλοιπα [msg.sender] + = msg.value; } συνάρτηση () πληρωτέα {απαιτείται (msg.data.length == 0); emit LogDepositReceived (msg.sender); } Γλώσσα κώδικα: JavaScript (javascript)

Ελέγξτε το μήκος δεδομένων στις εναλλακτικές λειτουργίες

Από το εναλλακτικές λειτουργίες δεν απαιτείται μόνο για μεταφορά απλού αιθέρα (χωρίς δεδομένα), αλλά και όταν δεν ταιριάζει καμία άλλη συνάρτηση, θα πρέπει να ελέγξετε ότι τα δεδομένα είναι κενά εάν η συνάρτηση εναλλαγής προορίζεται να χρησιμοποιηθεί μόνο για σκοπούς καταγραφής του Ether. Διαφορετικά, οι καλούντες δεν θα παρατηρήσουν εάν η σύμβασή σας χρησιμοποιείται λανθασμένα και πραγματοποιούνται κλήσεις που δεν υπάρχουν.

// bad function () πληρωτέο {emit LogDepositReceived (msg.sender); } // καλή λειτουργία () πληρωτέα {απαιτείται (msg.data.length == 0); emit LogDepositReceived (msg.sender); } Γλώσσα κώδικα: JavaScript (javascript)

Σημειώστε ρητά τις πληρωτέες συναρτήσεις και τις μεταβλητές κατάστασης

Ξεκινώντας από το Solidity 0.4.0, κάθε λειτουργία που λαμβάνει αιθέρα πρέπει να χρησιμοποιεί πληρωτέο τροποποιητή, διαφορετικά εάν η συναλλαγή έχει msg.value > 0 θα επιστρέψει (εκτός εάν αναγκαστεί).

Σημείωση: Κάτι που μπορεί να μην είναι προφανές: Ο πληρωτέος τροποποιητής ισχύει μόνο για κλήσεις από εξωτερικές συμβάσεις. Εάν καλέσω μια μη πληρωτέα συνάρτηση στη συνάρτηση πληρωτέας στο ίδιο συμβόλαιο, η μη πληρωτέα συνάρτηση δεν θα αποτύχει, αν και η τιμή msg.value εξακολουθεί να έχει οριστεί.

Σημειώστε ρητά την ορατότητα σε συναρτήσεις και μεταβλητές κατάστασης

Προσδιορίστε ρητά την ορατότητα των συναρτήσεων και των μεταβλητών κατάστασης. Οι συναρτήσεις μπορούν να οριστούν ως εξωτερικές, δημόσιες, εσωτερικές ή ιδιωτικές. Κατανοήστε τις διαφορές μεταξύ τους, για παράδειγμα, οι εξωτερικές μπορεί να είναι επαρκείς αντί για δημόσιες. Για μεταβλητές κατάστασης, δεν είναι δυνατή η εξωτερική. Η ρητή επισήμανση της ορατότητας θα διευκολύνει τη σύλληψη λανθασμένων υποθέσεων σχετικά με το ποιος μπορεί να καλέσει τη συνάρτηση ή να αποκτήσει πρόσβαση στη μεταβλητή.

  • Οι εξωτερικές λειτουργίες αποτελούν μέρος της διεπαφής συμβάσεων. Μια εξωτερική συνάρτηση f δεν μπορεί να κληθεί εσωτερικά (δηλ. Το f () δεν λειτουργεί, αλλά αυτό.f () λειτουργεί). Οι εξωτερικές λειτουργίες είναι μερικές φορές πιο αποτελεσματικές όταν λαμβάνουν μεγάλες συστοιχίες δεδομένων.
  • Οι δημόσιες λειτουργίες αποτελούν μέρος της διεπαφής συμβάσεων και μπορούν να κληθούν είτε εσωτερικά είτε μέσω μηνυμάτων. Για μεταβλητές δημόσιας κατάστασης, δημιουργείται μια αυτόματη συνάρτηση λήψης (δείτε παρακάτω).
  • Οι εσωτερικές λειτουργίες και οι μεταβλητές κατάστασης είναι προσβάσιμες μόνο εσωτερικά, χωρίς να το χρησιμοποιείτε.
  • Οι ιδιωτικές συναρτήσεις και οι μεταβλητές κατάστασης είναι ορατές μόνο για τη σύμβαση στην οποία καθορίζονται και όχι σε παράγωγα συμβόλαια. Σημείωση: Όλα όσα βρίσκονται μέσα σε μια σύμβαση είναι ορατά σε όλους τους παρατηρητές εκτός του blockchain, ακόμη και ιδιωτικές μεταβλητές.

// κακό uint x; // η προεπιλογή είναι εσωτερική για μεταβλητές κατάστασης, αλλά πρέπει να γίνει ρητή συνάρτηση buy () {// η προεπιλογή είναι δημόσια // δημόσιος κωδικός} // good uint private y; function buy () external {// μόνο δυνατότητα κλήσης εξωτερικά ή χρήση αυτού .buy ()} function function () public {// callable εξωτερικά, καθώς και εσωτερικά: η αλλαγή αυτού του κώδικα απαιτεί να σκεφτούμε και τις δύο περιπτώσεις. } function internalAction () internal {// internal code} Γλώσσα κώδικα: PHP (php)

Βλέπω SWC-100 και SWC-108

Κλείδωμα πραγμάτων σε συγκεκριμένη έκδοση μεταγλωττιστή

Τα συμβόλαια πρέπει να αναπτυχθούν με την ίδια έκδοση μεταγλωττιστή και σημαίες με τις οποίες έχουν δοκιμαστεί περισσότερο. Το κλείδωμα του pragma συμβάλλει στη διασφάλιση ότι τα συμβόλαια δεν αναπτύσσονται κατά λάθος χρησιμοποιώντας, για παράδειγμα, τον πιο πρόσφατο μεταγλωττιστή, ο οποίος μπορεί να έχει υψηλότερους κινδύνους σφαλμάτων που δεν έχουν εντοπιστεί. Τα συμβόλαια μπορούν επίσης να αναπτυχθούν από άλλους και το πραγματικό δείχνει την έκδοση του μεταγλωττιστή που προορίζεται από τους αρχικούς συντάκτες.

// κακή σταθερότητα πραγμάτων ^ 0,4,4; // καλή πρακτική σταθερότητα 0.4.4; Γλώσσα κώδικα: JavaScript (javascript)

Σημείωση: μια κυμαινόμενη έκδοση πραγμάτων (δηλ. ^ 0,4,25) θα μεταγλωττιστεί ωραία με 0,4,26-νυχτερινά..

Προειδοποίηση: Οι δηλώσεις Pragma μπορούν να επιτραπεί να αιωρούνται όταν ένα συμβόλαιο προορίζεται για κατανάλωση από άλλους προγραμματιστές, όπως στην περίπτωση με συμβόλαια σε βιβλιοθήκη ή πακέτο EthPM Διαφορετικά, ο προγραμματιστής θα πρέπει να ενημερώσει χειροκίνητα το πραγματικό για να μεταγλωττιστεί τοπικά.

Βλέπω SWC-103

Χρησιμοποιήστε εκδηλώσεις για την παρακολούθηση της συμβατικής δραστηριότητας

Μπορεί να είναι χρήσιμο να υπάρχει τρόπος παρακολούθησης της δραστηριότητας της σύμβασης μετά την ανάπτυξή της. Ένας τρόπος για να επιτευχθεί αυτό είναι να εξετάσετε όλες τις συναλλαγές του συμβολαίου, ωστόσο αυτό μπορεί να είναι ανεπαρκές, καθώς οι κλήσεις μηνυμάτων μεταξύ συμβάσεων δεν καταγράφονται στο blockchain. Επιπλέον, δείχνει μόνο τις παραμέτρους εισαγωγής και όχι τις πραγματικές αλλαγές που γίνονται στην κατάσταση. Επίσης, τα συμβάντα θα μπορούσαν να χρησιμοποιηθούν για την ενεργοποίηση λειτουργιών στο περιβάλλον χρήστη.

συμβόλαιο Φιλανθρωπία {χαρτογράφηση (διεύθυνση => uint) υπόλοιπα? συνάρτηση δωρεά () πληρωτέο δημόσιο {υπόλοιπα [msg.sender] + = msg.value; }} συμβόλαιο Παιχνίδι {function buyCoins () πληρωτέο κοινό {// 5% πηγαίνει στη φιλανθρωπική φιλανθρωπική οργάνωση.donate.value (msg.value / 20) (); }} Γλώσσα κώδικα: JavaScript (javascript)

Εδώ, η σύμβαση παιχνιδιού θα πραγματοποιήσει μια εσωτερική κλήση στο Charity.donate (). Αυτή η συναλλαγή δεν θα εμφανίζεται στη λίστα εξωτερικών συναλλαγών της Φιλανθρωπίας, αλλά είναι ορατή μόνο στις εσωτερικές συναλλαγές.

Ένα συμβάν είναι ένας βολικός τρόπος για να καταγράψετε κάτι που συνέβη στη σύμβαση. Τα συμβάντα που εκπέμπονται παραμένουν στο blockchain μαζί με τα άλλα δεδομένα συμβολαίου και είναι διαθέσιμα για μελλοντικό έλεγχο. Ακολουθεί μια βελτίωση στο παραπάνω παράδειγμα, χρησιμοποιώντας γεγονότα για να παρέχετε ένα ιστορικό των δωρεών του Φιλανθρωπικού.

συμβόλαιο Φιλανθρωπία {// καθορισμός συμβάντος LogDonate (uint _amount); χαρτογράφηση (διεύθυνση => uint) υπόλοιπα? συνάρτηση δωρεά () πληρωτέο δημόσιο {υπόλοιπα [msg.sender] + = msg.value; // emit event emit LogDonate (msg.value); }} συμβόλαιο Παιχνίδι {function buyCoins () πληρωτέο κοινό {// 5% πηγαίνει στη φιλανθρωπική φιλανθρωπική οργάνωση.donate.value (msg.value / 20) (); }} Γλώσσα κώδικα: JavaScript (javascript)

Εδώ, όλες οι συναλλαγές που πραγματοποιούνται μέσω της σύμβασης φιλανθρωπίας, είτε άμεσα είτε όχι, θα εμφανίζονται στη λίστα συμβάντων αυτού του συμβολαίου μαζί με το ποσό των δωρεών.

Σημείωση: Προτιμήστε νεότερες κατασκευές στερεότητας. Προτιμήστε κατασκευές / ψευδώνυμα όπως selfdestruct (over αυτοκτονία) και keccak256 (over sha3). Μοτίβα όπως απαιτείται (msg.sender.send (1 αιθέρας)) μπορούν επίσης να απλοποιηθούν στη χρήση μεταφοράς (), όπως στο msg.sender.transfer (1 αιθέρας). Ολοκλήρωση παραγγελίας Αρχείο καταγραφής αλλαγής στερεότητας για περισσότερες παρόμοιες αλλαγές.

Λάβετε υπόψη ότι τα «ενσωματωμένα» μπορούν να σκιάζονται

Είναι προς το παρόν δυνατό σκιά ενσωματωμένα σφαιρικά στο Solidity. Αυτό επιτρέπει στα συμβόλαια να παρακάμπτουν τη λειτουργικότητα των ενσωματωμένων, όπως msg και revert (). Αν και αυτό προορίζεται, Μπορεί να παραπλανήσει τους χρήστες μιας σύμβασης ως προς την πραγματική συμπεριφορά της σύμβασης.

σύμβαση PretendingToRevert {function revert () internal stable {}} contract ExampleContract is PretendingToRevert {function somethingBad () public {revert (); }}

Οι χρήστες συμβολαίων (και οι ελεγκτές) πρέπει να γνωρίζουν τον πλήρη έξυπνο πηγαίο κώδικα σύμβασης για κάθε εφαρμογή που σκοπεύουν να χρησιμοποιήσουν.

Αποφύγετε τη χρήση tx.origin

Ποτέ μην χρησιμοποιείτε το tx.origin για εξουσιοδότηση, ένα άλλο συμβόλαιο μπορεί να έχει μια μέθοδο που θα καλεί το συμβόλαιό σας (όπου ο χρήστης έχει κάποια χρήματα για παράδειγμα) και το συμβόλαιό σας θα εγκρίνει αυτήν τη συναλλαγή καθώς η διεύθυνσή σας είναι στο tx.origin.

συμβόλαιο MyContract {κάτοχος διεύθυνσης · συνάρτηση MyContract () public {owner = msg.sender; } λειτουργία sendTo (δέκτης διεύθυνσης, ποσό uint) δημόσιο {απαιτείται (tx.origin == ιδιοκτήτης); (bool επιτυχία,) = receiver.call.value (ποσό) (""); απαιτούν (επιτυχία)? }} σύμβαση AttackingContract {MyContract myContract; διευθυντής εισβολής; Λειτουργία AttackingContract (διεύθυνση myContractAddress) δημόσια {myContract = MyContract (myContractAddress); εισβολέας = msg.sender; } function () public {myContract.sendTo (επιτιθέμενος, msg.sender.balance); }} Γλώσσα κώδικα: JavaScript (javascript)

Θα πρέπει να χρησιμοποιήσετε το msg.sender για εξουσιοδότηση (εάν ένα άλλο συμβόλαιο καλέσει το συμβόλαιό σας, το msg.sender θα είναι η διεύθυνση του συμβολαίου και όχι η διεύθυνση του χρήστη που κάλεσε τη σύμβαση).

Μπορείτε να διαβάσετε περισσότερα γι ‘αυτό εδώ: Έγγραφα σταθερότητας

Προειδοποίηση: Εκτός από το πρόβλημα με την εξουσιοδότηση, υπάρχει πιθανότητα το tx.origin να αφαιρεθεί από το πρωτόκολλο Ethereum στο μέλλον, επομένως ο κώδικας που χρησιμοποιεί το tx.origin δεν θα είναι συμβατός με μελλοντικές κυκλοφορίες Vitalik: «ΜΗΝ υποθέτετε ότι η tx.origin θα συνεχίσει να είναι χρήσιμη ή σημαντική.»

Αξίζει επίσης να σημειωθεί ότι με τη χρήση του tx.origin περιορίζετε τη διαλειτουργικότητα μεταξύ συμβάσεων, επειδή το συμβόλαιο που χρησιμοποιεί το tx.origin δεν μπορεί να χρησιμοποιηθεί από άλλο συμβόλαιο, καθώς το συμβόλαιο δεν μπορεί να είναι το tx.origin.

Βλέπω SWC-115

Εξάρτηση χρονικής σήμανσης

Υπάρχουν τρεις βασικές σκέψεις κατά τη χρήση μιας χρονικής σήμανσης για την εκτέλεση μιας κρίσιμης λειτουργίας σε μια σύμβαση, ειδικά όταν οι ενέργειες περιλαμβάνουν μεταφορά χρημάτων.

Χειρισμός χρονικής σήμανσης

Να γνωρίζετε ότι η χρονική σήμανση του μπλοκ μπορεί να χειραγωγηθεί από έναν ανθρακωρύχο. Σκεφτείτε το σύμβαση:

uint256 σταθερό ιδιωτικό αλάτι = block.timestamp; λειτουργία τυχαίας (uint Max) σταθερές ιδιωτικές επιστροφές (αποτέλεσμα uint256) {// λάβετε τον καλύτερο σπόρο για τυχαιότητα uint256 x = αλάτι * 100 / Max; uint256 y = salt * block.number / (salt% 5); uint256 seed = block.number / 3 + (salt% 300) + Last_Payout + y; uint256 h = uint256 (block.blockhash (σπόρος)); επιστροφή uint256 ((h / x))% Max + 1; // τυχαίος αριθμός μεταξύ 1 και Max} Γλώσσα κώδικα: PHP (php)

Όταν το συμβόλαιο χρησιμοποιεί τη χρονική σήμανση για τη δημιουργία ενός τυχαίου αριθμού, ο ανθρακωρύχος μπορεί πραγματικά να δημοσιεύσει μια χρονική σήμανση εντός 15 δευτερολέπτων από την επικύρωση του μπλοκ, επιτρέποντας αποτελεσματικά στον ανθρακωρύχο να υπολογίσει μια επιλογή πιο ευνοϊκή για τις πιθανότητές τους στην κλήρωση. Οι χρονικές σημάνσεις δεν είναι τυχαίες και δεν πρέπει να χρησιμοποιούνται σε αυτό το πλαίσιο.

Ο κανόνας των 15 δευτερολέπτων

ο Κίτρινο χαρτί (Η προδιαγραφή αναφοράς του Ethereum) δεν καθορίζει έναν περιορισμό στο πόσα μπλοκ μπορούν να μετατοπιστούν στο χρόνο, αλλά προσδιορίζει ότι κάθε χρονική σήμανση πρέπει να είναι μεγαλύτερη από τη χρονική σήμανση του γονέα της. Δημοφιλείς εφαρμογές πρωτοκόλλου Ethereum Γκέθ και Ισοτιμία Και οι δύο απορρίπτουν μπλοκ με χρονική σήμανση πάνω από 15 δευτερόλεπτα στο μέλλον. Επομένως, ένας καλός κανόνας κατά την αξιολόγηση της χρήσης της χρονικής σήμανσης είναι: εάν η κλίμακα του συμβάντος που εξαρτάται από το χρόνο μπορεί να διαφέρει κατά 15 δευτερόλεπτα και να διατηρηθεί η ακεραιότητα, είναι ασφαλές να χρησιμοποιήσετε ένα block.timestamp.

Αποφύγετε τη χρήση του block.number ως χρονική σήμανση

Είναι δυνατό να εκτιμηθεί ένα χρονικό δέλτα χρησιμοποιώντας την ιδιότητα block.number και μέσος χρόνος αποκλεισμού, Ωστόσο, αυτό δεν είναι μελλοντική απόδειξη καθώς οι χρόνοι αποκλεισμού ενδέχεται να αλλάξουν (όπως αναδιοργανώσεις πιρούνι και το βόμβα δυσκολίας). Σε μια πώληση που καλύπτει ημέρες, ο κανόνας των 15 δευτερολέπτων επιτρέπει σε κάποιον να επιτύχει μια πιο αξιόπιστη εκτίμηση του χρόνου.

Βλέπω SWC-116

Προσοχή πολλαπλής κληρονομιάς

Όταν χρησιμοποιείτε πολλαπλή κληρονομικότητα στο Solidity, είναι σημαντικό να κατανοήσετε πώς ο μεταγλωττιστής συνθέτει το γράφημα κληρονομιάς.

τελικό συμβολαίου {uint public a; Λειτουργία Final (uint f) public {a = f; }} το συμβόλαιο Β είναι οριστικό {int public fee; συνάρτηση B (uint f) Final (f) public {} function setFee () public {fee = 3; }} το συμβόλαιο Γ είναι οριστικό {int public fee; συνάρτηση C (uint f) Final (f) public {} function setFee () public {fee = 5; }} η σύμβαση A είναι B, C {συνάρτηση A () δημόσια B (3) C (5) {setFee (); }} Γλώσσα κώδικα: PHP (php)

Όταν αναπτύσσεται ένα συμβόλαιο, ο μεταγλωττιστής θα γραμμικοποιήσει την κληρονομιά από τα δεξιά προς τα αριστερά (αφού η λέξη-κλειδί είναι οι γονείς παρατίθενται από το πιο βασικό-ως το πιο παραγόμενο). Εδώ είναι η γραμμικοποίηση της σύμβασης Α:

Τελικός <- σι <- ντο <- ΕΝΑ

Η συνέπεια της γραμμικοποίησης θα αποδώσει αξία αμοιβής 5, δεδομένου ότι το C είναι το πιο παράγωγο συμβόλαιο. Αυτό μπορεί να φαίνεται προφανές, αλλά φανταστείτε σενάρια όπου το C είναι σε θέση να επισκιάσει κρίσιμες λειτουργίες, να αναδιατάξει δυαδικές ρήτρες και να αναγκάσει τον προγραμματιστή να γράψει εκμεταλλεύσιμα συμβόλαια. Η στατική ανάλυση προς το παρόν δεν θέτει πρόβλημα με τις επισκιασμένες συναρτήσεις, επομένως πρέπει να ελεγχθεί χειροκίνητα.

Για να συμβάλει στη συνεισφορά, το Solith’s Github έχει ένα έργο με όλα τα ζητήματα που σχετίζονται με την κληρονομιά.

Βλέπω SWC-125

Χρησιμοποιήστε τον τύπο διασύνδεσης αντί της διεύθυνσης για την ασφάλεια τύπου

Όταν μια συνάρτηση παίρνει μια διεύθυνση σύμβασης ως επιχείρημα, είναι καλύτερο να περάσετε μια διεπαφή ή έναν τύπο σύμβασης παρά μια μη επεξεργασμένη διεύθυνση. Εάν η συνάρτηση καλείται αλλού στον πηγαίο κώδικα, ο μεταγλωττιστής θα παρέχει πρόσθετες εγγυήσεις ασφαλείας τύπου.

Εδώ βλέπουμε δύο εναλλακτικές λύσεις:

Σύμβαση Validator {function validate (uint) εξωτερικές επιστροφές (bool). } συμβόλαιο TypeSafeAuction {// good function validateBet (Validator _validator, uint _value) εσωτερικές επιστροφές (bool) {bool valid = _validator.validate (_value); έγκριση επιστροφής }} συμβόλαιο TypeUnsafeAuction {// bad function validateBet (διεύθυνση _addr, uint _value) εσωτερικές επιστροφές (bool) {Validator validator = Validator (_addr); bool valid = validator.validate (_value); έγκριση επιστροφής }} Γλώσσα κώδικα: JavaScript (javascript)

Τα οφέλη από τη χρήση του συμβολαίου TypeSafeAuction παραπάνω μπορούν να φανεί από το ακόλουθο παράδειγμα. Εάν το validateBet () καλείται με ένα όρισμα διεύθυνσης ή έναν τύπο συμβολαίου διαφορετικό από το Validator, ο μεταγλωττιστής θα εμφανίσει αυτό το σφάλμα:

συμβόλαιο NonValidator {} η δημοπρασία συμβολαίου είναι TypeSafeAuction {NonValidator nonValidator; στοίχημα λειτουργίας (uint _value) {bool valid = validateBet (nonValidator, _value); // TypeError: Μη έγκυρος τύπος για όρισμα στην κλήση συνάρτησης. // Ζητήθηκε μη έγκυρη σιωπηρή μετατροπή από συμβόλαιο NonValidator // σε σύμβαση Validator. }} Γλώσσα κώδικα: JavaScript (javascript)

Αποφύγετε τη χρήση extcodesize για έλεγχο λογαριασμών εξωτερικής ιδιοκτησίας

Ο ακόλουθος τροποποιητής (ή παρόμοιος έλεγχος) χρησιμοποιείται συχνά για την επαλήθευση του κατά πόσον πραγματοποιήθηκε κλήση από λογαριασμό εξωτερικής ιδιοκτησίας (EOA) ή από λογαριασμό συμβολαίου:

// bad modifier isNotContract (διεύθυνση _a) {uint size; συγκρότημα {size: = extcodesize (_a)} απαιτούν (μέγεθος == 0); _; } Γλώσσα κώδικα: JavaScript (javascript)

Η ιδέα είναι απλή: αν μια διεύθυνση περιέχει κώδικα, δεν είναι EOA αλλά συμβατικός λογαριασμός. Ωστόσο, μια σύμβαση δεν έχει διαθέσιμο πηγαίο κώδικα κατά την κατασκευή. Αυτό σημαίνει ότι ενώ ο κατασκευαστής βρίσκεται σε λειτουργία, μπορεί να κάνει κλήσεις σε άλλα συμβόλαια, αλλά το extcodeize για τη διεύθυνσή του επιστρέφει μηδέν. Ακολουθεί ένα ελάχιστο παράδειγμα που δείχνει πώς μπορεί να παρακαμφθεί αυτός ο έλεγχος:

OnlyForEOA {uint δημόσια σημαία; // bad modifier isNotContract (διεύθυνση _a) {uint len; συγκρότημα {len: = extcodesize (_a)} απαιτούν (len == 0); _; } function setFlag (uint i) public isNotContract (msg.sender) {flag = i; }} σύμβαση FakeEOA {buildor (address _a) public {OnlyForEOA c = OnlyForEOA (_a); c.setFlag (1); }} Γλώσσα κώδικα: JavaScript (javascript)

Επειδή οι διευθύνσεις συμβολαίων μπορούν να υπολογιστούν εκ των προτέρων, αυτός ο έλεγχος θα μπορούσε επίσης να αποτύχει εάν ελέγχει μια διεύθυνση που είναι κενή στο μπλοκ n, αλλά η οποία έχει αναπτύξει μια σύμβαση σε κάποιο μπλοκ μεγαλύτερο από το n.

Προειδοποίηση: Αυτό το ζήτημα είναι λεπτό. Εάν ο στόχος σας είναι να αποτρέψετε τη δυνατότητα κλήσης άλλων συμβολαίων από τη σύμβασή σας, ο έλεγχος εξωδικοποίησης είναι πιθανώς επαρκής. Μια εναλλακτική προσέγγιση είναι να ελέγξετε την τιμή του (tx.origin == msg.sender), αν και αυτό ισχύει επίσης έχει μειονεκτήματα.

Μπορεί να υπάρχουν άλλες καταστάσεις στις οποίες ο έλεγχος extcodesize εξυπηρετεί το σκοπό σας. Η περιγραφή όλων αυτών εδώ είναι εκτός πεδίου. Κατανοήστε τις υποκείμενες συμπεριφορές του EVM και χρησιμοποιήστε την κρίση σας.

Είναι ο κωδικός Blockchain σας ασφαλής?

Κλείστε έναν επιτόπιο έλεγχο 1 ημέρας με τους ειδικούς ασφαλείας μας. Κάντε κράτηση για τη δική σας επιμέλεια Ασφάλεια Έξυπνα συμβόλαια Αλληλεγγύη Ενημερωτικό δελτίο Εγγραφείτε στο ενημερωτικό δελτίο μας για τις τελευταίες ειδήσεις Ethereum, εταιρικές λύσεις, πόρους προγραμματιστών και πολλά άλλα. Διεύθυνση ηλεκτρονικού ταχυδρομείου Αποκλειστικό περιεχόμενοΠώς να δημιουργήσετε ένα επιτυχημένο προϊόν BlockchainΔιαδικτυακό σεμινάριο

Πώς να δημιουργήσετε ένα επιτυχημένο προϊόν Blockchain

Πώς να ρυθμίσετε και να εκτελέσετε έναν κόμβο EthereumΔιαδικτυακό σεμινάριο

Πώς να ρυθμίσετε και να εκτελέσετε έναν κόμβο Ethereum

Πώς να φτιάξετε το δικό σας Ethereum APIΔιαδικτυακό σεμινάριο

Πώς να φτιάξετε το δικό σας Ethereum API

Πώς να δημιουργήσετε ένα κοινωνικό κουπόνιΔιαδικτυακό σεμινάριο

Πώς να δημιουργήσετε ένα κοινωνικό κουπόνι

Χρήση εργαλείων ασφαλείας στην ανάπτυξη έξυπνων συμβάσεωνΔιαδικτυακό σεμινάριο

Χρήση εργαλείων ασφαλείας στην ανάπτυξη έξυπνων συμβάσεων

Το Μέλλον των Χρηματοοικονομικών Ψηφιακών Στοιχείων και του DeFiΔιαδικτυακό σεμινάριο

Το μέλλον των οικονομικών: Ψηφιακά περιουσιακά στοιχεία και DeFi

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me
Like this post? Please share to your friends:
Adblock
detector
map