Tema blockchaina nikada ne prestaje biti izvor ne samo svih vrsta hypea, već i ideja koje su vrlo vrijedne sa tehnološke tačke gledišta. Stoga nije zaobišao ni stanovnike sunčanog grada. Ljudi pažljivo promatraju, proučavaju, pokušavaju prenijeti svoju stručnost u tradicionalnoj informacijskoj sigurnosti na blockchain sisteme. Za sada je to na licu mjesta: jedan od razvoja Rostelecom-Solar-a može provjeriti sigurnost softvera zasnovanog na blockchain-u. I usput se javljaju neka razmišljanja o rješavanju primijenjenih problema blockchain zajednice. Jedan od ovih životnih hakova - kako odrediti adresu pametnog ugovora prije implementacije pomoću CREATE2 - danas želim podijeliti s vama ispod reza.
CREATE2 opcode je dodat u Constantinopol hard fork 28. februara ove godine. Kako je navedeno u EIP-u, ovaj opkod je uveden prvenstveno za državne kanale. Međutim, koristili smo ga da riješimo drugačiji problem.
Postoje korisnici sa stanjem na berzi. Svakom korisniku moramo dati Ethereum adresu na koju svako može slati tokene i na taj način dopuniti svoj račun. Nazovimo ove adrese "novčanici". Kada tokeni stignu u novčanike, moramo ih poslati u jedan novčanik (hotwallet).
U sljedećim odjeljcima analiziram opcije za rješavanje ovog problema bez CREATE2 i govorim vam zašto smo ih napustili. Ako vas zanima samo konačni rezultat, možete ga pronaći u odjeljku “Konačno rješenje”.
Ethereum adrese
Najjednostavnije rješenje je generiranje novih Ethereum adresa za nove korisnike. Ove adrese će biti novčanici. Za prijenos tokena iz novčanika u hotwallet, trebate potpisati transakciju pozivanjem funkcije transfer() sa privatnim ključem novčanika iz backenda.
Ovaj pristup ima sljedeće prednosti:
- to je jednostavno
- cijena prijenosa tokena iz novčanika u hotwallet jednaka je cijeni poziva funkcije transfer()
Međutim, odlučili smo se protiv ovog pristupa jer ima jedan veliki nedostatak: morate negdje pohraniti privatne ključeve. Ne samo da se mogu izgubiti, već morate pažljivo upravljati pristupom ovim ključevima. Ako je barem jedan od njih ugrožen, tokeni određenog korisnika neće doći do vrućeg novčanika.
Napravite poseban pametni ugovor za svakog korisnika
Uvođenje zasebnog pametnog ugovora za svakog korisnika omogućava vam da izbjegnete pohranjivanje privatnih ključeva za novčanike na serveru. Burza će pozvati ovaj pametni ugovor za prijenos tokena na hotwallet.
Odustali smo i od ovog rješenja, jer korisniku ne može biti prikazana njegova adresa novčanika bez implementacije pametnog ugovora (to je zapravo moguće, ali na prilično složen način s drugim nedostacima o kojima ovdje nećemo govoriti). Na berzi korisnik može kreirati onoliko računa koliko mu je potrebno, a svaki od njih treba svoj novčanik. To znači da trebamo potrošiti novac na implementaciju ugovora, a da nismo ni sigurni da će korisnik koristiti ovaj račun.
Opcode CREATE2
Kako bismo riješili problem prethodne metode, odlučili smo koristiti CREATE2 opcode. CREATE2 vam omogućava da unaprijed odredite adresu na kojoj će pametni ugovor biti raspoređen. Adresa se izračunava pomoću sljedeće formule:
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
gdje:
- adresa — adresa pametnog ugovora koji će zvati CREATE2
- sol - slučajna vrijednost
- init_code — bajt kod pametnog ugovora za implementaciju
Ovo osigurava da adresa koju dajemo korisniku zapravo sadrži željeni bajt kod. Štaviše, ovaj pametni ugovor se može primijeniti kad god nam zatreba. Na primjer, kada korisnik odluči da koristi svoj novčanik po prvi put.
Štaviše, možete izračunati adresu pametnog ugovora svaki put umjesto da je pohranjujete jer:
- adresa u formuli je konstantna, pošto je ovo adresa naše fabrike novčanika
- sol — hash user_id
- init_code je konstantan jer koristimo isti novčanik
Više poboljšanja
Prethodno rješenje još uvijek ima jedan nedostatak: morate platiti za implementaciju pametnog ugovora. Međutim, možete ga se riješiti. Da biste to učinili, možete pozvati funkciju transfer(), i onda samouništenje() u konstruktoru novčanika. A onda će gas za implementaciju pametnog ugovora biti vraćen.
Suprotno uvriježenom mišljenju, pametni ugovor možete implementirati na istu adresu više puta pomoću CREATE2 opcode-a. To je zato što CREATE2 provjerava da je nonce ciljne adrese nula (dodijeljena mu je vrijednost "1" na početku konstruktora). U ovom slučaju, funkcija samouništenje() resetuje nonce adrese svaki put. Dakle, ako ponovo pozovete CREATE2 sa istim argumentima, provjera nonce će proći.
Imajte na umu da je ovo rješenje slično opciji Ethereum adrese, ali bez potrebe za pohranjivanjem privatnih ključeva. Cijena prijenosa novca iz novčanika u hotwallet je približno jednaka cijeni pozivanja funkcije transfer(), budući da ne plaćamo implementaciju pametnog ugovora.
Konačna odluka
Originalno pripremio:
- funkcija dobivanja soli user_id
- pametni ugovor koji će pozvati CREATE2 opcode s odgovarajućom soli (tj. tvornica novčanika)
- bajt kod novčanika koji odgovara ugovoru sa sljedećim konstruktorom:
constructor () {
address hotWallet = 0x…;
address token = 0x…;
token.transfer (hotWallet, token.balanceOf (address (this)));
selfdestruct (address (0));
}
Za svakog novog korisnika prikazujemo njegovu/njenu adresu novčanika izračunavanjem
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
Kada korisnik prenese tokene na odgovarajuću adresu novčanika, naš backend vidi Transfer događaj s parametrom _to, jednako adresi novčanika. U ovom trenutku, već je moguće povećati saldo korisnika na berzi prije raspoređivanja novčanika.
Kada adresa novčanika akumulira dovoljan broj tokena, možemo ih sve odjednom prenijeti na hotwallet. Da bi to učinio, backend poziva funkciju tvornice pametnih ugovora, koja izvodi sljedeće radnje:
function deployWallet (соль uint256) {
bytes memory walletBytecode =…;
// invoke CREATE2 with wallet bytecode and salt
}
Tako se poziva konstruktor pametnog ugovora novčanika, koji prenosi sve svoje tokene na hotwallet adresu i zatim se samouništava.
Cijeli kod možete pronaći
Autor Pavel Kondratenkov, stručnjak za Ethereum
izvor: www.habr.com