Python ile Enerji Analizi (barissanli.com/python)

Baslangic
Python'a Giris - Petrol fiyat modeli
Gelecek/Futures fiyatları indirme
Kisa kodlama: Monte Carlo ile Pi hesabi
Oil price analysis(English)
Kayitzinciri(blockchain) Proof of work
Petrol fiyat analizi
Monte Carlo ile Petrol fiyat tahmini
Enerji depolama simulasyonu
Turkiye araba projeksiyonu
pow

Python ile Kayıtzinciri (Blockchain)'de İş Kanıtı(Proof of Work) örneği

Barış Sanlı, www.barissanli.com , barissanli2@gmail.com

Bu kodu yazalı sanırım 1 yıldan fazla olmuş. Aşağıdaki kod sıra ile SHA256 (şaa256 okunur) kullanarak, metinlerin özetini çıkarır. Sonra ProofOfWork (İş kanıtı)nda yer alan bulmacayı çözmeyi gösterir.

Daha önce Dünya Enerji Konseyi'nde verdiğim Kayıtzinciri/Blockchain dersinde demo olarak kullanmıştım [link]

Önce Kütüphaneler

Kodumuza başlamadan önce iki kütüphaneyi yükleyeceğiz.Biri hashlib diğeri de time. Asıl işlemleri hashlib yapıyor, time ise sadece süre ölçmekte kullanılacak

In [1]:
# özüt çıkarmak için
import hashlib
# süre de ölçelim
import time

Özütler

Özütleri anlaması biraz zor olabilir. Özüt dediğimiz tek taraflı bir fonksiyondur. Yani girdinin DNAsını çıkarır. Bu DNA, 16lı düzende bir sayı dizinidir. Ama DNA'dan girdiyi bulamazsınız. Sadece aynı girdiyi kullanarak, aynı DNA'yı üretirsiniz.

Mesela Windows şifreleri açık halde tutmaz. Onların DNA'larını yani SHA256 gibi özütlenmiş hallerini tutar. Ancak şifre doğru girilirse aynı SHA256 üretilir, bu da kaydedilmiş SHA256 kodu ile karşılaştırılır, doğruluğu tespit edilir.

  • sha256(metin) ----> sayıdizini

Bunun için kullanacağımız fonksiyon hashlib.sha256

Dikkat edilmesi gereken nokta ise metinden önce b konarak, unicode metinin özütlenebilir dizine çevrilmesidir

In [23]:
hashlib.sha256(b'baris')
Out[23]:
<sha256 HASH object @ 0x7f06f89d2e68>

İsterseniz bir de b olmadan deneyelim

In [24]:
hashlib.sha256('baris')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-9dfe76afb9d3> in <module>()
----> 1 hashlib.sha256('baris')

TypeError: Unicode-objects must be encoded before hashing

Gördüğümüz gibi hata mesajı : Unicode-objects must be encoded before hashing" oluştu. Bu sebeple metinlerin önünde b yi unutmayalım

Şimdi ise metinin okunabilir, yani 16lık sayı dizinini görmeye çalışalım, bunun için de hexdigest alt fonksiyonunu çağırmamız yeterli olacaktır.

In [25]:
hashlib.sha256(b'baris,67').hexdigest()
Out[25]:
'00ab7a19005385b58909cf6a7b843929ef4c3d42284fda1aa3808c33fbca8c9a'

Bu sayı dizininden girilen metnin "baris,67" olduğunu bulamayız. Tek tek tüm karakter ve sayıları denememiz gerekir. Ancak buraya "baris,67" yazan yine aynı metni girdiğinde aynı sayı dizinini oluşturur.

İş Kanıtı(Proof of Work) - Zorluk Derecesi

Bitcoinde de yer alan Proof of Work, İş kanıtı veya ispatı, aslında bir emek sarfedildiğinin ispatı olarak da anlaşılabilir. Ne için emek harcanmıştır? Bir karakter dizininden özel bir DNA kodu üretmek için.

Özütlerin en önemli özelliği, tahmin edilemez olması gibidir. Yani girdiyi bir karakter veya bir bit değiştirince sonuç inanılmaz değişir.

İnanmayanlar için deneyelim.

Önce 0 girelim sonra 1...

In [27]:
hashlib.sha256(b'0').hexdigest()
Out[27]:
'5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9'
In [28]:
hashlib.sha256(b'1').hexdigest()
Out[28]:
'6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b'

Yani kasa hırsızlığı yöntemleri ile özüt tahmin edemezsiniz. Yani rakamlara bakarak hedefe yaklaşıp yaklaşmadığınızı söyleyemezsiniz

In [31]:
hashlib.sha256(b'Bu metin 9 Subat Cumartesi gece 22:07:32 de Baris Sanli tarafindan yazildi').hexdigest()
Out[31]:
'baf28083d14368ab3a70a562d07ffad5f8d0a7519ba8429aba472f0a6be69489'

Şimdi ise sonuna sadece . yani nokta koyalım bakalım sonuç ne olacak

In [32]:
hashlib.sha256(b'Bu metin 9 Subat Cumartesi gece 22:07:32 de Baris Sanli tarafindan yazildi.').hexdigest()
Out[32]:
'71162bc4c0c0603f685ba33d29aec2da3dea8efe776a2a29aa802fa99ba19639'

Bir metinde baf..... ile başlayan bir DNA elde ederken, 1 nokta en sona koyunca sonuç inanılmaz değişti 711...... li bir diziye dönüştü

Bulmacasını çözeceğimiz metin, kendi web sitemin ismi olacak. Sıra ile bu metinden sonra bir sayı ekleyeceğiz. Çıkan sonuçların ilk karakterlerine bakacağız. zorluk ta belirtildiği sayıda sıfır (0) ile başlıyorsa, bulmacayı çözdük demektir. Dikkat etmeniz gereken zorluk sayısı 6'nın üzerine çıktıkca bekleme artacaktır.

Aşağıdaki kod ne yapıyor?

  • Bulmaca metnini belirliyor : kayit="www.barissanli.com"
  • Sonra zorluk derecesini, yani oluşan DNA'nın ilk kaç karakterinin 0 olması gerektiğini. Bu örnekte aradığımız ilk 5 karakteri 0 olan bir DNA dizini bulmak.
  • Sonra 1'den 100,000,000 yani 100 milyona kadar tüm sayıları sıra ile deneyerek, DNA'larının ilk karakterlerine bakacağız. İstediğimiz kadar 0 var ise program sonlanır
    • www.barissanli.com,1 --> a53111bd3bb5d77ac956bbbb19641a3da302b0e6ffcad5497d6ebf22ae969eda
    • www.barissanli.com,2 --> 4ad270acc15f2db5ca613a566e0e22a94d245116280f35401344d248713244df
    • ...... bir sürü deneme sonrasında
    • www.barissanli.com,301364 --> 00000f326f65c5a935dc9de59cf58c34c3f0e0fe83b61cbdc67ec36a6ed7904d
In [38]:
hashlib.sha256(str("www.barissanli.com,1").encode("utf-8")).hexdigest()
Out[38]:
'a53111bd3bb5d77ac956bbbb19641a3da302b0e6ffcad5497d6ebf22ae969eda'

Sabit metin ve zorluk derecemizi belirleyelim

In [39]:
kayit="www.barissanli.com"
zorluk=5

Şimdi 100 milyona kadar sayıları tek tek koyarak özüt alıp sonuca bakalım.

Eğer beş sıfır (00000) yani zorluk"0"* ile başlayan bir metin var ise

  • ozet[0:zorluk]==("0"*zorluk)

o zaman programı sonlandır, cevabı yaz

In [37]:
for i in range(0,100000000):
                mesaj=kayit+","+str(i)
                ozet=hashlib.sha256(str(mesaj).encode("utf-8")).hexdigest()
            
                if(ozet[0:zorluk]==("0"*zorluk)):
                        print(mesaj+"   Hash="+ozet)
                        break
www.barissanli.com,301364   Hash=00000f326f65c5a935dc9de59cf58c34c3f0e0fe83b61cbdc67ec36a6ed7904d
In [40]:
hashlib.sha256(str(mesaj).encode('utf-8')).hexdigest()
Out[40]:
'00000f326f65c5a935dc9de59cf58c34c3f0e0fe83b61cbdc67ec36a6ed7904d'

Zorluk derecesi ve süre

Bu sıfır bulma bulmacasında zorluk derecesi arttıkça daha fazla zaman harcanıyor, yani daha fazla bilgisayar gücü ve kWh, enerji. Şimdi yukarıdaki düzeneği bir fonksiyon haline getirerek önce işimizi kolaylaştıralım

Fonksiyonumuzun ismi ProofOfWork ve iki girdisi var msg ve zorluk

In [62]:
def ProofOfWork(msg, zorluk):
    start=time.time()
    for i in range(0,100000000):
                mesaj=msg+","+str(i)
                ozet=hashlib.sha256(str(mesaj).encode("utf-8")).hexdigest()          
                if(ozet[0:zorluk]==("0"*zorluk)):
                        print(mesaj+"   Hash="+ozet)
                        end=time.time()
                        print(zorluk,". zorluk derecesinde toplam zaman", (end-start)," saniye")
                        return i
                        break

Şimdi "baris" mesajını, 2. zorluk derecesi yani baştaki ilk iki karakter 0 olacak şekilde çalıştıralım

In [63]:
ProofOfWork("baris",2)
baris,67   Hash=00ab7a19005385b58909cf6a7b843929ef4c3d42284fda1aa3808c33fbca8c9a
2 . zorluk derecesinde toplam zaman 0.0025556087493896484  saniye
Out[63]:
67

Görüldüğü üzere 2 sıfır ile başlayan DNA veya özütü bulmak milisaniyeler mertebesinde zaman alıyor.

Şimdi 00 ile başlayan DNA bulma işinden 00000'la başlayan DNA bulmaya kadar geçen zamanlara bakalım

In [45]:
for zorluk in range(1,6):
    ProofOfWork("baris",zorluk)
baris,0   Hash=0a35925627b504b454ae29eb40dbe3fa04f75fb72dd457948b23839446953176
1 . zorluk derecesinde toplam zaman 0.006318330764770508  saniye
baris,67   Hash=00ab7a19005385b58909cf6a7b843929ef4c3d42284fda1aa3808c33fbca8c9a
2 . zorluk derecesinde toplam zaman 0.0010771751403808594  saniye
baris,2604   Hash=000ad897416ef73dfbc9378e1a2c0dc7f6424b5a254195063b76c537783697d6
3 . zorluk derecesinde toplam zaman 0.040496826171875  saniye
baris,109913   Hash=0000dcc0228940d7dc21a4a81a83f13b52cc7b40237297afb5d3da13a2ead210
4 . zorluk derecesinde toplam zaman 1.2077975273132324  saniye
baris,816526   Hash=0000022b0bff6852553a015228ddd8d5934b97a2dbcaf626f89118b6b219455f
5 . zorluk derecesinde toplam zaman 8.129325151443481  saniye

Dikkat ettiminiz mi? başında 4 sıfır olan metni bulmak 1.2 saniye sürerken, 5 tane sıfır olanı bulmak 8.1 saniye sürdü. Yani 1 sıfır eklemek tam 7 kat daha fazla zaman aldı.

Bitcoin'de iki blok yani kayıt arasındaki zaman azaldıkça, bulmaca zorluğu arttırılır. Yani daha çok sıfır olan bir bulmacanın çözülmesi istenir. Süre uzarsa da bu 0 sayısı azaltılır.

İşlem denemesi

Şimdi de bir işlem denemesi yapalım. Yani isim-web sayfası değil de bir işlem listesi oluşturarak, bunlardan DNA çıkaralım

Bir bloğu ikiye ayıralım, önce başı sonra da işlemlerin yer aldığı ana kısım yer alsın.

Bloğun başında:

  • sira -> kayıt sırası
  • ozut -> bir önceki kayıdın özütü olsun
  • denge -> denge ise daha önce aradığımız sayıda 0(sıfır) rakamlı özütü sağlayan rakam olsun. Yani bulmaca sonucu

İlk bloğumuz doğuş bloğu, yani herhangi bir öncüsü olmadığı için dilediğimiz rakamları seçebiliriz

In [59]:
sira=0
ozut=0
denge=0

Şimdi de kayıt oluşturalım

In [60]:
islem =  "Kayıt sırası:"+str(sira)+"\n"
islem+=  "Özüt:"+str(ozut)+"\n"
islem+=  "Denge:"+str(denge)+"\n"
islem+=  "-----------------------------\n"
islem+=  "1       Barış’tan Mehmet’e 10\n"
islem+=  "2       Ali’den Ayşe’ye 2\n"
islem+=  "3       Seyit’ten İbo’ya 5"
hashlib.sha256(islem.encode("utf-8")).hexdigest()  
Out[60]:
'b919eaa508582d537c0cdd7dd3803648afe2c755d6714c8858bb116cb42abfce'

Gördüğünüz gibi kayıdı sıradan özüt alma yaparsak rastgele DNA'sını oluşturuyor.

Bu doğuş özütü olsun şimdi bunu ekrana yazalım

In [61]:
print(islem)
Kayıt sırası:0
Özüt:0
Denge:0
-----------------------------
1       Barış’tan Mehmet’e 10
2       Ali’den Ayşe’ye 2
3       Seyit’ten İbo’ya 5

Daha önce yukarıda yazdığımız iş kanıtı kodunu kullanalım

In [82]:
zorluk=4
sira=1
ozut=0


for denge in range(0,100000000):
    islem =  "Kayıt sırası:"+str(sira)+"\n"
    islem+=  "Özüt:"+str(ozut)+"\n"
    islem+=  "Denge:"+str(denge)+"\n"
    islem+=  "-----------------------------\n"
    islem+=  "1       Barış’tan Mehmet’e 10\n"
    islem+=  "2       Ali’den Ayşe’ye 2\n"
    islem+=  "3       Seyit’ten İbo’ya 5"
    ozet=hashlib.sha256(str(islem).encode("utf-8")).hexdigest()
            
    if(ozet[0:zorluk]==("0"*zorluk)):
      print(islem+"\n\n\n  Hash="+ozet)
      break
        
ilk_blok=islem
ilk_ozut=ozet
Kayıt sırası:1
Özüt:0
Denge:2803
-----------------------------
1       Barış’tan Mehmet’e 10
2       Ali’den Ayşe’ye 2
3       Seyit’ten İbo’ya 5


  Hash=000009c3fe4cf834a0023fbb32327c29019af8535fa6fafbc9c3e56bdbb606f4

Yani yukarıdaki metinde, denge 65216 olunca tüm mesajın DNAsı 4 tane sıfır ile başlıyor.

Şimdi ikinci kayıdımıza geçerken bir önceki özütü bu kayıdın özüt satırına yerleştiriyoruz. Dikkat ederseniz işlemler de yeni işlemler oluyor.

In [83]:
zorluk=4
sira=2
ozut=ozet

for denge in range(0,100000000):
    islem =  "Kayıt sırası:"+str(sira)+"\n"
    islem+=  "Özüt:"+str(ozut)+"\n"
    islem+=  "Denge:"+str(denge)+"\n"
    islem+=  "-----------------------------\n"
    islem+=  "1       Ali’den Ayşe’ye 2\n"
    islem+=  "2       Barış’tan Mehmet’e 10\n"
    islem+=  "3       Seyit’ten İbo’ya 5"
    ozet=hashlib.sha256(str(islem).encode("utf-8")).hexdigest()
            
    if(ozet[0:zorluk]==("0"*zorluk)):
      print(islem+"\n\n\n   Hash="+ozet)
      break
        
ikinci_blok=islem
ikinci_ozut=ozet
Kayıt sırası:2
Özüt:000009c3fe4cf834a0023fbb32327c29019af8535fa6fafbc9c3e56bdbb606f4
Denge:131418
-----------------------------
1       Ali’den Ayşe’ye 2
2       Barış’tan Mehmet’e 10
3       Seyit’ten İbo’ya 5


   Hash=0000237ace12d02e612f126a94260e0ced89a7e5ebc9b2ee7349a580e89183af

İkinci kayıdımızda ilk kayıttan çıkan özütümüzü aldık ve bu kayıdın başlık kısmındaki özüt satırına ekledik. Tüm bir Bitcoin mantığı da basitçe bu. Gerçi Bitcoin daha güvenli olsun diye iki defa SHA256 yapıyor

Sonuç

İki blokluk yani kayıtlık bir işlem dizesinde İş kanıtı ile kısaca kayıtzinciri/blockchain mantığını göstermiş olduk. Şimdi kısaca tekrar iki bloğumuza da bakalım

  • Önce ilk blok
In [88]:
print(ilk_blok+"\n\n\n Bu kayıdın özütü:"+ilk_ozut+"\n\n Bu özüt de bir sonraki bloğa eklenecek")
Kayıt sırası:1
Özüt:0
Denge:2803
-----------------------------
1       Barış’tan Mehmet’e 10
2       Ali’den Ayşe’ye 2
3       Seyit’ten İbo’ya 5


 Bu kayıdın özütü:000009c3fe4cf834a0023fbb32327c29019af8535fa6fafbc9c3e56bdbb606f4

 Bu özüt de bir sonraki bloğa eklenecek
  • Şimdi de ikinci blok'a bakalım
In [89]:
print(ikinci_blok+"\n\n\n"+ikinci_ozut+"\n\n Bu özüt de bir sonraki bloğa eklenecek")
Kayıt sırası:2
Özüt:000009c3fe4cf834a0023fbb32327c29019af8535fa6fafbc9c3e56bdbb606f4
Denge:131418
-----------------------------
1       Ali’den Ayşe’ye 2
2       Barış’tan Mehmet’e 10
3       Seyit’ten İbo’ya 5


0000237ace12d02e612f126a94260e0ced89a7e5ebc9b2ee7349a580e89183af

 Bu özüt de bir sonraki bloğa eklenecek

Kısaca Bitcoin benzer prensiple çalışıyor. Umarım bu anlamanıza yardımcı olmuştur

Barış Sanlı, www.barissanli.com , barissanli2@gmail.com