Hvorfor atombytter er dårlige, og hvordan kanaler kan hjælpe dem, hvilke vigtige ting skete der i Konstantinopels hårde fork, og hvad man skal gøre, når man ikke har noget at betale for gas.
Hovedmotivationen for enhver sikkerhedsprofessionel er ønsket om at undgå ansvar.
Providence var venlig, jeg forlod ICO'en før den første uigenkaldelige transaktion, men fandt mig snart selv i at udvikle en kryptobørs.
Jeg er bestemt ikke Malchish Kibalchish, og ét strengt blik er nok til at få mig til at udlevere alle nøgler og adgangskoder. Derfor var mit hovedmål som arkitekt at placere kryptanalysens glødende brod så langt som muligt fra de infrastrukturelementer, der ligger mig nær.
Ikke dine nøgler, ikke dine problemer
Vi er ved at opbygge et system til udveksling af aktiver og ønsker at eliminere den mellemliggende opbevaring af disse aktiver, men vi skal sikre transaktionens sikkerhed.
Du kan fungere som dommer i en omstridt situation og udføre transaktioner med tegnebøger, der kræver to af de tre underskrifter: køber, sælger og escrow.
Hvis deltageren imidlertid angriber escrow-kontoen med succes, modtager vedkommende de ønskede to underskrifter.
En atomswap er en udvekslingsordning, hvor garanten er en smart kontrakt, der kun tillader ærlig adfærd.
Ligesom i gåden om ulven, geden og kålen, kan man kun handle efter ét korrekt scenarie og lide tab, hvis man afviger fra det.
Kun i stedet for glubske dyr, sørger en hashfunktion for orden, hvor det er så svært at finde en kollision, at det ikke engang er værd at starte.
Trin et: gåde
Lad os sige, at Alice en smuk morgen vil overføre nogle Bitcoin til Bob for en håndfuld "kryptoyuan".
- Hun laver en stor hemmelighed.
- Får en hash af ham
- Overfører bitcoins til en smart kontrakt, hvorfra Bob kan hæve penge ved at præsentere en hemmelighed (hashen fra den skal være lig med den, der er angivet i kontrakten)
- Hvis Bob ikke dukker op for at hente sine bitcoins inden aftenen, kan Alice tage dem tilbage.
Trin to: lokkemad
Bob går ind i spillet og overfører "krypto-euroen" til sin kontrakt, som er skrevet på en sådan måde, at:
- Alice kan gøre krav på sine "kryptomønter" ved at præsentere et hemmeligt nummer
- Tidligst til frokost kan Bob returnere depositummet, hvis Alice ikke dukker op.
Trin tre: Ledetråden ligger i maddingen
Alice kommer for at få sine penge og tager pengene fra Bobs kontrakt og afslører sin hemmelighed i processen.
Det sidste trin: mysteriet er løst
Bob ser transaktionen og uddrager med et skarpt blik hemmeligheden, som Alice præsenterede for kontrakten, fra den. Han bruger denne hemmelighed til at stjæle sine bitcoins.
Når tingene går galt
Hvis Alice pludselig viser sig at være dødelig, får Bob sin yuan til frokost.
Til gengæld returnerer Alice bitcoinen om aftenen, hvis den forræderiske Bob beslutter sig for at beholde pengene indtil bedre tider.
Hvis du foretrækker billeder frem for tekst, har Habr et mere detaljeret og visuelt eksemplar til dig. .
Forskellen mellem timeouts er ment som en beskyttelse mod en ondsindet Alice, der tager Bobs penge i allersidste øjeblik, og timeout'en udløber, mens han skriver hex i transaktionen med rystende fingre.
Deltagerne kan ikke miste deres penge, de bliver højst nødt til at vente på en refusion.
Blockchain-understøttelseDet er en simpel ordning, der kræver meget lidt af de interagerende blockchains:
- Understøttelse af smarte kontrakter med mindst én filial
- Begge blockchains skal understøtte de samme hashing-algoritmer (husk at tjekke den hemmelige længde)
- Tidslåse.
Ved første øjekast kunne man allerede sige til udvekslingen "farvel, vores møde var en fejltagelse", men det var det ikke.
Trods alle deres fordele imponerer atomswap-løsninger ikke med likviditet. Primært fordi fiat-delen i det mest populære par BTC-USD ikke var fuldt tokeniseret.
USDT's succes har skabt en bølge af ERC20 stablecoins for enhver smag, fra den depotbaserede USDC til den algoritmiske DAI.
Så for enkelhedens skyld fortsætter vi med at argumentere for, at Alice sælger Bob-bitcoins for nogle ERC20-tokens, og håber på stabilisatorernes succes, heldigvis har vi stadig mange flere tekniske problemer.
hastighed
Bitcoin og Ethereum er ikke særlig hurtige hver for sig, og her skal vi først vente på én indbetaling med alle bekræftelserne, derefter den anden.
Alt dette skyldes, at først bidrager deltageren, der kender hemmeligheden, med penge, og modstanderen venter til finalen og først derefter overfører sin andel.
Derudover har vi at gøre med et meget volatilt aktiv, så i løbet af denne tid kan kursen ændre sig ret markant, og det er ikke længere nemt at ændre betingelserne.
Privacy Policy
Enhver udveksling efterlader artefakter på begge blockchains. En opmærksom observatør kan bemærke identiske hashes i smarte kontrakter og drage en logisk konklusion om, at der er indgået en aftale her, hvorfra der kan drages en masse konklusioner fra valutakurser til skatter.
Når børsen kender til dine anliggender, er det ekstremt ubehageligt; når alle kender til det, er det dobbelt ubehageligt.
Usability
Blockchainens styrke generelt og etherens i særdeleshed. Lad os se, hvilke træk sælger og køber bliver nødt til at foretage.
Fra sælgers synspunkt er alt relativt simpelt: du skal bare overføre bitcoin til en p2sh-adresse. Med ether er alt meget mere kompliceret.
kontraktLad os se på den gennemsnitlige kontrakt for swap på GitHub:
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);
}
}
Advarsel! Brug ikke denne eller andre kontrakter fra artiklen i produktionen, de er kun skrevet til demonstrationsformål. Især denne her.
- Bob skal kalde token-kontraktens metode
approve, hvilket giver swap-kontrakten adgang til dens tokens - Bob opretter en swap og en kontrakt ved hjælp af metoden
transferFromtager afsenderens tokens til dens adresse - Alice i
withdrawafslører hemmeligheden, og kontrakten indkaldestransfer
De fleste tegnebøger og kryptobørser understøtter ikke approve tokens, og med god grund.
Brugerne selv laver ofte fejl og overfører blot tokens til en kontrakt, hvorefter tokensene simpelthen går tabt. Kommentarer til Etherscan er fulde af klager over de uheldige.
Og for at indgå en kontrakt skal du betale en provision i ETH, hvilket betyder, at begge deltagere skal fylde op på den, før transaktionen starter, og det er få, der ønsker at gøre.
Gasholder
Det første skridt er at fjerne afsenderkontrol, hvor det er muligt, og antage, at vi har nogen, der lider af for meget benzin og ringer til alle.
Moderniseret kontrakt
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);
}
}
Kontraktnøgledualisme og EIP 712
Som vi ved, kan en adresse i luften være en kontrakt, eller den kan være et subjekt, det vil sige en nøgle.
Hovedformålet med nøglen er at underskrive beskeder.
Vi kan bruge Bob-contract som afsender, som foretager alle de nødvendige gennemløb, efter at have verificeret Bob-keys underskrift, inden vi gør det.
Nu kan alle sponsorere en deltagers provision, men kun den, der kender nøglen, træffer beslutningen.
Bob-kontrakt
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);
}
}
Der er en standard for at arbejde med signaturer af komplekse datastrukturer i Ethereum. , kan du læse mere om det i
Del og erobre
Scenariet for hacking af en Ethereum-kontrakt ser ofte sådan ud:
- Deltageren indbetaler penge i kontrakten
- Så tager han pengene
- Noget går galt
- Svindleren tager pengene igen og igen
Hvis vi går tilbage til vores første eksempel, går noget galt, hvis mysteriet er et tomt sæt bytes.
Hvordan man stjæler en millionOpret en swap med en hash 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Dette er sha256 fra 0x0000000000000000000000000000000000000000000000000000000000000000
Vi videregiver hemmeligheden og tager vores poletter
Vi sender den igen og tager en andens fra os, alt sammen fordi 0 = 0
Ved at oprette en separat kontrakt for hver handel kan vi isolere kontrakter på EVM-niveau.
Men det er ikke alt: nu har hver transaktion sin egen adresse, som du kan overføre tokens til fra enhver tegnebog eller børs.
Opgivne kontrakter og create2
Men nu skal vi for hver transaktion oprette en kontrakt og vente på, at køberen overfører arbejdskraften "kryptofenig" dertil. I ordningen "kontrakter om morgenen, penge om aftenen" er der altid en risiko for, at køberen frafalder, og pengene til at oprette kontrakten er allerede brugt.
Er det muligt at gøre det sådan, at der er penge om morgenen og bytes om aftenen?
I Konstantinopels hard fork, udviklere tilføjede create2-instruktion, som opretter en ny kontrakt på en deterministisk adresse
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
hvor
- adresse — fabrikskontraktadresse
- salt - et tal, hvis betydning vi lærer i næste episode
- init_code — kontraktens bytekode og konstruktørparametre.
FabrikenInstruktionen fungerer kun via samling, så fabrikken ser lidt skræmmende ud:
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);
}
}
Din kontraktkode kan fås ved hjælp af web3:
const MyContract = new web3.eth.Contract(ABI, {})
const сode = MyContract.deploy({
data: BYTECODE,
arguments: contructorArgs
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(сode, salt);
På grund af begrænset soliditet kan gassen til kontrakten muligvis ikke beregnes korrekt på grund af nogle finesser ved Ethereum.
Det er især dejligt, at kontrakten i tilfælde af gasmangel mislykkes med en intern fejl, uden at der rapporteres, at der ikke var nok gas, som man kunne forvente.
Nu kan vi overføre tokens til kontrakter uden at oprette dem på forhånd, og indtil vi offentliggør dem på netværket, vil ingen gætte præcis, hvad kontrakten gør.
En krage vil ikke hakke et andet krageøje ud
Det er tydeligt, at en rigtig analytiker, især en der har fået gode investeringer i kampen mod regimets fjender gennem hvidvaskning af penge, ikke vil lade sig stoppe af sådanne barnlige tricks, og efter at have indgået kontrakten vil han stadig se hashen.
Hvordan sikrer man sig, at hashen ikke bliver eksponeret?
Vi flytter selve swappen off-chain: deltagerne udveksler underskrifter for at overføre til swap-kontrakten, og derefter afsløres hemmeligheden privat.
Trin for trinDer oprettes to "multi-signaturer", hvorfra penge kan hæves, hvis Alice og Bob har deres underskrifter.
For at forhindre, at en af deltagerne går offline, bliver en tragedie, lad os tilføje en god gammeldags timeout.
Alice og Bob foretager indbetalinger parallelt
- Alice laver en hemmelighed og giver Bob hemmelighedens hash og underskriften på den transaktion, der overfører bitcoins til swap-adressen.
- Bob giver Alice en underskrift for at hæve tokens til swap-kontrakten med den givne hash.
- Alice fortæller Bob en hemmelighed.
På dette tidspunkt indtræffer harmonien: Alice og Bob kan begge afslutte transaktionen når som helst. I et så venligt miljø kan de udveksle underskrifter for at hæve penge til deres endelige adresser.
For en udefrakommende iagttager ser det ud til, at pengene gik gennem en 2-ud af 2-kontrakt med flere underskrifter.
Denne ordning giver også begge parter mulighed for at foretage en indbetaling på samme tid, da hemmeligheden afsløres efter alle bekræftelser.
Niveau 2
Da vi kan hæve penge til én adresse og ikke offentliggøre en mellemliggende transaktion, er der intet, der forhindrer os i at hæve penge til flere adresser og foretage et ubegrænset antal mellemliggende transaktioner. Ikke at dette er et nødvendigt sæt for udveksling, men når man først begynder at indsamle swap, er det svært at stoppe.
Nu kan Alice og Bob gøre deres bedste. For eksempel automatisk beregne gennemsnitsprisen, udveksle satoshi pr. sekund, eller blot forbinde market makeren direkte med likviditetsmodtageren.
Trin for trin
- Sælgeren laver en hemmelighed og giver køberen en hash af hemmeligheden og en underskrift på transaktionen, hvor en del af pengene overføres til p2sh-swapadressen, og resten returneres til sælgers adresse.
- Køberen giver en underskrift, der tillader, at tokens og byttepenge kan hæves til modtagerens adresse med henblik på bytte.
- Sælgeren afslører hemmeligheden
- Historien gentager sig med en ny hemmelighed, mens der udover byttet og byttet også sker udbetaling af det tidligere købte til købers adresse og det allerede betalte til sælgers adresse.
Nu har vi adgang til højhastigheds p2p-handel, det vigtigste er at holde styr på tiden og lukke handlen inden timeout.
Men med lidt justering af vores kontrakter kan vi give vores kanaler udødelighed, hvilket vil gøre det meget nemmere for os at opbygge et netværk.
Men det vil vi tale om i næste episode.
Kilde: www.habr.com
