e
sv

Bir blockchain sosyal medya platformu tasarlayın ve oluşturun

avatar

Yazılım Method

  • e 0

    Mutlu

  • e 0

    Eğlenmiş

  • e 0

    Şaşırmış

  • e 0

    Kızgın

  • e 0

    Üzgün

Facebook ve Twitter gibi merkezileştirilmiş sosyal medya, tüm kullanım durumlarına uymaz. Örneğin, merkezileştirilmiş sosyal medya platformları, sağlayıcı olan merkezi bir otoriteye bağlıdır. Bu sağlayıcı, kullanıcı gönderilerini kaldırma veya gizleme yeteneğine sahiptir.

Ayrıca, merkezi sosyal medya değişken bir kayıt olduğu için potansiyel olarak değiştirilebilir. Bunun her türlü sonucu var. Örneğin, bir kullanıcının bir şey yayınladığında kanıtlaması zor olabilir. Bunun, patent davaları veya uzmanların tahminlerine dayalı olarak değerlendirilmesi gibi çeşitli ticari durumlar için etkileri olabilir.

Değişebilirlik ayrıca, bir kullanıcının gönderilerinin değiştirilebileceği veya içeriğin başka bir kullanıcının profili altında yayınlanabileceği hain eylemler riskini de beraberinde getirir.

İşte bu noktada blockchain bir oyun değiştirici olabilir. Bir blok zinciri, pratik olarak değişmez olan bir defterdir. Bozulması veya silinmesi mümkün olmayan kalıcı bir kayıt sağlar, bu da onu belirli sosyal ağ kullanım durumları için ideal hale getirir.

Bu yazıda, Ethereum'un üzerinde çalışacak, Chirper adlı bir blockchain sosyal medya platformu tasarlayıp oluşturacağız.

İçindekiler

Sosyal medya platformunun tasarlanması

Merkezi olmayan bir blok zinciri sosyal medya platformu tasarlamak için bilgilerin nasıl saklanacağını ve bunlara nasıl erişileceğini düşünmemiz gerekecek.

Bilgi depolama

Blok zincirine bilgi sağlamanın tek yolu, onu bir işlemin parçası olarak yerleştirmektir. İşlem bir bloğa eklendiğinde, blok zincirinin kalıcı kaydının bir parçası olur. Bu, saklanan bilgilerin aranmasının kolay olduğu anlamına gelmez.

Veriler blok zincirine girdikten sonra, onunla yapabileceğimiz ek eylemler vardır, ancak blok zincirine yazılan her şey paraya mal olur. Bu nedenle, işlevselliği etkinleştirmek için kesinlikle gerekli olan eylemlerle kendimizi sınırlamak en iyisidir.

indeksleme

Bu yazı itibariyle, Ethereum blok zincirinde 15 milyondan fazla blok var. Mesaj aramak için hepsini indirmek mümkün olmazdı. Bunun yerine, adresler ve diziler arasında bir eşlemeden oluşan bir dizin tutacağız.

Her adres için dizi, o adresin gönderildiği blokların seri numaralarını içerecektir. Bir kullanıcı uygulaması bu listeyi aldıktan sonra, blokları almak ve mesajları aramak için bir Ethereum uç noktasını sorgulayabilir.

Veri ve kontrol akışlarını belirtme

Ardından, bir kullanıcının nasıl mesaj göndereceğini ve mesajları nasıl bulacağını belirlememiz gerekiyor.

Mesaj gönderme

Mesaj göndermek için iki işlem gerekir:

  • Mesajın bir işlemin parçası olarak yazılması
  • Mesajın bloğunu dizine ekleme

Bu, mesaj göndermeyi uygulamak için kullanacağımız akıştır:

  1. Bir kullanıcı uygulaması, mesajla bir zincir üstü sözleşmeye bir işlem gönderir; mesaj otomatik olarak Ethereum kalıcı kaydına yazılır
  2. Sözleşme, başka bir akıllı sözleşme yerine doğrudan bir işlem tarafından çağrıldığını doğrular. Bu adım gereklidir çünkü mesajları bulmak için kullandığımız algoritma sadece doğrudan çağrılırsa çalışır (işlemlere baktığı için)
  3. Sözleşme, göndereni ve mevcut blok numarasını tanımlar
  4. Sözleşme, blok numarasını gönderenin mesaj blokları dizisine ekler. Göndericinin henüz bir mesaj blokları dizisi yoksa, sıfır uzunluklu bir dizi olarak kabul edildiğinden bunun bir önemi yoktur.

Mesaj bulma

Bu, bir kullanıcının mesajları bulmasını, okumasını ve yorumlamasını sağlamak için kullanacağımız akıştır:

  1. Bir kullanıcı uygulaması, istenen mesajlarla ilişkili adresle bir zincir üstü sözleşmeyi çağırır. Bu bir view işlevi (salt okunur bir işlev) olduğundan, yalnızca tek bir düğümde yürütülür ve herhangi bir gaza mal olmaz.
  2. Kullanıcı uygulaması, işlemleri de dahil olmak üzere listedeki blokları okur ve bu koşulları karşılayan ilgili işlemleri bulmak için filtreler:
    • Kaynak olarak aradığımız gönderici var mı?
    • Hedef olarak Chirper sözleşmesi var
    • (İsteğe bağlı) Doğru işlev imzasına sahip. Bu yalnızca Chirper'da işlemleri kabul eden birden fazla işlevimiz varsa gereklidir; bir gönderi için yalnızca bir işlevimiz varsa, işlev imzasını kontrol etmemize gerek yoktur.
  3. Kullanıcı uygulaması, kullanıcının gönderdiği gönderileri geri almak için işlem çağrısı verilerini dizelere dönüştürür
  4. Kullanıcı uygulaması, blok numaralarını zaman damgalarına dönüştürür
  5. Kullanıcı uygulaması, gönderileri (veya bunların bir alt kümesini) kullanıcıya görüntüler.

Sosyal medya platformu uygulamasını oluşturma

Bu makalede kullanılan uygulama kaynak kodu GitHub'da mevcuttur. İki dosya, bir Solidity sözleşmesi ve API'yi (sözleşmenin nasıl kullanılacağını) ve testleri (sözleşmenin doğru çalıştığının nasıl doğrulanacağını) içeren JavaScript kodu içerir.

Solidity sözleşmesinin yazılması

Asgari bir sözleşme kullanacağız, sosyal ağ blok zincirinde uygular.

İlk kod satırları, sözleşmeyi derlemek için kullanılan Solidity programlama dilinin lisansını ve sürümünü belirtir. Solidity hala hızlı bir şekilde gelişiyor ve önceki (v0.7.x) veya sonraki (v0.9.x) diğer sürümler sözleşmeyi doğru şekilde derlemeyebilir.

 // SPDX-Lisans-Tanımlayıcı: LİSANSSIZ
pragma sağlamlığı ^0.8.0;

Ardından, sözleşmeyi tanımlarız:

 sözleşme Chirper {

Ardından, bu sözleşmeye gönderilen her adres için blok listesini tutan veri yapısını ekliyoruz.

 // Bir adresin mesaj gönderdiği bloklar
    eşleme (adres => uint[]) MessageBlocks;

İşte zincir dışı uygulamaların bilgi göndermek için çağırdığı işlev.

 function post(string calldata _message) harici {
        // Mesajla ilgili herhangi bir şey yapmamıza gerek yok, sadece burada ihtiyacımız var
        // böylece işlemin bir parçası olur.

_message gerçekten ihtiyacımız yok, bu sadece zincir dışı kodun işleme koyması için bir parametredir. Bununla birlikte, onunla hiçbir şey yapmazsak, derleyici şikayet edecektir. Bu nedenle, bu davranıştan kaçınmak için onu ekleyeceğiz!

 (_İleti);

Şu anda, mesajı görmek için işleme bakmak ancak mesaj işlemin kendisindeyse mümkündür. Chirper sözleşmesi dahili olarak başka bir sözleşme tarafından çağrılırsa, bu olmaz; bu nedenle, bu eylemi desteklemiyoruz.

 require(msg.sender == tx.origin, "Yalnızca doğrudan çağrıldığında çalışır");

Not , bu basitlik için optimize edilmiş eğitim kodudur; bir üretim sisteminde, bunun yerine bu belirli gönderileri depoya koyarak daha yüksek bir gaz maliyetiyle dahili aramaları destekleyebiliriz.

Aynı kullanıcıdan birden fazla gönderi aynı bloğa eklenebilir. Bu olduğunda, blok numarasını bir kereden fazla yazarak kaynakları boşa harcamak istemiyoruz.

 // Henüz bir gönderi yoksa sadece blok numarasını ekleyin
        // bu blokta
        uint uzunluk = MessageBlocks[msg.sender].length;

Liste boşsa, elbette mevcut blok listede değildir.

 if (uzunluk == 0) {
            MessageBlocks[msg.sender].push(block.number);

Liste boş değilse, son giriş length-1 dizinindedir. Listedeki herhangi bir giriş mevcut blok ise, bu son giriş olacaktır. Sadece blok seri numaraları arttığından, son girişin mevcut blok numarasından küçük olup olmadığını kontrol etmek yeterlidir.

 } else if (MessageBlocks[msg.sender][length-1] <block.number) {

Bir dizinin sonuna bir değer eklemek için push işlevini kullanırız.

 MessageBlocks[msg.sender].push(block.number);
        }
    } // fonksiyon gönderisi

Bu işlev, belirli bir gönderici için engelleme listesini döndürür.

 işlev getSenderMessages (adres gönderen) genel görünüm 
        (uint[] bellek) {
        MessageBlocks[gönderici] döndür;
    } // getSenderMessages işlevi

} // Chirper sözleşmesi

JavaScript API'sini oluşturma

Şimdi, kullanıcıların akıllı sözleşmeyle etkileşime girmesini sağlamak için JavaScript API'sini oluşturacağız.

JavaScript API'sini ayrı bir modüle koymak, işleri gereksiz yere karmaşıklaştırır. Bunun yerine, GitHub deposundaki testler dosyasının en üstünde kodu görebilirsiniz.

Mesaj verileri, mesajın karakterlerinin ASCII kodunu temsil eden onaltılık rakamlar biçiminde gönderilir, uzunluk olarak 64 karakterin tamsayı katı olacak şekilde sıfırlarla doldurulur. Örneğin mesaj Hello ise aldığımız veri "48656c6c6f0000…0000" .

ethers.js kitaplığından aldığımız verileri normal bir dizeye dönüştürmek için aşağıdaki işlevi kullanıyoruz:

 const data2Str = str => {

İlk olarak, bu tek dizgiyi String.match ve bir normal ifade kullanarak bir diziye böldük.

[0-9a-f] tek bir onaltılık basamakla eşleşir; {2} , programa bunlardan ikisini eşleştirmesini söyler. [0-9a-f] {2} etrafındaki eğik çizgiler sisteme bunun bir normal ifade olduğunu söyler. g , yalnızca ilk ifadeyle değil, normal ifadeyle eşleşen tüm alt dizelerle eşleşmesi için genel bir eşleşme istediğimizi belirtir.

Bu çağrıdan sonra bir dizimiz var, ["48", "65", "6c", "6c", "6f", "00", "00" … "00"]

 bayt = str.match(/[0-9a-f]{2}/g)

Şimdi, tüm bu dolgu sıfırlarını kaldırmamız gerekiyor. Bir strateji, filter işlevini kullanmaktır. filter bir işlevi girdi olarak alır ve yalnızca işlevin true değerini döndürdüğü dizinin üyelerini döndürür. Bu durumda, yalnızca "00" değerine eşit olmayan dizi üyeleri.

 faydalıBytes = bytes.filter(x => x != "00")

Sonraki adım, doğru yorumlanması için her onaltılık sayıya 0x eklemektir. Bunu yapmak için map işlevini kullanıyoruz. Harita ayrıca bir işlevi girdi olarak alır ve bu işlevi dizinin her üyesinde çalıştırarak sonuçları bir dizi olarak döndürür. Bu aramadan sonra ["0x48", "0x65", "0x6c", "0x6c", "0x6f"]

 hexBytes = faydalıBytes.map(x => '0x' + x)

Şimdi, ASCII kod dizisini gerçek dizgeye çevirmemiz gerekiyor. Bunu String.fromCharCode kullanarak yapıyoruz. Ancak bu işlev, bir dizi yerine her karakter için ayrı bir argüman bekler. Sözdizimi ..["0x48", "0x65", "0x63" etc.] dizi üyelerini ayrı bağımsız değişkenlere dönüştürür.

 decodingStr = String.fromCharCode(...hexBytes)

Son olarak, ilk altı karakter gerçekte dize değil, meta verilerdir (örneğin, dize uzunluğu). Bu karakterlere ihtiyacımız yok.

 sonuç = kodu çözülmüşStr.slice(6)
  dönüş sonucu
} // data2Str

Belirli bir Chirper sözleşmesinde belirli bir göndericiden tüm mesajları alan işlev:

 const getMsgs = zaman uyumsuz (chirper, gönderen) => {

İlk olarak, ilgili mesajları içeren blokların listesini almak için Chirper'ı çağırıyoruz. getSenderMessages yöntemi bir tamsayı dizisi döndürür, ancak Ethereum tamsayıları 2^256-1'e kadar değişebildiğinden, bir dizi BigInt değeri alırız. .map(x => x.toNumber()) onları blokları almak için kullanabileceğimiz normal sayılara dönüştürür.

 blockList = (chirper.getSenderMessages(sender) bekleniyor).map(x => x.toNumber())

Ardından blokları alıyoruz. Bu işlem biraz karmaşık, bu yüzden adım adım ele alacağız.

Hem başlık hem de işlemler olmak üzere bir bloğu almak için, ethers.js provider.getBlockWithTransactions() işlevini kullanırız.

JavaScript tek iş parçacıklıdır, bu nedenle bu işlev hemen bir Promise nesnesiyle döner. async x => await ethers… kullanarak beklemesini söyleyebiliriz, ancak bu verimsiz olur.

Bunun yerine, bir dizi vaat oluşturmak için map kullanıyoruz. Ardından, tüm vaatler çözülene kadar beklemek için Promise.all kullanırız. Bu bize bir dizi Block nesnesi verir.

 bloklar = Promise.all'i bekleyin(
    blockList.map(x => ethers.provider.getBlockWithTransactions(x))
  )

timestamp , işlemin değil, bloğun bir işlevidir. Burada, daha sonra mesaja zaman damgasını ekleyebilmemiz için blok numaralarından zaman damgalarına bir eşleme oluşturuyoruz. Blok numarası, her İşlem nesnesine dahil edilir.

 // Zaman damgalarını al
  zaman damgaları = {}
  bloklar.harita(blok => zaman damgaları[blok.numarası] = blok.zaman damgası)

Her Block nesnesi bir işlem listesi içerir; ancak map bize bir dizi işlem dizisi verir. Tek bir dizideki işlemlerle uğraşmak daha kolaydır, bu yüzden onu düzleştirmek için Array.flat() kullanıyoruz.

 // Metinleri al
  allTxs =blocks.map(x => x.transactions).flat()

Artık ihtiyacımız olan işlemleri içeren bloklardan tüm işlemlere sahibiz. Ancak, bu işlemlerin çoğu alakasız. Yalnızca, hedefi Chirper olan, istediğimiz göndericiden işlem istiyoruz.

Chirper'ın birden fazla yöntemi olsaydı, hangi yöntemin çağrıldığını kontrol eden verilerin ilk dört baytını filtrelememiz gerekirdi. Ancak Chirper'ın yalnızca bir yöntemi olduğu için bu adım gerekli değildir.

 ourTxs = allTxs.filter(x => x.from == gönderen && x.to == chirper.address)

Son olarak, daha önce tanımladığımız data2Str fonksiyonunu kullanarak işlemleri faydalı mesajlara dönüştürmemiz gerekiyor.

 msgs = ourTxs.map(x => {dönüş {
    metin: data2Str(x.data),
    zaman: zaman damgaları[x.blockNumber]
  }})

  mesaj gönder
} // getMsgs

Bu fonksiyon bir mesaj gönderir. getMsgs aksine, blok zincirine yapılan önemsiz bir çağrıdır. Mesajların sırasının korunması için işlemin gerçekten bir bloğa eklenmesini bekler.

 const post = zaman uyumsuz (cıvıl cıvıl, mesaj) => {
  bekle (chirper.post(msg) bekleniyor).bekle()
} // İleti

Waffle ve Chai ile sözleşmeyi test etmek

Kontrat testlerini ethers.js ile çalışan akıllı bir sözleşme test kütüphanesi olan Waffle ile yazacağız. Ethereum sözleşmelerini test etmek için Waffle kullanma hakkında daha fazla bilgi edinmek için bu eğiticiye bakın.

Test için Chai kütüphanesini kullanacağız.

 const {bekle} = zorunlu ("chai")

Chai'nin çalışma şekli, başarılı veya başarısız olan bir async() işleviyle çeşitli varlıkları (bu durumda Chirper sözleşmesi) describe .

 tarif("Chirper", zaman uyumsuz () => {

Tanımlama işlevinin içinde describe varlığın sahip it gereken davranışlar olan işlevlere sahipsiniz.

 it("Bir kullanıcı tarafından gönderilen mesajları döndürmeli", async () => {
    mesajlar = ["Merhaba, dünya", "Shalom Olam", "Salut Mundi"]

İlk adımımız, aşağıdaki gibi bir ContractFactory kullanarak Chirper sözleşmesini dağıtmaktır:

 Chirper = bekle ethers.getContractFactory("Chirper")
    chirper = bekle Chirper.deploy()

Ardından, dizideki tüm mesajları göndeririz. Bir sonraki gönderiyi yapmadan önce her gönderiyi await , böylece mesajları düzensiz almaz ve aşağıdaki eşitlik karşılaştırmasının başarısız olmasına neden oluruz.

 for(var i=0; i<messages.length; i++)
      gönderiyi bekle(chirper, mesajlar[i])

getSigners işlevi , müşterimizin kimlik bilgilerine sahip olduğu hesapları alır. İlk giriş varsayılandır, bu nedenle kullanılan post işlevidir.

 fromAddr = (eters.getSigners() bekleniyor)[0].address

Ardından, mesajları almak için getMsgs .

 alınanMesajlar = getMsgs'yi bekle(chirper, fromAddr)

Bu map kullanımı, gönderdiğimiz mesajların listesinin aldığımız mesajların listesine eşit olup olmadığını kontrol etmemizi sağlar. map içindeki fonksiyon iki parametreyi kabul edebilir: listedeki değer ve konumu.

 mesajlar.map((msg,i) => bekle(msg).to.equal(alınanMesajlar[i].text))

  }) // gönderilen mesajları döndürmeli...

Doğru mesajları almak yeterli değildir. Uygulamanın doğru çalıştığını göstermek için ayrıca filtrelenmesi gereken mesajların aslında filtrelendiğini de göstermeliyiz.

 it("Alakasız mesajları yoksaymalı", async() => {  
    Chirper = bekle ethers.getContractFactory("Chirper")
    chirper1 = bekle Chirper.deploy()

Farklı bir adresten gelen mesajlar oluşturmak için o adrese ait cüzdanı almamız gerekiyor.

 otherWallet = (eters.getSigners() bekleniyor)[1]

Ardından, yeni imzalayanla yeni bir Chirper sözleşme nesnesi oluşturmak için connect işlevini kullanırız.

 chirper1a = chirper1.connect(diğerWallet)    

Aradığımız adresten, ancak başka bir chirper örneğe gönderilen mesajlar da alakasız.

 chirper2 = bekle Chirper.deploy()
    yazı bekle(chirper1, "Merhaba, dünya")
    // Farklı chirper örneği
    gönderiyi bekle(chirper2, "İlgili değil")
    // Aynı cıvıltı, farklı kaynak adresi
    wait post(chirper1a, "Merhaba dünya, başka birinden")
    yazı bekle(chirper1, "Merhaba, dünya, 2. yarı")
    wait post(chirper2, "Ayrıca alakalı değil (farklı chirper)")
    wait post(chirper1a, "Aynı cıvıltı, farklı kullanıcı, ayrıca alakasız")

    alınanMesajlar = getMsgs'yi bekle(chirper1, 
        (bekle ethers.getSigners())[0].address)
    beklenen = ["Merhaba dünya", "Merhaba dünya, 2. yarı"]
    beklenen.map((msg,i) => bekle(msg).to.equal(alınanMesajlar[i].text))     
  }) // alakasız mesajları yok saymalı

}) //Chirper'ı tanımla

Çözüm

Bu makalede, Ethereum blok zincirinde çalışan merkezi olmayan bir sosyal medya platformu olan Chirper'ın nasıl oluşturulacağını gösterdik.

Facebook veya Twitter'ın aksine, blok zinciri platformumuza mesaj göndermek kullanıcıya mal olacak. Bu beklenmelidir. Merkezi olmayan sistemler, merkezileştirilmiş muadillerinden daha maliyetlidir. Bu nedenle, muhtemelen ücretsiz sosyal ağlarda gördüğümüz kadar çok kedi resmi veya politik mem görmemiz olası değildir!

Öte yandan, Chirper blockchain sosyal medya platformumuz bazı avantajlar sunuyor.

Birincisi, kalıcı olarak değiştirilemez bir kayıttır. İkincisi, veriler zincir üzerinde halka açıktır ve iş mantığı, kullanıcı arayüzünden bağımsız olarak açık kaynaktır. Bu, belirli bir sağlayıcının kullanıcı arayüzüne bağlı olmak yerine, kullanıcıların aynı verilere erişimi korurken UI'leri değiştirebileceği anlamına gelir.

Daha iyi bir kullanıcı arayüzünün kabul görmesi için ağ etkilerine karşı mücadele etmesi gerekmeyeceğinden, daha iyi bir kullanıcı deneyimi ile sonuçlanan deneme ve rekabet için çok daha fazla alan olacaktır.

Umarım bu makaleden hoşlanmışsınızdır.

Bir blockchain sosyal medya platformu tasarla ve inşa et yazısı ilk olarak LogRocket Blog'da göründü.

etiketlerETİKETLER
Üzgünüm, bu içerik için hiç etiket bulunmuyor.

Sıradaki içerik:

Bir blockchain sosyal medya platformu tasarlayın ve oluşturun