Memahami Spesifikasi EVM di Kertas Kuning
Kertas Kuning (opens in a new tab) adalah spesifikasi formal untuk Ethereum. Kecuali jika diubah oleh proses EIP, dokumen ini berisi deskripsi yang tepat tentang bagaimana semuanya bekerja. Dokumen ini ditulis sebagai makalah matematika, yang mencakup terminologi yang mungkin tidak familier bagi pemrogram. Dalam makalah ini Anda akan belajar cara membacanya, dan lebih jauh lagi makalah matematika terkait lainnya.
Kertas Kuning yang Mana?
Seperti hampir semua hal lain di Ethereum, Kertas Kuning berevolusi seiring waktu. Agar dapat merujuk ke versi tertentu, saya mengunggah versi saat penulisan ini. Nomor bagian, halaman, dan persamaan yang saya gunakan akan merujuk ke versi tersebut. Ada baiknya Anda membukanya di jendela yang berbeda saat membaca dokumen ini.
Mengapa EVM?
Kertas kuning asli ditulis tepat pada awal pengembangan Ethereum. Dokumen ini menjelaskan mekanisme konsensus berbasis Bukti Kerja (PoW) asli yang pada awalnya digunakan untuk mengamankan jaringan. Namun, Ethereum mematikan Bukti Kerja dan mulai menggunakan konsensus berbasis Bukti Kepemilikan (PoS) pada bulan September 2022. Tutorial ini akan berfokus pada bagian-bagian kertas kuning yang mendefinisikan Mesin Virtual Ethereum (EVM). EVM tidak berubah oleh transisi ke Bukti Kepemilikan (kecuali untuk nilai kembalian dari opcode DIFFICULTY).
9 Model eksekusi
Bagian ini (hal. 12-14) mencakup sebagian besar definisi EVM.
Istilah state sistem mencakup semua yang perlu Anda ketahui tentang sistem untuk menjalankannya. Dalam komputer pada umumnya, ini berarti memori, konten register, dll.
Mesin Turing (opens in a new tab) adalah model komputasi. Pada dasarnya, ini adalah versi komputer yang disederhanakan, yang terbukti memiliki kemampuan yang sama untuk menjalankan komputasi yang dapat dilakukan komputer normal (semua yang dapat dihitung komputer dapat dihitung oleh mesin Turing dan sebaliknya). Model ini memudahkan untuk membuktikan berbagai teorema tentang apa yang dapat dan tidak dapat dihitung.
Istilah Turing-complete (opens in a new tab) berarti komputer yang dapat menjalankan perhitungan yang sama dengan mesin Turing. Mesin Turing dapat masuk ke dalam perulangan tak terbatas, dan EVM tidak bisa karena akan kehabisan gas, jadi EVM hanya bersifat quasi-Turing-complete.
9.1 Dasar-dasar
Bagian ini memberikan dasar-dasar EVM dan bagaimana perbandingannya dengan model komputasi lainnya.
Mesin tumpukan (stack machine) (opens in a new tab) adalah komputer yang menyimpan data perantara bukan di dalam register, melainkan di dalam tumpukan (stack) (opens in a new tab). Ini adalah arsitektur yang disukai untuk mesin virtual karena mudah diimplementasikan yang berarti bug, dan kerentanan keamanan, jauh lebih kecil kemungkinannya. Memori dalam tumpukan dibagi menjadi kata (word) 256-bit. Ini dipilih karena nyaman untuk operasi kriptografi inti Ethereum seperti proses hash Keccak-256 dan komputasi kurva eliptik. Ukuran maksimum tumpukan adalah 1024 item (1024 x 256 bit). Ketika opcode dieksekusi, mereka biasanya mendapatkan parameternya dari tumpukan. Ada opcode khusus untuk mengatur ulang elemen dalam tumpukan seperti POP (menghapus item dari atas tumpukan), DUP_N (menduplikasi item ke-N dalam tumpukan), dll.
EVM juga memiliki ruang volatil yang disebut memori yang digunakan untuk menyimpan data selama eksekusi. Memori ini diatur ke dalam kata 32-byte. Semua lokasi memori diinisialisasi ke nol. Jika Anda mengeksekusi kode Yul (opens in a new tab) ini untuk menambahkan sebuah kata ke memori, kode ini akan mengisi 32 byte memori dengan menambahkan nol pada ruang kosong di kata tersebut, yaitu, kode ini membuat satu kata - dengan nol di lokasi 0-29, 0x60 ke 30, dan 0xA7 ke 31.
mstore(0, 0x60A7)
mstore adalah satu dari tiga opcode yang disediakan EVM untuk berinteraksi dengan memori - opcode ini memuat sebuah kata ke dalam memori. Dua lainnya adalah mstore8 yang memuat satu byte ke dalam memori, dan mload yang memindahkan sebuah kata dari memori ke tumpukan.
EVM juga memiliki model penyimpanan (storage) non-volatil terpisah yang dipertahankan sebagai bagian dari state sistem - memori ini diatur ke dalam array kata (berlawanan dengan array byte yang dapat dialamatkan kata di tumpukan). Penyimpanan ini adalah tempat kontrak menyimpan data persisten - sebuah kontrak hanya dapat berinteraksi dengan penyimpanannya sendiri. Penyimpanan diatur dalam pemetaan kunci-nilai.
Meskipun tidak disebutkan di bagian Kertas Kuning ini, ada baiknya juga untuk mengetahui bahwa ada jenis memori keempat. Calldata adalah memori baca-saja yang dapat dialamatkan byte yang digunakan untuk menyimpan nilai yang diteruskan dengan parameter data dari sebuah transaksi. EVM memiliki opcode khusus untuk mengelola calldata. calldatasize mengembalikan ukuran data. calldataload memuat data ke dalam tumpukan. calldatacopy menyalin data ke dalam memori.
Standar arsitektur Von Neumann (opens in a new tab) menyimpan kode dan data dalam memori yang sama. EVM tidak mengikuti standar ini karena alasan keamanan - berbagi memori volatil memungkinkan untuk mengubah kode program. Sebaliknya, kode disimpan ke penyimpanan.
Hanya ada dua kasus di mana kode dieksekusi dari memori:
- Ketika sebuah kontrak membuat kontrak lain (menggunakan
CREATE(opens in a new tab) atauCREATE2(opens in a new tab)), kode untuk konstruktor kontrak berasal dari memori. - Selama pembuatan kontrak apa pun, kode konstruktor berjalan dan kemudian kembali dengan kode kontrak yang sebenarnya, juga dari memori.
Istilah eksekusi luar biasa (exceptional execution) berarti pengecualian yang menyebabkan eksekusi kontrak saat ini berhenti.
9.2 Gambaran umum biaya
Bagian ini menjelaskan bagaimana biaya gas dihitung. Ada tiga biaya:
Biaya opcode
Biaya inheren dari opcode tertentu. Untuk mendapatkan nilai ini, temukan grup biaya opcode di Lampiran H (hal. 28, di bawah persamaan (327)), dan temukan grup biaya di persamaan (324). Ini memberi Anda fungsi biaya, yang dalam banyak kasus menggunakan parameter dari Lampiran G (hal. 27).
Sebagai contoh, opcode CALLDATACOPY (opens in a new tab) adalah anggota grup Wcopy. Biaya opcode untuk grup tersebut adalah Gverylow+Gcopy×⌈μs[2]÷32⌉. Melihat Lampiran G, kita melihat bahwa kedua konstanta tersebut adalah 3, yang memberi kita 3+3×⌈μs[2]÷32⌉.
Kita masih perlu menguraikan ekspresi ⌈μs[2]÷32⌉. Bagian terluar, ⌈ <value> ⌉ adalah fungsi ceiling (pembulatan ke atas), sebuah fungsi yang jika diberikan sebuah nilai akan mengembalikan bilangan bulat terkecil yang masih tidak lebih kecil dari nilai tersebut. Sebagai contoh, ⌈2.5⌉ = ⌈3⌉ = 3. Bagian dalamnya adalah μs[2]÷32. Melihat bagian 3 (Konvensi) di hal. 3, μ adalah state mesin. State mesin didefinisikan di bagian 9.4.1 di hal. 13. Menurut bagian tersebut, salah satu parameter state mesin adalah s untuk tumpukan. Menggabungkan semuanya, tampaknya μs[2] adalah lokasi #2 di tumpukan. Melihat opcode tersebut (opens in a new tab), lokasi #2 di tumpukan adalah ukuran data dalam byte. Melihat opcode lain di grup Wcopy, CODECOPY (opens in a new tab) dan RETURNDATACOPY (opens in a new tab), mereka juga memiliki ukuran data di lokasi yang sama. Jadi ⌈μs[2]÷32⌉ adalah jumlah kata 32 byte yang diperlukan untuk menyimpan data yang sedang disalin. Menggabungkan semuanya, biaya inheren dari CALLDATACOPY (opens in a new tab) adalah 3 gas ditambah 3 per kata dari data yang sedang disalin.
Biaya berjalan
Biaya menjalankan kode yang kita panggil.
- Dalam kasus
CREATE(opens in a new tab) danCREATE2(opens in a new tab), konstruktor untuk kontrak baru. - Dalam kasus
CALL(opens in a new tab),CALLCODE(opens in a new tab),STATICCALL(opens in a new tab), atauDELEGATECALL(opens in a new tab), kontrak yang kita panggil.
Biaya perluasan memori
Biaya memperluas memori (jika perlu).
Dalam persamaan 324, nilai ini ditulis sebagai Cmem(μi')-Cmem(μi). Melihat bagian 9.4.1 lagi, kita melihat bahwa μi adalah jumlah kata dalam memori. Jadi μi adalah jumlah kata dalam memori sebelum opcode dan μi' adalah jumlah kata dalam memori setelah opcode.
Fungsi Cmem didefinisikan dalam persamaan 326: Cmem(a) = Gmemory × a + ⌊a2 ÷ 512⌋. ⌊x⌋ adalah fungsi floor (pembulatan ke bawah), sebuah fungsi yang jika diberikan sebuah nilai akan mengembalikan bilangan bulat terbesar yang masih tidak lebih besar dari nilai tersebut. Sebagai contoh, ⌊2.5⌋ = ⌊2⌋ = 2. Ketika a < √512, a2 < 512, dan hasil dari fungsi floor adalah nol. Jadi untuk 22 kata pertama (704 byte), biayanya naik secara linier dengan jumlah kata memori yang diperlukan. Di luar titik itu ⌊a2 ÷ 512⌋ bernilai positif. Ketika memori yang dibutuhkan cukup tinggi, biaya gas sebanding dengan kuadrat dari jumlah memori.
Catatan bahwa faktor-faktor ini hanya memengaruhi biaya gas inheren - ini tidak memperhitungkan pasar biaya atau tip kepada validator yang menentukan berapa banyak pengguna akhir diharuskan membayar - ini hanyalah biaya mentah untuk menjalankan operasi tertentu di EVM.
Baca lebih lanjut tentang gas.
9.3 Lingkungan eksekusi
Lingkungan eksekusi adalah sebuah tuple, I, yang mencakup informasi yang bukan bagian dari state rantai blok atau EVM.
| Parameter | Opcode untuk mengakses data | Kode Solidity untuk mengakses data |
|---|---|---|
| Ia | ADDRESS (opens in a new tab) | address(this) |
| Io | ORIGIN (opens in a new tab) | tx.origin |
| Ip | GASPRICE (opens in a new tab) | tx.gasprice |
| Id | CALLDATALOAD (opens in a new tab), dll. | msg.data |
| Is | CALLER (opens in a new tab) | msg.sender |
| Iv | CALLVALUE (opens in a new tab) | msg.value |
| Ib | CODECOPY (opens in a new tab) | address(this).code |
| IH | Bidang header blok, seperti NUMBER (opens in a new tab) dan DIFFICULTY (opens in a new tab) | block.number, block.difficulty, dll. |
| Ie | Kedalaman tumpukan panggilan untuk panggilan antar kontrak (termasuk pembuatan kontrak) | |
| Iw | Apakah EVM diizinkan untuk mengubah state, atau apakah ia berjalan secara statis |
Beberapa parameter lain diperlukan untuk memahami sisa bagian 9:
| Parameter | Didefinisikan di bagian | Arti |
|---|---|---|
| σ | 2 (hal. 2, persamaan 1) | State dari rantai blok |
| g | 9.3 (hal. 13) | Gas yang tersisa |
| A | 6.1 (hal. 8) | Substate yang masih harus dibayar (perubahan yang dijadwalkan saat transaksi berakhir) |
| o | 9.3 (hal. 13) | Output - hasil yang dikembalikan dalam kasus transaksi internal (ketika satu kontrak memanggil kontrak lain) dan panggilan ke fungsi view (ketika Anda hanya meminta informasi, jadi tidak perlu menunggu transaksi) |
9.4 Gambaran umum eksekusi
Sekarang setelah memiliki semua pendahuluan, kita akhirnya dapat mulai mengerjakan bagaimana EVM bekerja.
Persamaan 137-142 memberi kita kondisi awal untuk menjalankan EVM:
| Simbol | Nilai awal | Arti |
|---|---|---|
| μg | g | Gas yang tersisa |
| μpc | 0 | Penghitung program (program counter), alamat instruksi berikutnya yang akan dieksekusi |
| μm | (0, 0, ...) | Memori, diinisialisasi ke semua nol |
| μi | 0 | Lokasi memori tertinggi yang digunakan |
| μs | () | Tumpukan, awalnya kosong |
| μo | ∅ | Output, himpunan kosong sampai dan kecuali kita berhenti baik dengan data kembalian (RETURN (opens in a new tab) atau REVERT (opens in a new tab)) atau tanpanya (STOP (opens in a new tab) atau SELFDESTRUCT (opens in a new tab)). |
Persamaan 143 memberi tahu kita bahwa ada empat kemungkinan kondisi pada setiap titik waktu selama eksekusi, dan apa yang harus dilakukan dengannya:
Z(σ,μ,A,I). Z mewakili fungsi yang menguji apakah suatu operasi menciptakan transisi state yang tidak valid (lihat penghentian luar biasa). Jika dievaluasi menjadi True, state baru identik dengan yang lama (kecuali gas terbakar) karena perubahan belum diimplementasikan.- Jika opcode yang dieksekusi adalah
REVERT(opens in a new tab), state baru sama dengan state lama, sejumlah gas hilang. - Jika urutan operasi selesai, seperti yang ditandai oleh
RETURN(opens in a new tab)), state diperbarui ke state baru. - Jika kita tidak berada di salah satu kondisi akhir 1-3, lanjutkan berjalan.
9.4.1 State Mesin
Bagian ini menjelaskan state mesin secara lebih rinci. Ini menentukan bahwa w adalah opcode saat ini. Jika μpc kurang dari ||Ib||, panjang kode, maka byte tersebut (Ib[μpc]) adalah opcode. Jika tidak, opcode didefinisikan sebagai STOP (opens in a new tab).
Karena ini adalah mesin tumpukan (opens in a new tab), kita perlu melacak jumlah item yang dikeluarkan (δ) dan dimasukkan (α) oleh setiap opcode.
9.4.2 Penghentian Luar Biasa
Bagian ini mendefinisikan fungsi Z, yang menentukan kapan kita mengalami penghentian abnormal. Ini adalah fungsi Boolean (opens in a new tab), jadi ia menggunakan ∨ untuk logika or (opens in a new tab) dan ∧ untuk logika and (opens in a new tab).
Kita mengalami penghentian luar biasa jika salah satu dari kondisi ini benar:
-
μg < C(σ,μ,A,I) Seperti yang kita lihat di bagian 9.2, C adalah fungsi yang menentukan biaya gas. Tidak ada cukup gas yang tersisa untuk menutupi opcode berikutnya.
-
δw=∅ Jika jumlah item yang dikeluarkan untuk sebuah opcode tidak terdefinisi, maka opcode itu sendiri tidak terdefinisi.
-
|| μs || < δw Underflow tumpukan, tidak cukup item di tumpukan untuk opcode saat ini.
-
w = JUMP ∧ μs[0]∉D(Ib) Opcode-nya adalah
JUMP(opens in a new tab) dan alamatnya bukanJUMPDEST(opens in a new tab). Lompatan (jump) hanya valid ketika tujuannya adalahJUMPDEST(opens in a new tab). -
w = JUMPI ∧ μs[1]≠0 ∧ μs[0] ∉ D(Ib) Opcode-nya adalah
JUMPI(opens in a new tab), kondisinya benar (bukan nol) sehingga lompatan harus terjadi, dan alamatnya bukanJUMPDEST(opens in a new tab). Lompatan hanya valid ketika tujuannya adalahJUMPDEST(opens in a new tab). -
w = RETURNDATACOPY ∧ μs[1]+μs[2]>|| μo || Opcode-nya adalah
RETURNDATACOPY(opens in a new tab). Dalam opcode ini elemen tumpukan μs[1] adalah offset untuk membaca dari buffer data kembalian, dan elemen tumpukan μs[2] adalah panjang data. Kondisi ini terjadi ketika Anda mencoba membaca melampaui akhir buffer data kembalian. Perhatikan bahwa tidak ada kondisi serupa untuk calldata atau untuk kode itu sendiri. Ketika Anda mencoba membaca melampaui akhir buffer tersebut, Anda hanya mendapatkan nol. -
|| μs || - δw + αw > 1024
Limpahan tumpukan (stack overflow). Jika menjalankan opcode akan menghasilkan tumpukan lebih dari 1024 item, batalkan.
-
¬Iw ∧ W(w,μ) Apakah kita berjalan secara statis (¬ adalah negasi (opens in a new tab) dan Iw bernilai benar ketika kita diizinkan untuk mengubah state rantai blok)? Jika ya, dan kita mencoba operasi pengubahan state, itu tidak dapat terjadi.
Fungsi W(w,μ) didefinisikan kemudian dalam persamaan 150. W(w,μ) bernilai benar jika salah satu dari kondisi ini benar:
-
w ∈ {CREATE, CREATE2, SSTORE, SELFDESTRUCT} Opcode ini mengubah state, baik dengan membuat kontrak baru, menyimpan nilai, atau menghancurkan kontrak saat ini.
-
LOG0≤w ∧ w≤LOG4 Jika kita dipanggil secara statis, kita tidak dapat memancarkan entri Log. Semua opcode Log berada dalam rentang antara
LOG0(A0) (opens in a new tab) danLOG4(A4) (opens in a new tab). Angka setelah opcode Log menentukan berapa banyak topik yang dikandung entri Log tersebut. -
w=CALL ∧ μs[2]≠0 Anda dapat memanggil kontrak lain saat Anda statis, tetapi jika Anda melakukannya, Anda tidak dapat mentransfer ETH ke kontrak tersebut.
-
-
w = SSTORE ∧ μg ≤ Gcallstipend Anda tidak dapat menjalankan
SSTORE(opens in a new tab) kecuali Anda memiliki lebih dari Gcallstipend (didefinisikan sebagai 2300 di Lampiran G) gas.
9.4.3 Validitas Tujuan Lompatan
Di sini kita secara formal mendefinisikan apa itu opcode JUMPDEST (opens in a new tab). Kita tidak bisa hanya mencari nilai byte 0x5B, karena itu mungkin berada di dalam PUSH (dan karenanya merupakan data dan bukan opcode).
Dalam persamaan (153) kita mendefinisikan sebuah fungsi, N(i,w). Parameter pertama, i, adalah lokasi opcode. Yang kedua, w, adalah opcode itu sendiri. Jika w∈[PUSH1, PUSH32] itu berarti opcode tersebut adalah PUSH (tanda kurung siku mendefinisikan rentang yang mencakup titik akhir). Jika demikian, opcode berikutnya berada di i+2+(w−PUSH1). Untuk PUSH1 (opens in a new tab) kita perlu maju dua byte (PUSH itu sendiri dan nilai satu byte), untuk PUSH2 (opens in a new tab) kita perlu maju tiga byte karena itu adalah nilai dua byte, dll. Semua opcode EVM lainnya hanya sepanjang satu byte, jadi dalam semua kasus lain N(i,w)=i+1.
Fungsi ini digunakan dalam persamaan (152) untuk mendefinisikan DJ(c,i), yang merupakan himpunan (opens in a new tab) dari semua tujuan lompatan yang valid dalam kode c, dimulai dengan lokasi opcode i. Fungsi ini didefinisikan secara rekursif. Jika i≥||c||, itu berarti kita berada di atau setelah akhir kode. Kita tidak akan menemukan tujuan lompatan lagi, jadi cukup kembalikan himpunan kosong.
Dalam semua kasus lain, kita melihat sisa kode dengan pergi ke opcode berikutnya dan mendapatkan himpunan yang dimulai darinya. c[i] adalah opcode saat ini, jadi N(i,c[i]) adalah lokasi opcode berikutnya. Oleh karena itu, DJ(c,N(i,c[i])) adalah himpunan tujuan lompatan yang valid yang dimulai pada opcode berikutnya. Jika opcode saat ini bukan JUMPDEST, cukup kembalikan himpunan tersebut. Jika itu adalah JUMPDEST, sertakan dalam himpunan hasil dan kembalikan itu.
9.4.4 Penghentian normal
Fungsi penghentian H, dapat mengembalikan tiga jenis nilai.
- Jika kita tidak berada dalam opcode penghentian (halt), kembalikan ∅, himpunan kosong. Berdasarkan konvensi, nilai ini ditafsirkan sebagai Boolean salah (false).
- Jika kita memiliki opcode penghentian yang tidak menghasilkan output (baik
STOP(opens in a new tab) atauSELFDESTRUCT(opens in a new tab)), kembalikan urutan byte berukuran nol sebagai nilai kembalian. Perhatikan bahwa ini sangat berbeda dari himpunan kosong. Nilai ini berarti bahwa EVM benar-benar berhenti, hanya saja tidak ada data kembalian untuk dibaca. - Jika kita memiliki opcode penghentian yang menghasilkan output (baik
RETURN(opens in a new tab) atauREVERT(opens in a new tab)), kembalikan urutan byte yang ditentukan oleh opcode tersebut. Urutan ini diambil dari memori, nilai di bagian atas tumpukan (μs[0]) adalah byte pertama, dan nilai setelahnya (μs[1]) adalah panjangnya.
H.2 Set instruksi
Sebelum kita beralih ke subbagian terakhir dari EVM, 9.5, mari kita lihat instruksinya sendiri. Instruksi tersebut didefinisikan dalam Lampiran H.2 yang dimulai pada hal. 29. Apa pun yang tidak ditentukan sebagai berubah dengan opcode tertentu tersebut diharapkan tetap sama. Variabel yang berubah ditentukan dengan sebagai <sesuatu>′.
Sebagai contoh, mari kita lihat opcode ADD (opens in a new tab).
| Nilai | Mnemonic | δ | α | Deskripsi |
|---|---|---|---|---|
| 0x01 | ADD | 2 | 1 | Operasi penambahan. |
| μ′s[0] ≡ μs[0] + μs[1] |
δ adalah jumlah nilai yang kita keluarkan dari tumpukan. Dalam hal ini dua, karena kita menambahkan dua nilai teratas.
α adalah jumlah nilai yang kita masukkan kembali. Dalam hal ini satu, yaitu jumlahnya.
Jadi bagian atas tumpukan yang baru (μ′s[0]) adalah jumlah dari bagian atas tumpukan yang lama (μs[0]) dan nilai lama di bawahnya (μs[1]).
Daripada membahas semua opcode dengan "daftar yang membosankan", artikel ini hanya menjelaskan opcode yang memperkenalkan sesuatu yang baru.
| Nilai | Mnemonic | δ | α | Deskripsi |
|---|---|---|---|---|
| 0x20 | KECCAK256 | 2 | 1 | Menghitung hash Keccak-256. |
| μ′s[0] ≡ KEC(μm[μs[0] . . . (μs[0] + μs[1] − 1)]) | ||||
| μ′i ≡ M(μi,μs[0],μs[1]) |
Ini adalah opcode pertama yang mengakses memori (dalam hal ini, baca saja). Namun, ini mungkin meluas melampaui batas memori saat ini, jadi kita perlu memperbarui μi. Kita melakukan ini menggunakan fungsi M yang didefinisikan dalam persamaan 328 di hal. 29.
| Nilai | Mnemonic | δ | α | Deskripsi |
|---|---|---|---|---|
| 0x31 | BALANCE | 1 | 1 | Mendapatkan saldo dari akun yang diberikan. |
| ... |
Alamat yang saldonya perlu kita temukan adalah μs[0] mod 2160. Bagian atas tumpukan adalah alamatnya, tetapi karena alamat hanya 160 bit, kita menghitung nilai modulo (opens in a new tab) 2160.
Jika σ[μs[0] mod 2160] ≠ ∅, itu berarti ada informasi tentang alamat ini. Dalam hal itu, σ[μs[0] mod 2160]b adalah saldo untuk alamat tersebut. Jika σ[μs[0] mod 2160] = ∅, itu berarti alamat ini tidak diinisialisasi dan saldonya nol. Anda dapat melihat daftar bidang informasi akun di bagian 4.1 di hal. 4.
Persamaan kedua, A'a ≡ Aa ∪ {μs[0] mod 2160}, terkait dengan perbedaan biaya antara akses ke penyimpanan hangat (penyimpanan yang baru-baru ini diakses dan kemungkinan di-cache) dan penyimpanan dingin (penyimpanan yang belum diakses dan kemungkinan berada di penyimpanan yang lebih lambat yang lebih mahal untuk diambil). Aa adalah daftar alamat yang sebelumnya diakses oleh transaksi, yang karenanya seharusnya lebih murah untuk diakses, seperti yang didefinisikan di bagian 6.1 di hal. 8. Anda dapat membaca lebih lanjut tentang subjek ini di EIP-2929 (opens in a new tab).
| Nilai | Mnemonic | δ | α | Deskripsi |
|---|---|---|---|---|
| 0x8F | DUP16 | 16 | 17 | Menduplikasi item tumpukan ke-16. |
| μ′s[0] ≡ μs[15] |
Perhatikan bahwa untuk menggunakan item tumpukan apa pun, kita perlu mengeluarkannya, yang berarti kita juga perlu mengeluarkan semua item tumpukan di atasnya. Dalam kasus DUP<n> (opens in a new tab) dan SWAP<n> (opens in a new tab), ini berarti harus mengeluarkan dan kemudian memasukkan hingga enam belas nilai.
9.5 Siklus eksekusi
Sekarang setelah kita memiliki semua bagiannya, kita akhirnya dapat memahami bagaimana siklus eksekusi EVM didokumentasikan.
Persamaan (155) mengatakan bahwa dengan state yang diberikan:
- σ (state rantai blok global)
- μ (state EVM)
- A (substate, perubahan yang akan terjadi saat transaksi berakhir)
- I (lingkungan eksekusi)
State barunya adalah (σ', μ', A', I').
Persamaan (156)-(158) mendefinisikan tumpukan dan perubahannya karena sebuah opcode (μs). Persamaan (159) adalah perubahan gas (μg). Persamaan (160) adalah perubahan pada penghitung program (μpc). Terakhir, persamaan (161)-(164) menentukan bahwa parameter lainnya tetap sama, kecuali diubah secara eksplisit oleh opcode.
Dengan ini EVM sepenuhnya terdefinisi.
Kesimpulan
Notasi matematika sangat presisi dan telah memungkinkan Kertas Kuning untuk menentukan setiap detail Ethereum. Namun, ini memiliki beberapa kelemahan:
- Ini hanya dapat dipahami oleh manusia, yang berarti bahwa pengujian kepatuhan (opens in a new tab) harus ditulis secara manual.
- Pemrogram memahami kode komputer. Mereka mungkin memahami atau tidak memahami notasi matematika.
Mungkin karena alasan ini, spesifikasi lapisan konsensus (opens in a new tab) yang lebih baru ditulis dalam Python. Ada spesifikasi lapisan eksekusi dalam Python (opens in a new tab), tetapi belum lengkap. Sampai dan kecuali seluruh Kertas Kuning juga diterjemahkan ke Python atau bahasa serupa, Kertas Kuning akan terus digunakan, dan sangat membantu untuk dapat membacanya.