Akıllı kontratlarda fuzz testi ve invariant testi: Foundry ile bir yılda öğrendiklerim
Fuzz testi, aynı testi rastgele üretilmiş girdilerle yüzlerce, binlerce kez çalıştırmak. Foundry'de bir test fonksiyonuna parametre eklediğinizde, araç bu parametreler için rastgele değerler üretip testi defalarca çalıştırıyor. Bizim hatamız tam da burada çıktı: belirli bir yuvarlama durumunda, çok küçük tutarlarla yapılan bir işlem kullanıcının hak ettiğinden biraz fazla pay almasını sağlıyordu. Birim testlerimizde hep yuvarlak sayılar kullandığımız için bunu hiç görmemiştik.
Invariant testi ise bir adım daha ileri. Burada kontratta her zaman doğru olması gereken bir kural tanımlıyorsunuz. Örneğin toplam pay arzı, tüm kullanıcıların paylarının toplamına eşit olmalı. Ya da kasadaki varlık, kullanıcılara borçlu olunan toplamdan az olmamalı. Araç, kontrata rastgele sırayla rastgele fonksiyon çağrıları yapıyor ve her adımdan sonra bu kuralların hâlâ geçerli olup olmadığını kontrol ediyor.
Invariant testlerinin zor kısmı doğru kuralları bulmak. İlk yazdığımız kurallar çok genel olduğu için hiçbir şey yakalamadı. Sonra kontratın iş mantığını kağıda döktük: hangi değerler birbiriyle ilişkili, hangi durumda hangi değer hangi yönde değişmeli. Bu çalışma tek başına tasarımdaki iki zayıf noktayı ortaya çıkardı, daha test yazmadan.
İkinci zor kısım handler yazmak. Araca rastgele çağrı yaptırırken anlamsız çağrılarla zaman kaybetmemesi için çağrıları yönlendiren bir ara kontrat yazmanız gerekiyor. Örneğin para çekme fonksiyonunun yalnızca bakiyesi olan adreslerle çağrılmasını sağlamak gibi. Bunu yapmadığımızda testlerin büyük kısmı anlamsız ret durumlarında kayboluyordu.
Bu testler denetimin yerini tutmuyor, ama denetime çok daha temiz bir kodla gitmemizi sağladı. Denetçilerin bulduğu bulgu sayısı bir önceki denetime göre belirgin şekilde azaldı. Fuzz ya da invariant testi kullanan başka ekipler hangi kuralları yazıyor, merak ediyorum.



@endof