Ana içeriğe geç

Sarı Kağıdın Ethereum Sanal Makinesi Spesifikasyonlarını Anlama

EVM
Orta düzey
qbzzt
15 Mayıs 2022
15 dakikalık okuma minute read

Sarı Kağıt(opens in a new tab), Ethereum'un resmi spesifikasyonudur. EIP süreci tarafından düzenlenen yerler dışında, her şeyin nasıl çalıştığına dair net bir açıklama içerir. Programcıların anlaşılır bulmayabileceği terimler içeren matematiksel bir kağıt olarak yazılmıştır. Bu kağıtta, spesifikasyonu ve dolayısıyla bağlantılı diğer matematiksel kağıtları nasıl okuyacağınızı öğreneceksiniz.

Hangi Sarı Kağıt?

Ethereum'daki her şey gibi, Sarı Kağıt da zamanla evrimleşiyor. Spesifik bir versiyona atıfta bulunabilmek için yazımı devam eden versiyonu yükledim. Kullanacağım bölüm, sayfa ve denklem numaraları o versiyona ait olacaktır. Bu dokümanı okurken farklı bir pencerede Sarı Kağıdı açık tutmak iyi bir fikir olabilir.

Neden Ethereum Sanal Makinesi?

Orijinal sarı kağıt, Ethereum'un geliştirme sürecinin başında yazılmıştı. Başlangıçta ağı korumak için kullanılan mutabakat mekanizmasını temel alan orijinal iş ispatını açıklamaktadır. Bununla birlikte, Ethereum Eylül 2022'de iş ispatını bırakıp hisse ispatı tabanlı istemciyi kullanmaya başladı. Bu öğretici, sarı kağıdın Ethereum Sanal Makinesi'ni tanıttığı bölümlere değinecektir. EVM, (DIFFICULTY işlem kodunun dönüş değeri dışında) hisse ispatına geçiş nedeniyle değiştirilmemiştir.

9 Yürütüm modeli

Bu bölüm (sayfa 12-14) daha çok EVM'nin tanıtımını içeriyor.

Sistem durumu terimi, sistemi çalıştırmak için bilmeniz gereken her şeyi içerir. Bu, tipik bir bilgisayarda bellek, kayıt içerikleri vs. anlamlarına gelir.

Turing makinesi(opens in a new tab), bir hesaplama modelidir. Aslında bir bilgisayarın basitleştirilmiş bir halidir ve normal bir bilgisayarın hesaplamaları yapma kabiliyetine sahip olduğu kanıtlanmıştır (bir bilgisayarın hesaplayabileceği her şeyi bir Turing makinesi de hesaplayabilir). Bu model neyin hesaplanabilir olduğuna ve olmadığına dair değişik teorileri kanıtlamayı kolaylaştırır.

Turing-tamam(opens in a new tab) terimi, bir bilgisayarın hesapları bir Turing makinesi gibi çalıştırabileceği anlamına gelir. Turing makineleri sonsuz döngülere girebilir ancak EVM giremez; çünkü gazı biter, yani EVM sadece yarı-Turing-tamam niteliğindedir.

9.1 Temeller

Bu bölüm EVM'nin temellerini ve diğer hesaplama modelleri ile nasıl benzerlik ve farklılıklarını gösterir.

Bir yığın makinesi(opens in a new tab), ara verileri kayıtlarda değil, yığın(opens in a new tab)da depolayan bir bilgisayardır. Bu, hata ve güvenlik açıklarının bulunma olasılığının az olması sayesinde uygulanması kolay olduğundan sanal makineler için tercih edilen mimaridir. Yığındaki bellek 256 bitlik kelimelere bölünür. Bunun seçilme sebebi, Keccak-256 karmalaması ve eliptik eğri hesaplamaları gibi Ethereum'un temel kriptografik operasyonları için uygun olmasıdır. Yığının sahip olabileceği maksimum boyut 1024 bayttır. İşlem kodları yürütüldüklerinde parametrelerini genelde yığından alırlar. Yığındaki elementleri yeniden düzenlemeye yarayan POP (yığının başındaki öğeyi siler), DUP_N (yığındaki n'inci öğeyi kopyalar) gibi işlem kodları vardır.

EVM'nin ayrıca çalıştırma sürecinde veri depolama amacıyla kullanılan bellek adında geçici bir alanı vardır. Bu bellek, 32 baytlık kelimeler halinde düzenlenmiştir. Her bellek konumu sıfırdan başlatılır. Yul(opens in a new tab) kodunu belleğe bir kelime eklemek için çalıştırırsanız, 32 baytlık bir belleği kelimedeki sıfırlı boş alan ile dolduracaktır, yani 0-29, 0x60'tan 30'a ve 0xA7'den 31'e konumlarındaki sıfırlarla yeni bir kelime oluşturur.

1mstore(0, 0x60A7)

mstore, EVM'nin bellekle etkileşime girebilmek için sağladığı üç işlem kodundan biridir; belleğe bir kelime yükler. Diğer ikisi ise belleğe tek bir bayt yükleyen mstore8 ile bellekteki bir kelimeyi yığına taşıyan mload'dur.

EVM ayrıca sistem durumunun bir parçası olarak korunan ve geçici olmayan ayrı bir depolamaya sahiptir; bu bellek, kelime dizileri olarak düzenlenir (yığındaki kelime adreslenebilir bayt dizilerinin aksine). Bu depolama, sözleşmelerin kalıcı verilerini tuttuğu yerdir, bir sözleşme sadece kendi depolamasıyla etkileşime girebilir. Depolama, anahtar-değer eşlemeleri şeklinde düzenlenir.

Sarı Kağıdın bu kısmında bahsedilmemiş olsa da, dördüncü bir bellek türü olduğunu bilmemizde fayda var. Çağrı verileri, bir işlemin data parametresiyle aktarılan değerini depolamak için kullanılan bayt-adreslenebilir, salt okunur bir bellektir. EVM'nin calldata yönetimine yönleik özel işlem kodları vardır. calldatasize, verinin boyutunu döndürür. calldataload, veriyi yığına yükler. calldatacopy, veriyi belleğe kopyalar.

Standart Von Neumann mimarisi(opens in a new tab), kod ile veriyi aynı bellekte depolar. EVM güvenlik sebebiyle bu standarda uymaz; geçici belleğin paylaşılması, program kodunun değiştirilmesini mümkün kılar. Bunun yerine kod, depolamaya kaydedilir.

Kodun bellekten yürütüldüğü sadece iki durum vardır:

İstisnai yürütüm terimi, güncel sözleşmenin yürütümünün durmasına sebep olan bir istisnayı ifade eder.

9.2 Ücretlerle ilgili genel bilgi

Bu bölüm, gaz ücretlerinin nasıl hesapladığını anlatır. Üç maliyet kalemi vardır:

İşlem kodu maliyeti

Spesifik işlem kodunun öz maliyeti. Bu değere ulaşabilmek için Ek H'de (sayfa 28, (327). denklemin altında) işlem kodunun maliyet grubunu ve (324.) denklemdeki maliyet grubunu bulun. Bu size bir maliyet fonksiyonu verir, bu da çoğu durumda Ek G'deki (sayfa 27) parametreleri kullanır.

Örnek olarak CALLDATACOPY(opens in a new tab) işlem kodu Wcopy grubunun bir üyesidir. Bu grup için işlem kodu maliyeti Gverylow+Gcopy×⌈μs[2]÷32⌉ şeklindedir. Ek G'ye baktığımızda, iki sabit değerin de 3 olduğunu görürüz, bu da bize 3+3×⌈μs[2]÷32⌉ değerini verir.

Hala ⌈μs[2]÷32⌉ ifadesini çözmemiz gerekiyor. En dıştaki kısım olan ⌈ \<value> tavan fonksiyonudur ve değerden küçük olmayan en küçük tam sayıyı verir. Örneğin ⌈2.5⌉ = ⌈3⌉ = 3. İç kısım μs[2]÷32 şeklindedir. 3. bölüme (Yöntemler) bakarsak, sayfa 3'te μ, makinenin durumudur. Makine durumu sayfa 13, bölüm 9.4.1'de açıklanmıştır. O bölüme göre yığın için makine durumu parametrelerinden biri s'dir. Hepsini birleştirdiğimizde μs[2], yığındaki 2. konumdur. İşlem koduna(opens in a new tab) bakarsak, yığındaki 2. konum, verinin bayt cinsinden boyutudur. Grup Wcopy, CODECOPY(opens in a new tab) ve RETURNDATACOPY(opens in a new tab) içindeki diğer işlem kodlarına bakarsak, işlem kodlarının da aynı konumda veri boyutları olduğunu görürüz. Yani ⌈μs[2]÷32⌉, kopyalanan veriyi depolayabilmek için gereken 32 baytlık kelimelerin sayısıdır. Toparlamak gerekirse, CALLDATACOPY(opens in a new tab) işlem kodunun kalıtımsal maliyeti, kopyalanan veri kelimesi başına 3 gaz artı 3'tür.

Çalıştırma maliyeti

Çağrı yaptığımız kodun çalıştırma maliyetidir.

Bellek maliyetini genişletme

Bellek genişletme maliyeti (eğer gerekliyse).

  1. denklemde bu değer Cmemi')-Cmemi) olarak yazılmıştır. 9.4.1. bölüme baktığımızda μi değerinin bu bellekteki kelime sayısı olduğunu görürüz. Yani μi, bellekte işlem kodundan önce bulunan kelime sayısı ve μi', bellekte işlem kodundan sonra bulunan kelime sayısıdır.

Cmem fonksiyonu 326. denklemde tanımlanmıştır: Cmem(a) = Gmemory × a + ⌊a2 ÷ 512⌋. ⌊x⌋ taban fonksiyonudur. Bir değer verildiğinde o değerden büyük olmayan en büyük tam sayıyı verir. Örneğin, ⌊2.5⌋ = ⌊2⌋ = 2. a < √512, a2 < 512 ve taban fonksiyonunun sonucu 0 olduğunda. Yani ilk 22 kelime için (704 bayt), gereken bellek kelimesi sayısı arttıkça maliyet de doğrusal olarak artar. O noktanın ötesinde ⌊a2 ÷ 512⌋ pozitiftir. Gereken bellek yeteri kadar yüksek olduğunda gaz maliyeti bellek miktarının karesiyle orantılıdır.

Bu faktörlerin sadece kalıtımsal gaz maliyetini etkilediğini unutmayın. Ücret piyasasını ya da doğrulayıcılara yönelik son kullanıcının ne kadar ödemesi gerektiğini belirleyen ipuçlarını dikkate almaz; bu, sadece EVM'de belirli bir işlemi çalıştırmanın ham maliyetidir.

Gaz hakkında daha fazla bilgi edinin.

9.3 Yürütüm ortamı

Yürütme ortamları veri tabanında kayıtları oluşturan bir veri grubudur, I, blokzincirin durumu ya da ESM'nin bir parçası olmayan bilgiyi içerir.

ParametreVeriye erişecek işlem koduVeriye erişecek Solidity kodu
IaADDRESS(opens in a new tab)address(this)
IoORIGIN(opens in a new tab)tx.origin
IpGASPRICE(opens in a new tab)tx.gasprice
IdCALLDATALOAD(opens in a new tab), vs.msg.data
IsCALLER(opens in a new tab)msg.sender
IvCALLVALUE(opens in a new tab)msg.value
IbCODECOPY(opens in a new tab)address(this).code
IHNUMBER(opens in a new tab) ve DIFFICULTY(opens in a new tab) gibi blok başlığı alanlarıblock.number, block.difficulty, vs.
IeSözleşmeler arası çağrılar için çağrı yığınının derinliği (sözleşme oluşturma dahil)
IwEVM'nin durumu değiştirme izni var mı yoksa statik olarak mı çalışıyor?
  1. bölümün geri kalanını anlamak için birkaç parametre daha gereklidir:
ParametreAnlatıldığı bölümAnlam
σ2 (2. sayfa, 1. denklem)Blokzincirin durumu
g9.3 (13. sayfa)Kalan gaz
A6.1 (8. sayfa)Birikmiş yan durum (değişimler, işlem sonuna göre programlanmıştır)
o9.3 (13. sayfa)Çıktı - İç işlem durumunda (bir sözleşme bir diğerini aradığında) ve fonksiyonları görüntülemek için yapılan aramalarda (sadece bilgi istiyorken, yani bir işlem için beklemeye gerek yokken) döndürülen sonuçtur

9.4 Yürütme ile ilgili temel bilgiler

Ön hazırlıkların hepsi tamam olduğuna göre, artık EVM'nin nasıl çalıştığı üzerinde çalışmaya başlayabiliriz.

137-142 denklemleri bize EVM'yi çalıştırmak için ilk şartları veriyor:

SembolBaşlangıç değeriAnlam
μggKalan gaz
μpc0Program sayacı, yürütülecek yeni talimatın adresi
μm(0, 0, ...)Bellek, tamamen sıfırlardan başlatılır
μi0Kullanılan en yüksek bellek konumu
μs()Yığın, başlangıçta boştur
μoÇıktı, döndürülen veriyle (RETURN(opens in a new tab) ya da REVERT(opens in a new tab)) ya da onsuz (STOP(opens in a new tab) ya da SELFDESTRUCT(opens in a new tab)) durmazsak boş olan küme.
  1. denklem bize yürütüm sırasında her bir zaman noktasında dört olası durum olduğunu ve onlarla ne yapacağımızı söylüyor:

  2. Z(σ,μ,A,I). Z, bir işlemin geçersiz bir durum geçişi yapıp yapmadığını test eden bir fonksiyonu temsil eder (bkz. istisnai durma). Değerlendirme sonucu Doğru olursa, yeni durum eskisiyle aynı olur (gazın yanması dışında) çünkü değişiklikler uygulanmamıştır.

  3. Yürütülen işlem kodu REVERT(opens in a new tab) ise yeni durum yine eski durumla aynıdır, bir miktar gaz kaybedilmiştir.

  4. Eğer işlem dizisi RETURN(opens in a new tab)) ile gösterildiği gibi tamamlanmışsa durum, yeni duruma güncellenir.

  5. 1-3 uç koşullarından birinde değilsek, çalıştırmaya devam edin.

9.4.1 Makine Durumu

Bu bölüm makine durumunu daha detaylı bir şekilde anlatıyor. w'nin güncel işlem kodu olduğunu belirtiyor. Eğer μpc ||Ib|| kodun uzunluğundan daha azsa, o zaman o bayt (Ibpc]) işlem kodudur. Aksi halde işlem kodu, STOP(opens in a new tab) olarak tanımlanır.

Bu bir yığın makinesi olduğundan(opens in a new tab), her bir işlem kodu tarafından çıkarılmış (δ) ve sokulmuş (α) öğeleri takip etmemiz gerekir.

9.4.2 İstisnai Durma

Bu bölüm, anormal bir sonuca ulaştığımızda verilen Z fonksiyonunu tanımlar. Bu bir Boole(opens in a new tab) fonksiyonudur, dolayısıyla bir mantıksal veya için işaretini(opens in a new tab) ve bir mantıksal ve için işaretini kullanır(opens in a new tab).

Bu durumlardan biri doğruysa bir istisnai durma söz konusudur:

9.4.3 Sıçrama Varış Noktası Doğruluğu

Burada resmi olarak JUMPDEST(opens in a new tab) işlem kodlarını tanımlıyoruz. Sadece 0x5B bayt değerini arayamayız, çünkü bir PUSH'un içinde de olabilir (ve bu yüzden bir işlem kodu değil, veridir).

(153). denklemde bir fonksiyon tanımlıyoruz, N(i,w). İlk parametre olan i, işlem kodunun konumudur. İkinci parametre olan w, işlem kodunun kendisidir. w∈[PUSH1, PUSH32] uygularsak bu, işlem kodunun bir PUSH olduğu anlamına gelir (kare parantezler başlangıç ve bitiş noktaları arasında bir değer olabileceğini ifade eder). Bu durumda bir sonraki işlem kodu i+2+(w−PUSH1)'dedir. PUSH1(opens in a new tab) için iki bayt ilerlemeliyiz (PUSH'un kendisi ve bir bayt değeri), PUSH2(opens in a new tab) için de 3 bayt ilerlemeliyiz çünkü kendisi iki baytlık bir değerdir, vs. Diğer tüm EVM işlem kodları sadece bir bayt uzunluğundadır, bu yüzden bütün diğer durumlarda N(i,w)=i+1.

Bu fonksiyon 152. denklemde DJ(c,i) öğesini tanımlamak için kullanılır; söz konusu öğe, c kodunun içindeki tüm geçerli sıçrama varış noktalarından oluşan bir kümedir(opens in a new tab) ve i işlem kodu konumundan başlar. Bu fonksiyon tekrarlı olarak tanımlanır. i≥||c|| ise bu, kodumuzun sonunda ya da sonrasındayız demektir. Daha fazla sıçrama varış noktası bulmayacağız, sadece boş kümeyi döndüreceğiz.

Tüm ayrı durumlarda yeni işlem koduna giderek kodun geri kalanına bakarız ve buradan başlayan kümeyi alırız. c[i] güncel işlem kodudur, bu yüzden N(i,c[i]) bir sonraki işlem kodunun konumudur. Bu yüzden DJ(c,N(i,c[i])), sonraki işlem kodunda başlayan geçerli işlem kodlarının bir kümesidir. Eğer şu anki işlem kodu JUMPDEST değilse, sadece o kümeyi döndürün. JUMPDEST ise, sonuç kümesine dahil edin ve döndürün.

9.4.4 Normal durma

Durma fonksiyonu H, üç farklı değer türü döndürebilir.

H.2 Talimat kümesi

EVM'nin son alt kümesine olan 9.5'e gitmeden önce, talimatların kendilerine bir bakalım. Bu talimatlar, 29. sayfada başlayan Ek H.2'de tanımlanmıştır. O spesifik işlem koduyla değişen olarak belirtilmeyen her şeyin aynı kalması beklenir. Değişen değişkenler \<something>′ olarak belirtilir.

Örnek olarak ADD(opens in a new tab) işlem koduna bakalım.

DeğerAnımsatıcıδαAçıklama
0x01EKLE21Ekleme işlemi.
μ′s[0] ≡ μs[0] + μs[1]

δ yığından çıkardığımız değerlerin sayısıdır. Bu durumda iki tane var, çünkü en üst iki değeri ekliyoruz.

α geri ittiğimiz değerlerin sayısıdır. Bu durumda bir, toplam.

Bu yüzden yığının yeni başı (μ′s[0]), eski yığın başının (μs[0]) ve aşağısındaki eski değerin (μs[1]) toplamı olur.

Bu belge, "bıktırıcı bir listeyle" tüm işlem kodlarının üstünden geçmek yerine, sadece yeni bir şey tanıtan işlem kodlarını açıklıyor.

DeğerAnımsatıcıδαAçıklama
0x20KECCAK25621Keccak-256 karmasını hesaplar.
μ′s[0] ≡ KEC(μms[0] . . . (μs[0] + μs[1] − 1)])
μ′i ≡ M(μis[0]s[1])

Bu, belleğe erişen ilk işlem kodudur (bu durumda, salt okunur). Yine de, belleğin güncel sınırlarının ötesine kadar büyüyebilir, bu yüzden μi değerini güncellememiz gerekir. Bunu 29. sayfadaki 328. denklemde tanımlanan M fonksiyonunu kullanarak yaparız.

DeğerAnımsatıcıδαAçıklama
0x31BALANCE11Söz konusu hesabın bakiyesini alın.
...

Bakiyesini bulmamız gereken hesap: μs[0] mod 2160. Yığının başı adrestir, fakat adresler sadece 160 bit olduğu için modulo(opens in a new tab) 2160 değerini hesaplarız.

Eğer σ[μs[0] mod 2160] ≠ ∅ ise, bu adresle ilgili bilgi bulunduğu anlamına gelir. Bu durumda σ[μs[0] mod 2160]b, bu hesabın bakiyesidir. Eğer σ[μs[0] mod 2160] = ∅ ise, bu da adresin başlatılmadığını ve bakiyenin 0 olduğu anlamına gelir. Hesap bilgisi alanları listesini 4. sayfadaki 4.1. bölümünde bulabilirsiniz.

İkinci denklem olan A'a ≡ Aa ∪ {μs[0] mod 2160}, sıcak depolama (yakın zamanda erişilmiş ve muhtemelen önbellekte olan depolama) ile soğuk depolama (erişilmemiş ve muhtemelen daha yavaş ve alması daha pahalı olan depolama) arasındaki maliyet farkıyla alakalıdır. Aa, işlem tarafından önceden erişilmiş adreslerin listesidir, bu yüzden 8. sayfada 6.1. bölümde anlatıldığı üzere erişilmesi daha ucuz olmalıdır. EIP-2929(opens in a new tab)'da bu konuyla ilgili daha fazla okuma yapabilirsiniz.

DeğerAnımsatıcıδαAçıklama
0x8FDUP16161716. yığın öğesini çoğaltın.
μ′s[0] ≡ μs[15]

Herhangi bir yığın öğesini kullanabilmek için onu çıkarmamız gerektiğini, yani üstündeki her yığın öğesini çıkarmamız gerektiğini unutmayın. DUP<n>(opens in a new tab) ve SWAP<n>(opens in a new tab) durumlarında bu, on altı değere kadar ekleme ve çıkarma yapmak mecburiyeti anlamına gelir.

9.5 Yürütme döngüsü

Artık her parçasına hakim olduğumuza göre, EVM'nin yürütme döngüsünün nasıl belgelendiğini sonunda anlayabiliriz.

(155). denklem, durum belirtildiğinde şunu söyler:

  • σ (küresel blokzincir durumu)
  • μ (EVM durumu)
  • A (alt durum, değişiklikler işlem bittiğinde gerçekleşir)
  • I (yürütme ortamı)

Yeni durum: (σ', μ', A', I').

(156) ila (158). denklemler yığını ve işlem kodu sebepleri yığında olan değişiklikleri tanımlar (μs). (159). denklem gazdaki değişimdir (μg). (160). denklem program sayacındaki değişikliktir (μpc). Son olarak, (161) ila (164). denklemler, diğer parametrelerin işlem kodu tarafından açıkça değiştirilmediği sürece aynı kalacaklarını belirtir.

Artık EVM tamamen açıklanmıştır.

Sonuç

Matematiksel gösterim kesindir ve Sarı Kağıdın Ethereum'un her detayını belirtmesini sağlamıştır. Yine de, bazı dezavantajları vardır:

Belki bu sebeplerden yeni fikir birliği katmanı spesifikasyonları(opens in a new tab) Python'da yazılmaktadır. Python'da yürütüm katmanı spesifikasyonları(opens in a new tab) da mevcuttur fakat bunlar henüz tamamlanmamıştır. Sarı Kağıt eksiksiz olarak Python ya da başka bir dile çevrilmeden, Sarı Kağıt kullanımda kalmaya devam edecektir ve onu okuma olanağına sahip olmak faydalıdır.

Son düzenleme: @wackerow(opens in a new tab), 26 Mart 2024

Bu rehber yararlı oldu mu?