Penggunaan libp2p dalam op-stack

Ditulis oleh Joohhnnn

Aplikasi Libp2P di Optimism

Pada bagian ini, tujuan utamanya adalah untuk menjelaskan bagaimana Optimisme menggunakan Libb2P untuk menyelesaikan pembentukan jaringan P2P di Op-Node. Jaringan P2P terutama digunakan untuk menyampaikan informasi di node yang berbeda, seperti sequencer setelah menyelesaikan konstruksi blok Unsafe, dan menyebar melalui pub / sub gossiphub P2P. Libb2P juga berurusan dengan infrastruktur lain seperti jaringan, pengalamatan, dll dalam jaringan P2P.

Pelajari tentang libp2p

libp2p (disingkat dari "library peer-to-peer" atau "library peer-to-peer") adalah kerangka jaringan peer-to-peer (P2P) yang membantu mengembangkan aplikasi P2P. Ini berisi seperangkat protokol, spesifikasi, dan perpustakaan yang membuat komunikasi P2P antara peserta jaringan (juga dikenal sebagai "rekan" atau "rekan") lebih mudah (sumber[2] [3])。 Awalnya bagian dari proyek IPFS (InterPlanetary File), libp2p berkembang menjadi proyek yang berdiri sendiri yang menjadi tumpukan jaringan modular (sumber) untuk jaringan terdistribusi )。

libp2p adalah proyek open source dari komunitas IPFS yang menyambut kontribusi dari berbagai komunitas, termasuk membantu menulis spesifikasi, implementasi kode, dan membuat contoh dan tutorial[4] [5])。 libp2p terdiri dari beberapa blok bangunan, masing-masing dengan antarmuka yang sangat jelas, didokumentasikan, dan diuji yang membuatnya dapat disusun, diganti, dan karenanya dapat diupgrade )。 Sifat modular libp2p memungkinkan pengembang untuk memilih dan menggunakan hanya komponen yang diperlukan untuk aplikasi mereka, mempromosikan fleksibilitas dan efisiensi ketika membangun aplikasi web P2P.

Sumber daya terkait

  • Dokumentasi resmi untuk libp2p[6]
  • repositori GitHub libp2p[7]
  • Pengantar libp2p di ProtoSchool[8]

Arsitektur modular dan sifat open source libp2p menyediakan lingkungan yang baik untuk mengembangkan aplikasi P2P yang kuat, terukur, dan fleksibel, menjadikannya pemain penting di bidang jaringan terdistribusi dan pengembangan aplikasi jaringan.

implementasi libp2p

Saat menggunakan libp2p, Anda perlu menerapkan dan mengonfigurasi beberapa komponen inti untuk membangun jaringan P2P Anda. Berikut adalah beberapa aspek implementasi utama libp2p dalam aplikasi:

1. Pembuatan dan Konfigurasi Node:

Membuat dan mengkonfigurasi node libp2p adalah langkah paling dasar, yang mencakup pengaturan alamat jaringan node, identitas, dan parameter dasar lainnya. Kode penggunaan kunci:

libp2p. Baru()

2. Protokol Transportasi:

Pilih dan konfigurasikan protokol transport Anda (misalnya TCP, WebSockets, dll.) untuk memastikan komunikasi antar node. Kode penggunaan kunci:

tcpTransport := tcp. BaruTCPTransport()

3. ** Multiplexing dan Kontrol Aliran **:

  • Menerapkan multiplexing untuk memungkinkan beberapa aliran data bersamaan diproses pada satu koneksi.
  • Menerapkan kontrol aliran untuk mengelola laju transmisi data dan laju pemrosesan. Kode penggunaan kunci:

yamuxTransport := yamux. Baru()

4. Keamanan dan enkripsi:

  • Mengkonfigurasi lapisan transportasi yang aman untuk memastikan keamanan dan privasi komunikasi.
  • Menerapkan mekanisme enkripsi dan otentikasi untuk melindungi data dan mengotentikasi pihak yang berkomunikasi. Kode penggunaan kunci:

tlsTransport := tls. Baru()

5. Protokol dan Penanganan Pesan:

Tentukan dan terapkan protokol kustom untuk menangani operasi jaringan dan pertukaran pesan tertentu.

  • Proses pesan yang diterima dan mengirim tanggapan yang diperlukan. Kode penggunaan kunci:

tuan rumah. SetStreamHandler("/my-protocol/1.0.0", myProtocolHandler)

6. ** Penemuan dan Routing **:

  • Menerapkan mekanisme penemuan node untuk menemukan node lain dalam jaringan.
  • Menerapkan logika routing untuk menentukan bagaimana pesan yang diarahkan ke node yang benar dalam jaringan. Kode penggunaan kunci:

DHT := Kaddht. NewDHT(ctx, host, penyimpanan data. NewMapDatastore())

7. Perilaku dan kebijakan jaringan:

Tentukan dan terapkan perilaku dan kebijakan jaringan, seperti manajemen koneksi, penanganan kesalahan, dan coba lagi logika. Kode penggunaan kunci:

connManager := connmgr. NewConnManager (lowWater, highWater, gracePeriod)

8. Manajemen dan Penyimpanan Negara:

Kelola status node dan jaringan, termasuk status koneksi, daftar node, dan penyimpanan data. Kode penggunaan kunci:

toko sejawat := pstoremem. NewPeerstore()

9. Uji dan debug:

  • Tulis tes untuk aplikasi libp2p Anda untuk memastikan kebenaran dan keandalannya.
  • Gunakan alat debugging dan log untuk mendiagnosis dan menyelesaikan masalah jaringan. Kode penggunaan kunci:

Penebangan. SetLogLevel("libp2p", "DEBUG")

10. Dokumentasi dan Dukungan Komunitas:

  • Lihat dokumentasi libp2p untuk mempelajari tentang berbagai komponen dan API-nya.
  • Berkomunikasi dengan komunitas libp2p untuk dukungan dan pemecahan masalah.

}

Di atas adalah beberapa aspek utama yang perlu dipertimbangkan dan diterapkan saat menggunakan libp2p. Implementasi spesifik dari setiap proyek dapat bervariasi, tetapi aspek-aspek dasar ini diperlukan untuk membangun dan menjalankan aplikasi libp2p. Saat mengimplementasikan fungsi-fungsi ini, Anda dapat merujuk ke dokumentasi resmi libp2p[9] [10]dan repositori GitHub Contoh kode dan tutorial.

Penggunaan libp2p di OP-node

Untuk mengetahui hubungan antara op-node dan libp2p, kita harus mencari tahu beberapa pertanyaan

  • Mengapa libp2p? Mengapa tidak memilih devp2p (geth menggunakan devp2p)
  • Data atau proses apa yang terkait erat dengan jaringan P2P di OP-node
  • Bagaimana fitur ini diimplementasikan pada lapisan kode

Mengapa op-node membutuhkan jaringan libp2p

Pertama kita perlu memahami mengapa Optimisme membutuhkan jaringan P2P ** LibbP2P adalah protokol jaringan modular yang memungkinkan pengembang untuk membangun aplikasi peer-to-peer terdesentralisasi untuk berbagai kasus penggunaan (sumber[11] [12])(sumber [13])。 DevP2P, di sisi lain, terutama digunakan dalam ekosistem Ethereum dan disesuaikan untuk aplikasi Ethereum (Sumber )。 Fleksibilitas dan penerapan libp2p yang luas dapat menjadikannya pilihan utama bagi pengembang.

Op-Node terutama menggunakan titik fungsi libp2p

  • Digunakan oleh sequencer untuk meneruskan blok tidak aman yang dihasilkan ke node non-sequencer lainnya
  • Untuk node lain dalam mode non-sequencer untuk sinkronisasi cepat ketika terjadi celah (sinkronisasi rantai terbalik)
  • Lingkungan yang baik untuk mengadopsi sistem reputasi integral untuk mengatur keseluruhan node

Implementasi kode

inisialisasi kustom host

Host dapat dipahami sebagai node P2P, saat membuka node ini, Anda perlu membuat beberapa konfigurasi inisialisasi khusus untuk proyek Anda sendiri

Sekarang mari kita lihat metode Host di file op-node/p2p/host.go.

Fungsi ini terutama digunakan untuk mengatur host libp2p dan membuat berbagai konfigurasi. Berikut adalah bagian-bagian penting dari fungsi dan deskripsi Cina sederhana masing-masing:

  1. Periksa apakah P2P dinonaktifkan
    Jika P2P dinonaktifkan, fungsi kembali secara langsung.
  2. Dapatkan Peer ID dari Public Key
    Gunakan kunci publik dalam konfigurasi untuk menghasilkan ID Peer.
  3. Inisialisasi Peerstore
    Buat toko Peerstore dasar.
  4. Inisialisasi ekstensi Peerstore
    Di atas Peerstore dasar, buat Peerstore yang diperluas.
  5. Tambahkan kunci pribadi dan publik ke Peerstore
    Simpan kunci pribadi dan publik rekan di peerstore.
  6. Inisialisasi Connection Gater
    Digunakan untuk mengontrol koneksi jaringan.
  7. Inisialisasi Connection Manager
    Digunakan untuk mengelola koneksi jaringan.
  8. ** Mengatur Transmisi dan Mendengarkan Alamat **
    Atur protokol transport jaringan dan alamat mendengarkan host.
  9. ** Buat host libp2p **
    Gunakan semua pengaturan sebelumnya untuk membuat host libp2p baru.
  10. ** Inisialisasi rekan statis **
    Jika Anda memiliki peer statis yang dikonfigurasi, inisialisasi.
  11. Kembali ke Host
    Akhirnya, fungsi mengembalikan host libp2p yang dibuat.

Bagian kunci ini bertanggung jawab untuk menginisialisasi dan mengatur host libp2p, dan setiap bagian bertanggung jawab untuk aspek tertentu dari konfigurasi host.

func (conf * Config) Host (log log. Logger, metrik reporter. Reporter, metrik HostMetrics) (tuan rumah. Host, kesalahan) {  
    jika conf. NonaktifP2P {  
        kembali nihil, nihil  
    }  
    pub := conf. Priv.GetPublic()  
    pid, err := rekan. IDFromPublicKey(pub)  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal menurunkan pubkey dari kunci priv jaringan:%w", err)  
    }  
    basePs, err := disimpan. NewPeerstore(konteks. Latar belakang(), conf. Simpan, disimpan. DefaultOpts())  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal membuka peerstore:%w", err)  
    }  
    peerScoreParams := conf. PeerScoringParams()  
     scoreWaktu retensi. Durasi  
    jika peerScoreParams != nil {  
        Gunakan periode retensi yang sama seperti gosip jika tersedia  
        scoreRetention = peerScoreParams.PeerScoring.RetainScore  
    } lain {  
        Nonaktifkan skor GC jika penilaian rekan dinonaktifkan  
        scoreRetention = 0  
    }  
    ps, err := toko. NewExtendedPeerstore(konteks. Latar belakang(), log, jam. Jam, basePs, conf. Simpan, scoreRetention)  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal membuka peerstore yang diperluas:%w", err)  
    }  
    jika err := ps. AddPrivKey(pid, conf. Hak istimewa); err != nil {  
        kembali nihil, fmt. Errorf("gagal menyiapkan peerstore dengan priv key:%w", err)  
    }  
    jika err := ps. Tambahkan PubKey (pid, pub); err != nil {  
        kembali nihil, fmt. Errorf("gagal menyiapkan peerstore dengan kunci pub:%w", err)  
    }  
     connGtr gating. BlockingConnectionGater  
    connGtr, err = gating. NewBlockingConnectionGater(conf. Toko)  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal membuka penggater koneksi:%w", err)  
    }  
    connGtr = gating. AddBanExpiry(connGtr, ps, log, jam. Jam, metrik)  
    connGtr = gating. AddMetering(connGtr, metrik)  
    connMngr, err := DefaultConnManager(conf)  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal membuka pengelola koneksi: %w", err)  
    }  
    listenAddr, err := addrFromIPAndPort(conf. DengarkanIP, conf. DengarkanTCPPort)  
    jika err != nil {  
        kembali nihil, fmt. Errorf("gagal membuat addr dengar: %w", err)  
    }  
    tcpTransport := libp2p. Transportasi(  
        Tcp. BaruTCPTransport,  
        Tcp. WithConnectionTimeout(waktu. Menit*60)) // putuskan koneksi yang tidak digunakan  
    TODO: secara teknis kita juga dapat menjalankan node pada transportasi websocket dan QUIC Mungkin di masa depan?  
     Nat Lconf. NATManagerC // dinonaktifkan jika nihil  
    jika conf. NAT {  
        nat = basichost. BaruNATManager  
    }  
    memilih := []libp2p. Opsi{  
        libp2p. Identitas(conf. Priv),  
        Secara eksplisit mengatur user-agent, sehingga kita dapat membedakan dari pengguna Go libp2p lainnya.  
        libp2p. UserAgent(conf. UserAgent),  
        tcpTransport,  
        libp2p. WithDialTimeout(conf. TimeoutDial),  
        Tidak ada layanan relai, koneksi langsung antar rekan saja.  
        libp2p. DisableRelay(),  
        Host akan memulai dan mendengarkan jaringan langsung setelah konstruksi dari konfigurasi.  
        libp2p. ListenAddrs(dengarAddr),  
        libp2p. ConnectionGater(connGtr),  
        libp2p. ConnectionManager (connMngr),  
        libp2p. ResourceManager(nil), // TODO menggunakan antarmuka manajer sumber daya untuk mengelola sumber daya per rekan dengan lebih baik.  
        libp2p. Ping (benar),  
        libp2p. AutoNATServiceRateLimit(10, 5, waktu. Kedua*60),  
    }  
    jika conf. NoTransportSecurity {  
    } lain {  
        opts = tambahkan (opts, conf. Keamanan Host...)  
    }  
    h, err := libp2p. Baru(memilih...)  
    jika err != nil {  
    }  
    untuk i, peerAddr := range conf. StaticPeers {  
        jika err != nil {  
        }  
        Rekan statis[i]  = penambah  
    }  
    keluar := &extraHost{  
        Tuan rumah: h,  
        staticPeers: staticPeers,  
    }  
        keluar.monitorStaticPeers()  
    }  






        ...  
        n.gs, err = NewGossipSub(resourcesCtx, n.host, rollupCfg, setup, n.scorer, metrik, log)  
        jika err != nil {  
        }  
        ...  
  1. Pembuatan Authenticator: ** Blok Nama Tema Generasi **:
  • Hasilkan blocksTopicName menggunakan fungsi blocksTopicV1, yang memformat string berdasarkan L2ChainID dalam konfigurasi (cfg). String yang diformat mengikuti struktur tertentu: /optimism/{L2ChainID}/0/blocks.

  • Fungsi dengan memanggil ps. Join(blocksTopicName) mencoba menambahkan tema gosip blok. Jika terjadi kesalahan, itu mengembalikan pesan kesalahan yang menunjukkan bahwa topik tidak dapat digabungkan.

  • Menghasilkan goroutine baru untuk mencatat peristiwa topik menggunakan fungsi LogTopicEvents.

  • Membuat pelanggan menggunakan fungsi MakeSubscriber, yang merangkum BlocksHandler yang menangani peristiwa OnUnsafeL2Payload dari gossipIn. Goroutine baru dihasilkan untuk menjalankan subion yang disediakan.

    func JoinGossip(konteks p2pCtx. Konteks, peer.ID diri, ps *pubsub. PubSub, log log. Logger, cfg *rollup. Config, runCfg GossipRuntimeConfig, gossipIn GossipIn) (GossipOut, error) {
    blocksTopicName := blocksTopicV1(cfg) // mengembalikan fmt. Sprintf("/optimisme/%s/0/blok", cfg. L2ChainID.String())
    kembali nihil, fmt. Errorf("gagal mendaftar memblokir topik gosip:%w", err)
    }
    blocksTopic, err := ps. Gabung(blocksTopicName)
    jika err != nil {
    }
    jika err != nil {
    }
    pergi LogTopicEvents(p2pCtx, log. Baru("topik", "blok"), blocksTopicEvents)
    jika err != nil {
    }
    return &publisher{log: log, cfg: cfg, blocksTopic: blocksTopic, runCfg: runCfg}, nil

op-node/rollup/driver/state.go

func (s *Driver) eventLoop() {  
    untuk(){  
        ...  
            payload, err: = s.sequencer.RunNextSequencerAction (ctx)  
            jika err != nil {  
                Kesalahan tidak cukup parah untuk mengubah / menghentikan pengurutan tetapi harus dicatat dan diukur.  
                jika err := s.network.PublishL2Payload(ctx, payload); err != nil {  
            }  
            planSequencerAction() // jadwalkan tindakan sequencer berikutnya untuk menjaga perulangan pengurutan  
            }  
    }  
    ...  

Ketika ada blok yang hilang, sinkronisasi cepat melalui P2P

Ketika node dihubungkan kembali setelah downtime karena keadaan khusus, seperti menghubungkan kembali setelah downtime, beberapa blok (celah) mungkin tidak disinkronkan, dan ketika menghadapi situasi ini, mereka dapat dengan cepat melakukan sinkronisasi melalui rantai terbalik dari jaringan P2P.

Mari kita lihat fungsi checkForGapInUnsafeQueue di op-node/rollup/driver/state.go

Cuplikan kode mendefinisikan metode yang disebut checkForGapInUnsafeQueue, yang termasuk dalam struktur Driver. Tujuannya adalah untuk memeriksa kesenjangan data dalam antrian yang disebut "antrian tidak aman" dan mencoba untuk mengambil muatan yang hilang melalui metode sinkronisasi alternatif yang disebut altSync. Poin kuncinya di sini adalah bahwa metode ini adalah untuk memastikan kontinuitas data dan mencoba mengambil data yang hilang dari metode sinkronisasi lain ketika data yang hilang terdeteksi. Berikut adalah langkah-langkah utama fungsinya:

  1. Fungsi pertama mendapatkan UnsafeL2Head dan UnsafeL2SyncTarget dari s.derivation sebagai titik awal dan akhir dari rentang pemeriksaan.

  2. Fungsi memeriksa blok yang hilang antara awal dan akhir, yang dilakukan dengan membandingkan nilai Angka akhir dan awal.

  3. Jika celah data terdeteksi, fungsi akan meminta rentang data yang hilang dengan memanggil s.altSync.RequestL2Range (ctx, start, end). Jika end adalah referensi null (yaitu eth. L2BlockRef{}), fungsi akan meminta sinkronisasi rentang open-end, dimulai dengan start.

  4. Saat meminta data, fungsi mencatat log debug yang menunjukkan rentang data yang diminta.

  5. Fungsi akhirnya mengembalikan nilai kesalahan. Jika tidak ada kesalahan, itu mengembalikan nil

    checkForGapInUnsafeQueue memeriksa apakah ada celah dalam antrean yang tidak aman dan mencoba mengambil muatan yang hilang dari metode alt-sync.
    PERINGATAN: Ini hanya sinyal keluar, blok tidak dijamin akan diambil.
    Hasil diterima melalui OnUnsafeL2Payload.
    func (s *Driver) checkForGapInUnsafeQueue(konteks ctx. Konteks) kesalahan {
    mulai := s.derivation.UnsafeL2Head()
    akhir: = s.derivation.UnsafeL2SyncTarget ()
    Periksa apakah kita memiliki blok yang hilang antara awal dan akhir Mintalah mereka jika kita melakukannya.
    jika akhir == (eth. L2BlockRef{}) {
    s.log.Debug("meminta sinkronisasi dengan rentang open-end", "mulai", mulai)
    mengembalikan s.altSync.RequestL2Range (ctx, mulai, eth. L2BlockRef{})
    } lain jika akhir. Nomor > mulai. Angka+1 {
    s.log.Debug("meminta rentang blok L2 yang tidak aman", "mulai", mulai, "akhir", akhir, akhir, "ukuran", akhir. Nomor-mulai.Angka)
    mengembalikan s.altSync.RequestL2Range (ctx, mulai, akhir)
    }
    kembali nihil
    }

Fungsi RequestL2Range menandakan awal dan akhir blok permintaan ke saluran permintaan.

Permintaan kemudian didistribusikan ke saluran peerRequests melalui metode onRangeRequest, dan saluran peerRequests ditunggu oleh loop yang dibuka oleh beberapa peer, yaitu hanya satu peer yang akan memproses permintaan untuk setiap distribusi.

func (s *SyncClient) onRangeRequest(konteks ctx. Context, req rangeRequest) {  
        ...  
        untuk i := uint64(0); ; i++ {  
        num := req.end.Number - 1 - i  
        jika num <= req.start {  
            kembali  
        }  
        Periksa apakah kita sudah memiliki sesuatu di karantina  
        jika h, ok := s.quarantineByNum[num] ; Oke {  
            jika s.trusted.Contains(h) { // jika kita mempercayainya, cobalah untuk mempromosikannya.  
                s.tryPromote(h)  
            }  
            Jangan mengambil hal-hal yang sudah kita miliki kandidatnya.  
            Kami akan mengusirnya dari karantina dengan menemukan konflik, atau jika kami menyinkronkan cukup banyak blok lain  
            terus  
        }  
        if _, ok := s.inFlight[num] ; Oke {  
            .log. Debug("permintaan masih dalam penerbangan, bukan permintaan sinkronisasi penjadwalan ulang", "num", num)  
            lanjutkan // permintaan masih dalam penerbangan  
        }  
        pr := peerRequest{num: num, complete: new(atomic. Bool)}  
        .log. Debug("Menjadwalkan permintaan blok P2P", "num", num)  
        Nomor jadwal  
        Pilih {  
        kasus s.peerRequests <- pr:  
            s.inPesawat[num]  = pr.lengkap  
        Kasus <-CTX. Selesai():  
            .log. Info ("tidak menjadwalkan rentang sinkronisasi P2P penuh", "saat ini", num, "err", ctx. Err())  
            kembali  
        default: // peer mungkin sudah sibuk memproses permintaan  
            .log. Info ("tidak ada rekan yang siap menangani permintaan blok untuk lebih banyak permintaan P2P untuk riwayat blok L2", "saat ini", num)  
            kembali  
        }  
    }  
}

Mari kita lihat apa yang terjadi ketika rekan menerima permintaan ini.

Hal pertama yang perlu kita ketahui adalah bahwa tautan antara peer dan node yang meminta, atau pesan yang lewat, dilewatkan melalui aliran libp2p. Metode pemrosesan aliran diimplementasikan oleh simpul rekan penerima, dan pembuatan aliran dibuka oleh simpul pengirim.

Kita dapat melihat kode ini dalam fungsi init sebelumnya, di mana MakeStreamHandler mengembalikan handler, dan SetStreamHandler mengikat ID protokol ke handler ini, jadi setiap kali node pengirim membuat dan menggunakan aliran ini, handler yang dikembalikan dipicu.

n.syncSrv = NewReqRespServer(rollupCfg, l2Chain, metrik)  
Daftarkan protokol sinkronisasi dengan host libp2p  
payloadByNumber := MakeStreamHandler(resourcesCtx, log. Baru("melayani", "payloads_by_number"), n.syncSrv.HandleSyncRequest)  
n.host.SetStreamHandler(PayloadByNumberProtocolID(rollupCfg.L2ChainID), payloadByNumber)

Mari kita lihat bagaimana penanganannya ditangani di dalam pawang Fungsi ini pertama-tama melakukan pemeriksaan batas tarif global dan individual untuk mengontrol seberapa cepat permintaan diproses. Kemudian membaca dan memverifikasi nomor blok yang diminta, memastikan bahwa itu berada dalam kisaran yang wajar. Fungsi ini kemudian mendapatkan muatan potongan permintaan dari layer L2 dan menuliskannya ke aliran respons. Saat menulis data respons, ini menetapkan tenggat waktu penulisan untuk menghindari diblokir oleh koneksi rekan yang lambat selama proses penulisan. Akhirnya, fungsi mengembalikan nomor blok yang diminta dan kemungkinan kesalahan.

func (srv * ReqRespServer) handleSyncRequest (konteks ctx. Konteks, jaringan streaming. Stream) (uint64, error) {  
    peerId := aliran. Conn(). RemotePeer()  
    ambil token dari pembatas tarif global,  
    untuk memastikan tidak ada terlalu banyak pekerjaan server bersamaan antara peer yang berbeda.  
    jika err := srv.globalRequestsRL.Wait(ctx); err != nil {  
        kembali 0, fmt. Errorf("waktu habis menunggu batas laju sinkronisasi global:%w", err)  
    }  
    Temukan data pembatas tingkat peer, atau tambahkan sebaliknya  
    srv.peerStatsLock.Lock()  
    ps, _ := srv.peerRateLimits.Get(peerId)  
    jika ps == nil {  
        ps = &peerStat{  
            Permintaan: tingkat. NewLimiter (peerServerBlocksRateLimit, peerServerBlocksBurst),  
        }  
        srv.peerRateLimits.Add(peerId, ps)  
        Ps. Requests.Reserve() // hitung hit, tetapi buat itu menunda permintaan berikutnya daripada segera menunggu  
    } lain {  
        Hanya tunggu jika itu adalah peer yang ada, jika tidak, batas tarif instan Tunggu panggilan selalu salah.  
        Jika pemohon berpikir kami terlalu lama, maka itu masalah mereka dan mereka dapat memutuskan sambungan.  
        Kami akan memutuskan hubungan hanya ketika gagal membaca / menulis,  
        jika pekerjaan tidak valid (validasi rentang), atau ketika batas waktu sub tugas individu.  
        jika err := ps. Permintaan.Tunggu (ctx); err != nil {  
            kembali 0, fmt. Errorf("waktu habis menunggu batas laju sinkronisasi global:%w", err)  
        }  
    }  
    srv.peerStatsLock.Buka kunci()  
    Tetapkan batas waktu baca, jika tersedia  
    _ = aliran. SetReadDeadline(waktu. Sekarang(). Tambahkan (serverReadRequestTimeout))  
    Baca permintaan  
     req uint64  
    jika err := biner. Baca (aliran, biner. LittleEndian, &req); err != nil {  
        kembali 0, fmt. Errorf("gagal membaca nomor blok yang diminta:%w", err)  
    }  
    jika err := aliran. CloseRead(); err != nil {  
        kembali req, fmt. Errorf("gagal menutup sisi baca panggilan permintaan sinkronisasi P2P:%w", err)  
    }  
    Pastikan permintaan berada dalam kisaran blok yang diharapkan  
    jika req < srv.cfg.Genesis.L2.Number {  
        kembali req, fmt. Errorf("tidak dapat melayani permintaan untuk blok L2% d sebelum genesis %d: %w", req, srv.cfg.Genesis.L2.Number, invalidRequestErr)  
    }  
    max, err := srv.cfg.TargetBlockNumber(uint64(waktu. Sekarang(). Unix()))  
    jika err != nil {  
        kembali req, fmt. Errorf("tidak dapat menentukan jumlah blok target maksimum untuk memverifikasi permintaan:%w", invalidRequestErr)  
    }  
    jika req > max {  
        kembali req, fmt. Errorf("tidak dapat melayani permintaan untuk blok L2%d setelah blok maksimum yang diharapkan (%v): %w", req, max, invalidRequestErr)  
    }  
    payload, err := srv.l2.PayloadByNumber (ctx, req)  
    jika err != nil {  
        jika kesalahan. Apakah (err, ethereum. NotFound) {  
            kembali req, fmt. Errorf("peer meminta blok tidak dikenal berdasarkan nomor:%w", err)  
        } lain {  
            kembali req, fmt. Errorf("gagal mengambil payload untuk melayani peer:%w", err)  
        }  
    }  
    Kami menetapkan tenggat waktu penulisan, jika tersedia, untuk menulis dengan aman tanpa memblokir koneksi peer yang membatasi  
    _ = aliran. SetWriteDeadline(waktu. Sekarang(). Tambahkan(serverWriteChunkTimeout))  
    0 - resultCode: sukses = 0  
    1:5 - versi: 0  
     .tmp [5] byte  
    jika _, err := aliran. Tulis(tmp[:]); err != nil {  
        kembali req, fmt. Errorf("gagal menulis data header respons:%w", err)  
    }  
    w := tajam. NewBufferedWriter(aliran)  
    jika _, err := payload. Marsekal SSZ (w); err != nil {  
        kembali req, fmt. Errorf("gagal menulis payload untuk menyinkronkan respons: %w", err)  
    }  
    jika err := w.Close(); err != nil {  
        kembali req, fmt. Errorf("gagal menyelesaikan penulisan payload untuk menyinkronkan respons: %w", err)  
    }  
    kembali req, nil  
}

Pada titik ini, proses umum permintaan dan pemrosesan sinkronisasi rantai terbalik telah dijelaskan

Sistem reputasi poin di node p2p

Untuk mencegah node tertentu membuat permintaan dan respons jahat yang merusak keamanan seluruh jaringan, Optimisme juga menggunakan sistem poin.

Misalnya, di op-node/p2p/app_scores.go, ada serangkaian fungsi untuk mengatur skor peer

func (s *peerApplicationScorer) onValidResponse(id peer.ID) {  
    _, err := s.scorebook.SetScore(id, toko. IncrementValidResponses{Cap: s.params.ValidResponseCap})  
    jika err != nil {  
        s.log.Error("Tidak dapat memperbarui skor sejawat", "rekan", id, "err", err)  
        kembali  
    }  
}  
func (s *peerApplicationScorer) onResponseError(id peer.ID) {  
    _, err := s.scorebook.SetScore(id, toko. IncrementErrorResponses{Cap: s.params.ErrorResponseCap})  
    jika err != nil {  
        s.log.Error("Tidak dapat memperbarui skor sejawat", "rekan", id, "err", err)  
        kembali  
    }  
}  
func (s *peerApplicationScorer) onRejectedPayload(id peer.ID) {  
    _, err := s.scorebook.SetScore(id, toko. IncrementRejectedPayloads{Cap: s.params.RejectedPayloadCap})  
    jika err != nil {  
        s.log.Error("Tidak dapat memperbarui skor sejawat", "rekan", id, "err", err)  
        kembali  
    }  
}

Status integrasi node baru kemudian diperiksa sebelum ditambahkan

func AddScoring (gater BlockingConnectionGater, skor Scores, minScore float64) * ScoringConnectionGater {  
    return &ScoringConnectionGater{BlockingConnectionGater: gater, skor: skor, minScore: minScore}  
}  
func (g *ScoringConnectionGater) checkScore(p peer.ID) (izinkan bool) {  
    skor, err := g.scores.GetPeerScore(p)  
    jika err != nil {  
        mengembalikan false  
    }  
    mengembalikan skor >= g.minScore  
}  
func (g *ScoringConnectionGater) InterceptPeerDial(p peer.ID) (izinkan bool) {  
    mengembalikan g.BlockingConnectionGater.InterceptPeerDial(p) &&; g.checkScore(p)  
}  
func (g *ScoringConnectionGater) InterceptAddrDial(id peer.ID, ma multiaddr. Multiaddr) (izinkan bool) {  
    mengembalikan g.BlockingConnectionGater.InterceptAddrDial(id, ma) &&; g.checkScore(id)  
}  
func (g * ScoringConnectionGater) InterceptSecured (jaringan dir. Arah, id peer.ID, mas jaringan. ConnMultiaddrs) (izinkan bool) {  
    mengembalikan g.BlockingConnectionGater.InterceptSecured(dir, id, mas) &&; g.checkScore(id)  
}

Ringkasan

Konfigurasi libp2p yang tinggi membuat seluruh proyek p2p sangat dapat disesuaikan dan modular, di atas adalah logika utama implementasi libp2p yang dipersonalisasi oleh optimsim, dan detail lainnya dapat dipelajari secara rinci dengan membaca kode sumber di direktori p2p.

Lihat Asli
Halaman ini mungkin berisi konten pihak ketiga, yang disediakan untuk tujuan informasi saja (bukan pernyataan/jaminan) dan tidak boleh dianggap sebagai dukungan terhadap pandangannya oleh Gate, atau sebagai nasihat keuangan atau profesional. Lihat Penafian untuk detailnya.
  • Hadiah
  • Komentar
  • Bagikan
Komentar
0/400
Tidak ada komentar
  • Sematkan
Perdagangkan Kripto Di Mana Saja Kapan Saja
qrCode
Pindai untuk mengunduh aplikasi Gate
Komunitas
Bahasa Indonesia
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)