Ethereum Nasıl Çalışır?
Blok zincir teknolojisini ve Bitcoin’in nasıl çalıştığını önceki yazılarımda incelemiştim. Şimdi Ethereum’un nasıl çalıştığını ve Bitcoin’den farklı olarak neler yaptığını inceleyeceğiz. (Blok zincir teknolojisinde hiçbir alt yapınız yoksa lütfen önceki yazılarımızı okuyunuz.)
Öncelikle Ether ile Ethereum’un farklı şeyler olduğunu bilmeliyiz. Ether, Ethereum Blockchain’inde kullandığımız bir para birimiyken Ethereum en kaba tabirle işlemlerimizi yapan bir “dünya bilgisayarı”dır. Dünya bilgisayarının ne demek olduğuna geleceğiz fakat önce Ethereum’u özel yapan şeyin ne olduğunu inceleyelim.
Ethereum Bitcoin’den farklı ne yapıyor? Neden bilgisayar olarak anılıyor?
Bitcoin önceki yazımızda da bahsettiğimiz gibi kimin ne kadar varlığı olduğunu tutan bir muhasebe defteri gibi çalışıyordu. Bir işlem yapıldığında bu işlemle el değiştiren Bitcoin’ler bu deftere işleniyordu. Bu esnada da ağ bizim için bu işlemler yapılabilir ya da yapılamaz olduğunu denetliyordu. Ethereum ise Bitcoin’in aksine Turing Bütünlüğü (Turing Completeness)’ne sahiptir.
Bu noktada Turing bütünlüğünün ne olduğunu yüzeysel olarak inceleyelim: bu terim bilgisayar bilimlerinin kurucusu olarak kabul edilen Alan Turing’in tasarladığı Turing Makinesi’nin yapabildiği tüm işlemleri yapabilen makineleri işaret eder. Bu makine okuma, yazma ve bellekte saklama gibi temel işlemleri yapar. Ayrıca makine bu işlemleri yaparken her an bir durum (state) kavramını tutar.
Durum gündelik hayat için şu anı ifade ediyor diyebiliriz. Bu kavramı daha iyi anlayabilmek için yandaki diyagramı inceleyebiliriz. Örneğin sistem ilk açıldığında durumunu A olarak tutsun ve daha sonra Y işlemi yapılsın sistemin durumu artık B durumu olarak güncellenecektir.
Her durum işlemler için farklı çıktılar oluşturabilir ya da gelen komutları farklı değerlendirebilir. Temelde işleyen sistem biraz daha farklı olsa da örnek vermek gerekirse bilgisayarınız kapalıyken açma kapama tuşuna basarsanız bilgisayarınız açılır ve bilgisayarınızın durumu açık olarak güncellenir. Bilgisayarınızın durumu açıkken aynı işlemi yaparsanız bilgisayarınız kapanır ve durumunu kapalı olarak değiştirir.
Bilgisayar bilimlerinin doğuşunu ve Turing Makinesi hakkında detaylı bilgi edinmek için bunu ve bunu inceleyebilirsiniz
Ayrıca Alan Turing’in hayatını anlatan “Enigma” filmini de izleyebilirsiniz.
Özet olarak günümüzde kullandığımız bilgisayarların temel taşı Turing Makinesi’dir ve programlama dilleri de Turing Bütünlüğü içerirler. Bu sebeple yazının devamında daha aşina olduğumuz bilgisayar kelimesini kullanacağız.
Konumuza dönecek olursak Ethereum bir bilgisayar gibi kendisine verdiğimiz komutları çalıştırabilir ve Bitcoin’in aksine sadece gelen işlemleri yapılabilir ya da yapılamaz şeklinde değerlendirmez. Bu işlemleri bir bilgisayar gibi yürütebilir. Bu sebeple de Ethereum üzerinde yazılımlar yazılarak farklı bilgisayar uygulamaları üretilebilir. Bu bilgisayar blok zincir teknolojisiyle çalışır ve tek bir yerde değildir. Aynı Bitcoin’de olduğu gibi dağıtık bir yapıdadır. İşlemler de aynı şekilde ağa bağlanan miner’lar tarafından yapılır.
Bir diğer fark ise yukarıda bir giriş yapmaya çalıştığımız durum (state) kavramıdır. Bitcoin durumsuzluk (stateless) üzerine tasarlanmıştır. Bitcoin Nasıl Çalışır? yazımızda bahsettiğimiz gibi bir işleme izin verilip verilmeyeceğinin kararını vermek için doğrudan bakılabilecek bir hesap bakiyesi yoktur. Bunun yerine “Harcanmamış İşlem Çıktısı” (UTXO) (Unspent Transaction Output) üzerinden hesap bakiyesi hesaplanır. İşlemler miner’lar tarafından biz bloğa kaydedilir, doğrulanır ve ağa yayınlanır. Daha sonra da zincire eklenir. Bu süreçte kullanıcı yeni bir işlem yapmak istediğinde sistem bu işlemin yapılabilir olduğunun kararını vermek için blok zincirdeki kayıtları incelemeli ve kullanıcının ne kadar bakiyesini olduğunu hesaplamalıdır.
Örnek vermek gerekirse Emre Ayşe’ye 0,5 BTC yolladığında Emre’nin o anki 10 BTC’si de işleme sokulur. Bu işlem sırasında 0,5 BTC harcanmış olarak işaretlenirken (Blok zincirdeki bir bloğa “Emre -> 0,5 BTC -> Ayşe” olarak kaydedilir) 9,5 BTC harcanmamış olarak işaretlenir. Ayşe de Emre’den 0,5, Erhan’dan 0,8 ve Marie’den 0,1 BTC almış olsun. (Tüm gönderimler blok zincire miktarlarıyla kaydedilmiş olsun) Artık Ayşe’nin 1,4 BTC’lik harcanmamış işlem çıktısı (UTXO) bulunmaktadır. Ayşe bu 1,4 BTC’yi harcamak istediğinde bu UTXO’lar bulunur ve hesaplanır.
Ethereum ise durum tutan (stateful) bir mimari üzerine tasarlanmıştır. Bakiyeler bir merkle tree yapısında tutulur ve herhangi bir işlem gerçekleştiğinde merkle tree’deki ilgili hesap adresi bulunup bakiyesi güncellenir. (Merkle Tree yapısının nasıl çalıştığını incelemek için ilgili yazımızı okuyabilirsiniz.)
Ethereum da Bitcoin gibi merkeziyetsiz bir yapıdır ve durum kayıtlarının (Blok zincirin) tek olması gerekir. Aynı Bitocin’de olduğu gibi tek bir zincire sahip olunmalıdır. Bazı durumlarda bu şart çiğnenebilir. Bu gibi durumlarda da çatallanmalar (fork) gerçekleşebilir. Fakat Bitcoin’de olduğu gibi Ethereum’da da bu durum en uzun zincirin sürekli olarak en güncel zincir olarak kabul edilmesiyle önlenir ve her zaman bir tane zincir ile işlemlere devam edilir. (Detaylı olarak incelemek için bakınız.)
Bu noktada bir diğer önemli fark ise Ommer/Uncle blok’lardır. Fork durumlarında Bitcoin’deki zincire katılmayan bloklar tamamen geçersiz sayılırlar ve yetim (Orphan) blok olarak adlandırılırlar. Ethereum’da ise bu bloklara geçmişte uncle adı veriliyordu. Şu anda ise cinsiyetçi yaklaşımın önüne geçebilmek adına Ommer blok denmektedir. Ommer bloklar yetim bloklar gibi tamamen geçersiz sayılmazlar. Zincire eklenirler ve miner’ları da küçük de olsa ödüller kazanır. Bu sayede sistem daha küçük donanıma sahip miner’ları da ödüllendirerek daha merkeziyetsiz olmayı hedefler.
Yukarıdaki diyagramda mor bloklar Ommer bloktur. Görüldüğü gibi ağın en son durumunu ifade eden (kabul edilmiş) canonical zincire dahil olmasalar da zincirin yanında tutulurlar.
Ethereum’un Bitcoin’den yukarıda bahsettiğimiz büyük farklılıklına ek olarak kullanılan hash fonksiyonu gibi çeşitli farklılıkları olsa da diğer birçok konuda aynı alt yapıya sahiplerdir. Örneğin eşler arası ağ (Peer to Peer Network) ve PoW (Proof of Work) konsensüs algoritmaları aynı alt yapıda çalışırlar.
Şimdi Ethereum’a geri dönecek olursak bazı ana kavramları incelemeye başlayalım.
Account (Hesap)
Birbiriyle iletişim kurabilen ve 20 bayt’lık bir adrese sahip alt birimlerdir. Bunu telefon numarası gibi düşünebiliriz. Operatörünüzün Ethereum olduğunu düşünürsek telefon numaranız da sizin hesabınızı işaret eden adresinizdir.
Ethereum’da iki tür hesap vardır:
1 — Externally Owned Account (Harici Hesaplar)
Herhangi bir kod içermezler ve private anahtarlar tarafından kontrol edilirler. (private — public anahtarlar için bakınız.) Kullanıcı hesabı olarak düşünülebilir.
2 — Contract Account (Sözleşme Hesapları)
Daha sonra değineceğimiz akıllı sözleşmeleri tutan hesaplardır. Kendilerine özgü kodları vardır.
Hesaplar Arası İletişim
Yukarıda verdiğimiz örnekteki gibi hesaplar arası iletişim kurulabilir. Yani numaraya sahip olan her bir operatör kullanıcısı farklı bir numarayı arayarak onunla iletişime geçebilir. Ethereum ağında hesaplar arası iletişim kurulması için bir harici hesabın kendi private şifresini kullanarak bir işlemi (transaction) imzalaması gerekir. Sözleşme hesapları bir iletişim başlatamazlar. Fakat harici hesaplar gibi sözleşme hesapları da kendi aralarında iletişim kurabilirler. Aşağıdaki diyagram üzerinde bu iletişimleri daha detaylı olarak inceleyelim.
Diyagramda da gördüğümüz gibi iki harici hesap kendi aralarında iletişim kurabilirler. Bu iletişim Bitcoin ağında da olduğu gibi private ve public key’ler kullanılarak yapılır. Aynı şekilde bir harici hesap bir sözleşme hesabıyla da iletişim kurabilir. Mesajını yine kendi private key’i ile imzalaması gerekmektedir. Daha sonra bu iletişimin tetiklemesiyle birlikte sözleşme hesabı başka bir sözleşme hesabıyla iletişim kurabilir. Bu kısma daha sonra değineceğiz.
Sözleşme hesaplarıyla kurulan iletişimler genelde bir kod parçasının çağrılması ve çalıştırılması istemiyle kurulur.
Acounts State (Hesap Durumu)
Hesaplar adreslerine ek olarak bir de hesap durumlarını tutarlar. Hesap durumları ise 4 bileşenden oluşur.
1 — Nonce: Eğer hesap, harici hesapsa nonce değeri bu hesaptan oluşturulan işlem sayısını tutar. Eğer sözleşme hesabıysa da hesap tarafından oluşturulan sözleşmelerin sayısını tutar.
2 — Balance: Hesabın ne kadar WEI’ye sahip olduğunu tutar. 1 Ether 10¹⁸ Wei eder.
3 — Strorage Root: Hesaplarda bazı içerikler depolanabilir. Örneğin sözleşme hesaplarında sözleşmenin sahibinin harici hesabı depolanmak istenebilir ya da daha sonraki işlemlerde kullanılmak için bazı değişkenler oluşturulup hafızaya kaydedilmek istenebilir. Bu gibi kayıtlar hesabın Storage Root’unda tutulur. Bu root daha önce de gördüğümüz merkle tree yapısındadır.
4 — CodeHash: Harici hesaplarda bu değer boş bir metinin hash’i iken sözleşme hesaplarında hash’i alınarak tutulan bir kod parçasıdır. Bu kısmı da daha sonra açacağız.
Gas ve Ödeme
Ethereum ağında işlem yapmak için bir ücret ödenmelidir. Bu ücret yapılmak istenilen işlemin karmaşıklığıyla doğru orantılıdır. Bu ücret Ether’in bir alt birimi olan gwei ile hesaplanır. (10⁹ gwei = 1 ether)
Kullanıcı bir işlem yapmak istediğinde gas limit ve gas price adında iki değer belirler. Gas price 1 gas’ın karşılığının kaç gwei olduğudur. Gas limit ise belirlenen gas price üzerinden yapılması istenilen işlem için harcanması göze alınan maksimum gas’dır. Sonuç olarak gas limit X gas price = İşlem için harcanması göze alınan maksimum gwei
Yapmak istediğiniz işlem arka planda adım adım yapılırken belirlenen maksimum işlem ücreti (gas fee) miner’ın hesabına gider ve harcanmaya başlar ve ücret bittiğinde işlemler “out of gas” sayılır ve kalınan yerde bırakılır. Günün sonunda işlem başarılı bir şekilde yapılmamıştır ve belirlenen işlem ücreti bitmiştir. Eğer belirlenen işlem ücreti işlemlerin giderinden fazlaysa da kalan gwei’ler kullanıcıya iade edilir.
Bu noktada sözleşme hesapları arasında yapılan işlemlerin ücretlerini kimin ödediğini merak edebilirsiniz. Ancak bu noktada bir iletişimi ilk başlatacak kişinin her zaman harici bir hesap olduğunu hatırlatmak isterim. Harici hesaplar işlemleri için gas fee belirlerken işlem sırasında eğer sözleşmeler arası yürütülecek bir işlem varsa onun da ücretini ödeyebilecek şekilde belirlemelidir.
Burada aklınıza gas fee’lerin neden yapılacak işleme yetip yetmeyeceğinin önceden hesaplanamadığı sorusu gelebilir. Eğer bu hesaplama önden yapılabilseydi belirlediğimiz gas fee’nin işlemimiz için yetip yetmeyeceği önden hesaplanabilecek ve eğer yetersiz bir ücret belirlemişsek paramız hiç harcanmadan sistem uyarı verebilecekti.
Belirlediğimiz ücretlerin işlem sırasında adım adım harcanmasının ve aslında adının gas olmasının sebebi bir işlemin maliyetinin ne kadar olacağının önden hesaplanamamasından kaynaklanmaktadır. Burada Turing Makinesi’ne küçük bir geri dönüş yapacağım ve “Halting Problem”e (Durma Problemi) değineceğim.
Halting problem Turing makinesinde çalışacak bir programın sonsuza kadar çalışıp çalışmayacağını belirlemeye çalışan problemdir. Alan Turing 1936 yılında bir problemin sonsuza kadar çalışıp çalışmayacağının bilinemeyeceğini kanıtlamıştır. Özetle bir programın durup durmayacağını test eden G adında bir program yazdığımızı düşünelim. G programına kendisinin durup durmayacağını sorduğumuzda program net bir sonuç veremeyecektir. Çünkü kendisini durana kadar çalıştırması ve test etmesi gereklidir. Örneğin G programı 10t süre çalışsın ancak G’nin bunu test edebilmesi için 10t+1 süre çalışması gerekmektedir. Bu da bir çelişki yaratır.
Halting Problem’i detaylı olarak incelemek için bakınız.
Ethereum ağına dönecek olursak da bir işlemin durmaması miner için büyük bir maliyet demektir. Bu sebeple sonsuza kadar çalışan bir işlemin yapılmaması için belirlenen gas fee işlem sırasında harcanmaya başlanır ve fee bittiğinde işlem durur. Böylece bir kullanıcı ne kadar uzun bir işlem verirse versin karşılığını ödemek zorundadır.
İşlemler için fee ödendiği gibi depolama için de fee ödenir. Yukarıda bahsettiğimiz gibi her hesap belirli verileri Ethereum ağında depolayabilir ve bu depolama işlemi ağa aynı işlemlerde olduğu gibi büyük bir yük bindirebilir. Bu sebeple depolama işlemi için de ücret ödenmesi gerekir. Bu duruma ek olarak depolamayı azaltıcı yöndeki işlemler için de herhangi bir fee talep edilmez ve kullanıcılar bu işlemlere teşvik edilir.
Transactions (İşlemler) ve Mesajlar
Ethereum ağının bir bilgisayar gibi çalıştığını ve bu sayede kullanıcıların yapmak istediği işlemleri yapabildiğini söylemiştik. Peki bu işlemler nedir ve nasıl yapıdadır?
Ethereum ağında iki tür işlem vardır:
1 — Mesajlar: Harici hesaplar tarafından oluşturulurlar ve başka bir harici hesaba ya da sözleşme hesabına iletilebilirler.
2 — Sözleşme Oluşturucu İşlemler: Yeni Ethereum sözleşmeleri oluştururlar.
İşlemlerin türünden bağımsız olarak tuttuğu bazı değerler vardır.
1 — Nonce: İşlemi yapan kişinin gönderdiği işlem sayısı
2 — gasPrice: gas ücreti
3 — gasLimit: İşlem için harcanması göze alınan maksimum gas miktarı
4 — to: Alıcı adresi (Sözleşme oluşturucu işlemlerde sözleşme adresi henüz belli olmadığından bu kısım boştur.)
5 — Value: Mesajlarda gönderilen gwei miktarıdır. Sözleşme oluşturucu işlemlerde ise oluşturulacak sözleşmenin başlangıç bakiyesidir.
6 — Init: Sadece sözleşme oluşturucu işlemlerde mevcuttur ve yeni sözleşmenin kodunun başlatılması için kullanılır. Bir defa çalıştırılır ve sözleşmenin kodunu döndürür.
7 — Data: Sadece mesajlarda bulunur ve isteğe bağlı bir alandır.
8 — v,r,s: Bu değerler göndericinin kimliğini taşır ve gönderinin public key’inin elde edilmesini sağlar.
Hesaplar kısmında sözleşme hesapları arasındaki iletişimden bahsetmiştik. Fakat burada biraz daha detaylandırmak istiyorum. Sözleşmeler arasındaki işlemler genelde başka kod parçalarının çağırılmasıyla gerçekleşir. Hesaplar kısmında bahsettiğimiz gibi iletişimler her zaman harici hesaplar tarafından başlatılırlar. Sözleşmeler arası iletişimler harici hesaplar arasındaki iletişimin aksine bir metne dönüştürülmez ve kayıt altına alınmaz. Ethereum ağında var olurlar, yürütülürler ve yok olurlar.
Bloklar
Bloklar Bitcoin’de olduğu gibi bir miner tarafından oluşturulur. Ethereum’da bir bloğun oluşturulma süresi ~15 saniyedir.
Şimdi yandaki blok örneğindeki bazı ifadeleri inceleyelim. Blok yüksekliği, zaman damgası gibi ifadelere ek olarak işlemleri görebiliriz. Örneğin bu blokta işlemler 362 transactions + 160 contract internal transactions olarak ifade edilmiş. Bunlar yukarıda da bahsetmiş olduğumuz hesaplar arası işlemler. Hemen altında miner adresi, blok ödülü, zorluk ve boyut gibi ifadeleri görebiliyoruz. Ayrıca blok için kullanılan gas miktarı ve limitleri de görebiliriz. Bu ifadelere de yukarıda değinmiştik. Yakılan fee’ler (burnt fees) ise bloktaki tüm işlemler için ödenen fee’nin bir kısmıdır. Ethereum arzını sınırlandırmak adına son güncellemelerden biriyle sisteme dahil edilmiştir. Blok ödülü kısmına dönecek olursak 2 + 2.3–1,53 ifadesini görebiliriz. Buradaki 2 yeni basılan blok ödülüyken 2,3 blok fee’lerinden oluşur -1,53 ise yakılan fee’leri ifade eder. Bu işleme deflasyon denir. Daha sonraki yazılarımızda bu konuya da değineceğiz fakat kabaca bilgi vermek gerekirse enflasyon ifadesinin karşılığıdır. Bu durumu piyasadan yüksek miktarda altının çekilip yok edilmesine benzetebilirsiniz. Altın arzı talebi karşılayamayacağı için bir anda altının fiyatı artacaktır. Extra data miner tarafından bloğa eklenebilecek datadır.
Bu kavramlara ek olarak nonce, parent hash ve hash ifadeleri yer almaktadır. Bu kavramlara yabancıysanız bir önceki yazımızı inceleyebilirsiniz.
Şimdi ilk defa değineceğimiz bazı önemli kavramlara gelelim:
Bitcoin ile Ethereum arasındaki farklara değinirken uncle/ommer bloklara da değinmiştik. Buradaki örneğimizde sha3uncles ifadesi mevcut bloğun ommers’lerinin listesidir.
StateRoot (Durum Kökü)
Ethereum’un Bitcoin’in aksine durum tutan (stateful) bir yapı üzerine kurulduğunu söylemiştik. Ethereum’un global durumu içerdiği hesaplar ve bu hesapların durumlarının eşleşmesiyle oluşur. Bu eşleşmeler Merkle Particia Tree’de tutulur. İşte bu Merkle Tree’nin root’u StateRoot’tur.
Şekilde de görüldüğü gibi stateRoot açıldığında içerisinde hesap — hesap durumu eşleşmelerinin olduğu bir merkle tree ortaya çıkar. Hesaplar başlığında hesap durumunun Nonce, Balance, codeHash ve storageRoot gibi kavramları barındırdığını söylemiştik. StorageRoot da hesabın kendi verilerini yine bir merkle tree’de tuttuğu için burada da görüldüğü gibi iki merkle tree iç içe tutulmuş olur.
TransactionsRoot
Blokta tutulan bir diğer kök ise transactionsRoot’tur. Bu kökte blokta bulunan tüm işlemlerin bir listesi yer alır. İşlemlerin ne gibi özelliklere sahip olduğunu yukarıda incelemiştik.
ReceiptsRoot
Son merkle tree’miz ise ReceiptsRoot’tur. Bu root’u işlemlerin dekontu gibi düşünebiliriz. Transactions Root işlemleri nonce, gas, value gibi değerlerle tutarken Receipts Root önceki işlemlerin durumunu, kümülatif olarak gas tüketimini ve log işlemerini tutar. (log işlemlerine detaylı olarak değineceğiz.)
Merkle Tree konusunu detaylı olarak incelemek için: Merkle Tree yazımıza ve değerli hocamız Doğa Özcan’ın yazısına bakabilirsiniz.
Etheraum’da Hash işlemleri için Bitcoin’den farklı olarak Keccak256 fonksiyonu kullanılır.
Bazı denemeler yapabileceğiniz bir simülasyon.
Log
Log işlem kaydı gibi düşünülebilir. Ağda yapılan tüm işlemlerin kaydını tuttuğumuz bir günlük gibidir. Ethereum’da logger’ın hesap adresi ve logger’ın yaptığı işlemler tutulur. İşlem kaydı sırasında anlık olarak çok sayıda işlem yapılabileceği için yine hash fonksiyonlarıyla çalışan bloom filtresi kullanılır.
Yüzeysel olarak bloom filtresinden bahsetmek gerekirse M sayıda hash fonksiyonu ve N uzunluğunda bir liste oluşturulur. Veri bu fonksiyonlara sırayla sokulur. Elde edilen hash değeri index olarak kullanılarak listedeki ilgili yere bakılır. Bu yerde 0 değeri varsa veri bloom filtresinden geçer ve daha önce kaydedilmedi olarak döndürülür. Ancak o index’teki değer 1 ise filtre kesin olarak bu kaydın daha önce alınıp alınmadığını döndermez. Sadece olasılıksal olarak bir sonuç verir. (İşlemlerin hızlı yapılması gerektiğinden Hashmap işlemlerindeki kümelenme problemine çözüm sunmaz. Her zaman O(1)’de çalışır.)
Hashmap ve hash konuları için ilgili yazımızı inceleyebilirsiniz.
Bloom Filter ile ilgili detaylı bilgi için inceleyebilirsiniz.
EVM (Ethereum Virtual Machine)
Peki gelelim Ethereum bilgisayarının işlemlerinizi nasıl çalıştırdığına. İşlemleriniz Ethereum Virtual Machine (EVM)’de çalışır. EVM dağıtık olarak ağdaki birçok bilgisayarda tutulur ve işleminizi yapacak kişi işleminizi EVM’de çalıştırır. Hesaplar konusunda değindiğimiz codeHash ve işlemler başlığındaki init kavramlarına burada değineceğiz.
Sözleşme hesapları bir kod parçasıdır ve EVM tarafından derlenir ve çalıştırılır. EVM’nin kendine özgü bir bilgisayar dili vardır. Ancak biz bu dilde kod yazmak yerine Solidity gibi daha gelişmiş dillerde kodlarımızı yazarız. EVM bu kodlarımızı derleyerek (Solc compiler ile) BYTECODE dediğimiz yapıya dönüştürür ve çalıştırabileceği hale getirir. İnit kavramı da bu kodu çağıran bir kod parçasıdır ve daha önce de dediğimiz gibi bir defa çağrıldıktan sonra atılır. Ayrıca Solidity’de yazdığımız kodun bir çıktısı da ABI (Abstract Binary Interface)’dir. Bu kod frontend dediğimiz kullanıcı ile iletişim kurulan kullanıcı arayüzü yapısında kullanılır.
EVM kodları çalıştırmak dışında yine bir bilgisayar gibi verileri de kaydeder. Bu kayıt işlemi yine bilgisayarlarımızda olduğu gibi iki şekilde yapılır: Storage adını verdiğimiz ve verilerin ağda kalıcı olarak tutulduğu bir bölümü kullanabileceğimiz gibi memory adını verdiğimiz ve geçici verileri tuttuğumuz bir bölümü de kullanabiliriz. Örnek olarak bir banka uygulamasında müşteri bilgilerini silinmemek üzere storage’ta tutarken sisteme giriş yapan bir kullanıcının o anki işlemlerini yapabilmek adına hesap numarasını geçici olarak memory’de tutabilirsiniz. Kullanıcı çıkış yaptığında işlemleri bitmiş olacak ve tuttuğunuz hesap numarası değeri silinecektir. (Her giriş yapan kullanıcı için storage’ta yeni bir veri yapsaydık çok kısa sürede çok yüksek miktarlar ödememiz gerekirdi :) (Burada kullanıcının sisteme kaydolmasından değil de sadece girişi yapmasından bahsettiğime dikkat ediniz.))
Memory’de tuttuğumuz veriler işlemlerimiz bittikten sonra silineceği için bu verileri tutmanın maliyeti düşüktür. Buna karşın storage’ta tuttuğumuz veriler biz silinmesini isteyene kadar silinmeyeceği için maliyet bakımından pahalıdır. Ethereum ağında silme işlemlerinin tutulan verinin boyutunu küçülttüğü için teşvik edildiğini ve ücretsiz olarak yapıldığını unutmamak gerekir.
Ayrıca işlemlerin kendileri için belirlenmiş gas değerlerinin yürütme sırasında adım adım harcandığına değinmiştik. Gas yetersiz olduğunda işlem iptal edilir ve ne hesap durumunu ne de dolayısıyla Ethereum’un global durumunu değiştirmezdi. Bu sebeple substate denilen bir yapıda işlemin durumu adım adım kaydedilir. Eğer gas yeterli olursa ve substate geçerli durumu güncellemek için kullanılır ve yok edilir. Eğer geçersiz olursa tamamen silinir ve ana duruma hiçbir güncelleme yapılmaz. Ayrıca substate geri ödeme bakiyesi de burada tutulur. Storage’tan bir veri sildiğinizde bu işlem için harcanan gas değerinin geri iade edildiğini belirmiştik. İşte geri ödeme bakiyesi sıfırdan başlayarak eğer varsa her silme işleminiz için bir bir artar ve işlemin sonunda silme işlemlerini geri iade eder.
Ayrıca EVM minimum gas (instrinsic) belirlenmesi, herhangi bir işlemin yürütülebilir (gerekli şartları sağlayıp sağlamadığı) olup olmadığının belirlenmesi gibi işlemleri de yapar.
Intrinsic Gas Belirlenmesi
21000 gas default olarak belirlenir ve işlem maliyetleri bu değerinin üzerine eklenir. Bir işlem yapmak istediğinizde işlemin kodunun ya da işlemle birlikte gönderdiğiniz data’nın byte koduna bakılır. Bu kodda her 0 değeri için 4 gas her 1 değeri içinse 68 gas alınır. Ayrıca işleminiz sözleşme oluşturucu işlemse ekstra 32000 gas daha dahil edilir.
Daha sonra kullanıcıdan mesajının value değerine ek olarak intrinsic gas değeri talep edilir. Daha önce değindiğimiz gibi gas peşin olarak alınır ve işlemler yapıldıkça harcanır. Gas bittiğinde işlemler durur. Peşin olarak almak için de aşağıdaki gibi mesaj içeriğinizle gas fee’niz toplanır ve hesabınızdan bu toplam çekilmeye çalışılır. Örneğin işleminizin gas limitini 50000 olarak belirlediniz. Gas price’ınızı da 20 gwei olarak belirlediğinizi düşünelim. (gas price değeri de ağın yoğunluğuna göre belirlenir. Ethereum ağında aynı işlemi ağın daha az yoğun olduğu bir saatte yapmanız durumunda daha az fee ödeyebilirsiniz.) Mesajınız’ın value’si de 0,05 ether olsun. (Örneğin bir sözleşme yazdınız ve başlangıç balance değerinin 0,05 ether olmasını istiyorsunuz.) Bu durumda hesabınızdan çekilecek tutar aşağıdaki formülle hesaplanır.
Belirlediğiniz gas limitin intrinsic gas’den büyük olduğunu düşünelim. Bu durumda gas limit değerinizden instrinsic gas çıkarılacak ve kalan gas tutarı belirlediğiniz gas price ile çarpılarak ethere dönüştürülerek hesabınıza iade edilecektir.
Ayrıca işlemleriniz sırasında çalıştırmak istediğiniz kodlar hata verebilir. Bu gibi durumlarda hataya kadar harcanan gas gitse de kalan gas tarafınıza iade edilir. Bu durum Ethereum’un önceki sürümlerinde geçerli olmasa da Bizans güncellemesi ile kullanıcıya sunulmuştur.
Özet
İlk olarak Ethereum’un Bitcoin’den farklı olarak hem durum tuttuğunu hem de dağıtık olarak çalışan bir bilgisayar gibi çalıştığına değindik. Daha sonra Ethereum’u parçalara ayırdık ve bu parçalar üzerinden sistemi anlamaya çalıştık. Hadi şimdi bir senaryo üzerinden parçaları birleştirelim.
Diyelim ki siz Ethereum ağında bir kullanıcısınız ve bu bilgisayara bir işlem yaptırmak istiyorsunuz. Öncelikle bu ağa (bilgisayara) bağlanabileceğiniz bir hesaba ihtiyacınız olacak. Ne demiştik iki tür hesap vardı. Siz herhangi bir kod parçası olmadığınız için sizin hesabınız Harici hesap olacak. Size verilen bu hesabın da bazı özellikleri olacak: Örneğin sahip olduğunuz etheri tutan balance değeri
Evet artık bir hesabınız var ve bir işlem yapabilirsiniz. Ne demiştik, Ethereum’da bir işlem ya iki harici hesap arasında yapılır ya bir harici hesap ile sözleşme hesabı arasında yapılır ya da iki sözleşme hesabı arasında yapılır. Şimdi gelelim yapmak istediğiniz işleme. Ethereum ağında iki tür işlem yapabileceğinizi söylemiştik. Bunlardan ilki mesajlardı. İkincisi ise Sözleşme oluşturucu işlemlerdi. Diyelim ki siz yeni bir sözleşme oluşturmak istiyorsunuz. Öncelikle işleminizin geçerli bir işlem olup olmadığı kontrol edilir. Bu sırada hesap adresinizin geçerli olup olmadığına ve işleminizin imzalanıp imzalanmadığı gibi durumlara bakılır.
Daha sonra işlemleriniz sırasında harcanacak olan gas fee’yi önceden belirlemeniz gerekir. Belirlediğimiz gas fee ve varsa işlemimizin value’si hesabımızdan çekilir. Ardından bir substate oluşturulur ve işlemleriniz belirlediğiniz gas fee her adımda harcanarak yapılmaya başlanır. İşlem sonuçlarınız da bu substate’e kaydedilir. Eğer gas fee’niz tüm işlemlerin yapılmasına yetecek kadar fazlaysa tüm işlemleriniz yapılır, substate kullanılarak hesap durumunuz ve global durum güncellenir ve kalan fee tarafınıza iade edilir.
Sonuç olarak yeni durum bir merkle tree’de geçerli zincirin en güncel bloğuna yazılır. Ethereum global durumunun hesaplar ve hesap durumlarının tutulduğu bir yapıdan oluştuğunu unutmamak gerekir. Yani Ethereum’un en güncel durumu içerdiği hesapların güncel durumlarının toplamıdır diyebiliriz.
Günün sonunda gerekli şartları sağlamanız durumunda yeni bir sözleşme oluşturursunuz. Bu sözleşmenin de kendi hesabı ve balance değeri vardır. Eğer mesajınızla birlikte value olarak bir miktar ether gönderdiyseniz bu balance değeri başlangıç olarak bu etherleri tutar. Son olarak init çalıştırılır ve kodunuz dönderilir. Artık sözleşmeniz ile ağdaki tüm hesaplar iletişime geçebilir.
Belirlediğiniz gas işlemlerinizin bitmesine yetmezse işleminizin tamamı iptal edilir ve ne hesabınızın dolayısıyla ne de Ethereum’un global durumunda herhangi bir durum güncellemesi yapılmaz.
Sonuç olarak Ethereum’u parçalara bölerek inceledik. İlk okumanızda sistem biraz karışık gelebilir. Ancak kavramları not alarak tekrar okumanız durumunda birçoğu şey daha iyi oturacaktır. Ayrıca lütfen soru sormaktan çekinmeyin. Her zaman mail adreslerimden veya sosyal medya hesaplarımdan bana ulaşabilirsiniz.
Ethereum’un yakın zamanda Proof of Stake’e geçiş yapmayı planladığını da unutmamak gerekir. Bu geçişin ardından yeni bir Ethereum Nasıl Çalışıyor? yazısı bizi bekliyor olabilir. :)
Murat Can Baştuğ