Blockchain unchained: Az üres blokkok rejtelme

Feldobtatok egy jó kérdést, amire úgy ugrottam mint gyöngytyúk a takonyra, hiszen ezen már korábban én is sokat agyaltam és ott állt a queue-ban a “megfejtendő rejtélyek között”:

“Az AntPool miért bányászik üres blokkokat a Bitcoin láncon? Néha besegít a BTCC is. Szándékos rombolás, hátráltatás?”

A kérdés igen komplex, ezért kezdjük egy kis blockchain alapokkal. A Proof of Work (PoW) alapú blockchain gyártás lényege az, hogy mindenki közel ugyanolyan számítási kapacitással rendelkezik, ezért mindenkinek közel azonos esélye van megtalálni egy blockot. Egy korábbi cikkben már részletesen leírtam, hogy technikailag miként is képződik egy block (leading zeros mistery) és mit is jelent kiszámolni annak a hash-ét, ha azt nem olvastad, akkor lehet érdemes azzal kezdeni. Ami viszont abból a cikkből nem derül ki:

  • Minden miner egyszerre ugyanazt a blockot bányássza, pontosabban ugyanazon sorszámú (height) blockot bányássza ami persze minden bányásznál mást és mást tartalmaz. A feladatuk az, hogy megtalálják azt a hasht aminek az értéke alacsonyabb a targetnél (lásd másik cikkben a nullával kezdődő hashképzés módszerét).
  • Aki először tudja ezt elérni a nonce és a coinbase text módosításával (és a timestamp frissítésével), na azé a block. Szépen körbekürtöli a peer-to-peer networkön és elindul a block validálása. A propagálás és validálást követően a nodeok ezt a blockot hozzáfűzik a blockchainhez, majd az utolsó valid block tx-eit törlik a mempoolból, összerakják az új block headerjét, amihez összevállogatják az új tx-eket a mempoolból, megcsinálják a merkle tree-t és már indulhat is az újabb block vadászat.

A esélye annak, hogy egy érték (nonce, extraNonce) módosításával egy olyan hash-t kapj, amire igaz, hogy annak értéke kisebb a targetnél = 1/(232*difficulty). Tehát egy pool minél több számítási (double sha256) kapacitással rendelkezik annál nagyobb esélye van arra, hogy bejön neki egy megfelelő hash. Ez az esély azonban nem statikus, ha az lenne, akkor minden blockot nagy valószínűséggel a legnagyobb hashing power birtokosa gyártana le. Tény, hogy az esélyed minden újabb hashing kísérlettel javul, de a szórás miatt simán előfordulhat, hogy valamelyik poolnál akár az első nonce érték inkrementálásnál is bemákolja a megfelelő hash-t. A bemákolás mértékegységes a “Luck”. A Luck/Szerencse egy átlag szám (pontosabban kumulatív eloszlás), ami az adott pool korábbi hashing kísérlet/sikeres hash-ek arányából jön össze. Ha az átlaghoz képest gyorsabban sikerül kihozni egy érvényes hash-t, akkor a luck% alacsony, ha viszont az értéke 100%, na azt hívják bad lucknak, mikor a karma egyenlít. Ez egyébként egyáltalán nem ritka. Persze vannak olyan pillanatok is, amikor aranyeső van, itt egy példa arra amikor idén augusztus 7-én a SlushPool nevű cseh bányásztásaság behúzott 8 blockot alig 9 óra alatt:

Mindezt egyébként alig 200Ph/s sebességgel érték el, amikor nem kis teljesítmény volt, dehát ilyen ez a luck.

A PoW módszer mögött a játékelmélet alapját adó “Nash Equilibrium”, az az a Nash egyensúly módszere áll. Ennek ugye lényege, hogy amennyiben mindenki ugyanazon játékot játsza ugyanazon stratégia szerint, addig senkinek nem származhat abból előnye, ha a stragégián változtat, amíg mindenki más marad az eredeti stratégiánál. Jelen esetben a játékosok a minerek, a stratégia pedig a hash képzési módszer, nevezetesen a nonce növelés és túlcsordulás esetén az extraNonce/coinbase text módosítás.

A játékelmélet azonban kimond még egy nagyon fontos tézist, nevezetesen (wikipedia): “Észszerű feltételezni, hogy minden játékos a lehető legnagyobb nyereség elérésére, és a veszteség kockázatának minimalizálására törekszik.És itt meg is érkeztünk az üres blockkok rejtelméhez. Hogyan tud valaki üres blockokkal nyereséget növelni és kockázatokat csökkenteni?

Ha sikerül egy minernek elkészíteni egy blockot (értsd kiszámítja azt a hash-t, ami a target alatt van), akkor elkezdődik annak a propagálása és validálása. A block akkor tekinthető validnak, ha adott mennyiségű node elfogadja azt, pl.: senki sem nyújtja a kezét, hogy itt bizony van egy double spending vagy invalid transaction. Ez viszont idő, erőforrás és legfőképpen sávszélesség igényes feladat. Ráadásul a block mérete különösen fontos faktor ebben. Egy Christian Decker és Roger Wattenhofer nevéhez fűződő kutatási anyag (Information Propagation in the Bitcoin Network ) szerint átlagosan 12.6 másodperc alatt történik meg a propagálás, de ha a blockok 95 percentilisét nézzük akkor ez inkább 40 másodperc körül van. Van persze erről napi bontás is, akit részleteiben érdekel: http://bitcoinstats.com/network/propagation/

Ebből látható, hogy az utóbbi időben javult némileg az érték. Az átlag valahol 2 másodperc körül van, a 90 percentilis pedig 7-8 másodperc. Ez ugye azt jelenti, hogy 100 blokkonként van legalább 10 olyan block, aminek a propagálási ideje akár 10 vagy annál is több másodpercig is tarthat.

10 másodperc baromi hosszú idő arra, hogy addig álljanak az új block gyártás. Márpedig az új block gyártáshoz tudni kellene, hogy az előző block valid-e és annak minden trazakciója is rendben van-e. Ezért a legtöbb miner pool egy ügyes kis trükkel él:

  • Ahogy egy miner pool jelzi, hogy megtalált egy blockot a többi elcsípi a block headert, melyből legenerálnak egy teljes üres blockot, ami csak a még propagálás alatt álló block hashét és persze a saját rewardjukat a coinbase tx-et tartalmazza, majd addig is amíg megy az aktuális block propagálása már el is kezdik kiszámolni ennek az üres blocknak a hashét.
  • Közben folyik a propagálás és a validálás, ami mondjuk átlag 1-2mp alatt lezajlik és a pool eldobja ezt az üres blockot, hiszen itt még nem fektetett bele sok energiát a hashingelésbe és amúgy is csak a coinbase rewardot tartalmazza.
  • Viszont mi van akkor, ha a propagálás eltartott 40 másodpercig és további 1-2 másodperc kéne még hogy összerakja az új blockot és elkezdje előlről a hashinget? Ekkora a bányásznak mérlegelnie kell az esélyeit és azt, hogy megéri-e eldobni az eddigi munkáját, hiszen abba már tetemes erőforrást és pénzt ölt bele. Egy Antpool számára (aki kb 1,2Eh/s teljesítményt bitokol) ennek a 40 másodpercnyi üresjáratra elköltött teljesítménye majd 55x nagyobb mint amennyi a teljes bitcoin network hashing powere másodpercenként. Ezért egy megfelelően felparaméterezett algoritmus ilyenkor úgy dönthet, hogy “szarok a farmra” és én bizony ezt az üres blockot hashingelem tovább, hiszen az average luck alapján hamarabb tudja ezt befejezni és igaz, hogy így csak a coinbase rewardot kapja meg, de még így is jobban jár, mintha kidobta volna az ablakon ezt a teljesítményt.
  • Még az előző pontnál is triviálisabb az az eshetőség, amikor nemes egyszerűséggel bemákolják a propagálási idő alatt a következő (üres) block hashét, így egyrészt csak meg kell várniuk az aktuális block propagálását, másrészt (és ez a durva…), ők már rendelkeznek a következő block hashével is, így el tudják kezdeni annak a számítását is lényegesen hamarabb mint, hogy bárki más megtudná azt. Ezen utóbbi megállapításnak az eredménye, hogy ritkán de előfordul olyan amikor az Antpool sorban nem csak 1, de egyből kettő üres blockot is kikapar.

Jó kérdés, hogy ez a árt-e a hálózatnak, azért van-e sok tx a mempoolban mert a greedy AntPool üres blockokat bányászik?

A fenti két opció közül a második esetben (tehát amikor hamarabb kiszámolja az üres block hash-t minthogy befejeződne az előző propagálása) valójában ezzel nem sokat árt, hiszen kicsi az új block és az átlag néhány másodpercen belül terül is, ráadásul a block headerrel mindenki el is tudja kezdeni számolni az új blockot. Az első esetben azonban a miner pool gamblingel, vagyis előveszi a játékelmélet fent nevezett passzusát: “legnagyobb nyereség elérésére, és a veszteség kockázatának minimalizálására törekszik“. Ez az elmélet káros a hálózatra, hiszen nem csak a gamblingelő pool éget el rengeteg erőforrást egy üres block tovább számolására, hanem az összes többi miner is, aki mindeközben egyébként egy valid és tranzakciókkal telepakolt blockot probált kiszámolni. Persze az esetek nagy többségében a gamblingelő pool bebukja a kísérletet, nem lehet mindig szerencséje.

A baj az, hogy az utóbbi időben az AntPool nagyon sok olyan empty blockot gyárt, ami akár 10-20 perccel később csattan csak be minthogy befejeződne az előző block propagálása, ez pedig elég beteg módon arra utal, hogy a gyors pénzre hajtanak és amikor csak lehet nem dobnak el már elvégzett munkát.

Gazdaságilag miért jó ez nekik? itt szintén az egyensúly elmélet jön be a képbe: Egy tranzakciókkal teletömött block aktuális értéke a tx fee-vel és a coinbase rewarddal együtt akár 75 ezer dollárnak megfelelő bitcoin is lehet, ezzel szemben egy totálisan üres block is megér 45 ezer dollárt. Azonban – és itt jön egy kis csavar -: valójában valamelyest könnyebb kiszámolni egy üres (csak coinbaset) tartalmazó block hashét. Ez annyit jelent, hogy amikor végig pörgött egy nonce (ez ugye összesen 32 bit, unit32_t: kb 4 milliárd kísérlet), akkor újra kell számolni a teljes merkle tree-t a coinbase text módosítás miatt. A merkle tree-ben a fa bal és jobb ágain vannak felépítve a tranzakciók, melyeket össze kell hashelni minden párjával és azokat hashelni az ág fentebbi tagjára. Tehát ha a merkle tree-ben nagyon sok trazakció van, akkor ez minden egyes nonce végig pörgésnél elvisz néhány extra 10 ezer hash képzést, ami persze nem sok, de összességében a jelenlegi difficulty szinten már kimutatható overheadet jelentenek. Ezért az ‘hogyan-tovább-alrogitmus‘ ezt is figyelembe veszi, amikor mérlegeli, hogy mi éri meg jobban: előlről kezdeni nulláról a teletömött blockot, vagy folytatni az üres blockot, amin sokkal könnyebb kiszámolni az extraNonce-t. (Arról nem is beszélve, hogy az egy szem coinbase trazakció merkle tree-jét nagy valószínűséggel már ki sem kell számolni, mivel a mai informatikai eszközökön egy ilyen jellegű információ összes permutációját akár lehet tárolni egy in-memory db-ben. –> Lásd Covert ASICBOOST megoldás, ahol szintén inmemoryban tárolják az inner-hash összes variációját és manipulálják a merkletree-t)

[commercial_break]

Szóval lehet utálni az Antpoolt és a Bitmaint (rá is szolgálnak rendesen a gusztustalan üzletpolitikájuk miatt), de az üres trazakciók esetén egy teljesen racionális gazdasági döntést hoznak meg, amivel javarészt nem is ártanak túlságosan a bitcoin ökoszisztémának, hiszen olyan blockot propagálnak amit már hamarabb kiszámoltak minthogy az előző propagálása befejeződött volna. Ezzel persze ‘érdemtelenül’ (?) jutnak a block rewardhoz, de tény, hogy ezért a blockért is megoldolgoztak a hashing powerükkel, márpedig a bitcoin konszenzus motorják a Proof of Work adja, amit végülis elvégeztek.

Ezer más dologért lehet utálni az Antpool, de az “empty blockokért” (legalábbis amiket 1 percen belül propagálnak) nem indokolt, e mögött racionális érv és egy olyan kiskapu áll, amit az az ember (Nakamoto) hagyott benne a protokollban, aki egyébként lerakott egy olyan technológiai modellt, ami lassan 10 éve stabil és képes fejlődni. Persze a leányzó fekvése más az olyan esetekben, amikor 20 percnél tovább is kalkulálják az egyébként üres blockot. Itt nehéz nem élni azzal a feltételezéssel, hogy a Greg Maxwell által leírt ASICBOOST explanationben foglaltaknak megfelelően a mining pool, nem éppen covert asicboostot használ, amihez a kihasználja az üres merkletree-t aminek egyetlen ága a bal oldalon elhelyezkedő coinbase transaction, így garantálható a covert asicboost előfeltétele. De ez inkább csak az elvi lehetőséget támasztja alá, nyílt bizonyíték erre nincs és a Bitmain/Antpool tagadja, hogy valaha is használt volna asicboostot mainneten. Szemernyi kétségem sincs afelől, hogy egy olyan felelősségteljes ügyvezető csak igazat mondhat, aki ilyen szinten nyílvánul meg a saját követői előtt:

Nyilvánvalóan azon pooloknál a legnagyobb az esélye az empty blocknak, akik a legnagyobb számítási kapacitással rendelkeznek (és esetleg használják a covert asicboostot…), hiszen a nash equilibrium esetükben garantál nagyobb esélyt, hogy a propagálási idő alatt ki tudjanak számolni egy új block hash-t, de mint azt fentebb leírtam ez az esély közel sem lineáris. Éppen ezért van az, hogy néha még az UASF-No2X, Anti-NYA és úgy egyébként az egyész Bitcoin Core Dev teamet istenítő SlushPool is be-be dob a blockláncba egy üres blockot. Money talks… 40 ezer dollárt ők sem szívesen dobnának ki az ablakon csak azért,hogy ezzel 5-10 másodperccel meggyorsítsák a következő teletömött block generálását.

Ennyit a nagy rejtelemtől. Ma is tanultam valamit…

Bookmark the permalink.

12 Comments

  1. Köszönöm. Még többször át kell futnom, hogy megértsem. 🙂

    Annak mi lehet az oka – szintén Antpool – hogy míg a Segwit óta ez pl. egy tipikus “Weight”: 3,992.63, addig az Antpool többször is ennél lényegesen kisebb értékeket bányászott?

  2. az asicboot egyik merkleroot collision kereso megvalositasa (tx sorrend permutacio) nem kompatibilis a segwit-tel, igy kenytelen a masikat hasznalni, es uj coinbase tx-et csinalni, ekkor viszont megsporolja a merkleroot szamitast, ha ures a block akkor coinbase hash == merkelroot. csak igy rosszabb az asicboost “teljesitmenye”

    ugyanakkor a bcc lancon tudja hasznalni a tx permutaciot, igy ott nemkell neki ures blokkokat csinalnia.

    • Köszi! Igen, ez most a legnagyobb probléma. Most éppen a harmadik “csiki-csuki” felépítése van folyamatban a BHC láncon a EDA-val. Kíváncsi leszek, hogy meddig viszik le a difficulty-t. Meglátásom szerint a BCH lánc akár még 10%-os veszteség mellett is profitábilisebb lehet az ASICBOOST miatt, persze ehhez az kellene, hogy az összes érintett pool és azok relatív összes minere használja az asicboostot, ez viszont szerintem egyelőre nem adott. Kiváncsi lesz-ek, hogy valaha eljátszák-e BCH láncon a következő scenariot:
      – behúzzák úgy a diff-et, hogy a DARI szerint a BTC lánc cca 5%-kkal profitábilisebb maradjon. Így a privát minerek tovább bányásszák a főláncot, míg az ASICBOOST-ot használók tolják a BCH-t. Ehhez persze kellene az is, hogy a BTC lánc diffjét is leimádkozzák 5-10%-kkal, akkor lehetne csak az ASICBOOST farmokkal hatékonyan termelni a blockokat DARI parity esetén.

      Lesznek itt még érdekes kanyarok 🙂

  3. Alapos cikk, bravó! Érdemes lenne számszerűsíteni a bányász jutalom coinbase (6.25BTC/blokk) illetve fee arányát. Régen ez nagyjából 99-1% volt, de ma már jóval jelentősebb a feek aránya. 10-20-30%? Van erról grafikonod valahol? Mert ez jelentősen befolyásolja az üres blokk ‘árát’.

    • Konkrétan most chartot nem találok, holott az évek során sok ilyen elémkerült. A blockchair-en megnéztem az elmúlt 100 blokkot, ott átlagosan 0,6 és 1,2 BTC között volt a blokkonkénti fee mennyisége, szóval a 20% az megközelítőleg jó arányszám.

  4. És ha már itt tartunk, még pár kérdés:
    Amikor bejön egy új tx, amit úgy dönt a miner pool, hogy bevesz, akkor újraindítja a nonce pörgetést? (átlagban 2-3 tx van mp-ként)

    • Ez egy végtelenül rossz döntés lenne, hiszen ezzel resetelné az addigi teljes progresszt és kidobná az összes PoW-ot. Amikor egy mining pool úgy dönt, hogy akkor most ő csinál egy új blokkot, akkor ennek első lépéseként templateből legenerálja a blokkot, feltölti azt tranzakciókkal, berakja a coinbasetext-et, majd végig pörgeti a block headerben lévő nonceokat. Ha egyik sem volt jó, akkor módosít egy kicsit a coinbasetexen, újraszámolja a teljes markle fát és újra végig pörgeti a teljes nonce készletet és így halad tovább amig nem talál egy megfelelő block head hash-t, ami az adott difficulty szintnek megfelel.

  5. A mining pool koordinátor hogy egyezteti a pool tagok keresését? Mindenki kap egy tartományt, amiben keresi a nonce-t?

    • Igen. A mining pool munkamenetekre bontja a számítást és csak a blockheadert illetve a nonce ranget adja ki a konkrét workernek/minernek. Ez a Stratum(v1) protokoll, ami főleg az oka annak, hogy könnyedén lehet pl a nicehash-t 51%-os attackokra használni, hiszen a miner/worker konkrétan azt se tudja, hogy milyen blokkot számol, ő csak a header-t (80byte) kapja meg

  6. Annak van jelentősége, hogy a nonce-t sorban vagy összevissza próbálja az ember? (uccsó, leállok)

    • A block headerön belül semmi jelentőssége nincs annak, hogy a nonce-t hogyan pörgeted. A nonce 32 bites tároló és igazából csak abban segít, hogy a PoW-nál ne kelljen minden egyes iterációnál újra számolni a teljes Merkle fát, hanem csak 2^31 iteráció után. Semmilyen bizonyítást nem ismerek, ami alapján érdemes lenne ezt bármilyen más módon használni mint inkrementálással. Mivel a végeszközök, amik a konkrét SHA256-ot számolják ASIC-ek chipek, amik esetén lényegében a teljes számítás proci szinten van megvalósítva, így logikusan a leggyorsabb az ha növekvőben járod be a nonce-t nullától, hiszen olyankor a végrehajtási sorban a következő nonce meghatározása csak egy regiszter inkrementálás, ami nyilván a legolcsóbb és leggyorsabb művelet.

Leave a Reply

Your email address will not be published. Required fields are marked *