Ana içeriğe geç

Kontrat Geliştirilmesi

Akıllı kontratlarımız ile ilginç şeyler yapmaya bu adımda başlayabiliriz. Akıllı kontratlar yapısı gereği bir hayat döngüsünden geçmektedir. Oluşturulurlar, güncellenirler, katılınırlar (opt-in) ayrılınırlar (opt-out) ve silinirler. Her akıllı kontratta çok yaygın olarak kullanılan işlemlerin koşullu olarak hangi tür transfere denk geldiğini ifade eden yapılar bulunmaktadır.

Bu işlemlerin hangi tür olduğunu tespit etmek için "pyteal-helpers" dosyası içerisinde program.py dosyası bünyesinde "event" fonksiyonu bulunmaktadır. Bu fonksiyonun kontrolünü gerçekleştirdiği birkaç değer bulunmaktadır.

 def event(init: Expr = Reject(),delete: Expr = Reject(),update: Expr = Reject(),opt_in: Expr = Reject(),close_out: Expr = Reject(),no_op: Expr = Reject(),) -> Expr:return Cond([Txn.application_id() == Int(0), init],[Txn.on_completion() == OnComplete.DeleteApplication, delete],[Txn.on_completion() == OnComplete.UpdateApplication, update],[Txn.on_completion() == OnComplete.OptIn, opt_in],[Txn.on_completion() == OnComplete.CloseOut, close_out],[Txn.on_completion() == OnComplete.NoOp, no_op],) 

Tablo 139 program.py Kod Parçası

Event fonksiyonu içerisine bakıldığında hayat döngüsünde bulunan değerlere denk gelen fonksiyonların var olduğu göz önüne gelmektedir. Bu işlemlere Tablo 139'da ifade edildiği üzere bakılacak olunursa:

  • Txn.application_id(): Eğer 0 değerine sahipse yeni bir uygulama numarası atanmamıştır. Bu durumda zincir kontratın kurulum aşamasında olduğunu anlamaktadır.
  • Txn.on_completion(): İşlemlerin tamamlanması halinde hangi transfer metoduna karşılık geldiğini ifade etmektedir. Bu işlemler silme (delete), güncelleme (update), ekleme (opt-in), çıkış yapma (close_out) ve özel işlem yapma (no_op) işlemleri olmaktadır. No_op transferi üzerinde kendi hareketlerini belirlediğimiz fonksiyonlar yazılabilir.

Transferleri yazdığımız akıllı kontratlar içerisinde kullanabilmek için ilk olarak "pyteal_helpers" paketini kodumuza eklememiz gerekmektedir.

 from pyteal_helpers import program 

Tablo 140

Tablo 140'ta ifade edildiği üzere Pyteal kütüphanesini eklediğimiz satırın altına bu eklemeyi yapabiliriz. İçerisinde birçok metot bulunan "pyteal_helpers" kütüphanesi içerisinden sadece program fonksiyonunu kullanmamız yeteri olmaktadır.

 from pyteal import *from pyteal_helpers import programdef approval():return program.event(init=,)def clear():return Approve() 

Tablo 141

Akıllı kontratın içerisine girildiğinde önüne gelen tüm transferleri onaylaması yerine Tablo 141'de ifade edildiği üzere program fonksiyonunun içerisinde bunulduğu "event" metoduna parametre olarak "init" anahtarını eklemekteyiz.

Eklediğimiz "init" parametresi içerisine "Seq()" fonksiyonu eklememiz gerekmektedir. Bu fonksiyon birden fazla işlemi birbirine bağlamayı sağlamaktadır. Bir sayıcı devresi oluşturduğumuz için sayıcı değerini almaktadır. Sayıcı değerini oluşturmak için "approve" fonksiyonu içerisinde bir sayıcı değeri tutmamız gerekmektedir. Bu değer normal Python veri tiplerine kıyasla farklı kaydedilecektir.

 global_sayici = Bytes("sayici") 

Tablo 142

Akıllı kontrat yazım aşamasında değişken tanımlarken birkaç özelliğe dikkat edinilmesi gerekmektedir. Algorand akıllı kontratlarında veriler global ve local olarak iki farklı şekilde depolabildikleri için nasıl bir değişken olduğu kolaylık açısından tanım içerisinde belirtilebilir. Tanımlayacağımız değişken global türe sahip olacağı için "global_sayici" isimlendirmesini kullanmayı tercih ettik. Akıllı kontratta verilerin kaydedilmesi için Byte formatında olması gerekmektedir. Bu nedenle Tablo 142'de belirtildiği üzere tanımlanırken "Btyes" fonksiyonu içerisinde tanımlanması gerekmektedir. Ancak dikkat edilmesi gereken bu fonksiyona parametre olarak girilen "sayici" değerinin Byte değerinin kendisi olmaması tanımlayıcısı yani bir bakıma değişken ismi olmasıdır.

Değişkeni Algorand Akıllı Kontratına uygun bir şekilde kaydetmemizden sonra "init" içerisine uygun şekilde eklenebilir.

 from pyteal import *from pyteal_helpers import program
def approval():global_sayici = Bytes("sayici")return program.event(init= Seq(App.globalPut(global_sayici, Int(0))))def clear():return Approve()

Tablo 143

Tablo 143'da ifade edildiği üzere Seq() fonksiyonu içerisine ilk işlem eklenebilir. Bu işlem App.globalPut() fonksiyonu ile gerçekleştirilmektedir. Bu fonksiyon içerisine iki adet parametre almaktadır. Parametrelere teker teker bakılacak olunursa:

  • Değişken: İçerisine eklenecek Byte türünde tanımlanan değişkeni ifade etmektedir.
  • Değer: Değişkenin içerisine eklenecek değeri formatıyla beraber ifade etmektedir. Python üzerinde kullanılan ve küçük harf ile başlayan "int()" fonksiyonu yerine büyük harfle kullanılan ve Pyteal içerisinde gelen "Int()" fonksiyonunun kullanıldığı görünmektedir.

Genellikle bazı durumlarda bir tanımlayıcı olarak kontratı oluşturan veya dağıtan adresin bilgilerinin kontrat üzerinde yer alması gerekmektedir. Bu işlem için daha önce de yapıldığı üzere bir Byte türüne ait tanımlayıcı oluşturulmaktadır.

 global_tanimlayici = Bytes("tanimlayici") 

Tablo 144

Tanımlayıcıyı Tablo 144'te ifade edildiği üzere global olarak tanımlanmaktadır. Ancak önceki tanımlama ile kendi içerisinde farklılık gösterecektir. Bu değişiklik Byte türlerinden oluşmaktadır. Bir önceki kaydettiğimiz değer integer değeri olmaktadır ancak "global_tanimlayici" olarak kaydedilen değer bir "Byteslice" değeri olmaktadır. Byteslices baytlardan oluşan bir dizi olmaktadır ve string olarak düşünülebilir.

 from pyteal import *from pyteal_helpers import program
def approval():global_sayici = Bytes("sayici")global_tanimlayici = Bytes("tanimlayici")
return program.event(init= Seq(App.globalPut(global_sayici, Int(0)),App.globalPut(global_tanimlayici, Txn.sender())))def clear():return Approve()

Tablo 145

Tanımlanan bu tanımlayıcının da aynı şekilde kod içerisine eklenmesi gerekmektedir. Bu işlemi Tablo 145'de ifade edildiği üzere Seq() fonksiyonundan yararlanarak yapmaktayız. Önceki eklenen değerden sonra virgül koyularak bir sonraki satıra geçiş yapılır ve bu satır içerisine aynı şekilde "App.globalPut()" çağırılır. Bu fonksiyon ilk olarak kaydedilecek değişken olan "global_tanimlayıcı" değerini almaktadır. Aldığı bir diğer parametre ise kontrata eklenecek bu değişkenin değeridir. Gönderici adresin eklenmesini istememizden dolayı buraya "Txn.sender()" fonksiyonu eklenebilir. Bu fonksiyon 64 karakterli gönderici adresini kontrat içerisinde "global_tanimlayici" içerisine ekleyecektir.

 from pyteal import *from pyteal_helpers import program
def approval():global_sayici = Bytes("sayici")global_tanimlayici = Bytes("tanimlayici")
return program.event(init= Seq(App.globalPut(global_sayici, Int(0)),App.globalPut(global_tanimlayici, Txn.sender()),Approve()))def clear():return Approve()

Tablo 146

Son olarak "Seq()" fonksiyonunu "Approve()" komutu ile tamamlamaktayız. Bu şekilde "initialization" işlemi tamamlanmış olmaktadır. Kodumuzun bir kısmı Tablo 146'da ifade edildiği üzere hazır olduğu için "compile" edip test edebiliriz.

 ./build contracts.counter.step_01 

Tablo 147

Derleme işlemini başlatmak için tablo 147'de ifade edildiği üzere "build" komutunu uygun dosya yolu ile çalıştırabiliriz.

 #pragma version 5txn ApplicationIDint 0==bnz main_l12txn OnCompletionint DeleteApplication==bnz main_l11txn OnCompletionint UpdateApplication==bnz main_l10txn OnCompletionint OptIn==bnz main_l9txn OnCompletionint CloseOut==bnz main_l8txn OnCompletionint NoOp==bnz main_l7errmain_l7:int 0returnmain_l8:int 0returnmain_l9:int 0returnmain_l10:int 0returnmain_l11:int 0returnmain_l12:byte "sayici"int 0app_global_putbyte "tanimlayici"txn Senderapp_global_putint 1return 

Tablo 148 approval.teal

Derlenip Teal formatına getirilen kod incelendiğinde Teal mimarisinin nasıl oluştuğu gözler önüne sürülmektedir. Tablo 148'da ifade edilen "approval.teal" dosyasının neler yaptığına bakılacak olunursa:

  • Başlangıçta Teal dilinin versiyonu ifade edilmektedir.
  • Sonrasında ApplicationID tanımlayıcı tanımlanıp hemen altında bu tanımlayıcıya int 0'değeri girilmiştir. Bu durum yazılan kontratın şu anlık 0 uygulama numarasına sahip olduğunu ifade etmektedir.
  • Alt kısmına göz gezdirildiğinde Teal yapısı içerisinde tanımlanan fonksiyonlar yer almaktadır. Bu fonksiyonlar "main_lX" isimleri ile oluşmaktadır. Öncesinde bahsedilen "Oncompletion" değişkeni içerisine "DeleteApplication", "OptIn" ve "No-op" gibi integer değerlerini atamaktadır. Bu değerler kontrat içerisinde 1 değerine sahip olduklarında denk gelen işlem gerçekleştirilecektir.
  • Fonksiyon tanımlanması sonrasında bu fonksiyonlara verilecek girdilerin tanımlanması gerekmektedir. Herhangi bir silme veya güncelleme işlemi yapılmayacağı için bu fonksiyonların içerisine "int 0" değeri girilmektedir.
  • Main_l12 adı ile tanımlanan fonksiyon içerisinde akıllı kontrat üzerinde yaptığımız işlemler yer almaktadır. Sırasıyla gidilecek olunursa ilk olarak "byte" komutu ile değişken tanımlanır ve alt satırında bu tanımlayıcı içerisine int 0 değeri atanmaktadır. Atanma sonrası "app_global_put" ile zincire bu değer global olarak eklenmektedir. Aynı işlemler "tanimlayici" için de yapılmakta olunup değerine "sayici" tanımlayıcısına farklı olarak "int" değeri atanmamakta olunup "txn Sender" fonksiyonu ile adresi tanımlamaktayız.
  • İşlemin onaylaması için çıkış yapılırken "int 1" değeri girilir ve "return" ile dosya tamamlanır.

Şu ana kadar yazdığımız fonksiyon sadece "initialization" işlemini desteklemektedir. Ancak yazdığımız bu kontrat testlere sokulabilir. Testi sağlamak için ilk olarak Sandbox klasörü içerisine "cd" komutu ile girilmesi gerekmektedir.

 ./sandbox enter algod 

Tablo 149

Sandbox klasörü içerisinde terminalden Tablo 149'da ifade edildiği üzere komut çalıştırılmalıdır. Bu komut Docker konteynerları içerisine girilmesini sağlamaktadır.

 ls /data 

Tablo 150

Giriş sağlandıktan sonra öncesinde tanımladığımız bağlantıyı test edebiliriz. Bu işlem için Tablo 150'da ifade edilen komutu girebiliriz. Eğer karşımıza project içerisinde oluşturduğumuz dosyalar çıkıyorsa bağlama işlemi başarılı bir şekilde tamamlanmıştır.

 goal account list 

Tablo 151

Yayınlamadan önce Tablo 151'da ifade edilen komut ile sahip olunan local adreslere bakmamız gerekmektedir. Bu adreslerde birisini sonrasında kullanmak için kaydetmemiz gerekmektedir.

 goal app create --creator EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY --approval-prog /data/build/approval.teal --clear-prog /data/build/clear.teal --global-byteslices 1 --global-ints 1 --local-byteslices 0 --local-ints 0 

Tablo 152

Kontrat Tablo 152'da ifade edilen kod ile terminalden çalıştırılabilmektedir. Bu kod birkaç kısımdan oluşmaktadır. Bu kısımları teker teker incelememiz gerekirse:

  • goal app create: Kontratın oluşacağını ifade etmektedir.
  • Creator: Kontratın oluşturucu hesabını ifade etmektedir. Bu adresi local olarak "goal accound list" komutu ile elde edebiliriz.
  • Approval-prog:"aproval.teal" dosyasının konumunu ifade etmektedir.
  • Clear-prog:"clear.teal" dosyasının bulunduğu konumu ifade etmektedir.
  • Global-byteslices : Akıllı kontrat içerisinde bulunan global "byteslices" türüne sahip değişkenin sayısını ifade etmektedir. Kontratımız için bu değer "global_tanimlayici" olmaktadır.
  • Global-ints: Akıllı kontrat içerisinde bulunan global "int" türüne sahip değişkenlerin sayısını ifade etmektedir. Kontratımız için bu değer "global_sayici" olmaktadır.
  • Local-byteslices: Akıllı kontrat içerisinde bulunan "local byteslices" türüne sahip değişkenlerin sayısını ifade etmektedir.
  • Local-ints: Akıllı kontrat içerisinde bulunan local "ints" türüne sahip değişkenlerin sayısını ifade etmektedir.
 goal app info --app-id X 

Tablo 153

Çalıştırılan kod bir "app-id" değeri vermektedir. Tablo 153'da ifade edildiği üzere bu değeri komutu ile X yerine koyarak çalıştırdığımızda birçok bilgi çıkmaktadır.

 Application ID: 1Application account: WCS6TVPJRBSARHLN2326LRU5BYVJZUKI2VJ53CAWKYYHDE455ZGKANWMGMCreator: EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QYApproval hash: WBPQ6TZHTB5FZBL4PVRYMJ5SXTML3AF6FBKFQA7WYMSID5MA5ZEMGXBPEEClear hash: BJATCHES5YJZJ7JITYMVLSSIQAVAWBQRVGPQUDT5AZ2QSLDSXWWM46THOYMax global byteslices: 1Max global integers: 1Max local byteslices: 0Max local integers: 0 

Tablo 154

Tablo 154'de bir çıktı örneği ifade edilmiştir. Bu değerler "app" olarak adlandırılan kontratın bilgilerini ifade etmektedir.

 goal app read --global --app-id X 

Tablo 155

Aynı zamanda oluşturduğumuz akıllı kontratların depolaması bulunmaktadır. Bu depolamaya Tablo 155'da ifade edildiği şekilde bakınılacak olunursa bir json çıktısının oluşturduğu gözlemlenebilir.

 {"sayici": {"tt": 2},"tanimlayici": {"tb": "!ufffdaufffdufffdufffd)fRu0011ufffdufffdufffdoufffdVvu000bRufffd"Yufffdu0005ufffd&ufffdufffdu000eufffdu0002ufffd","tt": 1}} 

Tablo 156

Tablo 156'da akıllı kontratın depoladığı JSON verisi ifade edilmektedir. Bu dosya içerisinde tanımladığımız iki tanımlayıcı da yer almaktadır. Tanımlayıcıların içerisine kaydedilen bu değerler bazı anahtarlar ile ifade edilmiştir. Bu anahtarlar arasından "tb" anahtarı "Transection Bytes" anlamına gelerek tanımlayıcının içerisinde tuttuğu veriyi ifade etmektedir. Başta tanımlaman "sayici" değişkeninin değerinin 0 olmasından mütevellit herhangi bir "tb" değerinin oluşturulmasına gerek yoktur. Ancak 0 dışındaki herhangi bir değer için "tb" değeri oluşturulacaktır. İkinci anahtar kelime "tt" olmaktadır. Bu anahtar "Transection Type" anlamına gelerek tutulan tanımlayıcıların tipini etiketlemektedir. Bu değerin "tt=1" olması kaydedilen değerin byteslices türüne ait olduğunu gösterirken değerin "tt=2" olması kaydedilen değerin "int" türüne sahip olduğunu ifade etmektedir.

 goal app read --global --app-id X –guess-format 

Tablo 157

Oluşturulan çıktı ham durumda olmaktadır ve bazı "tanımlayıcı" gibi "byteslices" değerler okunamıyor durumda olmaktadır. Bu durumun çözülmesi için Tablo 157'de ifade edilen şekilde okuma fonksiyonu sonuna "--guess-format" ibaresi eklenebilir.

 {"sayici": {"tt": 2},"tanimlayici": {"tb": "EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY","tt": 1}} 

Tablo 158

Tablo 158'de okuma fonksiyonu sonrasına "--guess-format" anahtar kelimesi eklenilmesi sonrası oluşan çıktı ifade edilmektedir. Görüldüğü üzere artık "tanimlayici" değişkenin "tb" anahtar kelimesine denk gelen değeri 64 karakterden meydana gelen ve kontratı derlerken kullandığımız adres olmaktadır.

Artık "no-op" transfer türü içerisine kendi istediğimiz özellikleri ekleyebiliriz. Bu sayede kendi operasyonlarımızı tanımlayabiliriz. Eklenecek bu işlemler "program.event()" fonksiyonu içerisinde init parametresinden sonra yer alacaktır.

 op_arttir = Bytes("art")op_azalt = Bytes("az") 

Tablo 159

Daha öncesinde yazdığımız "step_01.py" dosyası içesinde kod yazımına devam ederiz. İlk olarak "approval" fonksiyonu içerisinde yeni değişkenleri Tablo 159'da ifade edildiği üzere tanımlayarak başlayabiliriz. Bu değişkenlerin global olmamasından dolayı tanımlarken global ibaresini eklemeye gerek bulunmamaktadır.

Kitabın önceki bölümlerinde yaptığımız üzere sıralı işlemleri transfer içerisinde yapmak istediğimiz zaman "Seq()" anahtar kelimesini kullanmaktaydık. Ancak transfer içerisinde şartlı koşul olarak "switch case" gibi çalışan bir "Cond()" fonksiyonu kullanabiliriz. Kullanılacak olunan bu "Cond()" fonksiyonu yapısı gereği argümanların yer aldığı array liste yapılarından bir araya gelmektedir. Arrayların ilk elemanı çalışma şartı olacaktır, ikinci eleman ise çalışacak işlem olmaktadır.

Array listesinde bulunan bu şartlar tekil olmaktadırlar. Eğer bir şart sağlanır ve denk gelen işlemi çalıştırılırsa diğer şartların ne olduğuna bakılmaksızın çalıştırılamaz. Eğer hiçbir şart sağlanmamışsa transfer işlemi gerçekleşmemiş olur ve hata verir.

 [Txn.application_args[0]= op_arttir, arttir] 

Tablo 160

Bakılacak ilk şart "Txn.application" listesinde yer alacak ilk elemanın arttır fonksiyonuna denk gelip gelmemesidir. Gelmesi halinde Tablo 160'da ifade edildiği üzere sonrasında tanımlayacağımız "arttir" adına sahip arttırma fonksiyonu çalışacaktır.

 no_op= Cond([Txn.application_args[0]== op_arttir, arttir],[Txn.application_args[0]== op_azalt, azalt],) 

Tablo 161

Tablo 161'da ifade edildiği üzere aynı yapı azaltma için de gerçekleştirilir. Oluşan arraylar ilk olarak belirtildiği gibi şartı almaktadır. Bu şart transferin içerisinde bulunan ilk argümanının hemen üst satırında tanımladığımız "op_azalt" ve "op_arttir" tanımlayıcılarının byte değerlerine denk gelip gelmemesine bakmaktadır. Sonrasında alınan ikinci parametre şartın sağlanması halinde gerçekleştirilecek fonksiyonu ifade etmektedir. Bu fonksiyonları henüz tanımlamamış olsak da birazdan tanımlayacağız.

No_op transfer türü içerisine gerekli şartların "Cond()" metodu ile eklenmesinden sonra arttırma ve azaltma fonksiyonları şartlı durumda tanımladığımız isimler ile oluşturulabilir. Bu fonksiyonlar birden fazla işlem yapacağı için kendi içlerinde "Seq()" metodu ile tanımlanacaktır.

 arttir = Seq(App.globalPut(global_sayici, App.globalGet(global_sayici) + Int(1)),Approve()) 

Tablo 162

Arttırma fonksiyonu her defasında global olarak tanımlanan global_sayici değerini alarak bir arttıracaktır. Bu işlemi gerçekleştirmek için Tablo 162'de ifade edildiği üzere bir fonksiyon yazılması gerekmektedir. Bu fonksiyonun işlevlerine bakılacak olunursa ilk olarak "App.globalPut()" fonksiyonu ile kontrat üzerine bir global değer konulmaktadır. Bu fonksiyon içerisine iki adet değer almaktadır. İlk değer akıllı kontrat üzerine konulacak değişkenin adı olmaktadır. Bu değer Byte türüne sahip olmaktadır ve tanımlar içerisinde "global_sayici" olarak kaydedilmiştir. Sonrasında alınacak ikinci değer kontrat içerisine aktarılacak bu tanımlayıcının değeri olmaktadır. Arttırma fonksiyonu tanımladığımız için önceki değeri alıp bir arttırması gerekmektedir. Bu işlemi gerçekleştirmek için "App.globalGet()" komutu ile kontrat üzerinden tanımlayıcıyı almaktadır. Sonrasında üzerine 1 değerine sahip integer eklemektedir. Bu integer tanımlaması yapılırken Python üzerinde bulunan "int()" fonksiyonu yerine Pyteal'ın sağladığı "Int()" fonksiyonunun kullanıldığı dikkat edilmesi gereken bir durumdur. Arttırılıp tanımlayıcıya aktarılan aktarılan değerin başarı ile sonuçlanması sonrasında transferin onaylanması gerekmektedir. Bu nedenle son olarak "Approve()" fonksiyonu eklenmektedir.

 arttir = Seq(App.globalPut(global_sayici, App.globalGet(global_sayici) + Int(1)),Approve())azalt = Seq(App.globalPut(global_sayici, App.globalGet(global_sayici) - Int(1)),Approve()) 

Tablo 163

Arttırma fonksiyonunun tanımlaması sonrasında aynı işlem azaltma için de gerçekleştirilecektir. Ancak bu sefer farklılık olarak Tablo 163'te ifade edildiği üzere kontrat üzerinden alınan "global_sayici" değeri bir arttırılmayacak olunup bir azaltılacaktır. Sonrasında kod hazır hale gelecektir.

 from pyteal import *from pyteal_helpers import program
def approval():global_sayici = Bytes("sayici")global_tanimlayici = Bytes("tanimlayici")
op_arttir = Bytes("art")op_azalt = Bytes("az")
arttir = Seq(App.globalPut(global_sayici, App.globalGet(global_sayici) + Int(1)),Approve())azalt = Seq(App.globalPut(global_sayici, App.globalGet(global_sayici) - Int(1)),Approve())return program.event(init= Seq(App.globalPut(global_sayici, Int(0)),App.globalPut(global_tanimlayici, Txn.sender()),Approve()),no_op=Cond([Txn.application_args[0] == op_arttir, arttir],[Txn.application_args[0] == op_azalt, azalt],),)def clear():return Approve()

Tablo 164

Tablo 164'te step_01.py dosyasını tamamı ifade edilmiştir. Sırasıyla yapılan işlemlere bakılacak olunursa:

  • Gerekli kütüphaneler dosya içerisine eklenir
  • Approval ve clear adında iki fonksiyon tanımlanır.
  • Approval fonksiyonu içerisine global olarak "sayici" ve "tanimlayici" değişkenleri eklenir.
  • Fonksiyonların terminal üzerinden çağırılmasını sağlayacak byte "arttir" ve "azalt" operatörü tanımlanır.
  • Arttırma ve azaltma fonksiyonu yazılır.
  • Kontratın başlangıçta sahip olacağı değerler tanımlanır.
  • No_op transfer türü içerisine şartlı olarak arttırma ve azaltma şartları girilir.
  • Clear fonksiyonuna gelen tüm transferler onaylanır.
 ./build.sh contracts.counter.step_01 

Tablo 165

Kontrat yazılmış ve derlenmeye hazır bir hale sahip olmuştur. Derleme işlemini gerçekleştirmek için Tablo 165'te ifade edildiği üzere "./build.sh" dosyası içerisine kodun bulunduğu adresin girilmesi gerekmektedir. Bu sayede kod derlenir ve ".teal" uzantılı dosyalar oluşur. Komutu çalıştırmak için Docker konteynerlerinden çıkış yapılıp project klasörüne giriş yapılması gerekmektedir.

 #pragma version 5txn ApplicationIDint 0==bnz main_l16txn OnCompletionint DeleteApplication==bnz main_l15txn OnCompletionint UpdateApplication==bnz main_l14txn OnCompletionint OptIn==bnz main_l13txn OnCompletionint CloseOut==bnz main_l12txn OnCompletionint NoOp==bnz main_l7errmain_l7:txna ApplicationArgs 0byte "art"==bnz main_l11txna ApplicationArgs 0byte "az"==bnz main_l10errmain_l10:byte "sayici"byte "sayici"app_global_getint 1-app_global_putint 1returnmain_l11:byte "sayici"byte "sayici"app_global_getint 1+app_global_putint 1returnmain_l12:int 0returnmain_l13:int 0returnmain_l14:int 0returnmain_l15:int 0returnmain_l16:byte "sayici"int 0app_global_putbyte "tanimlayici"txn Senderapp_global_putint 1return 

Tablo 166 approval.teal

Tablo 166'da "approval.teal" dosyasında "step_01.py" dosyası ile oluşturduğumuz akıllı kontratın derlenmiş hali yer almaktadır. Bu dosya çoğunlukla bir önceki dosyaya benzerlikler göstermektedir. Ancak farklılıklar da bulunmaktadır. Bu farklılıklar mainl10 ve mainl11 üzerinde kendilerini göstermektedir.

 ./sandbox enter algod 

Tablo 167

Derlenen teal kodu test edilmeye hazır bir hal almaktadır. Test işlemini gerçekleştirmek için Tablo 167'de ifade edildiği üzere algod olarak adlandırılan Docker konteynerlarına Sandbox ile giriş sağlamamız gerekmektedir. Bu komutu çalıştırmak için Sandbox klasörü içerisine girilmesi gerekmektedir.

 goal account list 

Tablo 168

Docker konteynerları içerisine girildikten sonra bu işlemin başarılı olup olmadığına Tablo 168'da ifade edilen şekilde bakılabilir. Bu liste içerisinden local adreslerin herhangi biri sonradan kullanılmak için kaydedilmektedir.

 goal app create --creator EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY --approval-prog /data/build/approval.teal --clear-prog /data/build/clear.teal --global-byteslices 1 --global-ints 1 --local-byteslices 0 --local-ints 0 

Tablo 169

Lokalde çalıştırmaya hazır olan kodu Tablo 169'da ifade edilen komutu çalıştırabiliriz. Sonrasında karşımıza derlenmiş bir kod çıkmaktadır. Pyteal bu kontrata kendi içeresinde bir numara atanmıştır ve bu numarayı kullanarak kontrata erişebiliriz. Çalıştırma kodunun içeriğine bakılması gerekmektedir. Bu kısımları teker teker incelememiz gerekirse:

  • Goal app create: Kontratın oluşacağını ifade etmektedir.
  • Creator: Kontratın oluşturucu hesabını ifade etmektedir. Bu adresi local olarak goal accound list komutu ile elde edebiliriz.
  • Approval-prog:"aproval.teal" dosyasının konumunu ifade etmektedir.
  • Clear-prog:"clear.teal" dosyasının bulunduğu konumu ifade etmektedir.
  • Global-byteslices: Akıllı kontrat içerisinde bulunan global "byteslices" türüne sahip değişkenin sayısını ifade etmektedir. Kontratımız için bu değer "global_tanimlayici" olmaktadır.
  • Global-ints: Akıllı kontrat içerisinde bulunan global "int" türüne sahip değişkenlerin sayısını ifade etmektedir. Kontratımız için bu değer "global_sayici" olmaktadır.
  • Local-byteslices: Akıllı kontrat içerisinde bulunan "local byteslices" türüne sahip değişkenlerin sayısını ifade etmektedir.
  • Local-ints: Akıllı kontrat içerisinde bulunan "local ints" türüne sahip değişkenlerin sayısını ifade etmektedir.
 goal app call --app-id X --app-arg "str:art" --from EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY 

Tablo 170

Kontratın derlenmesinden ve uygun uygulama kodunun atanmasından sonra fonksiyonlar denenebilir. Deneme işlemini gerçekleştirmek için Tablo 170'da ifade edilen terminal komutunu çalıştırmamız gerekmektedir. Bu komuta parça parça bakılacak olunursa:

  • App-id: Bir üst kısımda bulunan kodu çalıştırmamız halinde atanacak uygulama numarasını ifade etmektedir. X yerine bu numara yazılmalıdır.
  • --app-arg: Kontrat içerisine gönderilecek argümanları ifade etmektedir. Bu değerin ilk olarak türünün belirlenmesi gerekmektedir. Bizim projemiz için bu string türü olmaktadır. Sonrasında bu değişkenin bağlanacağı Byte değeri girilmelidir. "op_arttir = Bytes("art")" tanımlaması içerisinde bu değeri "art" olarak belirlediğimiz için komut içerisinde de "art" kelimesini kullanmaktayız.
  • --from: Kontrat içerisine argümanı gönderecek kullanıcının adresini ifade etmektedir. Local olarak tanımladığımız adreslerin biri kullanılabilir.
 goal app read --global --app-id 12 --guess-format 

Tablo 171

Sonrasında sonucu görüntülemek için Tablo 171'da ifade edilen komutu kullanabiliriz. Bu işlem kontrat depolaması görüntülenebilir.

 {"sayici": {"tt": 2,"ui": 1},"tanimlayici": {"tb": "EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY","tt": 1}} 

Tablo 172

Tablo 172'de ifade edildiği üzere öncesinde var olmayan "ui" değeri oluşmuştur. Bu değer aslında kontrat oluşturulurken 0 olarak atanmıştır. Ancak arttırma fonksiyonu gereği bu sıfır değeri üzerine bir eklenerek "ui": 1 olmaktadır.

 {"sayici": {"tt": 2,"ui": 2},"tanimlayici": {"tb": "EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY","tt": 1}} 

Tablo 173

Fonksiyon yeniden çağırıldığında "ui" değerinin bir arttığı görülebilir. Bu şekilde kontrat içerisinde yer alan değerler Tablo 173'de ifade edildiği gibi değiştirilebilir.

 goal app call --app-id 12 --app-arg "str:az" --from EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY 

Tablo 174

Aynı şekilde arttırma işlemi öncesinde tanımlanan azaltma işlemi için de uygulanabilir. Yapılması gereken tek değişiklik Tablo 174'de gösterildiği üzere "str:art" değeri yerine "str:az" değerinin kullanılması gerekmesidir. Sonrasında değişiklik kontrat depolamasına yansımaktadır.

 {"sayici": {"tt": 2,"ui": 1},"tanimlayici": {"tb": "EHIGDIXP6QUWMUQRTTI6W36TKZ3AWUVQEJMZ4BPTE3T32DWWALPVHSE3QY","tt": 1}} 

Tablo 175

Tablo 175'da ifade edildiği üzere azaltma komutunu çağırmamız halinde "ui":2 olan değer bir azalarak "ui": 1 değerine azalacaktır. Bu şekilde yazdığımız sayma kodunun başarılı bir şekilde çalıştığı görüntülenebilir.

Bu basamaklar ile Pyteal ile Algorand akıllı kontratların nasıl kurulduğunu, nasıl test edildiğini, hangi veri tiplerine sahip olduklarını ve kullanım alanlarını görüntülemiş olmaktayız.