Kuidas kindlalt uuendatavaid nutikaid lepinguid kirjutada!

Nutika lepingute turvaauditite platvormi QuillAudits töötamise ajal QuillHashis töötades anname suurema osa ajast arukate lepingute parimate turbetavade uurimisele. QuillAudits peab nutika lepingukoodi järgmisi selgeid ja olulisi tahke: Kas kood on turvaline. Kas kood vastab dokumentatsioonile (sh valge paber). Kas kood vastab gaasi efektiivse kasutamise, koodide loetavuse jms parimatele tavadele. Lepingute uuendamise lähenemisviis peab olema armee, et vältida vigade programmeerimisest tulenevat kahju pärast lepingu kasutuselevõttu.

Uuendatavate lepingute teema pole eetrimaailmas eriti uus. Nutikate lepingute uuendamiseks on mõned erinevad lähenemisviisid.

Mõned lähenemisviisid, mida arenduses kaalusime, on järgmised:

  1. Eraldi loogika ja andmed.
  2. Osaliselt uuendatav arukate lepingute süsteem.
  3. Eraldi loogika ja andmed võtmeväärtuste paarides.
  4. Igavene salvestus puhverserveri lepinguga

Kolme esimese lähenemisviisi korral saab lepingut uuendada, suunates kasutajad kasutama uut loogikalepingut (sellise resolveri nagu ENS kaudu) ja ajakohastades andmelepingu õigusi, et uus loogikaleping saaks kasutada seadistajaid. ei pea seda ümbersuunamist tegema ja see on nutikate lepingute värskendamiseks väga paindlik lähenemine. Leidsime, et puhverserveri lepingupõhise lähenemisega igavene salvestusruum on siiani veatu.

Lugejad on teretulnud kommenteerima, kui teate selle lähenemisviisi puudusi. See on arendajate kogukonnale väga kasulik.

Nutikate lepingute värskendamise vastu ja vastu on hea põhjus. Hea põhjus on see, et kõik hiljutised häkked põhinesid programmeerimisveal ja neid oli võimalik väga hõlpsalt parandada, kui oleks võimalik neid lepinguid uuendada.

Võimalus arukate lepingute uuendamiseks pärast nende kasutuselevõttu on siiski mõnevõrra vastupidine blockchaini eetikale ja muutumatusele. Inimesed peavad teid usaldama, et olete hea poiss. Üks asi, mis võiks olla mõistlik, oleks mitme sig-versiooniga versiooniuuendused, kus mitme inimese “OK” on vajalik enne uue lepingu juurutamist ja tal on juurdepääs salvestusruumile. Arvan, et muutumatud peavad olema salvestuskirjed. blokeeringus.Logikat tuleb aja jooksul täiustada, nagu ka kõigis tarkvaratehnika tavades. Esimeses versioonis ei saa vigadeta tarkvara väljatöötamist garanteerida.Ni nii, et mõne täiendava juhtimismehhanismiga täiustatavad nutikad lepingud võivad päästa palju häkke.

Selles postituses puudutan versiooniuuendusmehhanismi ja järelmeetmete postituses püüan leida parima lepingupõhise uuendamise juhtimismehhanismi.

Alustame siis lähenemisviisist !!

  • Kõige olulisem asi, mida lepingute uuendamisel arvestada, on see, kuidas uuendatud lepingus säilitada algse lepingu seisund.
  • Lepingu olekut saab eraldada lepingu funktsionaalsusest. See lähenemisviis võimaldab mitmel lepingul jagada sama olekut.
  • Selle lähenemisviisi korral toimib puhverserver muutumatu salvestuslepinguna ja delegeeritud leping sisaldab funktsionaalsust.
  • Mõlema lepingu salvestusstruktuur peab olema sarnane.
  • Lepingu loogika täiustamiseks peame volikirja alusel teatama uue volitatud lepingu aadressi.
  • Kui tehing saadetakse puhverserveri lepingule, ei tea ta tehingus määratud funktsiooni.
  • Puhverserveri leping proksib tehingut sellele, mida me nimetame delegeeritud lepinguks (mis sisaldab funktsionaalsuse loogikat). Seda tehakse emakeelena loodud EVM-i koodi abil - delegeeritud kõne.
Delegeeritud kõne korral saab leping käitusajal dünaamiliselt laadida koodi teiselt aadressilt. Salvestusruum, praegune aadress ja saldo viitavad endiselt helistamislepingule, ainult kood võetakse valitud aadressilt.
Kui puhverserveri leping kasutab delegeeritud lepingu funktsionaalsust, tehakse puhverserveri lepingus oleku muudatusi. See tähendab, et kahes lepingus tuleb määratleda sama mälu. Mälu mäluseadme järjekord peab vastama kahele lepingule.

Esitame need lepingud esialgu: -

  1. võtmehoidla leping (sisaldab jagatud olekut)
  2. Delegeeritud lepingV1 ja Delegeeritud lepingV2
  3. Puhverserveri leping (sisaldab delegeeritud kõne funktsionaalsust)

Võtmehoidla leping: -

See sisaldab kõigi salvestusoleku olekumuutujate ühist salvestusruumi, mida jagatakse nutika lepingu kõigi versioonide vahel. See sisaldab ka getter- ja setter-funktsioone, et värskendada ja saada riigi väärtus delegeeritud lepingust.

Võtmehoidlate lepingut saab pärast kasutuselevõtmist kasutada puhverserveri kaudu iga volitatud esindaja leping. Pärast võtmehoidla kasutuselevõttu ei saa me uusi loojaid ja hääletajaid luua, nii et nutika lepingu algse versiooni kavandamisel peame sellega arvestama.

Parim viis on võtmehoidla lepingus igat tüüpi väljade vastendamine. Kui kaardistamise võti on võtme nimi lihtsalt baitides ja kaardistamisel deklareeritud tüübi väärtus.

Näiteks: - kaardistamine (bytes32 => uint)

Nüüd saame seda kaardistamist kasutada, et seada ja saada täisarvu väärtust delegeeritud lepingust, kutsudes klahvi hoiustamisfunktsiooni ja setteri funktsiooni uinti tüübi jaoks. Näiteks: saame kogu tarne seada klahviga "totalSupply" ja mis tahes uinti väärtusega.

Kuid oodake, kuni midagi jääb puudu. Nüüd saab igaüks helistada meie võtmehoidlate hankelepingu sõlmimise ja määramise funktsioonile ning värskendada meie volikirjaga harjunud salvestusruumi seisukorda. Selle volitamata oleku muutuse vältimiseks võime kasutada puhverserveri lepingu aadressi kaardistamise võti.

kaardistamine (aadress => kaardistamine (bytes32 => uint)) uintStorage
Meie setteri funktsioonis:
funktsioon setUintStorage (bytes32 keyField, uint väärtus) avalik {
uintStorage [msg.sender] [keyField] = väärtus
}

Kuna me kasutame setteri funktsioonis msg.sender aadressi ja ainult see olekumuutus kajastub puhverserveri lepingu olekus, kui ta kasutab oleku saamiseks getterfunktsiooni.Samuti saame luua ka muid olekukaardistusi koos getteri ja setteri funktsioonidega, nagu on näidatud allolev kood: -

Delegeeritud leping: -

Delegeeritud leping sisaldab dApp-i tegelikku funktsionaalsust.See sisaldab ka KeyStorage-i lepingu kohalikku koopiat.Meie rakenduses dApp, kui lisame teatud funktsionaalsuse ja leidsime hiljem kasutuselevõetud lepingus vea, saame sel juhul luua volitatud isiku uue versiooni. leping.

Allpool toodud koodis on juurutatud delegeeritud lepingu versioon 1 („DelegateV1.sol”).

Pärast DelegateV1 juurutamist märkasime, et iga kasutaja saab määrata omanike arvu. Nüüd soovime nutikat lepingut uuendada nii, et omanike arvu saaks määrata ainult lepingu omanik.

Me ei saa eetris juba kasutusele võetud lepingu koodi muuta. Nii et ilmne lahendus on uue lepingu loomine ja ka uus leping sisaldab võtmeväärtuse lepingu kohalikku koopiat. Siin loome lepingu DelegateV2.sol, millele on lisatud ainult muutuja Omanik.

Nüüd oleme loonud uue lepingu, kuid eelmise lepingu säilitamine pole uues lepingu versioonis saadaval. Niisiis võime delegeeritud lepingu igasse versiooni lisada viite tegelikule keyStorage'i lepingule. Sel viisil jagavad kõik delegeeritud lepingu versioonid sama ladustamine.Aga üks asi ei ole siinkohal soovitav, peame igale kasutajale teatama lepingu uuendatud versiooni aadressi, et nad saaksid värskendatud lepingut kasutada.See kõlab lolliks. Nii et me ei salvesta võtmehoidlate lepingu tegelikku koopiat igas versioonis jagatud salvestus puhverserveri leping tuleb appi, lubab liikuda puhverserveri lepinguni.

Puhverserveri leping: -

Puhverserver kasutab funktsioonikõnede edastamiseks sihtleppele, mida saab uuendada, delegatecall opcode abil. Kuna delegaadikõne säilitab funktsioonikõne oleku, saab sihtlepingu lepingu loogikat värskendada ja olek püsib puhverserveri lepingus, et värskendatud sihtlepingu loogikat saaks kasutada. Nagu delegeeritud kõne puhul, jääb msg.sender puhverserveri lepingu helistaja omaks.

Delegeeritud kõne saab käitusajal dünaamiliselt laadida koodi teiselt aadressilt. Salvestusruum, praegune aadress ja saldo viitavad endiselt helistamislepingule, ainult kood võetakse valitud aadressilt.
Niisiis peame lihtsalt edastama uue versiooni aadressi puhverserveri lepingule funktsiooni upgradeTo kaudu.

Puhverserveri lepingu kood on tagavarafunktsioonis üsna keeruline, kuna siin kasutatakse madala taseme delegaatide kõnede koostamise koodi.

Jagage see lihtsalt kokku monteerimiskoodis tehtavate toimingutega: -

delegaadikõne (gaas, _impl, lisage (andmed, 0x20), laadige (andmed), 0, 0);

Ülaltoodud funktsiooni korral on delegaadi kõne sisselogimisega „lisa (andmed, 0x20)” sisendkoodiga „_impl” sisestuskood sisestusmälu suurusega „mload (data)” ja tagastab delegeeritud kõne 0 vea korral ning 1 õnnestumise ja tulemuse korral. varufunktsioon on mis iganes, mida nn lepingufunktsioon tagastab.

Puhverserveriga pikendame StorageState lepingut, mis sisaldab globaalset muutujat võtmehoidla lepingu aadressi salvestamiseks.

Siin on oluline ladustamisriigi lepingu pikendamise järjekord enne võlgnetavat lepingut. Seda salvestusriigi lepingut pikendatakse meie delegeeritud lepingutega ja kõik delegeeritud lepingus täidetavad funktsioonide loogikad pärinevad puhverserveri lepingust. Puhverserveri salvestusstruktuuri järjekord leping ja delegaadi leping peavad olema samad.

Nüüd suhtleb kasutaja alati dappiga puhverserveri lepingu sama aadressi kaudu ja võtmehoidlalepingu olekut näib olevat jagatud kõigi lepingu versioonide vahel, kuid tegelikult sisaldab puhverserveri leping ainult viide tegelikule keyStorage'i lepingule. Dellegate lepingud sisaldavad keyStorage'i lepingu kohalikku koopiat Getterite, setterite funktsioonide loogika saamiseks ja sarnase salvestusstruktuuri saamiseks nagu puhverserveri leping, kuid tegelikud salvestusmuudatused tehakse ainult puhverserveri lepingu kontekstist.

Koos juurutamine ja testimine: -

Katsejuhtumite väljund on siin 10 10 ja 20

Kutsume testversioonil kolm korda getNumberOfOwners (). Esiteks, et saada olekumuudatus DelegateV1 lepingu alusel .Teise aja jooksul, et saada riik DelegateV1 poolt muudetud DelegateV2 lepingust, õnnestus meil täielikult säilitada DelegateV1 muudetud olek ja kolmandat korda saate riigi muutmise teha DelegateV2 lepinguga.

Pange tähele, et helistame iga kord puhverserveri lepingu samalt aadressilt getNumberOfOwners (). Nii et meil õnnestus oma lepingu funktsioone värskendada, kaotamata eelmist olekut.

Kui kutsume setNumberOfOwners () muult aadressilt, välja arvatud kontolt [2], mis on lepingu omaniku aadress, siis taandub see viga.

Võimaldab artiklit lõpetada mõne skeemiga: -

kõne uuendamine delegateV2-le

Täielikku koodi näete siit: -

https://github.com/Quillhash/upradeableToken.git

Täname, et lugesite Loodetavasti on see juhend teile kasulik olnud ja aitab teil kindlalt täiustatavaid nutikaid lepinguid kirjutada ning tutvuge ka meie varasemate ajaveebipostitustega.
QuillHashis mõistame Ethereumi plokiahelat ja meil on hea arendajate meeskond, kes saavad välja töötada plokiahela rakendusi nagu Nutikad lepingud, dApps, DeFi, DEX Ethereumi plokiahelas.
Meie tööga kursis olemiseks liituge meie kogukonnaga: -
Telegram | Twitter | Facebook | LinkedIn

Viited:

https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88
https://medium.com/level-k/f Flexible-upgradability-for-smart-contracts-9778d80d1638
https://medium.com/cardstack/upgradable-contracts-in-solidity-d5af87f0f913
https://blog.zeppelinos.org/smart-contract-upgradeability-using-eternal-storage/
https://medium.com/rocket-pool/upgradable-solidity-contract-design-54789205276d