17 Mart 2019 Pazar

Ethereum Private POA (Proof-of-Authority) Network Kurmak

Blockchain üzerinde kurumsal uygulamalar oluşturmak için en çok kullanılan Blockchain teknolojilerinden birisi olarak Ethereum karşımıza çıkıyor. Çok kullanılmasının en önemli nedenleri programlanabilir olması, hem data hemde para’yı (Value) tutabilmesidir. 

Tek bir Ethereum adresinde ayrı ayrı birimlerden ör: USD,TL,EUR gibi düşünülebilir para tutulabiliyor, bu ise operasyonların tek bir adres üzerinden yapılabilmesinden dolayı önemli bir esneklik sağlıyor. Yani size para gönderecek birisinin adresinizi ve hangi birimden para göndereceğini bilmesi yeterli oluyor.

Kurumsal uygulamalarda Ethereum network’ü kurmak için dikkat edilmesi gereken en önemli husus consensus mekanizmasının doğru kurulmasıdır. Consensus türkçeye çevirirsek fikir birliği mekanizması demektir. Yani oluşturulan blokların nasıl oluşturulacağının ve zincire kabul edilebilmesinin şartlarının ne olacağının kararının verilmesidir.

Enerji sarfiyatının minimuma indirilmesi için consensus mekanizmasının doğru seçilmesi gerekmektedir. Private network tarafında kullanılan consensus mekanizması Proof-of-Authority olarak kurulmalıdırEthereum engine olarak Clique engine kullanılmalıdır.

Private network olarak adlandırılan bu networkler genellikle bir kurum tarafından kullanılmak için veya birden fazla kurumun aralarında kullanmak için kurdukları network’tür. Dışarıdan müdahelelere kapatılması veya sınırlandırılması gerekmektedir.

Proof-of-Authority mekanizmasında Bloklar  miner(madenci)  olarak çalışan düğüm tarafından oluşturuluyor. Networkü ayağa kaldırırken(genesis.json içerisinde) blokların Chain'e (zincire) eklenebilmesi için birden fazla node(düğüm) tarafından onaylanmasını isteyebilirsiniz.  Bu düğümlere sealer deniyor. Yani imzalayan mühürleyen anlamında. Bu mühürler olmadan blok ethererum zincirine eklenmiyor. Örnek vermek gerekirse bir kişi A bankasından işlem yapıyor ve işlemin gerçekleşmesi içinde B bankasının onayı gerekiyor. A bankasını ve B bankasını network'te sealer olarak tanımlarsanız A bankası bloğu oluşturup yollasa bile B bankası onaylamadan işlem gerçekleşmiş sayılmaz. Doğal olarak B bankası onaylayınca ilgili işlem gerçekleşir. Hatta araya birde merkez bakası gibi bir mekanizma koyup merkez bankası onaylamadan işlem  gerçekleşmez derseniz merkez bankasını da sealer olarak tanımlamalısınız.  Gördüğünüz gibi işlemler onaycılar mekanizmasından geçtikten sonra zincire ekleniyor ve gerçekleşiyor. İşin güzel tarafı bütün bunlar gerçekleşirken çok karmaşık yapıların mimarilerin içinde boğulmanıza gerek kalmıyor. Sadece bir düğümü ayağa kaldırmak ve network'e dahil etmek yeterli oluyor.

Ben kurulum yaparken resmi Ethereum implementasyonlarından Go dili ile geliştirilen Go Ethereum implementasyonunu kullandım. Go Ethereum kurulumunu https://ethereum.github.io/go-ethereum/install/ adresinden takip edebilirsiniz. 

Private network kurmak için öncelikle genesis.json dosyasını oluşturmalısınız. genesis.json dosyası düğümler ilk ayağa kalkarken ihtiyaçları olan configurasyonu vermeniz içindir. 

Genesis.json dosyasını oluşturmak için puppeth kullanabilirsiniz.  Github üzerinden puppeth https://github.com/puppeth/go-ethereum kodunu indirip build ederseniz puppeth için çalıştırılabilir dosya oluşmuş olacaktır.

Ben MACOS üzerinde çalıştığım için komutları ve kurulumları MACOS'a göre yaptım. Linux kurulumlarıda aşağı yukarı aynı şekilde yapılıyor belki windows üzerinde ufak farklılıklar olabilir. 

https://github.com/puppeth/go-ethereum  indirdiğim kodu build edip bin klasöründe ihtiyacım olan dosyaların oluştuğunu gördüm. Burada dikkat etmeniz gereken birkaç noktayı söyleyeceğim. Go implementasyonunu indirdiğim için build yaparken Go engine'e ihtiyacınız olacaktır. Öncesinde

brew install go
komutu terminalde çalıştırarak go kurulumu yapmanızı öneririm. problem çıkarsa sudo ile denemenizi öneririm.

Ben yıllarca windows üzerinde çalıştığım için MACOS üzerinde bunları yaparken biraz zorlanıyorum eğer linux üzerinde  çalışıyorsanız  bunlar sizin için çocuk oyuncağı olacaktır.

terminal üzerinde  go ethereum/build/bin klasöründe puppeth'i run ediyorum.

L52850MAC:~ osmansonmez$ cd go-ethereum/build/bin

L52850MAC:bin osmansonmez$ puppeth


Network name'i girip devam ediyorum. İsim olarak newgenesis veriyorum.




2. seçenek ile devam ediyorum.


1. seçenek ile devam ediyorum.


2. seçenek ile yani proof-of-authority seçeneği ile devam ediyorum.
ve kalan sorulara  devam ediyorum. ilk soru blok üretme süresi ne kadar olacak yani kaç saniyede bir blok üretilecek ben 5 saniye olarak veriyorum. 2. soru ise hangi hesaplar sealer olacak. Yani A bankası ve B bankasının public key'leri yani adreslerini burada gireceğiz. bunun için 2 tane ethereum adresi oluşturmamız gerekiyor. 
Adres oluşturmak için ethereum go'nun geth komutunu kullanacağız. Bunun için yeni bir terminal açmamız lazım. Terminalde geth komutları ile 2 adet ethereum hesabı oluşturacağız.



Ethereum hesabı oluşturmak için kullanacağımız komut geth account new komutudur.
komutu terminalde yazdığımızda bize hesap için şifre sormaktadır.  şifreyi girdikten sonra bize hesabı oluşturmaktadır.


ikinci adreside aynı şekilde oluşturalım ve bunları puppeth'a girelim.
Adres 1 :df6cc60abfdfdef40be53c75962b666a9febd3ef
Adres 2 :29e97a93c40d91a6cc86a03668bebecc3b989494


Tekrar puppeth ekranına dönelim.


puppeth üzerinden iki adet hesabı sealer yaptık aynı zamanda bu iki hesaba sabit olarak bir miktar ethereum yüklemesini söyledik.

Devam eden sorular başka prefunded hesaplar olacak mı bu soruya no yanıtını verdim ve benden network Id 'yi istedi. NetworkId olarak 1881' i verdim.  NetworkId değeri aynı network'e dahil olmak isteyen node'lar için önemli bir değerdir.

Daha sonra Manage existing genesis ve Export genesis configuration seçenekleri ile devam edilirse
puppeth içerisinde yer alan default klasöründe newgenesis.json dosyasının oluştuğunu göreceksiniz ve içeriği aşağıdaki gibi olacaktır.

{
  "config": {
    "chainId": 1881,
    "homesteadBlock": 1,
    "eip150Block": 2,
    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "eip155Block": 3,
    "eip158Block": 3,
    "byzantiumBlock": 4,
    "constantinopleBlock": 5,
    "clique": {
      "period": 5,
      "epoch": 30000
    }
  },
  "nonce": "0x0",
  "timestamp": "0x5c8e4466",
  "extraData": "0x000000000000000000000000000000000000000000000000000000000000000029e97a93c40d91a6cc86a03668bebecc3b989494df6cc60abfdfdef40be53c75962b666a9febd3ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x47b760",
  "difficulty": "0x1",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "alloc": {
    "29e97a93c40d91a6cc86a03668bebecc3b989494": {
      "balance": "0x200000000000000000000000000000000000000000000000000000000000000"
    },
    "df6cc60abfdfdef40be53c75962b666a9febd3ef": {
      "balance": "0x200000000000000000000000000000000000000000000000000000000000000"
    }
  },
  "number": "0x0",
  "gasUsed": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
newgenesis.json dosyasını oluşturduk. Aslında işin en büyük kısmını tamamladık sayılır. Artık 2 node'lu network'ü ayağa kaldırmak kaldı. Ben tamamını localde ayağa kaldıracağım. Dilerseniz kubernetes, docker veya openshift ortamında da ayağa kaldırabilirsiniz. Ben çok uzatmamak adına ilk etapta local'de ayağa kaldıracağım.

Öncelikle boot node ayağa kaldıracağım. Boot node nedir?
Boot node network'te bulunan node'ların birbirlerini bulabilmeleri için ayakta olan kayıt nodu'dur.
Herhangi bir transaction veya miner rolü yoktur. Esasında olay ayağa kalkan herhangi bir node'un  boot node'a ben burdayın diye haber vermesidir.

Yeni bir terminal açıp boot node'u ayağa kaldıralım.

komutlar : 

1bootnode -genkey boot.key
2- bootnode -nodekey boot.key -verbosity 9 -addr :30304

Komutları yazdıktan sonra  localde 30304 portundan boot node ayağa kalkmış olacaktır. 




bootnode bilgisini  diğer node'larla paylaşmak için enode adress bilgisini oluşturmamız gerekiyor.
enode bilgisi aşağıdaki gibi bir bilgi olmalıdır.

"enode://<your node public key>@<your node public ip>:30304"

node public key bilgisini aşağıdaki gibi oluşturmalıyız.

boot.key dosyasını vererek aşağıdaki komutu çalıştıralım.

bootnode -nodekey boot.key -writeaddress

komutu çalıştırınca bize yeni bir public key oluşturacaktır.

b19a42e8bf96953a0e365fbfbea7fba8aab55a057c086d12bd8584115e6e8b66e9a98d739e021eba2fb4b6f3eb451ffeef1287950cd596a80c88fbddc26ea6dc


yani boot node adresimiz:

enode://b19a42e8bf96953a0e365fbfbea7fba8aab55a057c086d12bd8584115e6e8b66e9a98d739e021eba2fb4b6f3eb451ffeef1287950cd596a80c88fbddc26ea6dc@127.0.0.1:30304

şeklinde olacaktır.


Şimdi Node'ları ayağa kaldıralım. Bunun için iki adet farklı klasöre ihtiyacımız olacaktır.

Node1 ve Node2 olarak 2 adet klasör açalım.

ilk komutumuz ilk node'u  yani Node1'i başlayacan konuma getirmek olacaktır. Burada daha önce oluşturduğumuz newgenesis.json dosyası gerekli olacaktır.

newgenesis.json dosyasını node1 ve node2 klasörlerine kopyalayalım. 

yeni bir terminal açalım ve node1 ve node2'yi ayarlayalım.

komut1 : geth --datadir node1/ init node1/newgenesis.json
komut2:  geth --datadir node2/ init node2/newgenesis.json

Komutları çalıştırınca node1 ve node2 klasörlerinde geth, keystore gibi klasörlerin oluştuğunu göreceksinizdir.

şimdi node'ları ayağa kaldırma zamanı:)

Hatırlıyorsanız 2 node'u  sealer olarak oluşturacaktık ve ilk başta newgenesis.json dosyasını oluştururken 2 adet ethereum hesabı oluşturmuştuk. Hesapları oluştururken 
şifre vermiştik. Şimdi node'ları ayağa kaldırırken bu hesapların bilgileri ve şifresi gerekiyor. Sebebi ise node transaction'u onaylarken vereceğimiz hesap ile onaylayacak. Yani mühürleyecek.

Hatırlıyorsanız hesapları geth komutu  ile oluşturmuştuk. hesaplar oluşunca geth'in kurulduğu ethereum klasöründe  bulunan keystore  klasöründe hesapların bilgilerinin hesap ismiyle bir dosyada tutulduğunu göreceksinizdir. 

29e97a93c40d91a6cc86a03668bebecc3b989494 hesabının keystore dosyasını node1/keystore altına,
df6cc60abfdfdef40be53c75962b666a9febd3ef hesabının keystore dosyasını node2/keystore altına kopyalayalım.

node1/ ve node2/ altında bu hesapların şifrelerini tutmak için password.txt isimli bir dosya oluşturalım ve ilgili hesabın şifresini bu dosyaya yazalım.

Node1'i ayağa kaldırmak için komutu oluşturalım.

geth --networkid 1881 --datadir "node1/" --bootnodes 'enode://b19a42e8bf96953a0e365fbfbea7fba8aab55a057c086d12bd8584115e6e8b66e9a98d739e021eba2fb4b6f3eb451ffeef1287950cd596a80c88fbddc26ea6dc@127.0.0.1:30304  --port  30305 --ipcdisable --syncmode full --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcport 8546 --unlock 29e97a93c40d91a6cc86a03668bebecc3b989494 --password node1/password.txt --mine  --keystore 'node1/keystore' console

komutu çalıştırınca node1 ayağa kalkar fakat herhangi bir mine işlemi yapmadığını ve blok oluşturmadığını göreceksinizdir.  Sebebi ise bütün sealer node'ların ayakta olmamasıdır.

ikinci sealer node yani node2'yi ayağa kaldıralım.

geth --networkid 1881 --datadir "node2/" --bootnodes 'enode://b19a42e8bf96953a0e365fbfbea7fba8aab55a057c086d12bd8584115e6e8b66e9a98d739e021eba2fb4b6f3eb451ffeef1287950cd596a80c88fbddc26ea6dc@127.0.0.1:30304'  --port  30306 --ipcdisable --syncmode full --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcport 8547 --unlock df6cc60abfdfdef40be53c75962b666a9febd3ef --password node2/password.txt --mine  --keystore 'node2/keystore' console

İki adet sealer node ayağa kaldırdık. İsterseniz bir tanede transaction node ayağa kaldıralım. Yani mine işlemi yapmasın.

geth --networkid 1881 --datadir "node3/" --bootnodes 'enode://b19a42e8bf96953a0e365fbfbea7fba8aab55a057c086d12bd8584115e6e8b66e9a98d739e021eba2fb4b6f3eb451ffeef1287950cd596a80c88fbddc26ea6dc@127.0.0.1:30304'  --port  30307 --ipcdisable --syncmode full --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcport 8548 --unlock console


2 adet miner bir adet transaction node ile  networkümüzü kurmuş bulunuyoruz.

Networkü kurarken ufak tefek problemlerle karşılaşmış olabilirsiniz ama yinede yılmadan çalıştırmaya çalışınız bir problem yaşarsanız lütfen sonmezosman@gmail adresine istediğiniz zaman mail atabilirsiniz.