Kaj so slabosti atomskih zamenjav in kako lahko kanali pomagajo, kaj pomembnega se je zgodilo s hardforkom Constantinople in kako ravnati, ko ni denarja za plin.
Glavna motivacija vsakega strokovnjaka za varnost je želja, da se izogne odgovornosti.
Usoda je bila milostna, zapustil sem ICO, preden je prišla prva nepovratna transakcija, a kmalu sem se znašel pri razvoju kripto borze.
Jaz sem se nedvoumno odločil, da ne bom malček Kibalčič, in že en strogi pogled zadostuje, da izdam vse ključe in gesla. Zato je bil moj glavni cilj kot arhitekta postaviti vroči žebelj kriptoanalize čim dlje od mi dragih elementov infrastrukture.
Niso tvoji ključi, niso tvoje težave.
Gradimo sistem za izmenjavo sredstev in želimo izključiti posredniško shranjevanje teh sredstev pri nas, vendar moramo zagotoviti varnost transakcije.
Lahko nastopimo kot sodnik v spornem primeru in izvedemo transakcije z denarnicami, ki zahtevajo dve od treh podpisov: kupca, prodajalca in eskro.
Vendar pa, če udeleženec uspešno napade eskro, pridobi želenih dveh podpisov.
Atomska zamenjava je shema menjave, kjer je jamstvo pametna pogodba, ki dovoljuje le pošteno ravnanje.
Kot v uganki o volku, kozi in zelje lahko deluješ le po eni sami pravilni poti in nosiš izgube, če se od nje odvrneš.
Samo namesto požrešnih živali red zagotavlja hash funkcija, pri kateri je iskanje trkov tako težko, da se sploh ne splača začeti.
Korak prvi: uganka.
Recimo, da enega lepega jutra želi Alisa prenesti Bobu bitcoin za pest 'kriptojanuarjev'.
- Ona postavi kakšno veliko skrivnost.
- Pridobi hash od njega.
- Prenese bitcoine na pametno pogodbo, od katere lahko Bob vzame denar, če predloži skrivnost (hash od nje mora biti enak tistemu, ki je naveden v pogodbi).
- Če se Bob ne pojavi po svoje bitcoine do večera, si jih lahko Alisa vzame nazaj.
Korak drugi: vaba.
V igro vstopi Bob in prenese 'kriptoevre' na svojo pogodbo, ki je napisana na tak način, da:
- Alisa lahko vzame 'kriptojane' z obelodanitvijo skrivne številke.
- Najprej po kosilu Bob, ob odsotnosti Alise lahko vrne depozit.
Korak tretji: uganka v vabi.
Alisa prihaja po svoj denar in vzame denar iz Bobovega pogodbe ter tako razkrije svojo skrivnost.
Zaključni korak: uganka je rešena
Transakcijo vidi Bob in z orlovim očesom iz nje izloči skrivnost, ki jo je Alisa predstavila pogodbi. To skrivnost uporablja, da si vzame svoje bitkoine.
Ko gre kaj narobe
Če se Alisa nenadoma izkaže za smrtno, Bob na kosilo vzame svoje juane.
Na svoj del, Alisa do večera vrne bitkoin, če se prevratni Bob odloči, da zadrži denar za boljše čase.
Če imate raje sliko pred besedilom, ima na Habrju za vas podrobnejše in slikovito .
Razlika med časovnimi izhodi je zasnovana tako, da nas zaščiti pred zlonamerno Aliso, ki vzame Bobove denarje v zadnjem trenutku, ko časovna omejitev poteče, medtem ko on z drhtečimi prsti vpisuje heks v transakcijo.
Udeleženci ne morejo izgubiti svojega denarja, najvišje, kar se lahko zgodi, je, da morajo počakati na vrnitev.
Podpora v blokčejnihTo je enostavna shema, ki od interakcijskih blokčejnov zahteva prav malo:
- Podpora pametnim pogodbam z vsaj enim razvejavanjem
- Oba blokčejna morata podpirati enake hash algoritme (ne pozabite preveriti dolžine skrivnosti)
- Časovne zaklepe.
Na prvi pogled bi že lahko rekli borzi 'zbogom, najina srečanja je bila napaka', a tu se zadeve še ne končajo.
Kljub vsem svojim prednostim rešitve na osnovi atomic swap ne presenečajo z likvidnostjo. V veliki meri zato, ker v najbolj priljubljeni par BTC-USD fiatni del še ni popolnoma tokeniziran.
Uspeh USDT je sprožil celotno valovno vrsto stabilnih kovancev v formatu ERC20 po želji, od najbolj zaščitnega USDC do najbolj algoritmičnega DAI.
Zato za enostavnost v nadaljevanju razmišljamo o tem, da Alisa prodaja Bobu bitkoine za nekatere ERC20 tokene in upamo na srečo stabilizatorjev, saj imamo še veliko bolj tehničnih težav.
Hitrost
Bitkoin in Ethereum po eni strani nista posebej hitra, zdaj pa moramo najprej čakati na en polog z vsemi potrditvami, nato pa na drugega.
Vse to je zato, ker najprej denar vplača udeleženec, ki pozna skrivnost, medtem ko nasprotnik čaka na dokončnost in šele nato prenese svoj del.
Poleg tega imamo opravka z izjemno volatilno sredstvo, tako da se medtem lahko tečaj precej spremeni, sprememba pogojev pa je že težavna.
Zasebnost
Vsaka izmenjava pušča artefakte na obeh blockchainih. Pozoren opazovalec lahko opazi identične hashe v pametnih pogodbah in se logično vpraša, da je prišlo do transakcije, iz česar lahko izpelje vrsto zaključkov, od tečajev do davčnih obveznosti.
Ko borza ve za tvoje posle, je to izjemno neprijetno, ko pa to ve vsak, je to dvakratno neprijetno.
Uporabnost
Posebnost blockchaina na splošno in Ethereuma posebej. Poglejmo, kakšne korake bo moral opraviti prodajalec in kupec.
Z vidika prodajalca je vse razmeroma preprosto: preprosto mora prenesti bitcoine na p2sh naslov. Z etrom pa je vse veliko bolj zapleteno.
PogodbaPoglejmo povprečno pogodbo za swap iz GitHub-a:
contract iERC20 {
function totalSupply() public view returns (uint256);
function transfer(address receiver, uint numTokens) public returns (bool);
function balanceOf(address tokenOwner) public view returns (uint);
function approve(address delegate, uint numTokens) public returns (bool);
function allowance(address owner, address delegate) public view returns (uint);
function transferFrom(address owner, address buyer, uint numTokens) public returns (bool);
}
contract Swapper {
struct Swap {
iERC20 token;
bytes32 hash;
uint amount;
uint refundTime;
bytes32 secret;
}
mapping (address => mapping(address => Swap)) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, uint refundTime) public {
require(swaps[msg.sender][receiver].amount == 0); // check is swap with given hash already exists
require(token.transferFrom(msg.sender, address(this), amount)); // transfer locked tokens to swap contract
swaps[msg.sender][receiver] = Swap(token, hash, amount, refundTime, 0x00); //create swap
}
function hashOf(bytes32 secret) public pure returns(bytes32) {
return sha256(abi.encodePacked(secret));
}
function withdraw(address owner, bytes32 secret) public {
Swap memory swap = swaps[owner][msg.sender];
require(swap.secret == bytes32(0));
require(swap.hash == sha256(abi.encodePacked(secret))); // swap exists
swaps[owner][msg.sender].secret = secret;
swap.token.transfer(msg.sender, swap.amount);
}
function refund(address receiver) public {
Swap memory swap = swaps[msg.sender][receiver];
require(now > swap.refundTime);
delete swaps[msg.sender][receiver];
swap.token.transfer(msg.sender, swap.amount);
}
}
Pozor! Ne uporabljajte te in drugih pogodb iz članka v produkciji, napisane so izključno za demonstracijo. Še posebej ta.
- Bob mora poklicati metodo pogodbe za tokene
approve, da pogodbi za swap omogoči dostop do svojih tokenov - Bob ustvari swap in pogodbo z metodo
transferFromin si prisvoji tokene pošiljatelja na svoj naslov - Alisa v
withdrawrazkriva skrivnost in pogodba pokličeprenos
Večina denarnic in kripto borz ne podpira approve žetonov in to ni brez razloga.
Uporabniki pogosto naredijo napake in enostavno prenesejo žetone na pogodbo, po čemer žetoni preprosto izginejo. Komentarji na Etherscan so polni obžalovanja nesrečnih.
Da bi poklicali pogodbo, je potrebno plačati provizijo v ETH, kar pomeni, da se morata oba udeleženca pred začetkom posla založiti, kar pa malo kdo želi početi.
Gazholder
Na začetku je treba odstraniti preverjanje pošiljatelja povsod, kjer je le mogoče, in predpostaviti, da imamo nekoga, ki trpi zaradi presežka plina in kliče pogodbe za vse, ki želijo.
Modernizirana pogodba
contract Swapper {
struct Swap {
iERC20 token;
address receiver;
uint amount;
address refundAddress;
uint refundTime;
}
mapping (bytes32 => Swap) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public {
require(swaps[hash].amount == 0); // use hash once
require(token.transferFrom(msg.sender, address(this), amount));
swaps[hash] = Swap(token, receiver, amount, refundAddress, refundTime);
}
function withdraw(bytes memory secret) public {
bytes32 hash = sha256(secret);
Swap memory swap = swaps[hash];
require(swap.amount > 0);
delete swaps[hash];
swap.token.transfer(swap.receiver, swap.amount);
}
function refund(bytes32 hash) public {
Swap memory swap = swaps[hash];
require(now > swap.refundTime);
delete swaps[hash];
swap.token.transfer(swap.refundAddress, swap.amount);
}
}
Pogodben ključni dualizem in EIP 712
Kot vemo, lahko je naslov v etru pogodba ali subjekt, s preprostimi besedami ključ.
Glavna naloga ključa je podpisovati različna sporočila.
Kot pošiljatelja lahko uporabimo Bobovo pogodbo, ki izvede vse potrebne korake, potem ko predhodno preveri podpis Bobovega ključa.
Zdaj lahko kdorkoli sponzorira provizijo udeleženca, a odločitev sprejema le tisti, ki pozna ključ.
Bobova pogodba
library EIP712ProxyLibrary {
function hashCommand(address sender, iERC20 token, Swapper swapper, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public view returns(bytes32);
}
contract ProxyBob {
address owner;
constructor(address _owner) public {
owner = _owner;
}
function createSwap(Swapper swapper, iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime, uint8 v, bytes32 r, bytes32 s) public {
require(owner == ecrecover(EIP712ProxyLibrary.hashCommand(address(this), token, swapper, hash, receiver, amount, refundAddress, refundTime), v, r, s));
token.approve(address(swapper), amount);
swapper.create(token, hash, receiver, amount, refundAddress, refundTime);
}
}
Za delo s podpisi zapletenih podatkovnih struktur v Ethereumu obstaja standard , več o tem lahko preberete v
Delite in vladajte
Tipičen scenarij hekerskega napada na Ethereum pogodbo izgleda tako:
- Udeleženec položi sredstva na pogodbo
- Nato vzame sredstva nazaj
- Nekaj gre narobe
- Napadalec vsakič spet vzame denar
Če se vrnemo k našemu prvemu primeru, nekaj gre narobe, če je uganka prazna množica bajtov.
Kako ukrasti milijonUstvarimo swap s hashom 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
To je sha256 od 0x0000000000000000000000000000000000000000000000000000000000000000
Predamo skrivnost in vzamemo svoje tokene
Predamo še enkrat in vzamemo tuje, vse zato, ker 0 = 0
Z ustvarjanjem ločenih pogodb za vsako transakcijo lahko izoliramo pogodbe na ravni EVM.
Toda to še ni vse: zdaj ima vsaka transakcija svoj naslov, kamor lahko pošljemo tokene iz katere koli denarnice ali borze.
Zapuščene pogodbe in create2
Toda zdaj za vsako transakcijo moramo ustvariti pogodbo in počakati, da kupcu prenese svoj trud ‘kriptodohodek’. V shemi ‘zjutraj pogodbe, zvečer denar’ obstaja vedno nevarnost, da se kupec odmakne, medtem ko je eter za ustvarjanje pogodbe že porabljen.
Ali res ne moremo narediti tako, da zjutraj denar, zvečer pa bajti?
V hardforku Constantinople so razvijalci dodali ukaz create2, ki ustvari novo pogodbo na determiniranem naslovu
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
Kjer
- address — naslov fabrike pogodbe
- salt — neka številka, katere pomen bomo izvedeli v naslednji epizodi
- init_code — bajt-koda pogodbe in parametri konstruktorja.
FabikaUkaz deluje le preko assembly, zato fabrika izgleda nekoliko grozeče:
contract Factory {
event Deployed(address addr, uint256 salt);
function create2(bytes memory code, uint256 salt) public {
address addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), salt)
}
emit Deployed(addr, salt);
}
}
Koda vaše pogodbe je dostopna s pomočjo web3:
const MyContract = new web3.eth.Contract(ABI, {})
const code = MyContract.deploy({
data: BYTECODE,
arguments: contructorArgs
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(code, salt);
Zaradi omejene podpore v solidity se lahko plin za pogodbo nepravilno izračuna zaradi nekaterih odtenkov etra.
Še posebej prijetno je, da v primeru pomanjkanja plina pogodba pade z notranjo napako, ne da bi sporočila, da plina ni dovolj, kot bi lahko pričakovali.
Sedaj lahko prevajamo žetone na pogodbe, ne da bi jih vnaprej ustvarili, in dokler jih ne objavimo v omrežju, nihče ne bo uganil, kaj pogodba počne.
Vran vranovu oči ne izkljuje.
Očitno tovrstne otroške zvijače ne bodo ustavile pravega analitika, zlasti tistega, ki je prejel dobre naložbe za boj proti režimu s pranjem denarja, in po ustvarjanju pogodbe bo vseeno videl hash.
Kako narediti, da hash ne zasveti?
Samo swap prenašamo v off-chain: udeleženci izmenjujejo podpise za prenos na swap-pogodbo, nato pa se skrivnost zasebno razkrije.
Korak za korakom.Ustvarijo se dva 'multisiga', s katerih je mogoče dvigniti sredstva ob prisotnosti podpisov Alice in Boba.
Da izhod iz omrežja katerikoli od udeležencev ne postane tragedija, dodamo staro dobro časovno omejitev.
Alice in Bob hkrati vplačujeta depozite.
- Alice si zamisli skrivnost in Bomu posreduje hash skrivnosti ter podpis transakcije, ki prenese bitcoine na naslov swap.
- Bob Alice pošlje podpis za dvig žetonov na pogodbi swap s zamišljenim hashom.
- Alice Bomu razkrije skrivnost.
V tem trenutku pride do harmonije: tako Alice kot Bob lahko kadar koli zaključita posel. V takšnem prijaznem okolju lahko izmenjata podpise za dvig denarja na končne naslove.
Za zunanjega opazovalca se zdi, da so denarja potekli skozi pogodbo z multipodpisom 2 od 2.
Ta shema prav tako omogoča obema stranema, da hkrati vplačujeta depozite, saj se skrivnost zmisli šele po vseh potrditvah.
Level 2.
Ker lahko dvigujemo denar na en naslov in ne objavljamo vmesne transakcije, nas nič ne ovira, da dvigujemo denar na več naslovov in izvajamo neomejeno število vmesnih transakcij. Ni nujno, da je to osnovni nabor za izmenjavo, vendar je težko prenehati, ko začneš zbirati swap.
Sedaj bosta Alice in Bob lahko polno stopila v akcijo. Na primer, samodejno izračunavati povprečno ceno, izmenjujoč po satoshijih na sekundo, ali preprosto neposredno povezati ustvarjalca trga in prejemnika likvidnosti.
Korak za korakom.
- Prodajalec si zamisli skrivnost in kupcu izroči hash skrivnosti ter podpis transakcije, kjer del sredstev preide na p2sh naslov swap, medtem ko se preostanek vrne na naslov prodajalca.
- Kupec prenese podpis, ki omogoča prenos žetonov in vračila na naslov prejemnika.
- Prodajalec razkrije skrivnost
- Zgodovina se ponavlja z novo skrivnostjo, pri čemer se k swapu in vračilu doda še prenos prej kupljenega na naslov kupca in že plačanega na naslov prodajalca.
Zdaj imamo dostop do visoko hitre p2p trgovine, pomembno je spremljati čas in skleniti transakcijo pred potekom časa.
Vendar pa lahko z nekoliko prilagoditve naših pogodb podarimo našim kanalom nesmrtnost, kar močno poenostavi ustvarjanje omrežja.
Toda o tem bomo govorili v naslednji epizodi.
Izvor: habr.com
