From 071446e8d31f3dabb54cd545a87f8181628b869b Mon Sep 17 00:00:00 2001 From: Joshua <62268199+minimalsm@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:07:56 +0000 Subject: [PATCH 1/9] i18n(pl): translation import part 03 of 13 (24 files) --- .../pos/attestations/index.md | 92 ++ .../pos/block-proposal/index.md | 69 ++ .../consensus-mechanisms/pos/faqs/index.md | 173 +++ .../consensus-mechanisms/pos/gasper/index.md | 52 + .../docs/consensus-mechanisms/pos/index.md | 107 +- .../consensus-mechanisms/pos/keys/index.md | 102 ++ .../pos/pos-vs-pow/index.md | 69 ++ .../pos/rewards-and-penalties/index.md | 91 ++ .../pos/weak-subjectivity/index.md | 39 + .../pos/withdrawal-credentials/index.md | 64 ++ .../docs/consensus-mechanisms/pow/index.md | 95 +- .../consensus-mechanisms/pow/mining/index.md | 76 +- .../dagger-hashimoto/index.md | 329 ++++++ .../mining/mining-algorithms/ethash/index.md | 1022 +++++++++++++++++ .../pow/mining/mining-algorithms/index.md | 42 + .../pl/developers/docs/dapps/index.md | 82 +- .../block-explorers/index.md | 354 +++--- .../docs/data-and-analytics/index.md | 67 +- .../index.md | 118 ++ .../docs/data-availability/index.md | 84 ++ .../data-structures-and-encoding/index.md | 32 + .../patricia-merkle-trie/index.md | 266 +++++ .../data-structures-and-encoding/rlp/index.md | 163 +++ .../data-structures-and-encoding/ssz/index.md | 150 +++ 24 files changed, 3381 insertions(+), 357 deletions(-) create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/attestations/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/block-proposal/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/faqs/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/gasper/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/keys/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pos/withdrawal-credentials/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md create mode 100644 public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md create mode 100644 public/content/translations/pl/developers/docs/data-availability/blockchain-data-storage-strategies/index.md create mode 100644 public/content/translations/pl/developers/docs/data-availability/index.md create mode 100644 public/content/translations/pl/developers/docs/data-structures-and-encoding/index.md create mode 100644 public/content/translations/pl/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md create mode 100644 public/content/translations/pl/developers/docs/data-structures-and-encoding/rlp/index.md create mode 100644 public/content/translations/pl/developers/docs/data-structures-and-encoding/ssz/index.md diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/attestations/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/attestations/index.md new file mode 100644 index 00000000000..1a5e2dee893 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/attestations/index.md @@ -0,0 +1,92 @@ +--- +title: "Poświadczenia" +description: "Opis zaświadczeń proof-of-stake na Ethereum." +lang: pl +--- + +Od walidatora oczekuje się, że utworzy, podpisze i rozgłosi poświadczenie w każdej epoce. Na tej stronie opisano, jak wyglądają te poświadczenia oraz jak są przetwarzane i przekazywane między klientami konsensusu. + +## Czym jest poświadczenie? {#what-is-an-attestation} + +W każdej [epoce](/glossary/#epoch) (6,4 minuty) walidator proponuje sieci poświadczenie. Poświadczenie dotyczy określonego slotu w epoce. Celem poświadczenia jest zagłosowanie za widokiem łańcucha przez walidatora, w szczególności za ostatnim uzasadnionym blokiem i pierwszym blokiem w bieżącej epoce (znanymi jako punkty kontrolne `source` i `target`). Informacje te są łączone dla wszystkich uczestniczących walidatorów, umożliwiając sieci osiągnięcie konsensusu co do stanu łańcucha bloków. + +Poświadczenie zawiera następujące składniki: + +- `aggregation_bits`: lista bitowa walidatorów, w której pozycja odpowiada indeksowi walidatora w jego komitecie; wartość (0/1) wskazuje, czy walidator podpisał `dane` (tj. czy jest aktywny i zgadza się z proponującym blok) +- `data`: szczegóły dotyczące poświadczenia, zdefiniowane poniżej +- `signature`: podpis BLS, który agreguje podpisy poszczególnych walidatorów + +Pierwszym zadaniem walidatora poświadczającego jest zbudowanie `danych`. `Dane` zawierają następujące informacje: + +- `slot`: numer slotu, do którego odnosi się poświadczenie +- `index`: numer identyfikujący komitet, do którego należy walidator w danym slocie +- `beacon_block_root`: główny hasz bloku, który walidator widzi na czele łańcucha (wynik zastosowania algorytmu wyboru forka) +- `source`: część głosowania w sprawie nieodwołalności, wskazująca, co walidatorzy postrzegają jako najnowszy uzasadniony blok +- `target`: część głosowania w sprawie nieodwołalności, wskazująca, co walidatorzy postrzegają jako pierwszy blok w bieżącej epoce + +Po zbudowaniu `danych`, walidator może zmienić bit w `aggregation_bits` odpowiadający jego własnemu indeksowi walidatora z 0 na 1, aby pokazać, że brał udział. + +Na koniec walidator podpisuje poświadczenie i rozgłasza je w sieci. + +### Poświadczenie zagregowane {#aggregated-attestation} + +Przekazywanie tych danych w sieci dla każdego walidatora wiąże się ze znacznym narzutem. Dlatego poświadczenia od poszczególnych walidatorów są agregowane w podsieciach, zanim zostaną szerzej rozgłoszone. Obejmuje to agregowanie podpisów, tak aby rozgłaszane poświadczenie zawierało `dane` konsensusu i pojedynczy podpis utworzony przez połączenie podpisów wszystkich walidatorów, którzy zgadzają się z tymi `danymi`. Można to sprawdzić za pomocą `aggregation_bits`, ponieważ dostarcza to indeks każdego walidatora w jego komitecie (którego ID jest podane w `danych`), który można wykorzystać do odpytywania poszczególnych podpisów. + +W każdej epoce 16 walidatorów w każdej podsieci jest wybieranych na `agregatorów`. Agregatorzy zbierają wszystkie poświadczenia, o których usłyszą w sieci gossip, które mają `dane` równoważne z ich własnymi. Nadawca każdego pasującego poświadczenia jest zapisywany w `aggregation_bits`. Agregatorzy następnie rozgłaszają agregat poświadczeń do szerszej sieci. + +Gdy walidator zostaje wybrany na proponującego blok, pakuje zagregowane poświadczenia z podsieci aż do najnowszego slotu w nowym bloku. + +### Cykl życia włączenia poświadczenia {#attestation-inclusion-lifecycle} + +1. Generowanie +2. Propagacja +3. Agregacja +4. Propagacja +5. Włączenie + +Cykl życia poświadczenia jest przedstawiony na poniższym schemacie: + +![cykl życia poświadczenia](./attestation_schematic.png) + +## Nagrody {#rewards} + +Walidatorzy są nagradzani za przesyłanie poświadczeń. Nagroda za poświadczenie zależy od flag uczestnictwa (źródło, cel i głowa), nagrody podstawowej i wskaźnika uczestnictwa. + +Każda z flag uczestnictwa może mieć wartość „prawda” lub „fałsz”, w zależności od przesłanego poświadczenia i jego opóźnienia włączenia. + +Najlepszy scenariusz ma miejsce, gdy wszystkie trzy flagi mają wartość „prawda”, w którym to przypadku walidator zarobi (za każdą prawidłową flagę): + +`nagroda += nagroda podstawowa * waga flagi * wskaźnik poświadczania flagi / 64` + +Wskaźnik poświadczania flagi jest mierzony za pomocą sumy efektywnych sald wszystkich walidatorów poświadczających dla danej flagi w porównaniu z całkowitym aktywnym saldem efektywnym. + +### Nagroda podstawowa {#base-reward} + +Nagroda podstawowa jest obliczana na podstawie liczby walidatorów poświadczających i ich efektywnych sald stakowanego etheru: + +`nagroda podstawowa = efektywne saldo walidatora x 2^6 / SQRT(Efektywne saldo wszystkich aktywnych walidatorów)` + +#### Opóźnienie włączenia {#inclusion-delay} + +W momencie, gdy walidatorzy głosowali nad głową łańcucha (`blok n`), `blok n+1` nie został jeszcze zaproponowany. Dlatego poświadczenia są naturalnie włączane **jeden blok później**, więc wszystkie poświadczenia, które głosowały za tym, że `blok n` jest głową łańcucha, zostały włączone do `bloku n+1`, a **opóźnienie włączenia** wynosi 1. Jeśli opóźnienie włączenia podwoi się do dwóch slotów, nagroda za poświadczenie zmniejszy się o połowę, ponieważ do obliczenia nagrody za poświadczenie, nagroda podstawowa jest mnożona przez odwrotność opóźnienia włączenia. + +### Scenariusze poświadczeń {#attestation-scenarios} + +#### Brakujący walidator głosujący {#missing-voting-validator} + +Walidatorzy mają maksymalnie 1 epokę na przesłanie swojego poświadczenia. Jeśli poświadczenie zostało pominięte w epoce 0, mogą je przesłać z opóźnieniem włączenia w epoce 1. + +#### Brakujący agregator {#missing-aggregator} + +W sumie jest 16 agregatorów na epokę. Ponadto losowi walidatorzy subskrybują **dwie podsieci na 256 epok** i służą jako kopia zapasowa na wypadek braku agregatorów. + +#### Brakujący proponujący blok {#missing-block-proposer} + +Należy pamiętać, że w niektórych przypadkach szczęśliwy agregator może również stać się proponującym blok. Jeśli poświadczenie nie zostało włączone, ponieważ brakuje proponującego blok, następny proponujący blok pobierze zagregowane poświadczenie i włączy je do następnego bloku. Jednakże **opóźnienie włączenia** wzrośnie o jeden. + +## Dalsza lektura {#further-reading} + +- [Poświadczenia w specyfikacji konsensusu z adnotacjami Vitalika](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#attestationdata) +- [Poświadczenia w eth2book.info](https://eth2book.info/capella/part3/containers/dependencies/#attestationdata) + +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/block-proposal/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/block-proposal/index.md new file mode 100644 index 00000000000..440b51ceb96 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/block-proposal/index.md @@ -0,0 +1,69 @@ +--- +title: Propozycja bloku +description: "Wyjaśnienie, w jaki sposób bloki są proponowane w Ethereum z dowodem stawki." +lang: pl +--- + +Bloki są podstawowymi jednostkami łańcucha bloków. Bloki są oddzielnymi jednostkami informacji, które są przekazywane między węzłami, uzgadniane i dodawane do bazy danych każdego węzła. Ta strona wyjaśnia, w jaki sposób są one produkowane. + +## Wymagania wstępne {#prerequisites} + +Proponowanie bloków jest częścią protokołu dowodu stawki. Aby lepiej zrozumieć tę stronę, zalecamy zapoznanie się z [dowodem stawki](/developers/docs/consensus-mechanisms/pos/) oraz [architekturą bloku](/developers/docs/blocks/). + +## Kto produkuje bloki? {#who-produces-blocks} + +Konta walidatorów proponują bloki. Konta walidatorów są zarządzane przez operatorów węzłów, którzy uruchamiają oprogramowanie walidatora jako część swoich klientów wykonawczych i klientów konsensusu oraz zdeponowali co najmniej 32 ETH w kontrakcie depozytowym. Jednak każdy walidator jest tylko od czasu do czasu odpowiedzialny za zaproponowanie bloku. Ethereum mierzy czas w slotach i epokach. Każdy slot trwa dwanaście sekund, a 32 sloty (6,4 minuty) tworzą jedną epokę. Każdy slot to okazja do dodania nowego bloku w Ethereum. + +### Losowy wybór {#random-selection} + +Pojedynczy walidator jest wybierany pseudolosowo do zaproponowania bloku w każdym slocie. W łańcuchu bloków nie ma czegoś takiego jak prawdziwa losowość, ponieważ gdyby każdy węzeł generował prawdziwie losowe liczby, nie mogłyby osiągnąć konsensusu. Zamiast tego celem jest uczynienie procesu wyboru walidatora nieprzewidywalnym. Losowość w Ethereum jest osiągana za pomocą algorytmu o nazwie RANDAO, który miesza hasz od proponenta bloku z ziarnem, które jest aktualizowane co blok. Ta wartość służy do wyboru określonego walidatora z całego zestawu walidatorów. Wybór walidatora jest ustalany z wyprzedzeniem dwóch epok jako sposób na ochronę przed niektórymi rodzajami manipulacji ziarnem. + +Chociaż walidatorzy dodają do RANDAO w każdym slocie, globalna wartość RANDAO jest aktualizowana tylko raz na epokę. Aby obliczyć indeks następnego proponenta bloku, wartość RANDAO jest mieszana z numerem slotu, aby dać unikalną wartość w każdym slocie. Prawdopodobieństwo wyboru pojedynczego walidatora nie wynosi po prostu `1/N` (gdzie `N` = całkowita liczba aktywnych walidatorów). Zamiast tego jest ono ważone efektywnym saldem ETH każdego walidatora. Maksymalne efektywne saldo wynosi 32 ETH (oznacza to, że `saldo < 32 ETH` prowadzi do niższej wagi niż `saldo == 32 ETH`, ale `saldo > 32 ETH` nie prowadzi do wyższej wagi niż `saldo == 32 ETH`). + +Tylko jeden proponent bloku jest wybierany w każdym slocie. W normalnych warunkach jeden producent bloku tworzy i publikuje pojedynczy blok w przeznaczonym dla niego slocie. Utworzenie dwóch bloków dla tego samego slotu jest wykroczeniem podlegającym slashingowi, często znanym jako „ekwiwokacja”. + +## Jak tworzony jest blok? {#how-is-a-block-created} + +Oczekuje się, że proponent bloku będzie rozgłaszał podpisany blok beacon, który jest budowany na ostatniej głowie łańcucha zgodnie z widokiem jego własnego, lokalnie uruchomionego algorytmu wyboru forka. Algorytm wyboru forka stosuje wszelkie poświadczenia w kolejce pozostałe z poprzedniego slotu, a następnie znajduje blok o największej skumulowanej wadze poświadczeń w swojej historii. Ten blok jest rodzicem nowego bloku utworzonego przez proponenta. + +Proponent bloku tworzy blok, zbierając dane z własnej lokalnej bazy danych i widoku łańcucha. Zawartość bloku pokazano w poniższym fragmencie kodu: + +```rust +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data + graffiti: Bytes32 + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + sync_aggregate: SyncAggregate + execution_payload: ExecutionPayload +``` + +Pole `randao_reveal` przyjmuje weryfikowalną wartość losową, którą proponent bloku tworzy, podpisując numer bieżącej epoki. `eth1_data` to głos na widok kontraktu depozytowego przez proponenta bloku, w tym na root drzewa Merkle depozytów oraz całkowitą liczbę depozytów, które umożliwiają weryfikację nowych depozytów. `graffiti` to opcjonalne pole, które można wykorzystać do dodania wiadomości do bloku. `proposer_slashings` i `attester_slashings` to pola zawierające dowody na to, że niektórzy walidatorzy popełnili wykroczenia podlegające slashingowi, zgodnie z widokiem łańcucha przez proponenta. `deposits` to lista nowych depozytów walidatorów, o których wie proponent bloku, a `voluntary_exits` to lista walidatorów, którzy chcą wyjść, o których proponent bloku usłyszał w sieci plotek warstwy konsensusu. `sync_aggregate` to wektor pokazujący, którzy walidatorzy zostali wcześniej przypisani do komitetu synchronizacji (podzbioru walidatorów, którzy obsługują dane lekkiego klienta) i uczestniczyli w podpisywaniu danych. + +`execution_payload` umożliwia przekazywanie informacji o transakcjach między klientami wykonawczymi a klientami konsensusu. `execution_payload` to blok danych wykonawczych, który jest zagnieżdżony wewnątrz bloku beacon. Pola wewnątrz `execution_payload` odzwierciedlają strukturę bloku opisaną w Yellow Paper Ethereum, z tym wyjątkiem, że nie ma ommerów, a `prev_randao` istnieje w miejsce `difficulty`. Klient wykonawczy ma dostęp do lokalnej puli transakcji, o których usłyszał w swojej własnej sieci plotek. Transakcje te są wykonywane lokalnie w celu wygenerowania zaktualizowanego trie stanu, znanego jako post-state. Transakcje są zawarte w `execution_payload` jako lista o nazwie `transactions`, a post-state jest podany w polu `state-root`. + +Wszystkie te dane są gromadzone w bloku beacon, podpisywane i rozgłaszane do peerów proponenta bloku, którzy propagują je dalej do swoich peerów itd. + +Przeczytaj więcej o [anatomii bloków](/developers/docs/blocks). + +## Co dzieje się z blokiem? {#what-happens-to-blocks} + +Blok jest dodawany do lokalnej bazy danych proponenta bloku i rozgłaszany do peerów za pośrednictwem sieci plotek warstwy konsensusu. Gdy walidator otrzyma blok, weryfikuje dane w nim zawarte, w tym sprawdza, czy blok ma prawidłowego rodzica, odpowiada prawidłowemu slotowi, czy indeks proponenta jest zgodny z oczekiwaniami, czy ujawnienie RANDAO jest prawidłowe i czy proponent nie został poddany slashingowi. `execution_payload` jest rozpakowywany, a klient wykonawczy walidatora ponownie wykonuje transakcje z listy, aby sprawdzić proponowaną zmianę stanu. Zakładając, że blok przejdzie wszystkie te kontrole, każdy walidator dodaje blok do swojego własnego kanonicznego łańcucha. Następnie proces rozpoczyna się od nowa w następnym slocie. + +## Nagrody za blok {#block-rewards} + +Proponent bloku otrzymuje zapłatę za swoją pracę. Istnieje `base_reward`, która jest obliczana jako funkcja liczby aktywnych walidatorów i ich efektywnych sald. Proponent bloku otrzymuje następnie ułamek `base_reward` za każde prawidłowe poświadczenie zawarte w bloku; im więcej walidatorów poświadczy blok, tym większa nagroda dla proponenta bloku. Istnieje również nagroda za zgłaszanie walidatorów, którzy powinni zostać poddani slashingowi, równa `1/512 * efektywne saldo` za każdego walidatora poddanego slashingowi. + +[Więcej o nagrodach i karach](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) + +## Dalsza lektura {#further-reading} + +- [Wprowadzenie do bloków](/developers/docs/blocks/) +- [Wprowadzenie do proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Specyfikacje konsensusu Ethereum](https://github.com/ethereum/consensus-specs) +- [Wprowadzenie do Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) +- [Aktualizacja Ethereum](https://eth2book.info/) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/faqs/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/faqs/index.md new file mode 100644 index 00000000000..555b8d67848 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/faqs/index.md @@ -0,0 +1,173 @@ +--- +title: "Najczęściej zadawane pytania" +description: "Najczęściej zadawane pytania dotyczące proof-of-stake Ethereum." +lang: pl +--- + +## Czym jest proof-of-stake {#what-is-proof-of-stake} + +Proof-of-stake to klasa algorytmów, które mogą zapewnić bezpieczeństwo blockchainów poprzez zagwarantowanie, że aktywa wartościowe zostaną utracone przez atakujących, którzy działają nieuczciwie. Systemy proof-of-stake wymagają zestawu walidatorów, aby udostępnić pewne aktywa, które mogą zostać zniszczone, jeśli walidator zaangażuje się w udowodnione nieuczciwe zachowanie. Ethereum wykorzystuje mechanizm proof-of-stake do zabezpieczania blockchaina. + +## Jak proof-of-stake ma się do proof-of-work? {#comparison-to-proof-of-work} + +Zarówno proof-of-work, jak i proof-of-stake są mechanizmami, które ekonomicznie zniechęcają złośliwe podmioty do spamowania lub oszukiwania sieci. W obu przypadkach węzły, które aktywnie uczestniczą w konsensusie, umieszczają pewne zasoby „w sieci”, które utracą w przypadku niewłaściwego zachowania. + +W proof-of-work tym zasobem jest energia. Węzeł, znany jako górnik, uruchamia algorytm, którego celem jest obliczenie wartości szybciej niż jakikolwiek inny węzeł. Najszybszy węzeł ma prawo zaproponować blok do łańcucha. Aby zmienić historię łańcucha lub zdominować propozycję bloku, górnik musiałby mieć tak dużą moc obliczeniową, że zawsze wygrywałby wyścig. Jest to zaporowo drogie i trudne do wykonania, chroniąc łańcuch przed atakami. Energia wymagana do „wydobywania” przy użyciu proof-of-work jest realnym zasobem, za który płacą górnicy. + +Proof-of-stake wymaga od węzłów, zwanych walidatorami, wyraźnego przesłania aktywa kryptowalutowego do inteligentnego kontraktu. Jeśli walidator zachowa się niewłaściwie, kryptowaluta może zostać zniszczona, ponieważ „stakuje” +on swoje aktywa bezpośrednio do łańcucha, a nie pośrednio poprzez wydatek energetyczny. + +Proof-of-work jest znacznie bardziej energochłonny, ponieważ energia elektryczna jest spalana w procesie wydobywania. Proof-of-stake, z drugiej strony, wymaga tylko bardzo małej ilości energii — walidatory Ethereum mogą nawet działać na urządzeniu o niskim poborze mocy, takim jak Raspberry Pi. Mechanizm proof-of-stake Ethereum jest uważany za bezpieczniejszy niż proof-of-work, ponieważ koszt ataku jest większy, a konsekwencje dla atakującego są poważniejsze. + +Proof-of-work kontra proof-of-stake to kontrowersyjny temat. [Blog Vitalika Buterina](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-are-the-benefits-of-proof-of-stake-as-opposed-to-proof-of-work) oraz debata pomiędzy Justinem Drake'em a Lyn Alden dobrze podsumowują te argumenty. + + + +## Czy proof-of-stake jest energooszczędny? {#is-pos-energy-efficient} + +Tak. Węzły w sieci proof-of-stake zużywają niewielką ilość energii. W badaniu przeprowadzonym przez stronę trzecią stwierdzono, że cała sieć proof-of-stake Ethereum zużywa około 0,0026 TWh/rok — około 13 000 razy mniej niż gaming w samych Stanach Zjednoczonych. + +[Więcej o zużyciu energii przez Ethereum](/energy-consumption/). + +## Czy proof-of-stake jest bezpieczny? {#is-pos-secure} + +Proof-of-stake Ethereum jest bardzo bezpieczny. Mechanizm ten był badany, rozwijany i rygorystycznie testowany przez osiem lat przed uruchomieniem. Gwarancje bezpieczeństwa różnią się od blockchainów proof-of-work. W proof-of-stake złośliwi walidatorzy mogą być aktywnie karani („odcinani”) i wyrzucani z zestawu walidatorów, co kosztuje znaczną ilość ETH. W przypadku proof-of-work atakujący może powtarzać swój atak, dopóki ma wystarczającą moc hashowania. Przeprowadzenie równoważnych ataków na proof-of-stake Ethereum jest również bardziej kosztowne niż w przypadku proof-of-work. Aby wpłynąć na żywotność łańcucha, wymagane jest co najmniej 33% całkowitego zestakowanego etheru w sieci (z wyjątkiem przypadków bardzo wyrafinowanych ataków o bardzo niskim prawdopodobieństwie powodzenia). Aby kontrolować zawartość przyszłych bloków, wymagane jest co najmniej 51% całkowitego zestakowanego ETH, a do zmiany historii potrzebne jest ponad 66% całkowitej stawki. Protokół Ethereum zniszczyłby te aktywa w scenariuszach ataku 33% lub 51% oraz poprzez konsensus społeczny w scenariuszu ataku 66%. + +- [Więcej o obronie proof-of-stake w Ethereum przed atakującymi](/developers/docs/consensus-mechanisms/pos/attack-and-defense) +- [Więcej o projekcie proof-of-stake](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) + +## Czy proof-of-stake sprawia, że Ethereum jest tańsze? {#does-pos-make-ethereum-cheaper} + +Nie. Koszt wysłania transakcji (opłata za gaz) jest określany przez dynamiczny rynek opłat, który rośnie wraz ze wzrostem zapotrzebowania sieci. Mechanizm konsensusu nie ma na to bezpośredniego wpływu. + +[Więcej o gazie](/developers/docs/gas). + +## Czym są węzły, klienty i walidatorzy? {#what-are-nodes-clients-and-validators} + +Węzły to komputery podłączone do sieci Ethereum. Klienty to uruchamiane przez nich oprogramowanie, które zamienia komputer w węzeł. Istnieją dwa rodzaje klientów: klienty wykonawcze i klienty konsensusu. Oba są potrzebne do utworzenia węzła. Walidator jest opcjonalnym dodatkiem do klienta konsensusu, który umożliwia węzłowi uczestnictwo w konsensusie proof-of-stake. Oznacza to tworzenie i proponowanie bloków po wybraniu walidatora i poświadczaniu bloków, o których słyszą w sieci. Aby uruchomić walidator, operator węzła musi wpłacić 32 ETH do kontraktu depozytowego. + +- [Więcej o węzłach i klientach](/developers/docs/nodes-and-clients) +- [Więcej o stakowaniu](/staking) + +## Czy proof-of-stake to nowy pomysł? {#is-pos-new} + +Nie. Użytkownik na BitcoinTalk [zaproponował podstawową ideę proof-of-stake](https://bitcointalk.org/index.php?topic=27787.0) jako ulepszenie do Bitcoin w 2011 roku. Minęło jedenaście lat, zanim był on gotowy do wdrożenia w sieci głównej Ethereum. Niektóre inne sieci wdrożyły proof-of-stake wcześniej niż Ethereum, ale nie specyficzny mechanizm Ethereum (znany jako Gasper). + +## Co jest wyjątkowego w proof-of-stake Ethereum? {#why-is-ethereum-pos-special} + +Mechanizm proof-of-stake Ethereum jest unikalny w swojej konstrukcji. Nie był to pierwszy mechanizm proof-of-stake, który został zaprojektowany i wdrożony, ale jest najbardziej niezawodny. Mechanizm proof-of-stake jest znany jako „Casper”. Casper definiuje, w jaki sposób walidatorzy są wybierani do proponowania bloków, w jaki sposób i kiedy poświadczenia są dokonywane, w jaki sposób poświadczenia są liczone, nagrody i kary przyznawane walidatorom, warunki cięcia, mechanizmy awaryjne, takie jak wyciek nieaktywności, oraz warunki „finalizacji”. Finalizacja to warunek, że aby blok został uznany za stałą część łańcucha kanonicznego, musi zostać przegłosowany przez co najmniej 66% wszystkich zestakowanych ETH w sieci. Badacze opracowali Casper specjalnie dla Ethereum, a Ethereum jest pierwszym i jedynym blockchainem, który go wdrożył. + +Jako dodatek do Casper, proof-of-stake Ethereum wykorzystuje algorytm wyboru forka o nazwie LMD-GHOST. Jest to wymagane w przypadku wystąpienia sytuacji, w której istnieją dwa bloki dla tego samego slotu. Tworzy to dwa forki blockchainu. LMD-GHOST wybiera tego, który ma największą „wagę” poświadczeń. Waga to liczba poświadczeń ważona efektywnym bilansem walidatorów. LMD-GHOST jest unikalny dla Ethereum. + +Połączenie Casper i LMD_GHOST jest znane jako Gasper. + +[Więcej o Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) + +## Czym jest cięcie? {#what-is-slashing} + +Cięcie to termin określający zniszczenie części stawki walidatora i wyrzucenie go z sieci. Ilość ETH utraconych w wyniku cięcia skaluje się wraz z liczbą usuniętych walidatorów — oznacza to, że walidatorzy działający w zmowie są karani surowiej niż pojedyncze osoby. + +[Więcej o slashingu](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties#slashing) + +## Dlaczego walidatorzy potrzebują 32 ETH? {#why-32-eth} + +Walidatorzy muszą stakować ETH, aby mieć coś do stracenia, jeśli zachowają się niewłaściwie. Powodem, dla którego muszą zestakować 32 ETH, jest umożliwienie działania węzłów na skromnym sprzęcie. Gdyby minimalna stawka ETH na walidatora była niższa, wówczas liczba walidatorów, a tym samym liczba wiadomości, które muszą być przetwarzane w każdym slocie, wzrosłaby, co oznacza, że do uruchomienia węzła potrzebny byłby mocniejszy sprzęt. + +## Jak wybierani są walidatorzy? {#how-are-validators-selected} + +Pojedynczy walidator jest wybierany pseudolosowo, aby zaproponować blok w każdym slocie przy użyciu algorytmu o nazwie RANDAO, który łączy hash od proponenta bloku z ziarnem, które jest aktualizowane co blok. Ta wartość służy do wyboru określonego walidatora z całego zestawu walidatorów. Wybór walidatora jest ustalany na dwie epoki z góry. + +[Więcej o wyborze walidatora](/developers/docs/consensus-mechanisms/pos/block-proposal) + +## Co to jest stake grinding? {#what-is-stake-grinding} + +Stake grinding to kategoria ataków na sieci proof-of-stake, w których atakujący próbuje wpłynąć na algorytm wyboru walidatorów na korzyść własnych walidatorów. Ataki stake grinding na RANDAO wymagają około połowy wszystkich zestakowanych ETH. + +[Więcej o stake grinding](https://eth2book.info/altair/part2/building_blocks/randomness/#randao-biasability) + +## Czym jest social slashing? {#what-is-social-slashing} + +Social slashing to zdolność społeczności do skoordynowania forka łańcucha bloków w odpowiedzi na atak. Umożliwia to społeczności odzyskanie stanu sprzed sfinalizowania nieuczciwego łańcucha przez atakującego. Social slashing może być również użyty przeciwko atakom cenzurującym. + +- [Więcej o social slashing](https://ercwl.medium.com/the-case-for-social-slashing-59277ff4d9c7) +- [Vitalik Buterin o social slashing](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) + +## Czy zostanę zslashowany? {#will-i-get-slashed} + +Jako walidator, bardzo trudno jest zostać poddanym slashingowi, chyba że celowo dopuszczasz się złośliwego zachowania. Slashing jest stosowany tylko w bardzo specyficznych scenariuszach, w których walidatorzy proponują wiele bloków dla tego samego slotu lub zaprzeczają samym sobie swoimi atestacjami - jest bardzo mało prawdopodobne, aby takie sytuacje powstały przypadkowo. + +[Więcej o warunkach slashingu](https://eth2book.info/altair/part2/incentives/slashing) + +## Na czym polega problem „nic do stracenia”? {#what-is-nothing-at-stake-problem} + +Problem „nic do stracenia” to koncepcyjny problem w niektórych mechanizmach proof-of-stake, gdzie istnieją tylko nagrody, a nie ma kar. Jeśli nie ma nic do stracenia, pragmatyczny walidator z równą chęcią poświadczy dowolny, a nawet wiele forków łańcucha bloków, ponieważ zwiększa to jego nagrody. Ethereum omija ten problem, używając warunków finalizacji i slashingu, aby zapewnić jeden kanoniczny łańcuch. + +[Więcej o problemie „nic do stracenia”](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed) + +## Czym jest algorytm wyboru forka? {#what-is-a-fork-choice-algorithm} + +Algorytm wyboru forka implementuje zasady określające, który łańcuch jest kanoniczny. W optymalnych warunkach nie ma potrzeby stosowania reguły wyboru forka, ponieważ na każdy slot przypada tylko jeden proponujący blok i jest tylko jeden blok do wyboru. Czasami jednak wiele bloków dla tego samego slotu lub późno napływające informacje prowadzą do wielu opcji organizacji bloków w pobliżu początku łańcucha. W takich przypadkach wszyscy klienci muszą identycznie implementować te same zasady, aby upewnić się, że wszyscy wybierają prawidłową sekwencję bloków. Algorytm wyboru forka koduje te zasady. + +Algorytm wyboru forka w Ethereum nazywa się LMD-GHOST. Wybiera on fork z największą wagą atestacji, czyli ten, za którym głosowała większość zastakowanych ETH. + +[Więcej o LMD-GHOST](/developers/docs/consensus-mechanisms/pos/gasper/#fork-choice) + +## Czym jest finalizacja w proof-of-stake? {#what-is-finality} + +Finalizacja w proof-of-stake to gwarancja, że dany blok jest stałą częścią kanonicznego łańcucha i nie może zostać odwrócony, chyba że dojdzie do awarii konsensusu, w której atakujący spali 33% całego zastakowanego etheru. Jest to finalizacja „kryptoekonomiczna”, w przeciwieństwie do „finalizacji probabilistycznej”, która ma zastosowanie w łańcuchach bloków typu proof-of-work. W finalizacji probabilistycznej nie ma jawnych stanów sfinalizowanych/niesfinalizowanych dla bloków - po prostu staje się coraz mniej prawdopodobne, że blok może zostać usunięty z łańcucha w miarę starzenia się, a użytkownicy sami określają, kiedy są wystarczająco pewni, że blok jest „bezpieczny”. W przypadku finalizacji kryptoekonomicznej, na pary bloków kontrolnych musi zagłosować 66% zastakowanego etheru. Jeśli ten warunek jest spełniony, bloki pomiędzy tymi punktami kontrolnymi są jawnie „sfinalizowane”. + +[Więcej o finalizacji](/developers/docs/consensus-mechanisms/pos/#finality) + +## Czym jest „słaba subiektywność”? {#what-is-weak-subjectivity} + +Słaba subiektywność to cecha sieci proof-of-stake, w której informacje społeczne są wykorzystywane do potwierdzenia bieżącego stanu łańcucha bloków. Nowe węzły lub węzły ponownie dołączające do sieci po długim okresie bycia offline mogą otrzymać najnowszy stan, dzięki czemu węzeł może natychmiast sprawdzić, czy znajduje się na prawidłowym łańcuchu. Stany te są znane jako „punkty kontrolne słabej subiektywności” i można je uzyskać od innych operatorów węzłów w sposób pozapasmowy, z eksploratorów bloków lub z kilku publicznych punktów końcowych. + +[Więcej o słabej subiektywności](/developers/docs/consensus-mechanisms/pos/weak-subjectivity) + +## Czy proof-of-stake jest odporny na cenzurę? {#is-pos-censorship-resistant} + +Odporność na cenzurę jest obecnie trudna do udowodnienia. Jednak w przeciwieństwie do proof-of-work, proof-of-stake oferuje opcję koordynowania slashingów w celu ukarania cenzurujących walidatorów. Nadchodzą zmiany w protokole, które oddzielają budowniczych bloków od proponujących bloki i wprowadzają listy transakcji, które budowniczowie muszą uwzględnić w każdym bloku. Ta propozycja jest znana jako separacja proponującego i budowniczego (proposer-builder separation) i pomaga zapobiegać cenzurowaniu transakcji przez walidatorów. + +[Więcej o separacji proponującego i budowniczego](https://notes.ethereum.org/@fradamt/H1TsYRfJc#Original-basic-scheme) + +## Czy system proof-of-stake w Ethereum może być celem ataku 51%? {#pos-51-attack} + +Tak. Proof-of-stake jest podatny na ataki 51%, tak samo jak proof-of-work. Zamiast wymagać 51% mocy haszującej sieci, atakujący potrzebuje 51% wszystkich zastakowanych ETH. Atakujący, który zgromadzi 51% całkowitego stake'u, zyskuje kontrolę nad algorytmem wyboru forka. Umożliwia to atakującemu cenzurowanie określonych transakcji, przeprowadzanie reorganizacji krótkiego zasięgu i ekstrakcję MEV poprzez zmianę kolejności bloków na swoją korzyść. + +[Więcej o atakach na proof-of-stake](/developers/docs/consensus-mechanisms/pos/attack-and-defense) + +## Czym jest koordynacja społeczna i dlaczego jest potrzebna? {#what-is-social-coordination} + +Koordynacja społeczna jest ostatnią linią obrony dla Ethereum, która pozwoliłaby na odzyskanie uczciwego łańcucha po ataku, który sfinalizował nieuczciwe bloki. W takim przypadku społeczność Ethereum musiałaby skoordynować się „pozapasmowo” i zgodzić się na użycie uczciwego forka mniejszościowego, dokonując w procesie slashingu walidatorów atakującego. Wymagałoby to również, aby aplikacje i giełdy uznały ten uczciwy fork. + +[Przeczytaj więcej o koordynacji społecznej](/developers/docs/consensus-mechanisms/pos/attack-and-defense#people-the-last-line-of-defense) + +## Czy w proof-of-stake bogaci stają się bogatsi? {#do-rich-get-richer} + +Im więcej ETH ktoś stakuje, tym więcej walidatorów może uruchomić i tym więcej nagród może zgromadzić. Nagrody skalują się liniowo z ilością zastakowanych ETH, a każdy otrzymuje taki sam zwrot procentowy. Proof-of-work wzbogaca bogatych bardziej niż proof-of-stake, ponieważ bogatsi górnicy, którzy kupują sprzęt na dużą skalę, korzystają z ekonomii skali, co oznacza, że związek między bogactwem a nagrodą jest nieliniowy. + +## Czy proof-of-stake jest bardziej scentralizowany niż proof-of-work? {#is-pos-decentralized} + +Nie, proof-of-work ma tendencję do centralizacji, ponieważ koszty kopania rosną i eliminują z rynku osoby fizyczne, następnie małe firmy i tak dalej. Obecnym problemem z proof-of-stake jest wpływ płynnych instrumentów pochodnych stakowania (LSD). Są to tokeny reprezentujące ETH zastakowane przez jakiegoś dostawcę, które każdy może wymieniać na rynkach wtórnych bez konieczności odstakowywania rzeczywistych ETH. LSD pozwalają użytkownikom stakować mniej niż 32 ETH, ale tworzą również ryzyko centralizacji, w którym kilka dużych organizacji może skończyć kontrolując dużą część stake'u. Dlatego [solo staking](/staking/solo) jest najlepszą opcją dla Ethereum. + +[Więcej o centralizacji stake'u w LSD](https://notes.ethereum.org/@djrtwo/risks-of-lsd) + +## Dlaczego mogę stakować tylko ETH? {#why-can-i-only-stake-eth} + +ETH jest natywną walutą Ethereum. Kluczowe jest posiadanie jednej waluty, w której denominowane są wszystkie stake'i, zarówno do rozliczania efektywnych sald w celu ważenia głosów, jak i dla bezpieczeństwa. Samo ETH jest fundamentalnym składnikiem Ethereum, a nie inteligentnym kontraktem. Włączenie innych walut znacznie zwiększyłoby złożoność i zmniejszyło bezpieczeństwo stakowania. + +## Czy Ethereum jest jedynym łańcuchem bloków z proof-of-stake? {#is-ethereum-the-only-pos-blockchain} + +Nie, istnieje kilka łańcuchów bloków z proof-of-stake. Żaden nie jest identyczny z Ethereum; mechanizm proof-of-stake w Ethereum jest unikalny. + +## Czym jest Połączenie (The Merge)? {#what-is-the-merge} + +Połączenie (The Merge) to moment, w którym Ethereum wyłączyło swój mechanizm konsensusu oparty na proof-of-work i włączyło mechanizm konsensusu oparty na proof-of-stake. Połączenie (The Merge) miało miejsce 15 września 2022 r. + +[Więcej o Połączeniu (The Merge)](/roadmap/merge) + +## Czym są żywotność i bezpieczeństwo? {#what-are-liveness-and-safety} + +Żywotność i bezpieczeństwo to dwa fundamentalne aspekty bezpieczeństwa łańcucha bloków. Żywotność to dostępność finalizującego się łańcucha. Jeśli łańcuch przestaje się finalizować lub użytkownicy nie mogą łatwo uzyskać do niego dostępu, są to awarie żywotności. Niezwykle wysoki koszt dostępu również można uznać za awarię żywotności. Bezpieczeństwo odnosi się do tego, jak trudno jest zaatakować łańcuch - tj. sfinalizować sprzeczne punkty kontrolne. + +[Przeczytaj więcej w dokumentacji Casper](https://arxiv.org/pdf/1710.09437.pdf) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/gasper/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/gasper/index.md new file mode 100644 index 00000000000..b78a7004af7 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/gasper/index.md @@ -0,0 +1,52 @@ +--- +title: Gasper +description: "Wyjaśnienie mechanizmu „Proof-of stake”." +lang: pl +--- + +Gasper jest kombinacją Casper the Friendly Finality Gadget (Casper-FFG) i algorytmu wyboru zmiany LMD-GHOST. Łącznie te elementy tworzą mechanizm konsensusu zabezpieczający przed atakiem na Ethereum. Casper to mechanizm, który unowocześnia niektóre bloki do „sfinalizowanych”, tak aby nowi uczestnicy sieci mogli mieć pewność, że synchronizują łańcuch kanoniczny. Algorytm wyboru forka wykorzystuje zgromadzone głosy, aby upewnić się, że węzły mogą z łatwością wybrać prawidłową pozycję, gdy forki pojawią się w łańcuchu bloków (ang. "Blockchain"). + +**Uwaga!** Pierwotna definicja Casper-FFG została odrobinę zaktualizowana w celu uwzględnienia w Gasperze. Na tej stronie rozważamy zaktualizowaną wersję. + +## Wymogi wstępne + +Aby zrozumieć ten materiał, należy przeczytać stronę wprowadzającą na temat [dowodu stawki](/developers/docs/consensus-mechanisms/pos/). + +## Rola Gaspera {#role-of-gasper} + +Gasper opiera się na podstawach łańcucha bloków proof-of-stake, w którym węzły dostarczają token ether jako depozyt zabezpieczający, który może zostać zniszczony, jeśli owe węzły są leniwe lub nieuczciwe w proponowaniu lub walidacji bloków. Gasper to mechanizm definiujący, w jaki sposób walidatorzy są nagradzani i karani, decydują, które bloki akceptować i odrzucać oraz na którym forku blockchaina budować. + +## Czym jest finalizacja? {#what-is-finality} + +Ostateczność jest właściwością niektórych bloków, która oznacza, że nie można ich odwrócić, chyba że doszło do krytycznej awarii konsensusu, a atakujący zniszczył co najmniej 1/3 całkowitego stakowanego etheru. Sfinalizowane bloki można traktować jako informacje, co do których blockchain ma pewność. Blok musi przejść przez dwuetapową procedurę uaktualnienia, aby został sfinalizowany: + +1. Dwie trzecie całkowitego stakowanego etheru musi zagłosować za włączeniem tego bloku do łańcucha kanonicznego. Ten warunek uaktualnia blok do statusu "uzasadniony". Jest mało prawdopodobne, że uzasadnione bloki zostaną odwrócone, ale w pewnych warunkach jest to możliwe. +2. Gdy kolejny blok zostanie uzasadniony na bazie uzasadnionego bloku, zostaje on uaktualniony do statusu "sfinalizowany". Sfinalizowanie bloku jest zobowiązaniem do włączenia go do łańcucha kanonicznego. Nie można go odwrócić, chyba że atakujący zniszczy ether o wartości milionów (miliardów USD). + +Te uaktualnienia bloków nie zdarzają się w każdym slocie. Zamiast tego, tylko bloki graniczne epoki mogą być uzasadniane i finalizowane. Te bloki są znane jako "punkty kontrolne". Uaktualnianie uwzględnia pary punktów kontrolnych. Między dwoma kolejnymi punktami kontrolnymi musi istnieć "łącze superwiększości" (tzn. dwie trzecie całego stakowanego etheru głosuje, że punkt kontrolny B jest prawidłowym potomkiem punktu kontrolnego A), aby uaktualnić starszy punkt kontrolny do statusu sfinalizowany, a nowszy blok do statusu uzasadniony. + +Ponieważ ostateczność wymaga zgody dwóch trzecich, że blok jest kanoniczny, atakujący nie może utworzyć alternatywnego sfinalizowanego łańcucha bez: + +1. Posiadania lub manipulowania dwiema trzecimi całkowitego stakowanego etheru. +2. Zniszczenia co najmniej jednej trzeciej całkowitego stakowanego etheru. + +Pierwszy warunek wynika z faktu, że do sfinalizowania łańcucha wymagane są dwie trzecie stakowanego etheru. Drugi warunek wynika z faktu, że jeśli dwie trzecie całkowitej stawki zagłosowało za obydwoma forkami, to jedna trzecia musiała zagłosować za obydwoma. Podwójne głosowanie jest warunkiem slashingu, który byłby maksymalnie ukarany, a jedna trzecia całkowitej stawki zostałaby zniszczona. Według stanu na maj 2022 r. wymaga to od atakującego spalenia etheru o wartości około 10 miliardów USD. Algorytm, który uzasadnia i finalizuje bloki w Gasperze, jest nieznacznie zmodyfikowaną formą [Casper the Friendly Finality Gadget (Casper-FFG)](https://arxiv.org/pdf/1710.09437.pdf). + +### Zachęty i slashing {#incentives-and-slashing} + +Walidatorzy są nagradzani za uczciwe proponowanie i walidowanie bloków. Ether jest przyznawany jako nagroda i dodawany do ich stawki. Z drugiej strony, walidatorzy, którzy są nieobecni i nie podejmują działań, gdy są do tego wezwani, tracą te nagrody, a czasami niewielką część swojej istniejącej stawki. Jednak kary za bycie offline są niewielkie i w większości przypadków sprowadzają się do kosztów alternatywnych w postaci utraconych nagród. Jednak niektóre działania walidatorów są bardzo trudne do wykonania przypadkowo i świadczą o złośliwych zamiarach, takie jak proponowanie wielu bloków dla tego samego slotu, poświadczanie wielu bloków dla tego samego slotu lub zaprzeczanie poprzednim głosowaniom w punktach kontrolnych. Są to zachowania "podlegające slashingowi", które są surowiej karane – slashing skutkuje zniszczeniem części stawki walidatora i usunięciem go z sieci walidatorów. Ten proces trwa 36 dni. W Dniu 1 nakładana jest kara początkowa w wysokości do 1 ETH. Następnie ether walidatora poddanego slashingowi powoli wyczerpuje się w okresie wyjścia, ale w Dniu 18 otrzymuje on "karę korelacyjną", która jest większa, gdy więcej walidatorów zostanie poddanych slashingowi w tym samym czasie. Maksymalna kara to cała stawka. Te nagrody i kary mają na celu zachęcanie uczciwych walidatorów i zniechęcanie do ataków na sieć. + +### Wyciek z powodu braku aktywności {#inactivity-leak} + +Oprócz bezpieczeństwa Gasper zapewnia również "wiarygodną żywotność". Jest to warunek, że tak długo, jak dwie trzecie całkowitego stakowanego etheru głosuje uczciwie i zgodnie z protokołem, łańcuch będzie mógł zostać sfinalizowany niezależnie od jakiejkolwiek innej aktywności (takiej jak ataki, opóźnienia lub slashingi). Innymi słowy, jedna trzecia całkowitego stakowanego etheru musi zostać w jakiś sposób naruszona, aby zapobiec sfinalizowaniu łańcucha. W Gasperze istnieje dodatkowa linia obrony przed awarią żywotności, znana jako "wyciek z powodu braku aktywności". Mechanizm ten aktywuje się, gdy łańcuch nie został sfinalizowany przez ponad cztery epoki. Stawka walidatorów, którzy nie poświadczają aktywnie łańcucha większościowego, jest stopniowo uszczuplana, aż większość odzyska dwie trzecie całkowitej stawki, zapewniając, że awarie żywotności są tylko tymczasowe. + +### Wybór forka {#fork-choice} + +Oryginalna definicja Casper-FFG zawierała algorytm wyboru forka, który narzucał zasadę: `follow the chain containing the justified checkpoint that has the greatest height`, gdzie wysokość jest definiowana jako największa odległość od bloku genezy. W Gasperze oryginalna zasada wyboru forka jest wycofana na rzecz bardziej zaawansowanego algorytmu o nazwie LMD-GHOST. Należy pamiętać, że w normalnych warunkach zasada wyboru forka jest niepotrzebna – w każdym slocie jest jeden proponent bloku, a uczciwi walidatorzy go poświadczają. Algorytm wyboru forka jest wymagany tylko w przypadkach dużej asynchroniczności sieci lub gdy nieuczciwy proponent bloku postąpił dwuznacznie. Jednak gdy takie przypadki mają miejsce, algorytm wyboru forka jest kluczową obroną, która zabezpiecza prawidłowy łańcuch. + +LMD-GHOST to skrót od "latest message-driven greedy heaviest observed sub-tree". Jest to pełen żargonu sposób zdefiniowania algorytmu, który wybiera jako kanoniczny fork z największą skumulowaną wagą poświadczeń (greedy heaviest subtree) i że jeśli od walidatora zostanie odebranych wiele wiadomości, pod uwagę brana jest tylko najnowsza (latest-message driven). Przed dodaniem najcięższego bloku do swojego łańcucha kanonicznego, każdy walidator ocenia każdy blok za pomocą tej zasady. + +## Dalsza lektura {#further-reading} + +- [Gasper: Łączenie GHOST i Casper](https://arxiv.org/pdf/2003.03052.pdf) +- [Casper the Friendly Finality Gadget](https://arxiv.org/pdf/1710.09437.pdf) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/index.md index c10748db991..f94c4b801f0 100644 --- a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/index.md +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/index.md @@ -1,92 +1,99 @@ --- title: Proof-of-stake (PoS) -description: Wyjaśnienie protokołu konsensusu bazującego na dowodzie stawki (ang. proof-of-stake) i jego roli w Ethereum. +description: "Wyjaśnienie protokołu konsensusu bazującego na dowodzie stawki (ang. proof-of-stake) i jego roli w Ethereum." lang: pl -incomplete: true --- -Ethereum przechodzi na mechanizm konsensusu zwany dowodem stawki (ang. proof-of-stake, skr. PoS) z poprzednio wykorzystywanego [dowodu wykonanej pracy](/developers/docs/consensus-mechanisms/pow/) (ang. proof-of-work, skr. PoW). Taki plan istniał od zawsze, ponieważ skalowanie Ethereum przez uaktualnienia do [Eth2](/roadmap/) jest kluczowym elementem strategii obranej przez społeczność. Właściwe opracowanie PoS jest jednak dużym wyzwaniem technicznym i nie tak oczywistym jak wykorzystanie PoW do uzyskiwania konsensusu w obrębie sieci. +Proof-of-stake (PoS) leży u podstaw [mechanizmu konsensusu](/developers/docs/consensus-mechanisms/) Ethereum. W sieci Ethereum włączono mechanizm proof-of-stake w 2022 roku, ponieważ jest on bezpieczniejszy, mniej energochłonny i lepszy do wdrażania nowych rozwiązań skalujących w porównaniu z poprzednią architekturą [proof-of-work](/developers/docs/consensus-mechanisms/pow). ## Wymagania wstępne {#prerequisites} -Aby lepiej rozumieć tę stronę, zalecamy zapoznanie się najpierw z tematyką [mechanizmów konsensualnych](/developers/docs/consensus-mechanisms/). +Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznać się z [mechanizmami konsensusu](/developers/docs/consensus-mechanisms/). ## Czym jest dowód stawki (PoS)? {#what-is-pos} -Dowód stawki (ang. proof-of-stake) jest rodzajem [mechanizmu konsensualnego](/developers/docs/consensus-mechanisms/) wykorzystywanego w sieciach bazujących na technologii blockchain, aby uzyskiwać rozproszony konsensus. +proof-of-stake jest sposobem udowodnienia, że walidatorzy włożyli coś cennego do sieci, co może zostać zniszczone, jeśli będą postępować nieuczciwie. W modelu Ethereum proof-of-stake walidatorzy jawnie inwestują kapitał w formie ETH w inteligentnym kontrakcie na Ethereum. Walidator jest odpowiedzialny za sprawdzanie, czy nowe bloki propagowane przez sieć są ważne, a czasami także za tworzenie i propagowanie nowych bloków. Jeśli spróbują oszukać sieć (na przykład proponując kilka bloków, kiedy powinni wysłać jeden lub wysyłając sprzeczne poświadczenia) część z ich zestakowanego ETH może zostać zniszczona. -Wymaga się w nim od użytkowników zastawienia należących do nich ETH, aby mogli stać się walidatorami w sieci. Walidatorzy są odpowiedzialni za to samo, co górnicy w mechanizmie [proof-of-work](/developers/docs/consensus-mechanisms/pow/): porządkowanie transakcji i tworzenie nowych bloków, żeby wszystkie węzły były w stanie zgodnie się porozumieć odnośnie do stanu sieci. +## Walidatorzy {#validators} -System proof-of-stake wiąże się z wieloma udoskonaleniami w stosunku do proof-of-work: +Aby uczestniczyć jako walidator, użytkownik musi zdeponować 32 ETH do kontraktu depozytowego i uruchomić trzy oddzielne części oprogramowania: klienta wykonawczego, klienta konsensusu i klienta walidatora. Po wpłaceniu depozytu w ETH użytkownik dołącza do kolejki aktywacyjnej, która ogranicza tempo dołączania nowych walidatorów do sieci. Po aktywacji walidatorzy otrzymują nowe bloki od węzłow równorzędnych w sieci Ethereum. Transakcje dostarczone do bloku są wykonane ponownie, aby sprawdzić, czy zaproponowane zmiany stanu Ethereum są ważne oraz czy sygnatura bloku jest sprawdzona. Walidator wysyła następnie głos (nazywany poświadczeniem) na korzyść tego bloku w całej sieci. -- lepsza wydajność energetyczna – nie musisz zużywać wiele energii wykopując bloki; -- niższe bariery wejścia, obniżone wymagania sprzętowe – nie musisz posiadać elitarnego sprzętu, aby mieć szansę wytwarzania nowych bloków; -- większa odporność na centralizację – proof-of-stake powinien prowadzić do pojawienia się większej liczby węzłów w sieci; -- lepsza obsługa łańcuchów odłamkowych (ang. shard chains) – kluczowa aktualizacja w kwestii skalowania sieci Ethereum +Podczas gdy w przypadku mechanizmu proof-of-work synchronizacja bloków zależy od trudności wydobycia, w przypadku mechanizmu proof-of-stake tempo jest stałe. Czas w mechanizmie proof-of-stake sieci Ethereum jest podzielony na sloty (12 sekund) i epoki (32 sloty). Jeden walidator jest losowo wybierany na proponenta bloków w każdym slocie. Ten walidator jest odpowiedzialny za utworzenie nowego bloku i wysłanie go do innych węzłów w sieci. Ponadto w każdym slocie wybierana jest losowo komisja walidatorów, której głosy są używane do określenia ważności proponowanego bloku. Podzielenie walidatorów na komitety jest ważne dla utrzymania obciążenia sieci na poziomie możliwym do opanowania. Komitety dzielą walidatorów tak, aby każdy aktywny walidator poświadczał w każdej epoce, ale nie w każdym slocie. -## Proof-of-stake, zastawianie i walidatorzy {#pos-staking-validators} +## Jak transakcja jest wykonywana w Ethereum PoS {#transaction-execution-ethereum-pos} -Proof-of-stake to bazowy mechanizm aktywizacji walidatorów po otrzymaniu wymaganego zastawu. W przypadku Ethereum użytkownicy będą musieli zestakować 32 ETH, aby zostać walidatorami. Walidatorzy wybierani są losowo do wytwarzania bloków, a także są odpowiedzialni za sprawdzanie oraz potwierdzanie bloków niewytworzonych przez siebie. Stake (zastaw) użytkownika jest też wykorzystywany jako sposób zachęcania walidatorów do dobrego zachowania. Na przykład użytkownik może stracić część zastawionych środków za przejście w tryb offline (odmowę walidacji), a nawet cały zastaw, jeżeli dopuści się celowej zmowy. +Poniżej znaleźć można kompletne wyjaśnienie tego, w jaki sposób transakcja zostaje wykonana w ramach modelu Ethereum proof-of-stake. -## Jak działa proof-of-stake z Ethereum? {#how-does-pos-work} +1. Użytkownik tworzy i podpisuje [transakcję](/developers/docs/transactions/) swoim kluczem prywatnym. Zwykle jest to obsługiwane przez portfel lub bibliotekę, taką jak [ethers.js](https://docs.ethers.org/v6/), [web3js](https://docs.web3js.org/), [web3py](https://web3py.readthedocs.io/en/v5/) itp., ale pod maską użytkownik wysyła żądanie do węzła za pomocą [JSON-RPC API](/developers/docs/apis/json-rpc/) Ethereum. Użytkownik definiuje ilość gazu, którą jest gotowy zapłacić jako napiwek dla walidatora, aby zachęcić go do włączenia transakcji do bloku. [Napiwki](/developers/docs/gas/#priority-fee) są wypłacane walidatorowi, podczas gdy [opłata podstawowa](/developers/docs/gas/#base-fee) jest spalana. +2. Transakcja jest przesyłana do [klienta wykonawczego](/developers/docs/nodes-and-clients/#execution-client) Ethereum, który weryfikuje jej ważność. To oznacza zapewnienie, że wysyłający posiada wystarczającą ilość ETH, aby wypełnić transakcję, oraz że podpisał ją odpowiednim kluczem. +3. Jeśli transakcja jest ważna, klient wykonawczy dodaje ją do lokalnego mempoolu (listy oczekujących transakcji) oraz nadaje ją do innych węzłów poprzez sieć plotkującą warstwy wykonawczej. Kiedy inne węzły usłyszą o transakcji, również dodają ją do własnego lokalnego mempoolu. Zaawansowani użytkownicy mogą powstrzymać się od rozgłaszania swojej transakcji i zamiast tego przekazać ją do wyspecjalizowanych kreatorów bloków, takich jak [Flashbots Auction](https://docs.flashbots.net/flashbots-auction/overview). Pozwala im to organizować transakcje w nadchodzących blokach w celu uzyskania maksymalnego zysku ([MEV](/developers/docs/mev/#mev-extraction)). +4. Jeden z węzłów walidatora w sieci jest proponującym blok dla aktualnego slota, uprzednio zostając wybranym pseudo losowo używając RANDAO. Ten węzeł jest odpowiedzialny za stworzenie i nadanie następnego bloku, aby dodać go do blockchainu Ethereum oraz za aktualizację globalnego stanu. Węzeł składa się z trzech części: klienta wykonawczego, klienta konsensusu oraz klienta walidatora. Klient wykonawczy grupuje transakcje z lokalnego mempoolu w "ładunek wykonawczy" i wykonuje je lokalnie, aby wygenerować zmianę stanu. Ta informacja przekazywana jest do klienta konsensusu, gdzie ładunek wykonawczy jest zawijany jako część "bloku śledzącego", który zawiera również informację o nagrodach, karach, ucięciach, poświadczeniach itd. To umożliwia sieci uzgodnienie kolejności bloków na przedzie łańcucha. Komunikacja między klientem wykonawczym a klientem konsensusu jest opisana bardziej szczegółowo w artykule [Connecting the Consensus and Execution Clients](/developers/docs/networking-layer/#connecting-clients). +5. Inne węzły odbierają blok śledzący na sieci plotkującej wewnątrz warstwy konsensusu. Przekazują go do klienta wykonawczego, gdzie transakcje są wykonywane ponownie lokalnie w celu gwarancji ważności proponowanej zmiany stanu. Klient walidatora następnie poświadcza, że blok jest ważny i jest kolejnym logicznym blokiem w jego widoku łańcucha (co oznacza, że jest on zbudowany na łańcuchu o największej wadze poświadczeń, zgodnie z definicją w [zasadach wyboru forka](/developers/docs/consensus-mechanisms/pos/#fork-choice)). Blok zostaje dodany do lokalnej bazy danych w każdym węźle, który go poświadcza. +6. Transakcja może zostać uznana "sfinalizowaną" jeśli została częścią łańcucha z połączeniem superwiększościowym pomiędzy dwoma punktami kontrolnymi. Punkty kontrolne występują na początku każdej epoki i istnieją, aby pod uwagę wzięty został fakt, że tylko podzbiór aktywnych walidatorów poświadcza w każdym slocie, podczas gdy wszyscy aktywni walidatorzy poświadczają na przez całą epokę. Połączenie superwiększościowe może zatem zostań zademonstrowane tylko na przełomie dwóch epok (sytuacja ta ma miejsce, kiedy 66% całego zestakowanego na sieci ETH zgadza się w sprawie dwóch punktów kontrolnych). -W przeciwieństwie do proof-of-work walidatorzy nie muszą zużywać znacznych ilości mocy obliczeniowych, ponieważ są wybierani losowo i nie konkurują ze sobą. Nie muszą wydobywać bloków, potrzebują jedynie wytwarzać je, gdy zostaną wybrani i sprawdzać zaproponowane bloki, gdy wybranymi nie są. Taka walidacja znana jest jako poświadczanie. Możesz myśleć o poświadczaniu, jak o mówieniu „dla mnie ten blok wygląda dobrze”. Walidatorzy są nagradzani za proponowanie nowych bloków i poświadczanie tych, które ujrzeli. +Więcej szczegółów na temat nieodwołalności można znaleźć poniżej. -Jeżeli poświadczasz szkodliwe bloki, tracisz zastaw. +## Nieodwołalność {#finality} -### Łańcuch śledzący {#the-beacon-chain} +Transakcja ma "nieodwołalność" w rozproszonych sieciach, kiedy jest częścią bloku, którego nie można zmienić bez spalenia dużej ilości ETH. W sieci Ethereum z proof-of-stake zarządza się tym za pomocą bloków „punktów kontrolnych”. Pierwszy blok w każdej epoce jest punktem kontrolnym. Walidatorzy głosują na pary punktów kontrolnych, które uznają za ważne. Jeśli para punktów kontrolnych przyciągnie głosy reprezentujące co najmniej dwie trzecie całości stakowanego ETH, punkty kontrolne są uaktualniane. Nowszy z nich dwóch (cel) staje się „uzasadniony”. Wcześniejszy z nich dwóch jest już uzasadniony, ponieważ stanowił „cel” w poprzedniej epoce. Teraz został uaktualniony do stanu „sfinalizowany”. Ten proces aktualizacji punktów kontrolnych jest obsługiwany przez **[Casper the Friendly Finality Gadget (Casper-FFG)](https://arxiv.org/pdf/1710.09437)**. Casper-FFG to narzędzie do finalizacji bloków dla konsensusu. Gdy blok zostanie sfinalizowany, nie można go cofnąć ani zmienić bez slashingu większości stakerów, co czyni to ekonomicznie nieopłacalnym. -Gdy Ethereum zastąpi proof-of-work przez proof-of-stake, zostanie dodana złożoność [łańcuchów odłamkowych](/roadmap/danksharding/). Są to oddzielne blockchainy, które będą potrzebowały walidatorów do przetwarzania transakcji i tworzenia nowych bloków. Planowane są 64 łańcuchy odłamkowe, a wszystkie one wymagają współdzielonego porozumienia w kwestii stanu sieci. Potrzebna jest więc dodatkowa koordynacja, która zostanie zrealizowana z użyciem [łańcucha nawigacyjnego](/roadmap/beacon-chain/). +Aby odwrócić sfinalizowany blok, napastnik musiałby zobowiązać się do utraty co najmniej jednej trzeciej całkowitej podaży stakowanego ETH. Dokładny powód jest wyjaśniony w tym [wpisie na blogu Fundacji Ethereum](https://blog.ethereum.org/2016/05/09/on-settlement-finality/). Jako że nieodwołalność wymaga większości dwóch trzecich, napastnik mógłby powstrzymać sieć przed osiągnięciem nieodwołalności, głosując jedną trzecią stakowanej całości. Istnieje mechanizm obrony przed tym: [wyciek z powodu braku aktywności](https://eth2book.info/bellatrix/part2/incentives/inactivity). Jest on aktywowany za każdym razem, gdy łańcuch nie zdoła sfinalizować więcej niż czterech epok. Wyciek nieaktywności powoduje odpływ stakowanych ETH od walidatorów głosujących przeciwko większości, co pozwala większości odzyskać większość dwóch trzecich i sfinalizować łańcuch. -Łańcuch śledzący odbiera informację o stanie z odłamków (fragmentów) i udostępnia ją innym odłamkom, aby sieć mogła pozostać zsynchronizowana. Łańcuch śledzący zarządza również walidatorami, od rejestrowania ich depozytów zastawnych po wydawanie im nagród i kar. +## Bezpieczeństwo kryptoekonomiczne {#crypto-economic-security} -Oto jak działa ten proces. +Prowadzenie walidatora jest zobowiązaniem. Od walidatora oczekuje się, że będzie dysponował wystarczającym sprzętem i łącznością, aby móc uczestniczyć w walidacji i proponowaniu bloków. W zamian walidator otrzymuje zapłatę w ETH (jego stakowane saldo rośnie). Z drugiej strony uczestnictwo w charakterze walidatora otwiera użytkownikom również nowe możliwości atakowania sieci w celu uzyskania osobistego zysku lub sabotażu. Aby temu zapobiec, walidatorzy nie otrzymują nagród w postaci ETH, jeśli nie wezmą udziału na wezwanie, a ich dotychczas stakowane środki mogą zostać zniszczone, jeśli zachowają się nieuczciwie. Dwa podstawowe zachowania mogą być uznane za nieuczciwe: proponowanie wielu bloków w pojedynczym slocie (dwuznaczność) oraz zgłaszanie sprzecznych poświadczeń. -### Jak działa walidacja {#how-does-validation-work} +Liczba cięć ETH zależy od tego, ilu walidatorów również zostanie uciętych mniej więcej w tym samym czasie. Jest to znane jako [„kara za korelację”](https://eth2book.info/bellatrix/part2/incentives/slashing#the-correlation-penalty) i może być niewielka (~1% stawki dla pojedynczego walidatora poddanego slashingowi) lub może skutkować zniszczeniem 100% stawki walidatora (masowe zdarzenie slashingu). Nakłada się ją w połowie okresu wymuszonego wyjścia, który rozpoczyna się natychmiastową karą (nawet 1 ETH) w dniu 1, karą korelacyjną w dniu 18 i ostatecznie wyrzuceniem z sieci w dniu 36. Codziennie otrzymują drobne kary za poświadczenia, ponieważ są obecni w sieci, ale nie oddają głosów. Wszystko to znaczy, że skoordynowany atak byłby bardzo kosztowny dla napastnika. -Gdy zlecasz transakcję na odłamku, walidator będzie odpowiedzialny za dodanie twojej transakcji do bloku odłamków. Walidatorzy są algorytmicznie wybierani przez łańcuch śledzący, aby proponować nowe bloki. +## Wybór forka {#fork-choice} -#### Poświadczanie {#attestation} +Gdy sieć działa w sposób optymalny i uczciwy, na czele łańcucha znajduje się tylko jeden nowy blok i poświadczają go wszyscy walidatorzy. Może się jednak zdarzyć, że walidatorzy będą mieli różne poglądy na temat czoła łańcucha z powodu latencji sieci lub z powodu niejasnej odpowiedzi proponenta bloku. W związku z tym klienci konsensusu wymagają algorytmu decydującego, którego z nich należy preferować. Algorytm używany w Ethereum z proof-of-stake nazywa się [LMD-GHOST](https://arxiv.org/pdf/2003.03052.pdf) i działa poprzez identyfikację forka, który ma największą wagę poświadczeń w swojej historii. -Jeżeli walidator nie został wybrany do proponowania nowego bloku odłamkowego, musi poświadczyć propozycję innego walidatora i potwierdzić, że wszystko wygląda jak powinno. To właśnie poświadczanie jest zapisywane w łańcuchu śledzącym, a nie sama transakcja. +## Proof-of-stake a bezpieczeństwo {#pos-and-security} -Do poświadczenia każdego bloku odłamków potrzeba co najmniej 128 walidatorów – są oni znani jako „komitet”. +Zagrożenie [atakiem 51%](https://www.investopedia.com/terms/1/51-attack.asp) wciąż istnieje w przypadku proof-of-stake, tak jak w przypadku proof-of-work, ale jest jeszcze bardziej ryzykowne dla atakujących. Napastnik potrzebowałby 51% stakowanego ETH. Następnie mógłby wykorzystać swoje własne poświadczenia w celu zapewnienia, że preferowanym forkiem jest ten z największą liczbą zgromadzonych poświadczeń. „Waga” zgromadzonych poświadczeń jest tym, czego klienci konsensu używają do określenia właściwego łańcucha, więc ten napastnik byłby w stanie sprawić, że kanoniczny będzie jego fork. Przewaga proof-of-stake nad proof-of-work polega jednak na tym, że społeczność ma elastyczność w montażu kontrataku. Na przykład uczciwi walidatorzy mogliby zadecydować o dalszym budowaniu łańcucha mniejszościowego i zignorowaniu forka napastnika, zarazem zachęcając aplikacje, giełdy i pule, aby zrobiły to samo. Mogliby oni również zadecydować o przymusowym usunięciu napastnika z sieci i zniszczeniu jego stakowanego ETH. Są to silne ekonomiczne środki obrony przed atakiem 51%. -Komitet ma ramy czasowe na zaproponowanie i walidację bloku odłamkowego. Jest to znane pod nazwą „slot”. W obrębie slotu wytwarzany jest wyłącznie jeden poprawny blok. W pojedynczej „epoce” istnieją 32 sloty. Po każdej epoce komitet jest rozwiązywany i formowany ponownie z innych, losowych uczestników. Pomaga to dbać o zabezpieczanie odłamków przed złymi figurantami. +Oprócz ataków w stylu 51%, wrogie podmioty mogą również próbować innych złośliwych czynności takich jak: -#### Odnośniki krzyżowe {#rewards-and-penalties} +- ataki o dalekim zasięgu (jednak gadżet nieodwołalności neutralizuje ten front ataku) +- reorganizacje o krótki zasięgu (jednak wzmocnienie proponującego oraz terminy poświadczeń ograniczają ten problem) +- ataki poprzez odbicia i równoważenie (również ograniczone przez wzmocnienie proponującego, jednak te ataki i tak zostały zademonstrowane jedynie w wyidealizowanym stanie sieci) +- ataki lawinowe (zneutralizowane poprzez zasadę algorytmu wyboru rozgałęzienia, która bierze pod uwagę jedynie najnowszą wiadomość) -Gdy tylko propozycja nowego bloku odłamkowego ma wystarczającą liczbę poświadczeń, tworzony jest „odnośnik krzyżowy”, który potwierdza włączenie bloku, jak i Twojej transakcji, w łańcuchu śledzącym. +Ogólnie rzecz biorąc, udowodniono, że mechanizm proof-of-stake w postaci, w jakiej został wdrożony w sieci Ethereum, jest bezpieczniejszy ekonomicznie niż proof-of-work. -Gdy tylko pojawi się odnośnik krzyżowy, walidator, który zaproponował blok, otrzymuje swoją nagrodę. +## Zalety i wady {#pros-and-cons} -#### Nieodwołalność {#finality} +| Zalety | Wady | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| Stakowanie ułatwia pojedynczym osobom udział w zabezpieczaniu sieci, co sprzyja decentralizacji. węzeł walidatora można prowadzić na zwykłym laptopie. Pule stakingu pozwalają użytkownikom stakować bez posiadania 32 ETH. | Mechanizm proof-of-stake jest nowszy i mniej sprawdzony w boju niż proof-of-work | +| Zastawianie jest bardziej zdecentralizowane. Ekonomia skali nie ma zastosowania w taki sam sposób, jak w przypadku wydobycia PoW. | Wdrożenie mechanizmu proof-of-stake jest bardziej skomplikowane niż w przypadku proof-of-work | +| Mechanizm proof-of-stake oferuje większe bezpieczeństwo kryptoekonomiczne niż proof-of-work | Aby uczestniczyć w mechanizmie proof-of-stake Ethereum, użytkownicy muszą uruchomić trzy elementy oprogramowania. | +| Do zachęcenia uczestników sieci potrzeba mniejszej emisji nowego ETH | | -W sieciach rozproszonych transakcja osiąga „nieodwołalność”, gdy staje się częścią bloku, który nie może się zmienić. +### Porównanie z proof-of-work {#comparison-to-proof-of-work} -Żeby osiągnąć to w modelu proof-of-stake, wykorzystywany jest Casper, protokół nieodwołalności, który zakłada, że walidatorzy muszą być zgodni odnośnie do stanu bloku w pewnych punktach kontrolnych. Gdy tylko zgodzi się ze sobą 2/3 walidatorów, blok jest finalizowany. Walidatorzy stracą cały zastaw, jeżeli spróbują odwołać tę operację później z użyciem ataku 51%. +Ethereum pierwotnie używało proof-of-work, lecz zmieniło model na proof-of-stake we wrześniu 2022 roku. PoS oferuje kilka przewag wobec PoW, takich jak: -Jak to ujął Vlad Zamfir, przypomina to sytuację, w której sprzęt górników biorących udział w ataku 51% uległby natychmiastowemu spaleniu. - -## Proof-of-stake i bezpieczeństwo - -W modelu proof-of-stake zagrożenie [atakiem 51%](https://www.investopedia.com/terms/1/51-attack.asp) wciąż istnieje, lecz jest jeszcze bardziej ryzykowne dla napastników. Aby przeprowadzić taki atak, potrzebujesz kontroli nad co najmniej 51% zastawionych ETH. To nie tylko mnóstwo pieniędzy, ale prawdopodobnie spowodowałoby spadek wartości ETH. Motywacja do zniszczenia wartości waluty jest bardzo mała, jeżeli masz w tej walucie większościowy udział. Motywacja, aby utrzymać sieć bezpieczną i w dobrym stanie, jest mocniejsza. - -Aby zapobiegać innym aktom złego zachowania, łańcuch śledzący będzie koordynować cięcia zastawów, odrzucenia i inne sankcje. Walidatorzy będą również odpowiedzialni za zgłaszanie tego typu incydentów. - -## Wady i zalety {#pros-and-cons} - -| Zalety | Wady | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | -| Zastawianie (staking) ułatwia ci uruchamianie węzła. Nie wymaga ogromnych inwestycji w sprzęt czy energię. A nawet wtedy, gdy nie masz wystarczającej ilości ETH, aby je zastawić, możesz przyłączać się do syndykatów zastawnych (ang. staking pools). | Proof-of-stake jest jeszcze w powijakach, a w porównaniu z proof-of-work jest systemem mniej zaprawionym w bojach. | -| Zastawianie jest bardziej zdecentralizowane. Pozwala na zwiększające się uczestnictwo, zaś więcej węzłów nie oznacza zwiększenia % zwrotów, jak w przypadku wydobywania. | | -| Zastawianie pozwala na bezpieczny sharding (wykorzystanie bloków i łańcuchów odłamkowych). Łańcuchy odłamkowe pozwalają Ethereum na wytwarzanie wielu bloków w tym samym czasie, zwiększając transakcyjną przepustowość. Fragmentacja sieci w systemie proof-of-work ograniczyłaby po prostu energię potrzebną do zdyskredytowania części sieci. | | +- lepsza wydajność energetyczna — nie trzeba zużywać dużych ilości energii na obliczenia proof-of-work; +- niższe bariery wejścia, mniejsze wymagania sprzętowe — nie ma potrzeby posiadania elitarnego sprzętu, aby mieć szansę na tworzenie nowych bloków; +- zmniejszenie ryzyka centralizacji — mechanizm proof-of-stake powinien doprowadzić do powstania większej liczby węzłów zabezpieczających sieć; +- ze względu na niskie zapotrzebowanie na energię, trzeba wydać mniej ETH, aby zachęcić do udziału; +- kary ekonomiczne za niewłaściwe zachowanie czynią ataki w stylu 51% bardziej kosztownymi dla atakującego w porównaniu z proof-of-work +- społeczność może uciec się do społecznego odzyskiwania uczciwego łańcucha, jeśli atak 51% pokonałby obronę kryptowalutową. ## Dalsza lektura {#further-reading} -- [What is Proof of Stake](https://consensys.net/blog/blockchain-explained/what-is-proof-of-stake/), _ ConsenSys_ -- [The Beacon Chain Ethereum 2.0 explainer you need to read first](https://ethos.dev/beacon-chain/), _Ethos.dev_ +- [Proof of Stake – często zadawane pytania](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html) _Vitalik Buterin_ +- [Czym jest Proof of Stake](https://consensys.net/blog/blockchain-explained/what-is-proof-of-stake/) _ConsenSys_ +- [Czym jest Proof of Stake i dlaczego ma to znaczenie](https://bitcoinmagazine.com/culture/what-proof-of-stake-is-and-why-it-matters-1377531463) _Vitalik Buterin_ +- [Dlaczego Proof of Stake (listopad 2020)](https://vitalik.eth.limo/general/2020/11/06/pos2020.html) _Vitalik Buterin_ +- [Proof of Stake: Jak nauczyłem się kochać słabą subiektywność](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) _Vitalik Buterin_ +- [Atak i obrona w Ethereum z proof-of-stake](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs) +- [Filozofia projektowania Proof of Stake](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) _Vitalik Buterin_ +- [Wideo: Vitalik Buterin wyjaśnia Lexowi Fridmanowi, czym jest proof-of-stake](https://www.youtube.com/watch?v=3yrqBG-7EVE) -## Tematy powiązane {#related-topics} +## Powiązane tematy {#related-topics} - [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/keys/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/keys/index.md new file mode 100644 index 00000000000..c890516f267 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/keys/index.md @@ -0,0 +1,102 @@ +--- +title: Klucze w proof-of-stake Ethereum +description: "Wytłumaczenie kluczy używanych w mechanizmie konsensusu Ethereum proof-of-stake" +lang: pl +--- + +Ethereum zabezpiecza aktywa użytkownika za pomocą kryptografii klucza publicznego i prywatnego. Klucz publiczny jest używany jako podstawa adresu Ethereum — to znaczy, że jest widoczny dla wszystkich i używany jako unikalny identyfikator. Klucz prywatny (lub „tajny”) powinien być zawsze dostępny tylko dla właściciela konta. Klucz prywatny jest używany do „podpisywania” transakcji i danych, dzięki czemu kryptografia może udowodnić, że posiadacz zatwierdza jakieś działanie określonego klucza prywatnego. + +Klucze Ethereum są generowane przy użyciu [kryptografii krzywych eliptycznych](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography). + +Jednak gdy Ethereum przeszło z [dowodu pracy](/developers/docs/consensus-mechanisms/pow) na [dowód stawki](/developers/docs/consensus-mechanisms/pos), do Ethereum dodano nowy typ klucza. Oryginalne klucze nadal działają dokładnie tak samo jak wcześniej — nie wprowadzono żadnych zmian w kluczach zabezpieczających konta opartych na krzywej eliptycznej. Użytkownicy potrzebowali jednak nowego typu klucza do udziału w proof-of-stake poprzez stakowanie ETH i uruchamianie walidatorów. Potrzeba ta wynikała z wyzwań skalowalności związanych z wieloma wiadomościami przechodzącymi między dużą liczbą walidatorów, które wymagały metody kryptograficznej, którą można łatwo zagregować, aby zmniejszyć ilość komunikacji wymaganej do osiągnięcia konsensusu w sieci. + +Ten nowy typ klucza wykorzystuje [schemat podpisu cyfrowego **Boneh-Lynn-Shacham (BLS)**](https://wikipedia.org/wiki/BLS_digital_signature). BLS umożliwia bardzo wydajną agregację podpisów, ale także pozwala na inżynierię wsteczną zagregowanych indywidualnych kluczy walidatorów i jest idealny do zarządzania działaniami między walidatorami. + +## Dwa typy kluczy walidatora {#two-types-of-keys} + +Przed przejściem na proof-of-stake, użytkownicy Ethereum mieli tylko jeden klucz prywatny oparty na krzywej eliptycznej, aby uzyskać dostęp do swoich środków. Wraz z wprowadzeniem dowodu stawki, użytkownicy, którzy chcieli być stakerami solo, potrzebowali również **klucza walidatora** i **klucza do wypłat**. + +### Klucz walidatora {#validator-key} + +Klucz podpisujący walidatora składa się z dwóch elementów: + +- **Prywatny** klucz walidatora +- **Publiczny** klucz walidatora + +Celem prywatnego klucza walidatora jest podpisywanie operacji w łańcuchu (on-chain), takich jak propozycje bloków i atesty. Z tego powodu klucze te muszą być przechowywane w gorącym portfelu. + +Ta elastyczność ma tę zaletę, że umożliwia bardzo szybkie przenoszenie kluczy podpisujących walidatora z jednego urządzenia na drugie, jednak w przypadku ich zgubienia lub kradzieży złodziej może **działać na szkodę** na kilka sposobów: + +- Odciąć walidatora, poprzez: + - Bycie proponentem i podpisanie dwóch różnych bloków śledzących dla tego samego slotu + - Bycie poświadczającym i podpisanie poświadczenia, które „otacza” inne poświadczenie + - Bycie poświadczającym i podpisanie dwóch różnych poświadczeń mających ten sam cel +- Wymusić dobrowolne wyjście, które zatrzymuje walidatora od stakowania i przyznaje dostęp do jego salda ETH właścicielowi wycofanego klucza + +**Publiczny klucz walidatora** jest zawarty w danych transakcji, gdy użytkownik wpłaca ETH do kontraktu depozytowego stakowania. Są to tzw. _dane depozytowe_ i pozwalają one Ethereum zidentyfikować walidatora. + +### Dane uwierzytelniające do wypłaty {#withdrawal-credentials} + +Każdy walidator ma właściwość znaną jako _dane uwierzytelniające do wypłaty_. Pierwszy bajt tego 32-bajtowego pola identyfikuje typ konta: `0x00` reprezentuje oryginalne dane uwierzytelniające BLS (przed Shapellą, niewypłacalne), `0x01` reprezentuje starsze dane uwierzytelniające wskazujące na adres wykonawczy, a `0x02` reprezentuje nowoczesny typ danych uwierzytelniających z reinwestowaniem. + +Walidatorzy z kluczami BLS `0x00` muszą zaktualizować te dane uwierzytelniające, aby wskazywały na adres wykonawczy w celu aktywacji wypłat nadwyżki salda lub pełnej wypłaty ze stakowania. Można to zrobić, podając adres wykonawczy w danych depozytu podczas początkowego generowania klucza, _LUB_ używając klucza do wypłat w późniejszym czasie do podpisania i rozgłoszenia komunikatu `BLSToExecutionChange`. + +[Więcej na temat danych uwierzytelniających do wypłaty walidatora](/developers/docs/consensus-mechanisms/pos/withdrawal-credentials/) + +### Klucz do wypłat {#withdrawal-key} + +Klucz wypłaty będzie wymagany do zaktualizowania poświadczeń wypłaty, aby wskazywały na adres wykonawczy, jeśli nie został ustawiony podczas początkowego depozytu. Umożliwi to rozpoczęcie przetwarzania płatności nadwyżek salda, a także pozwoli użytkownikom w pełni wypłacić zestakowane ETH. + +Podobnie jak klucze walidatora, klucze wypłaty również składają się z dwóch elementów: + +- **Prywatny** klucz do wypłat +- **Publiczny** klucz do wypłat + +Utrata tego klucza przed aktualizacją danych uwierzytelniających do wypłaty do typu `0x01` oznacza utratę dostępu do salda walidatora. Walidator może nadal podpisywać poświadczenia i bloki, ponieważ działania te wymagają prywatnego klucza walidatora, jednak nie ma żadnej zachęty, jeśli klucze wypłaty zostaną utracone. + +Oddzielenie kluczy walidatora od kluczy konta Ethereum umożliwia uruchamianie wielu walidatorów przez jednego użytkownika. + +![schemat klucza walidatora](validator-key-schematic.png) + +**Uwaga**: Wyjście z obowiązków stakowania i wypłacenie salda walidatora wymaga obecnie podpisania [dobrowolnego komunikatu o wyjściu (VEM)](https://mirror.xyz/ladislaus.eth/wmoBbUBes2Wp1_6DvP6slPabkyujSU7MZOFOC3QpErs&1) kluczem walidatora. Jednakże, [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) to propozycja, która w przyszłości pozwoli użytkownikowi na uruchomienie wyjścia walidatora i wypłatę jego salda poprzez podpisanie komunikatów o wyjściu kluczem do wypłat. Zmniejszy to założenia dotyczące zaufania, umożliwiając stakerom, którzy delegują ETH do [dostawców stakowania jako usługi](/staking/saas/#what-is-staking-as-a-service), zachowanie kontroli nad swoimi środkami. + +## Wyprowadzanie kluczy z frazy seed {#deriving-keys-from-seed} + +Gdyby każde zestakowane 32 ETH wymagało nowego zestawu 2 całkowicie niezależnych kluczy, zarządzanie kluczami szybko stałoby się nieporęczne, szczególnie dla użytkowników uruchamiających wielu walidatorów. Zamiast tego wiele kluczy walidatora można uzyskać z jednego wspólnego tajnego klucza, a przechowywanie tego pojedynczego tajnego klucza umożliwia dostęp do wielu kluczy walidatora. + +[Mnemoniki](https://en.bitcoinwiki.org/wiki/Mnemonic_phrase) i ścieżki to ważne funkcje, z którymi użytkownicy często się spotykają, gdy [uzyskują dostęp](https://ethereum.stackexchange.com/questions/19055/what-is-the-difference-between-m-44-60-0-0-and-m-44-60-0) do swoich portfeli. Mnemonik jest sekwencją słów, które działają jako początkowe ziarno dla klucza prywatnego. W połączeniu z dodatkowymi danymi, mnemonik generuje hash znany jako „klucz główny”. Można to porównać do korzenia drzewa. Odgałęzienia od tego korzenia można następnie wyprowadzić za pomocą ścieżki hierarchicznej, dzięki czemu węzły podrzędne mogą istnieć jako kombinacje hashu węzła nadrzędnego i jego indeksu w drzewie. Przeczytaj o standardach [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) i [BIP-19](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) do generowania kluczy na podstawie mnemoników. + +Ścieżki te mają następującą strukturę, która będzie znana użytkownikom, którzy mieli do czynienia z portfelami sprzętowymi: + +``` +m/44'/60'/0'/0` +``` + +Ukośniki w tej ścieżce oddzielają komponenty klucza prywatnego w następujący sposób: + +``` +master_key / purpose / coin_type / account / change / address_index +``` + +Ta logika pozwala użytkownikom na dołączenie jak największej liczby walidatorów do jednej **frazy mnemonicznej**, ponieważ korzeń drzewa może być wspólny, a zróżnicowanie może następować na gałęziach. Użytkownik może **wyprowadzić dowolną liczbę kluczy** z frazy mnemonicznej. + +``` + [m / 0] + / + / +[m] - [m / 1] + \ + \ + [m / 2] +``` + +Każda gałąź jest oddzielona znakiem `/`, więc `m/2` oznacza rozpoczęcie od klucza głównego i podążanie za gałęzią 2. Na poniższym schemacie pojedyncza fraza mnemoniczna jest używana do przechowywania trzech kluczy wypłat, każdy z dwoma powiązanymi walidatorami. + +![logika klucza walidatora](multiple-keys.png) + +## Dalsza lektura {#further-reading} + +- [Wpis na blogu Ethereum Foundation autorstwa Carla Beekhuizena](https://blog.ethereum.org/2020/05/21/keys/) +- [EIP-2333 generowanie kluczy BLS12-381](https://eips.ethereum.org/EIPS/eip-2333) +- [EIP-7002: Wyjścia wyzwalane przez warstwę wykonawczą](https://web.archive.org/web/20250125035123/https://research.2077.xyz/eip-7002-unpacking-improvements-to-staking-ux-post-merge) +- [Zarządzanie kluczami na dużą skalę](https://docs.ethstaker.cc/ethstaker-knowledge-base/scaled-node-operators/key-management-at-scale) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md new file mode 100644 index 00000000000..bb14d436579 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md @@ -0,0 +1,69 @@ +--- +title: "Dowód stawki(proof-of-stake) vs dowód pracy(proof-of-work)" +description: "Porównanie mechanizmów konsensusu Ethereum, opartych na proof-of-stake i proof-of-work" +lang: pl +--- + +Kiedy Ethereum zostało uruchomione, mechanizm proof-of-stake wciąż wymagał wielu badań i prac nad rozwojem, zanim stwierdzono, że odpowiednio zabezpieczy blockchain Ethereum. Mechanizm proof-of-work był o wiele prostszy, i jego działanie sprawdzone, przez blockchain bitcoina, co pozwalało developerom Ethereum na jego łatwą i szybką implementację, by uruchomić Ethereum. Rozwinięcie mechanizmu proof-of-stake, do punktu, gdzie może zostać wykorzystany, zajęło osiem lat. + +Ta strona wyjaśnia powody dla których, Ethereum przeszło z mechanizmu proof-of-work na proof-of-stake, i przedstawia kompromisy z tym związane. + +## Bezpieczeństwo {#security} + +Badacze Ethereum twierdzą, że mechanizm proof-of-stake jest bardziej bezpieczny od mechanizmu proof-of-work. Jednak mechanizm ten, dopiero niedawno po raz pierwszy, został zaimplementowany do prawdziwej, głównej sieci Ethereum, więc jego działanie jest mniej sprawdzone. W poniższych sekcjach omówiono zalety i wady modelu bezpieczeństwa w mechanizmie proof-of-stake, w porównaniu do mechanizmu proof-of-work. + +### Koszt ataku {#cost-to-attack} + +W systemie dowodu stawki walidatorzy są zobowiązani do zdeponowania („stakowania”) co najmniej 32 ETH w inteligentnym kontrakcie. Ethereum może zniszczyć zastakowany ether, aby ukarać walidatorów, którzy działają nieprawidłowo. Aby osiągnąć konsensus, co najmniej 66% całkowitej ilości zastakowanego etheru musi zagłosować za określonym zestawem bloków. Bloki, na które zagłosowało >=66% stawki, stają się „sfinalizowane”, co oznacza, że nie można ich usunąć ani zreorganizować. + +Atak na sieć może oznaczać uniemożliwienie sfinalizowania łańcucha lub zapewnienie określonej organizacji bloków w łańcuchu kanonicznym, co w jakiś sposób przynosi korzyść atakującemu. Wymaga to od atakującego odwrócenia ścieżki uczciwego konsensusu, albo poprzez zgromadzenie dużej ilości etheru i bezpośrednie głosowanie nim, albo poprzez nakłonienie uczciwych walidatorów do głosowania w określony sposób. Pomijając wyrafinowane ataki o niskim prawdopodobieństwie, które nakłaniają uczciwych walidatorów do określonego działania, koszt ataku na Ethereum to koszt stawki, którą atakujący musi zgromadzić, aby wpłynąć na konsensus na swoją korzyść. + +Najniższy koszt ataku to >33% całkowitej stawki. Atakujący posiadający >33% całkowitej stawki może spowodować opóźnienie finalizacji, po prostu przechodząc w tryb offline. Jest to stosunkowo niewielki problem dla sieci, ponieważ istnieje mechanizm znany jako „wyciek bezczynności”, który powoduje wyciek stawki od walidatorów offline, dopóki większość online nie będzie reprezentować 66% stawki i nie będzie mogła ponownie sfinalizować łańcucha. Teoretycznie możliwe jest również, że atakujący spowoduje podwójną finalizację z nieco ponad 33% całkowitej stawki, tworząc dwa bloki zamiast jednego, gdy zostanie poproszony o bycie producentem bloku, a następnie podwójnie zagłosuje wszystkimi swoimi walidatorami. Każdy fork wymaga jedynie, aby 50% pozostałych uczciwych walidatorów zobaczyło każdy blok jako pierwsze, więc jeśli uda im się odpowiednio zgrać w czasie swoje komunikaty, mogą być w stanie sfinalizować oba forki. Ma to niskie prawdopodobieństwo powodzenia, ale gdyby atakującemu udało się spowodować podwójną finalizację, społeczność Ethereum musiałaby zdecydować, za którym forkiem podążać, w którym to przypadku walidatorzy atakującego zostaliby ukarani cięciem na drugim forku. + +Mając >33% całkowitej stawki, atakujący ma szansę wywrzeć niewielki (opóźnienie finalizacji) lub poważniejszy (podwójna finalizacja) wpływ na sieć Ethereum. Przy ponad 14 000 000 ETH zastakowanych w sieci i reprezentatywnej cenie 1000 USD/ETH, minimalny koszt przeprowadzenia tych ataków wynosi `1000 x 14 000 000 x 0,33 = 4 620 000 000 USD`. Atakujący straciłby te pieniądze poprzez cięcie i zostałby wyrzucony z sieci. Aby ponownie zaatakować, musiałby zgromadzić >33% stawki (ponownie) i spalić ją (ponownie). Każda próba ataku na sieć kosztowałaby ponad 4,6 miliarda dolarów (przy cenie 1000 USD/ETH i 14 milionach zastakowanych ETH). Atakujący jest również wyrzucany z sieci, gdy zostanie ukarany cięciem, i musi dołączyć do kolejki aktywacyjnej, aby ponownie dołączyć. Oznacza to, że szybkość ponownego ataku jest ograniczona nie tylko szybkością, z jaką atakujący może zgromadzić >33% całkowitej stawki, ale także czasem potrzebnym na wprowadzenie wszystkich swoich walidatorów do sieci. Za każdym razem, gdy atakujący atakuje, staje się on znacznie biedniejszy, a reszta społeczności staje się bogatsza dzięki wynikającemu z tego szokowi podażowemu. + +Inne ataki, takie jak ataki 51% lub odwrócenie finalizacji z 66% całkowitej stawki, wymagają znacznie więcej ETH i są o wiele bardziej kosztowne dla atakującego. + +Porównaj to z dowodem pracy. Koszt przeprowadzenia ataku na Ethereum z dowodem pracy był kosztem konsekwentnego posiadania >50% całkowitego hashrate'u sieci. Sprowadzało się to do kosztów sprzętu i jego eksploatacji, o wystarczającej mocy obliczeniowej, aby konsekwentnie prześcigać innych górników w obliczaniu rozwiązań dowodu pracy. Ethereum było w większości wydobywane przy użyciu kart GPU, a nie układów ASIC, co utrzymywało niskie koszty (chociaż gdyby Ethereum pozostało przy dowodzie pracy, kopanie za pomocą układów ASIC mogłoby stać się bardziej popularne). Przeciwnik musiałby zakupić dużo sprzętu i zapłacić za energię elektryczną, aby zaatakować sieć Ethereum z dowodem pracy, ale całkowity koszt byłby niższy niż koszt wymagany do zgromadzenia wystarczającej ilości ETH do przeprowadzenia ataku. Atak 51% jest ~[20 razy tańszy](https://youtu.be/1m12zgJ42dI?t=1562) w przypadku dowodu pracy niż w przypadku dowodu stawki. Gdyby atak został wykryty, a łańcuch poddany hard forkowi w celu usunięcia zmian, atakujący mógłby wielokrotnie używać tego samego sprzętu do atakowania nowego forka. + +### Złożoność {#complexity} + +Dowód stawki jest znacznie bardziej złożony niż dowód pracy. Może to być argument na korzyść dowodu pracy, ponieważ trudniej jest przypadkowo wprowadzić błędy lub niezamierzone efekty do prostszych protokołów. Jednak złożoność została okiełznana dzięki latom badań i rozwoju, symulacji i wdrożeń w sieciach testowych. Protokół dowodu stawki został niezależnie wdrożony przez pięć oddzielnych zespołów (na każdej z warstw wykonawczej i konsensusu) w pięciu językach programowania, zapewniając odporność na błędy klientów. + +Aby bezpiecznie rozwijać i testować logikę konsensusu dowodu stawki, Beacon Chain został uruchomiony dwa lata przed wdrożeniem dowodu stawki w sieci głównej Ethereum. Beacon Chain działał jako piaskownica do testowania dowodu stawki, ponieważ był to działający blockchain implementujący logikę konsensusu dowodu stawki, ale bez dotykania prawdziwych transakcji Ethereum – w efekcie po prostu osiągając konsensus sam na sobie. Gdy był on stabilny i wolny od błędów przez wystarczająco długi czas, Beacon Chain został „połączony” z siecią główną Ethereum. Wszystko to przyczyniło się do okiełznania złożoności dowodu stawki do tego stopnia, że ryzyko niezamierzonych konsekwencji lub błędów klienta było bardzo niskie. + +### Powierzchnia ataku {#attack-surface} + +Dowód stawki jest bardziej złożony niż dowód pracy, co oznacza, że istnieje więcej potencjalnych wektorów ataku, z którymi trzeba sobie poradzić. Zamiast jednej sieci peer-to-peer łączącej klientów, istnieją dwie, z których każda implementuje oddzielny protokół. Wstępne wybranie jednego konkretnego walidatora do zaproponowania bloku w każdym slocie stwarza potencjał do ataku typu „odmowa usługi”, w którym duże ilości ruchu sieciowego przełączają tego konkretnego walidatora w tryb offline. + +Istnieją również sposoby, w jakie atakujący mogą starannie zaplanować w czasie publikację swoich bloków lub poświadczeń, tak aby zostały one odebrane przez pewną część uczciwej sieci, wpływając na nich, aby głosowali w określony sposób. Wreszcie, atakujący może po prostu zgromadzić wystarczającą ilość ETH, aby stakować i zdominować mechanizm konsensusu. Każdy z tych [wektorów ataku ma powiązane mechanizmy obronne](/developers/docs/consensus-mechanisms/pos/attack-and-defense), ale nie trzeba się przed nimi bronić w przypadku dowodu pracy. + +## Decentralizacja {#decentralization} + +Dowód stawki jest bardziej zdecentralizowany niż dowód pracy, ponieważ wyścigi zbrojeń w sprzęcie do wydobycia zwykle wypierają z rynku osoby fizyczne i małe organizacje. Chociaż technicznie każdy może rozpocząć wydobycie przy użyciu skromnego sprzętu, prawdopodobieństwo otrzymania jakiejkolwiek nagrody jest znikomo małe w porównaniu z instytucjonalnymi operacjami wydobywczymi. W przypadku dowodu stawki koszt stakowania i procentowy zwrot z tej stawki są takie same dla wszystkich. Obecnie uruchomienie walidatora kosztuje 32 ETH. + +Z drugiej strony, wynalezienie płynnych instrumentów pochodnych stakowania doprowadziło do obaw o centralizację, ponieważ kilku dużych dostawców zarządza dużymi ilościami zastakowanego ETH. Jest to problematyczne i należy to jak najszybciej naprawić, ale jest to również bardziej złożone, niż się wydaje. Scentralizowani dostawcy usług stakowania niekoniecznie mają scentralizowaną kontrolę nad walidatorami – często jest to po prostu sposób na stworzenie centralnej puli ETH, którą wielu niezależnych operatorów węzłów może stakować bez konieczności posiadania przez każdego uczestnika własnych 32 ETH. + +Najlepszą opcją dla Ethereum jest uruchamianie walidatorów lokalnie na komputerach domowych, co maksymalizuje decentralizację. Dlatego Ethereum opiera się zmianom, które zwiększają wymagania sprzętowe do uruchomienia węzła/walidatora. + +## Zrównoważony rozwój {#sustainability} + +Dowód stawki to niskoemisyjny sposób na zabezpieczenie blockchaina. W ramach dowodu pracy górnicy rywalizują o prawo do wydobycia bloku. Górnicy odnoszą większe sukcesy, gdy mogą szybciej wykonywać obliczenia, co zachęca do inwestycji w sprzęt i zużycie energii. Zaobserwowano to w przypadku Ethereum, zanim przeszło ono na dowód stawki. Krótko przed przejściem na dowód stawki Ethereum zużywało około 78 TWh rocznie – tyle, co mały kraj. Jednak przejście na dowód stawki zmniejszyło te wydatki na energię o ~99,98%. Dowód stawki uczynił Ethereum energooszczędną, niskoemisyjną platformą. + +[Więcej o zużyciu energii przez Ethereum](/energy-consumption) + +## Emisja {#issuance} + +Ethereum z dowodem stawki może płacić za swoje bezpieczeństwo, emitując znacznie mniej monet niż Ethereum z dowodem pracy, ponieważ walidatorzy nie muszą płacić wysokich kosztów energii elektrycznej. W rezultacie ETH może zmniejszyć swoją inflację, a nawet stać się deflacyjny, gdy duże ilości ETH są spalane. Niższe poziomy inflacji oznaczają, że bezpieczeństwo Ethereum jest tańsze niż w przypadku dowodu pracy. + +## Jesteś raczej wzrokowcem? Dla wzrokowców {#visual-learner} + +Obejrzyj, jak Justin Drake wyjaśnia zalety dowodu stawki w porównaniu z dowodem pracy: + + + +## Dalsza lektura {#further-reading} + +- [Filozofia projektowania dowodu stawki według Vitalika](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) +- [Często zadawane pytania dotyczące dowodu stawki według Vitalika](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) +- [Film „Prosto wyjaśnione” na temat PoS kontra PoW](https://www.youtube.com/watch?v=M3EFi_POhps) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md new file mode 100644 index 00000000000..512d5fb38bd --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md @@ -0,0 +1,91 @@ +--- +title: Nagrody i kary w mechanizmie proof-of-stake +description: "Dowiedz się o motywatorach wewnątrzprotokołowych w Ethereum opartym na mechanizmie proof-of-stake." +lang: pl +--- + +Ethereum jest zabezpieczone za pomocą swojej natywnej kryptowaluty, etheru (ETH). Operatorzy węzłów, którzy chcą uczestniczyć w walidacji bloków i identyfikacji głowy łańcucha, wpłacają ether do [kontraktu depozytowego](/staking/deposit-contract/) w Ethereum. Otrzymują oni następnie wynagrodzenie w etherze za uruchamianie oprogramowania walidatora, które sprawdza ważność nowych bloków otrzymywanych przez sieć peer-to-peer i stosuje algorytm wyboru forka w celu zidentyfikowania głowy łańcucha. + +Walidator ma dwie podstawowe role: 1) sprawdzanie nowych bloków i „atestowanie” ich, jeśli są prawidłowe, 2) proponowanie nowych bloków po losowym wybraniu z całej puli walidatorów. Jeśli walidator nie wykona żadnego z tych zadań na żądanie, traci wypłatę w etherze. Walidatorzy są również czasami odpowiedzialni za agregację podpisów i uczestnictwo w komitetach synchronizacyjnych. + +Istnieją również pewne działania, które bardzo trudno jest wykonać przypadkowo i które wskazują na złośliwe zamiary, takie jak proponowanie wielu bloków dla tego samego slotu lub atestowanie wielu bloków dla tego samego slotu. Są to zachowania podlegające „slashingowi”, które skutkują spaleniem pewnej ilości etheru walidatora (do 1 ETH), zanim walidator zostanie usunięty z sieci, co trwa 36 dni. Ether walidatora poddanego slashingowi powoli wyczerpuje się w okresie wyjścia, ale 18. dnia otrzymuje on „karę korelacyjną”, która jest tym większa, im więcej walidatorów zostanie poddanych slashingowi w tym samym czasie. Struktura motywacyjna mechanizmu konsensusu wynagradza zatem uczciwość i karze złych aktorów. + +Wszystkie nagrody i kary są stosowane raz na epokę. + +Czytaj dalej, aby poznać więcej szczegółów... + +## Nagrody i kary {#rewards} + +### Nagrody {#rewards} + +Walidatorzy otrzymują nagrody, gdy oddają głosy zgodne z większością innych walidatorów, gdy proponują bloki i gdy uczestniczą w komitetach synchronizacyjnych. Wartość nagród w każdej epoce jest obliczana na podstawie `base_reward`. Jest to podstawowa jednostka, na podstawie której obliczane są inne nagrody. `base_reward` reprezentuje średnią nagrodę otrzymywaną przez walidatora w optymalnych warunkach w każdej epoce. Jest ona obliczana na podstawie efektywnego salda walidatora i całkowitej liczby aktywnych walidatorów w następujący sposób: + +``` +base_reward = effective_balance * (base_reward_factor / (base_rewards_per_epoch * sqrt(sum(active_balance)))) +``` + +gdzie `base_reward_factor` to 64, `base_rewards_per_epoch` to 4, a `sum(active balance)` to całkowita ilość stakowanego etheru u wszystkich aktywnych walidatorów. + +Oznacza to, że podstawowa nagroda jest proporcjonalna do efektywnego salda walidatora i odwrotnie proporcjonalna do liczby walidatorów w sieci. Im więcej walidatorów, tym większa ogólna emisja (jako `sqrt(N)`), ale mniejsza `base_reward` na walidatora (jako `1/sqrt(N)`). Czynniki te wpływają na APR węzła stakingowego. Przeczytaj uzasadnienie w [notatkach Vitalika](https://notes.ethereum.org/@vbuterin/rkhCgQteN?type=view#Base-rewards). + +Całkowita nagroda jest następnie obliczana jako suma pięciu składników, z których każdy ma wagę określającą, ile każdy składnik dodaje do całkowitej nagrody. Składniki to: + +``` +1. głosowanie za źródłem: walidator oddał terminowy głos za prawidłowym źródłowym punktem kontrolnym +2. głosowanie za celem: walidator oddał terminowy głos za prawidłowym docelowym punktem kontrolnym +3. głosowanie za głową: walidator oddał terminowy głos za prawidłowym blokiem głowy +4. nagroda komitetu synchronizacyjnego: walidator uczestniczył w komitecie synchronizacyjnym +5. nagroda proponenta: walidator zaproponował blok w prawidłowym slocie +``` + +Wagi dla każdego składnika są następujące: + +``` +TIMELY_SOURCE_WEIGHT uint64(14) +TIMELY_TARGET_WEIGHT uint64(26) +TIMELY_HEAD_WEIGHT uint64(14) +SYNC_REWARD_WEIGHT uint64(2) +PROPOSER_WEIGHT uint64(8) +``` + +Suma tych wag wynosi 64. Nagroda jest obliczana jako suma odpowiednich wag podzielona przez 64. Walidator, który terminowo oddał głosy na źródło, cel i głowę, zaproponował blok i uczestniczył w komitecie synchronizacyjnym, może otrzymać `64/64 * base_reward == base_reward`. Jednak walidator zwykle nie jest proponentem bloku, więc jego maksymalna nagroda wynosi `64-8 /64 * base_reward == 7/8 * base_reward`. Walidatorzy, którzy nie są ani proponentami bloków, ani nie należą do komitetu synchronizacyjnego, mogą otrzymać `64-8-2 / 64 * base_reward == 6.75/8 * base_reward`. + +Dodatkowa nagroda jest dodawana w celu motywowania do szybkich atestacji. Jest to `inclusion_delay_reward`. Ma ona wartość równą `base_reward` pomnożonej przez `1/delay`, gdzie `delay` to liczba slotów oddzielających propozycję bloku od atestacji. Na przykład, jeśli atestacja zostanie przesłana w ciągu jednego slotu od propozycji bloku, atestujący otrzymuje `base_reward * 1/1 == base_reward`. Jeśli atestacja dotrze w następnym slocie, atestujący otrzyma `base_reward * 1/2` i tak dalej. + +Proponenci bloków otrzymują `8 / 64 * base_reward` za **każdą ważną atestację** zawartą w bloku, więc rzeczywista wartość nagrody skaluje się wraz z liczbą atestujących walidatorów. Proponenci bloków mogą również zwiększyć swoją nagrodę, włączając do proponowanego bloku dowody niewłaściwego zachowania innych walidatorów. Te nagrody to „marchewki”, które zachęcają walidatorów do uczciwości. Proponent bloku, który uwzględni slashing, zostanie nagrodzony `slashed_validators_effective_balance / 512`. + +### Kary {#penalties} + +Do tej pory rozważaliśmy idealnie zachowujących się walidatorów, ale co z walidatorami, którzy nie oddają terminowych głosów na głowę, źródło i cel lub robią to powoli? + +Kary za pominięcie głosów na cel i źródło są równe nagrodom, które atestujący otrzymałby, gdyby je przesłał. Oznacza to, że zamiast dodania nagrody do ich salda, z ich salda jest usuwana równoważna wartość. Nie ma kary za pominięcie głosu na głowę (tj. głosy na głowę są tylko nagradzane, nigdy karane). Nie ma kary związanej z `inclusion_delay` – nagroda po prostu nie zostanie dodana do salda walidatora. Nie ma również kary za nieproponowanie bloku. + +Przeczytaj więcej o nagrodach i karach w [specyfikacjach konsensusu](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md). Nagrody i kary zostały dostosowane w aktualizacji Bellatrix – zobacz, jak Danny Ryan i Vitalik omawiają to w filmie [Peep an EIP](https://www.youtube.com/watch?v=iaAEGs1DMgQ). + +## Slashing {#slashing} + +Slashing jest poważniejszym działaniem, które skutkuje przymusowym usunięciem walidatora z sieci i związaną z tym utratą jego stakowanego etheru. Istnieją trzy sposoby, w jakie walidator może zostać poddany slashingowi, a wszystkie sprowadzają się do nieuczciwego proponowania lub atestowania bloków: + +- Proponując i podpisując dwa różne bloki dla tego samego slotu +- Atestując blok, który „otacza” inny (skutecznie zmieniając historię) +- Poprzez „podwójne głosowanie”, atestując dwóch kandydatów na ten sam blok + +Jeśli te działania zostaną wykryte, walidator podlega slashingowi. Oznacza to, że 0,0078125 jest natychmiast spalane dla walidatora z 32 ETH (skalowane liniowo z aktywnym saldem), a następnie rozpoczyna się 36-dniowy okres usuwania. W tym okresie usuwania stawka walidatora stopniowo maleje. W połowie okresu (18. dnia) nakładana jest dodatkowa kara, której wielkość skaluje się wraz z całkowitą stawką etheru wszystkich walidatorów poddanych slashingowi w ciągu 36 dni poprzedzających zdarzenie slashingu. Oznacza to, że im więcej walidatorów jest poddawanych slashingowi, tym większa jest jego skala. Maksymalny slashing to pełne efektywne saldo wszystkich walidatorów poddanych slashingowi (tzn. jeśli wielu walidatorów jest poddawanych slashingowi, mogą stracić całą swoją stawkę). Z drugiej strony, pojedyncze, odizolowane zdarzenie slashingu spala tylko niewielką część stawki walidatora. Ta kara w połowie okresu, która skaluje się wraz z liczbą walidatorów poddanych slashingowi, nazywana jest „karą korelacyjną”. + +## Wyciek z powodu nieaktywności {#inactivity-leak} + +Jeśli warstwa konsensusu nie sfinalizowała się przez ponad cztery epoki, aktywowany jest protokół awaryjny zwany „wyciekiem z powodu nieaktywności”. Ostatecznym celem wycieku z powodu nieaktywności jest stworzenie warunków niezbędnych do odzyskania finalności łańcucha. Jak wyjaśniono powyżej, finalność wymaga zgody 2/3 większości całkowitej stakowanej puli etheru na źródłowe i docelowe punkty kontrolne. Jeśli walidatorzy reprezentujący ponad 1/3 wszystkich walidatorów przejdą w tryb offline lub nie prześlą poprawnych atestacji, superwiększość 2/3 nie będzie w stanie sfinalizować punktów kontrolnych. Wyciek z powodu nieaktywności pozwala na stopniowe zmniejszanie stawki należącej do nieaktywnych walidatorów, aż będą kontrolować mniej niż 1/3 całkowitej stawki, co pozwoli pozostałym aktywnym walidatorom na sfinalizowanie łańcucha. Niezależnie od tego, jak duża jest pula nieaktywnych walidatorów, pozostali aktywni walidatorzy w końcu będą kontrolować >2/3 stawki. Utrata stawki jest silnym bodźcem dla nieaktywnych walidatorów do jak najszybszej reaktywacji! Scenariusz wycieku z powodu nieaktywności miał miejsce w sieci testowej Medalla, gdy <66% aktywnych walidatorów nie było w stanie osiągnąć konsensusu co do aktualnej głowy blockchainu. Wyciek z powodu nieaktywności został aktywowany i ostatecznie odzyskano finalność! + +Projekt nagród, kar i slashingu w mechanizmie konsensusu zachęca poszczególnych walidatorów do prawidłowego zachowania. Jednak z tych wyborów projektowych wyłania się system, który silnie motywuje do równej dystrybucji walidatorów między wieloma klientami i powinien silnie zniechęcać do dominacji jednego klienta. + +## Dalsza lektura {#further-reading} + +- [Aktualizacja Ethereum: Warstwa motywacyjna](https://eth2book.info/altair/part2/incentives) +- [Zachęty w hybrydowym protokole Casper Ethereum](https://arxiv.org/pdf/1903.04205.pdf) +- [Specyfikacja z adnotacjami Vitalika](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#rewards-and-penalties-1) +- [Wskazówki dotyczące zapobiegania slashingowi w Eth2](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) +- [Analiza kar za slashing w ramach EIP-7251](https://ethresear.ch/t/slashing-penalty-analysis-eip-7251/16509) + +_Źródła_ + +- _[https://benjaminion.xyz/eth2-annotated-spec/phase0/beacon-chain/](https://benjaminion.xyz/eth2-annotated-spec/phase0/beacon-chain/)_ diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md new file mode 100644 index 00000000000..42ab7e19a6c --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md @@ -0,0 +1,39 @@ +--- +title: "Słaba podmiotowość" +description: "Wyjaśnienie słabej subiektywności i jej roli w PoS Ethereum." +lang: pl +--- + +Subiektywność w łańcuchach bloków odnosi się do polegania na informacjach społecznych w celu uzgodnienia bieżącego stanu. Może istnieć wiele prawidłowych forków, które są wybierane zgodnie z informacjami zebranymi od innych węzłów w sieci. Przeciwieństwem jest obiektywność, która odnosi się do łańcuchów, w których istnieje tylko jeden możliwy prawidłowy łańcuch, co do którego wszystkie węzły muszą się zgodzić, stosując swoje zakodowane zasady. Istnieje również trzeci stan, znany jako słaba subiektywność. Odnosi się to do łańcucha, który może postępować obiektywnie po tym, jak początkowe ziarno informacji zostanie pobrane społecznie. + +## Wymagania wstępne {#prerequisites} + +Aby zrozumieć tę stronę, konieczne jest najpierw zrozumienie podstaw [dowodu stawki](/developers/docs/consensus-mechanisms/pos/). + +## Jakie problemy rozwiązuje słaba subiektywność? {#problems-ws-solves} + +Subiektywność jest nieodłączną cechą łańcuchów bloków z dowodem stawki, ponieważ wybór prawidłowego łańcucha spośród wielu forków odbywa się poprzez liczenie historycznych głosów. Naraża to łańcuch bloków na kilka wektorów ataku, w tym ataki dalekiego zasięgu, w których węzły, które uczestniczyły bardzo wcześnie w łańcuchu, utrzymują alternatywny fork, który udostępniają znacznie później dla własnej korzyści. Alternatywnie, jeśli 33% walidatorów wypłaci swoją stawkę, ale nadal będzie poświadczać i produkować bloki, mogą oni wygenerować alternatywnego forka, który jest sprzeczny z łańcuchem kanonicznym. Nowe węzły lub węzły, które były przez długi czas offline, mogą nie być świadome, że atakujący walidatorzy wypłacili swoje środki, więc atakujący mogliby ich oszukać, aby podążali za nieprawidłowym łańcuchem. Ethereum może rozwiązać te wektory ataku poprzez narzucenie ograniczeń, które zmniejszają subiektywne aspekty mechanizmu — a tym samym założenia dotyczące zaufania — do absolutnego minimum. + +## Punkty kontrolne słabej subiektywności {#ws-checkpoints} + +Słaba subiektywność jest zaimplementowana w Ethereum z dowodem stawki za pomocą „punktów kontrolnych słabej subiektywności”. Są to korzenie stanu, co do których wszystkie węzły w sieci zgadzają się, że należą do kanonicznego łańcucha. Służą temu samemu celowi „uniwersalnej prawdy” co bloki genezy, z tą różnicą, że nie znajdują się na pozycji genezy w łańcuchu bloków. Algorytm wyboru forka ufnie zakłada, że stan łańcucha bloków zdefiniowany w tym punkcie kontrolnym jest poprawny oraz że niezależnie i obiektywnie weryfikuje łańcuch od tego momentu. Punkty kontrolne działają jako „limity cofania”, ponieważ bloki znajdujące się przed punktami kontrolnymi słabej subiektywności nie mogą być zmienione. To podważa ataki dalekiego zasięgu, po prostu przez zdefiniowanie forków dalekiego zasięgu jako nieprawidłowych w ramach projektu mechanizmu. Zapewnienie, że punkty kontrolne słabej subiektywności są od siebie oddalone mniej niż okres wypłaty walidatora, gwarantuje, że walidator, który tworzy fork łańcucha, zostanie ukarany cięciem co najmniej o pewną kwotę progową, zanim będzie mógł wypłacić swoją stawkę, a nowi uczestnicy nie będą mogli zostać oszukani i skłonieni do podążania za nieprawidłowymi forkami przez walidatorów, którzy wypłacili już swoją stawkę. + +## Różnica między punktami kontrolnymi słabej subiektywności a sfinalizowanymi blokami {#difference-between-ws-and-finalized-blocks} + +Sfinalizowane bloki i punkty kontrolne słabej subiektywności są traktowane inaczej przez węzły Ethereum. Jeśli węzeł dowie się o dwóch konkurujących ze sobą sfinalizowanych blokach, wówczas ma problem z wyborem — nie ma sposobu, aby automatycznie zidentyfikować, który jest forkiem kanonicznym. Jest to symptomem awarii konsensusu. W przeciwieństwie do tego, węzeł po prostu odrzuca każdy blok, który jest sprzeczny z jego punktem kontrolnym słabej subiektywności. Z perspektywy węzła punkt kontrolny słabej subiektywności stanowi absolutną prawdę, której nie można podważyć nową wiedzą od innych węzłów. + +## Na ile słaba jest ta subiektywność? {#how-weak-is-weak} + +Subiektywny aspekt dowodu stawki w Ethereum to wymóg posiadania niedawnego stanu (punktu kontrolnego słabej subiektywności) z zaufanego źródła w celu synchronizacji. Ryzyko otrzymania złego punktu kontrolnego słabej subiektywności jest bardzo niskie, ponieważ można je sprawdzić w kilku niezależnych źródłach publicznych, takich jak eksploratory bloków lub wiele węzłów. Jednakże zawsze wymagany jest pewien stopień zaufania do uruchomienia dowolnej aplikacji, na przykład zaufanie, że deweloperzy oprogramowania stworzyli uczciwe oprogramowanie. + +Punkt kontrolny słabej subiektywności może nawet być częścią oprogramowania klienta. Można argumentować, że atakujący może uszkodzić punkt kontrolny w oprogramowaniu i z równą łatwością może uszkodzić samo oprogramowanie. Nie ma prawdziwej kryptograficzno-ekonomicznej drogi obejścia tego problemu, ale wpływ niegodnych zaufania deweloperów jest minimalizowany w Ethereum dzięki istnieniu wielu niezależnych zespołów klienckich, z których każdy buduje równoważne oprogramowanie w różnych językach, a wszystkie z nich mają żywotny interes w utrzymaniu uczciwego łańcucha. Eksploratory bloków mogą również dostarczać punkty kontrolne słabej subiektywności lub sposób na porównanie punktów kontrolnych uzyskanych z innych miejsc z dodatkowym źródłem. + +Wreszcie o punkty kontrolne można poprosić inne węzły; być może inny użytkownik Ethereum, który prowadzi pełny węzeł, może dostarczyć punkt kontrolny, który walidatorzy mogą następnie zweryfikować z danymi z eksploratora bloków. Ogólnie rzecz biorąc, zaufanie dostawcy punktu kontrolnego słabej subiektywności można uznać za równie problematyczne co zaufanie deweloperom klienta. Ogólny wymagany poziom zaufania jest niski. Należy zauważyć, że te rozważania stają się ważne tylko w bardzo mało prawdopodobnym przypadku, gdy większość walidatorów zmówi się, aby stworzyć alternatywny fork łańcucha bloków. W każdych innych okolicznościach do wyboru jest tylko jeden łańcuch Ethereum. + +## Dalsza lektura {#further-reading} + +- [Słaba subiektywność w Eth2](https://notes.ethereum.org/@adiasg/weak-subjectvity-eth2) +- [Vitalik: Jak nauczyłem się kochać słabą subiektywność](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) +- [Słaba subiektywność (dokumentacja Teku)](https://docs.teku.consensys.io/concepts/weak-subjectivity) +- [Faza 0 – Przewodnik po słabej subiektywności](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/weak-subjectivity.md) +- [Analiza słabej subiektywności w Ethereum 2.0](https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/withdrawal-credentials/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/withdrawal-credentials/index.md new file mode 100644 index 00000000000..f21902cc181 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pos/withdrawal-credentials/index.md @@ -0,0 +1,64 @@ +--- +title: "Poświadczenia wypłaty" +description: "Wyjaśnienie typów poświadczeń wypłat walidatora (0x00, 0x01, 0x02) i ich implikacji dla stakerów Ethereum." +lang: pl +--- + +Każdy walidator ma **poświadczenie wypłaty**, które określa, jak i gdzie można wypłacić stakowane ETH i nagrody. Typ poświadczenia jest wskazany przez pierwszy bajt: `0x00`, `0x01` lub `0x02`. Zrozumienie tych typów jest ważne dla walidatorów zarządzających swoją stawką. + +## 0x00: Poświadczenia sprzed aktualizacji Shapella {#0x00-credentials} + +Typ `0x00` to oryginalny format poświadczeń wypłaty sprzed aktualizacji Shapella (kwiecień 2023). Walidatorzy z tym typem poświadczeń nie mają ustawionego adresu wypłaty w warstwie wykonawczej, co oznacza, że ich środki pozostają zablokowane w warstwie konsensusu. Jeśli nadal masz poświadczenia `0x00`, musisz je zaktualizować do `0x01` lub `0x02`, zanim będziesz mógł otrzymywać jakiekolwiek wypłaty. + +## 0x01: Starsze poświadczenia wypłat {#0x01-credentials} + +Typ `0x01` został wprowadzony wraz z aktualizacją Shapella i stał się standardem dla walidatorów, którzy chcieli ustawić adres wypłaty w warstwie wykonawczej. Z poświadczeniami `0x01`: + +- Każde saldo powyżej 32 ETH jest **automatycznie przesyłane** na Twój adres wypłaty +- Pełne wyjścia przechodzą przez standardową kolejkę wyjść +- Nagrody powyżej 32 ETH nie mogą być reinwestowane — są okresowo wypłacane + +**Dlaczego niektórzy walidatorzy nadal używają 0x01:** Jest to prostsze i dobrze znane rozwiązanie. Wielu walidatorów dokonało depozytu po aktualizacji Shapella i już posiada ten typ, który działa dobrze dla tych, którzy chcą automatycznych wypłat nadwyżki salda. + +**Dlaczego nie jest to zalecane:** Z typem `0x01` tracisz możliwość reinwestowania nagród powyżej 32 ETH. Każda nadwyżka jest automatycznie wypłacana, co ogranicza potencjał zarobkowy walidatora i wymaga oddzielnego zarządzania wypłaconymi środkami. + +## 0x02: Reinwestujące poświadczenia wypłat {#0x02-credentials} + +Typ `0x02` został wprowadzony wraz z aktualizacją Pectra i jest obecnie **zalecanym wyborem** dla walidatorów. Walidatorzy z poświadczeniami `0x02` są czasami nazywani "walidatorami reinwestującymi". + +Z poświadczeniami `0x02`: + +- Nagrody powyżej 32 ETH są **reinwestowane** w przyrostach co 1 ETH aż do maksymalnego efektywnego salda 2048 ETH +- Częściowe wypłaty muszą być zlecane ręcznie (automatyczne wypłaty mają miejsce tylko powyżej progu 2048 ETH) +- Walidatorzy mogą konsolidować wielu walidatorów 32 ETH w jednego walidatora o wyższym saldzie +- Pełne wyjścia są nadal obsługiwane przez standardową kolejkę wyjść + +Zarówno częściowe wypłaty, jak i konsolidacje mogą być wykonane za pośrednictwem [Launchpad Validator Actions](https://launchpad.ethereum.org/en/validator-actions). + +**Dlaczego walidatorzy powinni preferować typ 0x02:** Oferuje on lepszą efektywność kapitałową dzięki reinwestowaniu, większą kontrolę nad terminami wypłat i wspiera konsolidację walidatorów. Dla samodzielnych stakerów, którzy z czasem gromadzą nagrody, oznacza to, że ich efektywne saldo – a tym samym ich nagrody – mogą wzrosnąć powyżej 32 ETH bez ręcznej interwencji. + +**Ważne:** Po konwersji z `0x01` na `0x02` nie można cofnąć tej zmiany. + +Szczegółowy przewodnik dotyczący konwersji na poświadczenia typu 2 oraz funkcji MaxEB można znaleźć na [stronie wyjaśniającej MaxEB](/roadmap/pectra/maxeb/). + +## Co powinienem wybrać? {#what-should-i-pick} + +- **Nowi walidatorzy:** Wybierzcie `0x02`. To nowoczesny standard z lepszym reinwestowaniem i elastycznością. +- **Obecni walidatorzy 0x01:** Rozważcie konwersję do `0x02`, jeśli chcecie, aby nagrody były reinwestowane powyżej 32 ETH lub planujecie konsolidację walidatorów. +- **Obecni walidatorzy 0x00:** Zaktualizujcie natychmiast – nie możecie dokonywać wypłat bez aktualizacji poświadczeń. Najpierw musicie dokonać konwersji na `0x01`, a następnie możecie dokonać konwersji na `0x02`. + +## Narzędzia do zarządzania poświadczeniami wypłat {#withdrawal-credential-tools} + +Kilka narzędzi obsługuje wybór lub konwersję między typami poświadczeń: + +- **[Ethereum Staking Launchpad](https://launchpad.ethereum.org/en/validator-actions)** – oficjalne narzędzie do depozytów i zarządzania walidatorami, w tym konwersji poświadczeń i konsolidacji +- **[Pectra Staking Manager](https://pectrastaking.com)** – interfejs internetowy z obsługą wallet-connect do konwersji i konsolidacji +- **[Pectra Validator Ops CLI Tool](https://github.com/Luganodes/Pectra-Batch-Contract)** – narzędzie wiersza poleceń do konwersji wsadowych +- **[Ethereal](https://github.com/wealdtech/ethereal)** – narzędzie CLI do operacji na Ethereum, w tym zarządzania walidatorami + +Pełną listę narzędzi do konsolidacji i szczegółowe instrukcje dotyczące konwersji można znaleźć w [Narzędzia do konsolidacji MaxEB](/roadmap/pectra/maxeb/#consolidation-tooling). + +## Dalsza lektura {#further-reading} + +- [Klucze w proof-of-stake Ethereum](/developers/docs/consensus-mechanisms/pos/keys/) – dowiedz się o kluczach walidatora i ich związku z poświadczeniami wypłat +- [MaxEB](/roadmap/pectra/maxeb/) – szczegółowy przewodnik po aktualizacji Pectra i funkcji maksymalnego efektywnego salda diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/index.md index e69191a9bb2..56455c8dc9d 100644 --- a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/index.md +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/index.md @@ -1,97 +1,114 @@ --- -title: Proof-of-work (PoW) -description: Wyjaśnienie protokołu konsensusu proof-of-work i jego roli w Ethereum. +title: Proof of work (PoW) +description: "Wyjaśnienie protokołu konsensusu proof-of-work i jego roli w Ethereum." lang: pl -incomplete: true --- -Ethereum, podobnie jak Bitcoin, używa obecnie protokołu konsensusu o nazwie [proof-of-work (PoW)](https://wikipedia.org/wiki/Proof_of_work). Pozwala to węzłom sieci Ethereum na uzgodnienie stanu wszystkich informacji zapisanych w blockchainie Ethereum i zapobiega niektórym rodzajom ataków ekonomicznych. +Sieć Ethereum na początku używała mechanizmu konsensusu zwanego **[Proof-of-work (PoW)](/developers/docs/consensus-mechanisms/pow)**. To pozwalało węzłom sieci Ethereum na uzgadnianie stanu wszystkich informacji zarejestrowanych na łańcuchu bloków Ethereum i zapobiegało niektórym rodzajom ataków ekonomicznych. Jednakże w 2022 roku Ethereum wyłączyło mechanizm proof-of-work i zamiast niego zaczęło używać [proof-of-stake](/developers/docs/consensus-mechanisms/pos). -## Warunki wstępne {#prerequisites} + + + + + proof-of-work odtąd został wycofany. Ethereum nie używa już proof-of-work jako części swojego mechanizmu konsensusu. Zamiast tego, używa proof-of-stake. Przeczytaj więcej o [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) i [stakingu](/staking/). + + + -Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznać się z [transakcjami](/developers/docs/transactions/) i [blokami](/developers/docs/blocks/). +## Wymagania wstępne {#prerequisites} -## Czym jest proof-of-work (PoW)? {#what-is-pow} +Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznanie się z [transakcjami](/developers/docs/transactions/), [blokami](/developers/docs/blocks/) i [mechanizmami konsensusu](/developers/docs/consensus-mechanisms/). -Proof-of-work (PoW) jest mechanizmem pozwalającym zdecentralizowanej sieci Ethereum na osiągnięcie konsensusu, lub akceptuje takie rzeczy jak salda konta i kolejność transakcji. Zapobiega to „podwójnemu wydawaniu” swoich monet przez użytkowników i zapewnia, że ​​łańcuch Ethereum jest niezwykle trudny do zaatakowania lub nadpisania. +## Czym jest Proof-of-work (PoW)? {#what-is-pow} + +Konsensus Nakamoto, który wykorzystuje proof-of-work, to mechanizm, który kiedyś pozwalał zdecentralizowanej sieci Ethereum osiągnąć konsensus (tzn. wszystkie węzły dochodzą do porozumienia) w takich kwestiach, jak salda kont i kolejność transakcji. To uniemożliwiało użytkownikom 'podwójne wydawanie' ich monet i gwarantowało, że łańcuch Ethereum był niezwykle trudny do atakowania i manipulowania. Te właściwości bezpieczeństwa pochodzą teraz z mechanizmu proof-of-stake, wykorzystując mechanizm konsensusu znany jako [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/). ## Proof-of-work i wydobycie {#pow-and-mining} -Proof-of-work to podstawowy algorytm, który określa poziom trudności i zasady wykonywania pracy przez górników. Wydobycie to sama „praca”. Jest to akt dodawania prawidłowych bloków do łańcucha. Jest to ważne, ponieważ długość łańcucha pomaga sieci wykryć prawidłowy łańcuch Ethereum i zrozumieć aktualny stan Ethereum. Im więcej „pracy” zostanie wykonane, im dłuższy łańcuch i im wyższy numer bloku, tym większa pewność co do aktualnego stanu rzeczy w sieci. +proof-of-work jest głównym algorytmem, który ustala trudność oraz zasady pracy wykonywanej przez górników na blockchainie typu proof-of-work. Wydobycie to sama „praca”. Jest to akt dodawania prawidłowych bloków do łańcucha. Jest to ważne, ponieważ długość łańcucha pomaga sieci podążać za prawidłowym rozgałęzieniem blockchainu. Im więcej „pracy” zostanie wykonane, im dłuższy łańcuch i im wyższy numer bloku, tym większa pewność co do aktualnego stanu rzeczy w sieci. [Więcej o wydobyciu](/developers/docs/consensus-mechanisms/pow/mining/) -## Jak działa proof-of-work Ethereum? {#how-it-works} +## Jak działał mechanizm proof-of-work w Ethereum? {#how-it-works} -Transakcje Ethereum są przetwarzane w blokach. Każdy blok zawiera: +Transakcje Ethereum są przetwarzane w blokach. W wycofanym już mechanizmie proof-of-work w Ethereum każdy blok zawierał: - trudności bloku – na przykład: 3,324,092,183,262,715 - mixHash – na przykład: `0x44bca881b07a6a09f83b130798072441705d9a665c5ac8bdf2f39a3cdf3bee29` - nonce – na przykład: `0xd3ee432b4fb3d26b` -Te dane bloku są bezpośrednio związane z PoW. +Te dane bloku były bezpośrednio związane z mechanizmem proof-of-work. ### Praca na potrzeby proof-of-work {#the-work} -Protokół proof-of-work, znany jako Ethash, wymaga od górników intensywnego wyścigu prób i błędów, aby znaleźć blok nonce. Do łańcucha można dodać tylko bloki z poprawnym nonce. +Protokół proof-of-work, Ethash, wymagał od górników, aby przeszli przez intensywny wyścig prób i błędów w celu znalezienia wartości nonce dla bloku. Tylko bloki z prawidłowym nonce mogły być dodane do łańcucha. -Podczas wyścigu o utworzenie bloku, górnik wielokrotnie umieszcza zbiór danych, który można uzyskać tylko po pobraniu i uruchomieniu pełnego łańcucha (tak jak robi to górnik), za pomocą funkcji matematycznej. Ma to na celu wygenerowanie mixHash, który jest poniżej docelowego nonce, zgodnie z trudnością bloku. Najlepszym sposobem na to jest metoda prób i błędów. +Podczas wyścigu o utworzenie bloku górnik wielokrotnie przepuszczał przez funkcję matematyczną zbiór danych, który można było uzyskać jedynie poprzez pobranie i uruchomienie pełnego łańcucha (tak jak robi to górnik). Ten zbiór danych służył do wygenerowania wartości mixHash poniżej celu, który jest podyktowany trudnością bloku. Najlepszym sposobem na to jest metoda prób i błędów. -Trudność określa cel hashu. Im niższy cel, tym mniejszy zestaw prawidłowych hashów. Po wygenerowaniu jest to niezwykle łatwe do zweryfikowania przez innych górników i klientów. Nawet jeśli jedna transakcja miałaby się zmienić, hash byłby zupełnie inny, sygnalizując oszustwo. +Trudność określała cel dla haszu. Im niższy cel, tym mniejszy zestaw prawidłowych hashów. Po wygenerowaniu, było to niezwykle łatwe do zweryfikowania przez innych górników i klientów. Nawet gdyby jedna transakcja uległa zmianie, hasz byłby zupełnie inny, co sygnalizowałoby oszustwo. -Haszowanie ułatwia wykrycie oszustwa. Ale PoW jako proces jest również dużym środkiem odstraszającym do atakowania łańcucha. +Haszowanie ułatwia wykrycie oszustwa. Ale proces proof-of-work był również istotnym czynnikiem zniechęcającym do atakowania łańcucha. ### Proof-of-work i bezpieczeństwo {#security} -Górnicy są zachęcani do wykonywania tych prac w głównym łańcuchu Ethereum. W niewielkim stopniu zachęca się podzbiór górników do uruchomienia własnego łańcucha – podważa to system. Blockchainy opierają się na jednym stanie jako źródle prawdy. Użytkownicy zawsze wybierają najdłuższy lub „najcięższy” łańcuch. +Górnicy mieli motywację, aby wykonywać tę pracę w głównym łańcuchu Ethereum. Niewielka była motywacja, aby podzbiór górników zakładał własny łańcuch — podważa to cały system. Blockchainy opierają się na jednym stanie jako źródle prawdy. -Celem programu PoW jest rozszerzenie łańcucha. Najdłuższy łańcuch jest najbardziej wiarygodny jako prawidłowy, ponieważ wykonano na nim najwięcej pracy obliczeniowej. W systemie PoW Ethereum prawie niemożliwe jest tworzenie nowych bloków, które usuwają transakcje lub tworzą fałszywe transakcje, lub utrzymują drugi łańcuch. Dzieje się tak, ponieważ złośliwy górnik musiałby zawsze rozwiązywać blok n-razy szybciej niż wszyscy inni. +Celem proof-of-work było przedłużenie łańcucha. Najdłuższy łańcuch był najbardziej wiarygodny pod względem poprawności, ponieważ wymagał najwięcej mocy obliczeniowej do wygenerowania. W systemie Ethereum proof-of-work niemal niemożliwe było stworzenie nowego bloku, który wymazywał transakcje, tworzył fałszywe transakcje lub utrzymywał drugi łańcuch. Wynikało to z tego, że złośliwy górnik musiałby zawsze rozwiązać nonce bloku szybciej niż wszyscy inni. -Aby konsekwentnie tworzyć złośliwe, ale ważne bloki, potrzebujesz ponad 51% mocy wydobycia sieci, aby pokonać wszystkich innych. Potrzebujesz dużo mocy obliczeniowej, aby móc wykonać tę ilość „pracy”. A wydatkowanie energii może nawet przewyższyć zyski, jakie możesz osiągnąć w ataku. +Aby konsekwentnie tworzyć złośliwe, ale poprawne bloki, złośliwy górnik musiałby posiadać ponad 51% całej mocy wydobywczej sieci, aby pokonać wszystkich innych. Taka ilość "pracy" wymaga tak wielkiej ilości drogiej mocy obliczeniowej i zużytej energii, że może to przeważyć zyski z wykonanego ataku. ### Ekonomia proof-of-work {#economics} -PoW jest również odpowiedzialny za emisję nowej waluty do systemu i zachęcanie górników do wykonywania pracy. +proof-of-work było również odpowiedzialne za emisję nowej waluty do systemu i zachęcenie górników do wykonania pracy. -Górnicy, którzy pomyślnie utworzyli blok, są nagrodzeni w 2 świeżo wybitnych ETH i wszystkie opłaty transakcyjne w ramach bloku. Górnik może również otrzymać 1,75 Eth na blok wuja. To poprawny blok, utworzony jednocześnie z udanym blokiem, przez innego górnika. Zwykle dzieje się to z powodu opóźnień w sieci. +Od czasu [aktualizacji Constantinople](/ethereum-forks/#constantinople) górnicy, którzy pomyślnie utworzyli blok, byli nagradzani dwoma nowo wybitymi ETH i częścią opłat transakcyjnych. Bloki ommer również otrzymywały 1,75 ETH. Bloki ommer były poprawnymi blokami stworzonymi przez górnika praktycznie w tym samym czasie, gdy inny górnik tworzył blok kanoniczny, co ostatecznie było rozsądzane na podstawie informacji, który łańcuch został zbudowany jako pierwszy. Bloki ommer zdarzały się głównie przez opóźnienie sieci. ## Nieodwołalność {#finality} -W sieciach rozproszonych transakcja osiąga „nieodwołalność”, gdy staje się częścią bloku, który nie może się zmienić. +Transakcja ma "nieodwołalność" na Ethereum, kiedy jest częścią bloku, którego nie można zmienić. -Ponieważ górnicy działają w sposób zdecentralizowany, możliwe jest wydobycie dwóch ważnych bloków jednocześnie. Tworzy to tymczasowy fork. Ostatecznie jeden łańcuch stanie się akceptowanym łańcuchem, gdy kolejny blok zostanie wydobyty i dodany, co sprawi, że będzie dłuższy. +Ponieważ górnicy pracowali w zdecentralizowany sposób, dwa poprawne bloki mogły być wykopane w tym samym czasie. Tworzy to tymczasowy fork. Ostatecznie jeden z tych łańcuchów stawał się akceptowanym łańcuchem po wydobyciu i dołączeniu kolejnego bloku, który powodował jego wydłużenie. -Ale aby jeszcze bardziej skomplikować sprawy, transakcje, które zostały odrzucone na tymczasowym forku, mogły być zawarte w zaakceptowanym łańcuchu. Oznacza to, że może on zostać odwrócony. Zatem nieodwołalność odnosi się do czasu, w którym należy poczekać przed uznaniem transakcji za nieodwracalną. Dla Ethereum zalecany czas to 6 bloków lub nieco ponad 1 minuta. Następnie można z względną pewnością powiedzieć, że transakcja zakończyła się sukcesem. Oczywiście można dłużej czekać na jeszcze większą pewność. +Aby skomplikować jeszcze nieco tę kwestię, transakcje odrzucone na tymczasowym rozgałęzieniu nie mogły zostać zawarte w zaakceptowanym łańcuchu. Oznacza to, że może on zostać odwrócony. Zatem nieodwołalność odnosi się do czasu, w którym należy poczekać przed uznaniem transakcji za nieodwracalną. W poprzedniej wersji Ethereum opartej na proof-of-work, im więcej bloków zostało wykopanych na konkretnym bloku `N`, tym większa była pewność, że transakcje w `N` powiodły się i nie zostaną cofnięte. Teraz, w modelu proof-of-stake, finalizacja jest jawną, a nie probabilistyczną właściwością danego bloku. -Należy o tym pamiętać podczas projektowania zdecentralizowanych aplikacji, ponieważ błędne przedstawianie informacji o transakcjach użytkownikom byłoby kiepskim doświadczeniem. Zwłaszcza jeśli transakcja ma wysoką wartość. +## Zużycie energii przez proof-of-work {#energy} -Pamiętaj, że ten czas nie zawiera czasu oczekiwania na odebranie transakcji przez górnika. +Istotnym punktem krytyki modelu proof-of-work jest ilość energii zużywanej do zabezpieczenia sieci. Aby utrzymać bezpieczeństwo i decentralizację, Ethereum w modelu proof-of-work wykorzystywało duże zasoby energii. Krótko przed przejściem na proof-of-stake górnicy Ethereum zużywali łącznie około 70 TWh/rok (mniej więcej tyle samo co Czechy – według [digiconomist](https://digiconomist.net/) z 18 lipca 2022 r.). -## Wady i zalety {#pros-and-cons} +## Zalety i wady {#pros-and-cons} -| Zalety | Wady | -| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| PoW jest neutralny. Nie potrzebujesz ETH, aby rozpocząć, a nagrody blokowe pozwalają przejść od 0ETH do salda dodatniego. W przypadku [proof of stake](/developers/docs/consensus-mechanisms/pos/) potrzebujesz ETH na początek. | PoW zużywa tak dużo energii, że jest to szkodliwe dla środowiska. | -| PoW to wypróbowany i przetestowany mechanizm konsensusu, dzięki któremu Bitcoin i Ethereum były bezpieczne i zdecentralizowane od wielu lat. | Jeśli chcesz kopać, potrzebujesz tak specjalistycznego sprzętu, że to duża inwestycja na początek. | -| W porównaniu z proof-of-stake jest to stosunkowo łatwe w realizacji. | Ze względu na coraz większe zapotrzebowanie obliczeniowe, pule wydobywcze mogą potencjalnie zdominować grę wydobywczą, co prowadzi do centralizacji i zagrożeń dla bezpieczeństwa. | +| Zalety | Wady | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Model proof-of-work jest neutralny. Nie potrzebujesz ETH, aby rozpocząć, a nagrody blokowe pozwalają przejść od 0ETH do salda dodatniego. W przypadku [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) na początek potrzebujesz ETH. | Model proof-of-work zużywa tyle energii, że jest szkodliwy dla środowiska. | +| Model proof-of-work jest przetestowanym mechanizmem konsensusu, który zapewniał bezpieczeństwo i decentralizację sieciom Bitcoin, jak i Ethereum przez wiele lat. | Jeśli chcesz kopać, potrzebujesz tak specjalistycznego sprzętu, że na początek jest to duża inwestycja. | +| W porównaniu z proof-of-stake jest to stosunkowo łatwe w realizacji. | Ze względu na coraz większe zapotrzebowanie obliczeniowe, pule wydobywcze mogą potencjalnie zdominować grę wydobywczą, co prowadzi do centralizacji i zagrożeń dla bezpieczeństwa. | -## W porównaniu z proof of stake {#compared-to-pos} +## W porównaniu z proof-of-stake {#compared-to-pos} -Na wysokim poziomie proof of stake ma ten sam cel co proof of work: pomoc w osiągnięciu konsensusu przez zdecentralizowaną sieć w bezpieczny sposób. Ma jednak pewne różnice w procesie i pracownikach: +Na wysokim poziomie, model proof-of-stake ma taki sam cel co proof-of-work: pomóc zdecentralizowanej sieci osiągnąć konsensus w bezpieczny sposób. Ma jednak pewne różnice w procesie i pracownikach: -- PoS zmienia znaczenie mocy obliczeniowej dla ETH -- PoS zastępuje górników walidatorami. Walidatorzy stawiają ETH w celu aktywacji możliwości tworzenia nowych bloków. +- Model proof-of-stake zamienia moc obliczeniową na zestakowane ETH. +- Model proof-of-stake zamienia górników na walidatorów. Walidatorzy stawiają ETH w celu aktywacji możliwości tworzenia nowych bloków. - Walidatorzy nie konkurują o tworzenie bloków, zamiast tego są wybierani losowo przez algorytm. - Nieodwołalność jest jaśniejsza: w niektórych punktach kontrolnych, jeżeli 2/3 zatwierdzających zgadza się co do stanu bloku, jest on uważany za ostateczny. Walidatorzy muszą postawić na to całą swoją stawkę, więc jeśli spróbują się zmówić, stracą ją. [Więcej o proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +## Jesteś raczej wzrokowcem? Dla wzrokowców {#visual-learner} + + + ## Dalsza lektura {#further-reading} - [Atak większościowy](https://en.bitcoin.it/wiki/Majority_attack) -- [O nieodwołalności rozliczenia](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) +- [O nieodwołalności rozliczeń](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) + +### Filmy {#videos} + +- [Techniczne wyjaśnienie protokołów proof-of-work](https://youtu.be/9V1bipPkCTU) -## Tematy powiązane {#related-topics} +## Powiązane tematy {#related-topics} - [Wydobywanie](/developers/docs/consensus-mechanisms/pow/mining/) -- [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/index.md index 51abd48b82c..93605f1cd19 100644 --- a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/index.md +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/index.md @@ -1,56 +1,86 @@ --- -title: Wydobywanie -description: Wyjaśnienie jak działa wydobycie w Ethereum i jak pomaga utrzymać Ethereum bezpieczne i zdecentralizowane. +title: Wydobycie +description: "Wyjaśnienie jak kopanie działało na Ethereum." lang: pl -incomplete: true --- + + + + +proof-of-work nie jest już podstawowym mechanizmem konsensusu Ethereum, co oznacza, że kopanie zostało wyłączone. Zamiast tego, sieć Ethereum jest zabezpieczona przez walidatorów, którzy stakują ETH. Możesz zacząć stakować swoje ETH już dziś. Przeczytaj więcej na The Merge, proof-of-stake, oraz staking. Ta strona ma charakter wyłącznie historyczny. + + + + ## Wymagania wstępne {#prerequisites} -Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznanie się z [transakcjami](/developers/docs/transactions/), [blokami](/developers/docs/blocks/) i [proof-of-work](/developers/docs/consensus-mechanisms/pow/). +Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznać się z [transakcjami](/developers/docs/transactions/), [blokami](/developers/docs/blocks/) i [mechanizmem proof-of-work](/developers/docs/consensus-mechanisms/pow/). ## Czym jest wydobycie w Ethereum? {#what-is-ethereum-mining} -Wydobycie to proces tworzenia bloku złożonego z transakcji, aby dodać go do blockchaina Ethereum. +Kopanie to proces tworzenia bloków transakcji, które mają być dodane do łańcucha bloków Ethereum w obecnie przestarzałej architekturze proof-of-work. + +Słowo kopanie pochodzi z kontekstu analogii złota i kryptowalut. Złoto czy metale szlachetne są ograniczone tak samo, jak cyfrowe tokeny a jedynym sposobem na zwiększenie łącznej objętości w systemie proof-of-work jest kopanie. W modelu Ethereum proof-of-stake jedynym sposobem na zwiększenie podaży było kopanie. Jednak w przeciwieństwie do metali szlachetnych czy złota, kopanie Ethereum było również sposobem na zabezpieczenie sieci przez tworzenie, weryfikację, publikowanie i propagowanie bloków w łańcuchu bloków. + +Kopanie eteru = zabezpieczanie sieci -Ethereum, tak jak Bitcoin, obecnie korzysta z mechanizmu konsensusu [proof-of-work (PoW)](/developers/docs/consensus-mechanisms/pow/). Górnictwo jest siłą napędową proof-of-work. Górnicy Ethereum - komputery obsługujące oprogramowanie - wykorzystują czas i moc obliczeniową do przetwarzania transakcji i produkcji bloków. +Kopanie jest podstawą każdego łańcucha bloków opartego na proof-of-work. Górnicy Ethereum — komputery z uruchomionym oprogramowaniem — używali swojego czasu i mocy obliczeniowej do przetwarzania transakcji i produkowania bloków przed przejściem na proof-of-stake. ## Dlaczego górnicy istnieją? {#why-do-miners-exist} -W zdecentralizowanych systemach, takich jak Ethereum, musimy dopilnować, aby wszyscy zgodzili się na kolejność transakcji. Górnicy pomagają w tym poprzez rozwiązywanie trudnych obliczeniowo łamigłówek w celu produkcji bloków, które służą jako sposób zabezpieczenia sieci przed atakami. +W zdecentralizowanych systemach, takich jak Ethereum, musimy dopilnować, aby wszyscy zgodzili się na kolejność transakcji. Górnicy pomagali w tym poprzez rozwiązywanie wymagających obliczeniowo zagadek, aby wyprodukować bloki, zabezpieczyć sieć przed atakami. + +[Więcej o mechanizmie proof-of-work](/developers/docs/consensus-mechanisms/pow/) + +Każdy mógł wcześniej kopać na sieci Ethereum używające swojego komputera. Jednakże nie każdy mógł kopać eter (ETH) zyskownie. W większości przypadków górnicy musieli kupować dedykowany sprzęt komputerowy i mieć dostęp do niedrogich źródeł energii. Przeciętny komputer miał niewielkie szanse, aby zdobyć wystarczająco dużo nagród blokowych, żeby pokryć koszty związane z kopaniem. + +### Koszt wydobycia {#cost-of-mining} -[Więcej o proof of work](/developers/docs/consensus-mechanisms/pow/) +- Potencjalne koszty sprzętu niezbędnego do budowy i utrzymania statku górniczego +- Koszt elektryczny zasilania statku górniczego +- Kiedy kopałeś za pośrednictwem poola, pobierał on zwykle określoną stałą opłatę procentową od każdego bloku wygenerowanego przez pool +- Środki te przeznaczone są na pokrycie wydatków na personel i wydatków administracyjnych Agencji (tytuły 1 i 2) oraz jej wydatków operacyjnych związanych z programem prac (tytuł 3). -## Jak są wydobywane transakcje Ethereum {#how-ethereum-transactions-are-mined} +Aby dalej badać rentowność wydobycia, użyj kalkulatora wydobycia, takiego jak ten dostarczany przez [Etherscan](https://etherscan.io/ether-mining-calculator). -1. Użytkownik pisze i podpisuje żądanie [transakcji](/developers/docs/transactions/) kluczem prywatnym niektórych [ kont](/developers/docs/accounts/). -2. Użytkownik wysyła żądanie transakcji do całej sieci Ethereum z jakiegoś [węzła](/developers/docs/nodes-and-clients/). +## Jak wydobywano transakcje Ethereum {#how-ethereum-transactions-were-mined} + +Treść poniżej daje ogląd na to, w jaki sposób transakcje były kopane w Ethereum proof-of-work. Analogiczny opis tego procesu dla mechanizmu proof-of-stake w Ethereum można znaleźć [tutaj](/developers/docs/consensus-mechanisms/pos/#transaction-execution-ethereum-pos). + +1. Użytkownik tworzy i podpisuje żądanie [transakcji](/developers/docs/transactions/) kluczem prywatnym jakiegoś [konta](/developers/docs/accounts/). +2. Użytkownik rozgłasza żądanie transakcji do całej sieci Ethereum z jakiegoś [węzła](/developers/docs/nodes-and-clients/). 3. Po usłyszeniu o nowym żądaniu transakcji, każdy węzeł w sieci Ethereum dodaje żądanie do swojej lokalnej pamięci, listy wszystkich żądań transakcji, o których słyszał, a które nie zostały jeszcze zatwierdzone do blockchaina w bloku. -4. W pewnym momencie węzeł górniczy agreguje kilkadziesiąt lub kilkaset żądań transakcji w potencjalny [blok](/developers/docs/blocks/), w sposób maksymalizujący zarabiane [opłaty transakcyjne](/developers/docs/gas/), ale nie przekraczając limitu gazu blokowego. Następnie węzeł wydobywczy: - 1. Weryfikuje ważność każdego żądania transakcji (tj. nikt nie próbuje przenieść eteru z konta, dla którego nie złożył podpisu, żądanie nie jest zniekształcone itp.), a następnie wykonuje kod żądania, zmieniając stan ich lokalnej kopii EVM. Górnik otrzymuje opłatę transakcyjną za każde takie żądanie transakcji na własny rachunek. - 2. Rozpoczyna proces tworzenia „certyfikatu legalności” proof-of-work dla potencjalnego bloku, gdy wszystkie żądania transakcji w bloku zostaną zweryfikowane i wykonane na lokalnej kopii EVM. +4. W pewnym momencie węzeł wydobywczy agreguje kilkadziesiąt lub kilkaset żądań transakcji w potencjalny [blok](/developers/docs/blocks/) w sposób, który maksymalizuje zarabiane przez niego [opłaty transakcyjne](/developers/docs/gas/), jednocześnie nie przekraczając limitu gazu bloku. Następnie węzeł wydobywczy: + 1. Weryfikuje ważność każdego żądania transakcji (tzn. nikt nie próbuje przelać etheru z konta, dla którego nie ma podpisu, żądanie nie jest nieprawidłowe itp.), a następnie wykonuje kod żądania, zmieniając stan swojej lokalnej kopii EVM. Górnik otrzymuje opłatę transakcyjną za każde takie żądanie transakcji na własny rachunek. + 2. Rozpoczyna proces tworzenia "certyfikatu legalności" proof-of-work dla potencjalnego bloku po zweryfikowaniu i wykonaniu wszystkich żądań transakcji w bloku na lokalnej kopii EVM. 5. W końcu górnik zakończy produkcję certyfikatu dla bloku, który zawiera nasze konkretne żądanie transakcji. Górnik następnie emituje wypełniony blok, który zawiera certyfikat i sumę kontrolną żądanego nowego stanu EVM. 6. Inne węzły słyszą o nowym bloku. Weryfikują certyfikat, samodzielnie wykonują wszystkie transakcje na bloku (w tym transakcję oryginalnie wyemitowaną przez naszego użytkownika) i sprawdzają, czy suma kontrolna ich nowego stanu EVM po wykonaniu wszystkich transakcji jest zgodna z sumą kontrolną stanu zgłaszanego przez blok górnika. Dopiero wtedy węzły dołączają ten blok do ogona swojego blokchaina i akceptują nowy stan EVM jako stan kanoniczny. 7. Każdy węzeł usuwa wszystkie transakcje w nowym bloku z lokalnej pamięci niespełnionych żądań transakcji. 8. Nowe węzły dołączające do sieci pobierają kolejno wszystkie bloki, w tym blok zawierający naszą interesującą transakcję. Inicjują lokalną kopię EVM (która zaczyna się jako EVM w stanie pustym), a następnie przechodzą przez proces wykonywania każdej transakcji w każdym bloku na wierzchu ich lokalnej kopii EVM, weryfikując po drodze sumy kontrolne stanu w każdym bloku. -Każda transakcja jest wydobywana (zawarta w nowym bloku i po raz pierwszy propagowana) jednorazowo, ale wykonywana i weryfikowana przez każdego uczestnika procesu przechodzenia do stanu kanonicznego EVM. Podkreśla to jedną z głównych mantr blockchain: **Nie ufaj, weryfikuj**. +Każda transakcja jest wydobywana (zawarta w nowym bloku i po raz pierwszy propagowana) jednorazowo, ale wykonywana i weryfikowana przez każdego uczestnika procesu przechodzenia do stanu kanonicznego EVM. To podkreśla jedną z głównych mantr blockchain: **Nie ufaj, weryfikuj**. + +## Bloki Ommer (wujkowe) {#ommer-blocks} + +Kopanie bloków w proof-of-work było probabilistyczne w takim sensie, że czasem dwa ważne bloki opublikowane były w tym samym czasie w wyniku opóźnienia sieci. W tym przypadku protokół musiał określić najdłuższy (i tym samym najbardziej "ważny") łańcuch, jednocześnie zapewniając sprawiedliwość wobec górników poprzez częściowe obdarowanie zaproponowanego ważnego bloku, który ostatecznie nie został zamieszczony. Zachęcało to do dalszej decentralizacji sieci, ponieważ mniejsi górnicy, którzy mogli doświadczać większych opóźnień, wciąż mogli generować zyski poprzez nagrody za bloki [ommer](/glossary/#ommer). + +Termin „ommer” jest preferowanym pojęciem neutralnym pod względem płci dla rodzeństwa bloku macierzystego, ale czasami używa się także nazwy „wujek”. **Odkąd Ethereum przeszło na mechanizm proof-of-stake, bloki ommer nie są już wydobywane**, ponieważ w każdym slocie wybierany jest tylko jeden proponujący. Możesz zobaczyć tę zmianę, przeglądając [historyczny wykres](https://ycharts.com/indicators/ethereum_uncle_rate) wydobytych bloków ommer. -## Demo wizualne {#a-visual-demo} +## Demonstracja wizualna {#a-visual-demo} Zobacz, jak Austin poprowadzi Cię przez wydobycie i blockchain typu „proof-of-work”. -## Dalsza lektura {#further-reading} +## Algorytm wydobywczy {#mining-algorithm} -## Powiązane narzędzia {#related-tools} +Sieć główna Ethereum używała zawsze tylko jednego algorytmu wydobywczego – ['Ethash'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/). Ethash był następcą oryginalnego algorytmu R&D znanego jako ['Dagger-Hashimoto'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/). -- [Najlepsi górnicy Ethereum](https://etherscan.io/stat/miner?range=7&blocktype=blocks) -- [Kalkulator wydobycia Ethereum](https://minerstat.com/coin/ETH) +[Więcej o algorytmach wydobywczych](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/). -## Tematy powiązane {#related-topics} +## Powiązane tematy {#related-topics} -- [Paliwo](/developers/docs/gas/) -- [Maszyna Wirtualna Ethereum (EVM)](/developers/docs/evm/) +- [Gaz](/developers/docs/gas/) +- [EVM](/developers/docs/evm/) - [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md new file mode 100644 index 00000000000..e07f33ea1d5 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md @@ -0,0 +1,329 @@ +--- +title: Dagger-Hashimoto +description: "Szczegółowe omówienie algorytmu Dagger-Hashimoto." +lang: pl +--- + +Dagger-Hashimoto był oryginalną implementacją badawczą i specyfikacją algorytmu wydobywczego Ethereum. Dagger-Hashimoto został zastąpiony przez [Ethash](#ethash). Wydobycie zostało całkowicie wyłączone podczas [Połączenia](/roadmap/merge/) 15 września 2022 r. Od tego czasu Ethereum jest zabezpieczane za pomocą mechanizmu [dowodu stawki](/developers/docs/consensus-mechanisms/pos). Ta strona ma charakter historyczny – zawarte tu informacje nie są już istotne dla Ethereum po Połączeniu. + +## Wymagania wstępne {#prerequisites} + +Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznanie się z [konsensusem dowodu pracy](/developers/docs/consensus-mechanisms/pow), [wydobyciem](/developers/docs/consensus-mechanisms/pow/mining) i [algorytmami wydobywczymi](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms). + +## Dagger-Hashimoto {#dagger-hashimoto} + +Dagger-Hashimoto ma na celu spełnienie dwóch założeń: + +1. **Odporność na ASIC**: korzyść z tworzenia specjalistycznego sprzętu dla algorytmu powinna być jak najmniejsza +2. **Weryfikowalność przez lekkiego klienta**: blok powinien być efektywnie weryfikowalny przez lekkiego klienta. + +Dzięki dodatkowej modyfikacji określamy również, w jaki sposób w razie potrzeby można osiągnąć trzeci cel, ale kosztem dodatkowej złożoności: + +**Przechowywanie pełnego łańcucha**: wydobycie powinno wymagać przechowywania pełnego stanu blockchain (ze względu na nieregularną strukturę trie stanu Ethereum przewidujemy, że możliwe będzie pewne przycinanie, szczególnie w przypadku niektórych często używanych kontraktów, ale chcemy to zminimalizować). + +## Generowanie DAG {#dag-generation} + +Kod algorytmu zostanie zdefiniowany poniżej w języku Python. Najpierw podajemy `encode_int` do porządkowania (marshaling) liczb całkowitych bez znaku o określonej precyzji do ciągów znaków. Podana jest również jego odwrotność: + +```python +NUM_BITS = 512 + +def encode_int(x): + "Zakoduj liczbę całkowitą x jako ciąg 64 znaków przy użyciu schematu big-endian" + o = '' + for _ in range(NUM_BITS / 8): + o = chr(x % 256) + o + x //= 256 + return o + +def decode_int(s): + "Odkoduj liczbę całkowitą x z ciągu znaków przy użyciu schematu big-endian" + x = 0 + for c in s: + x *= 256 + x += ord(c) + return x +``` + +Następnie zakładamy, że `sha3` jest funkcją, która przyjmuje i zwraca liczbę całkowitą, a `dbl_sha3` jest funkcją podwójnego sha3; jeśli konwertujesz ten kod referencyjny na implementację, użyj: + +```python +from pyethereum import utils +def sha3(x): + if isinstance(x, (int, long)): + x = encode_int(x) + return decode_int(utils.sha3(x)) + +def dbl_sha3(x): + if isinstance(x, (int, long)): + x = encode_int(x) + return decode_int(utils.sha3(utils.sha3(x))) +``` + +### Parametry {#parameters} + +Parametry używane w algorytmie to: + +```python +SAFE_PRIME_512 = 2**512 - 38117 # Największa bezpieczna liczba pierwsza mniejsza niż 2**512 + +params = { + "n": 4000055296 * 8 // NUM_BITS, # Rozmiar zbioru danych (4 gigabajty); MUSI BYĆ WIELOKROTNOŚCIĄ 65536 + "n_inc": 65536, # Przyrost wartości n na okres; MUSI BYĆ WIELOKROTNOŚCIĄ 65536 + # z epochtime=20000 daje 882 MB wzrostu rocznie + "cache_size": 2500, # Rozmiar pamięci podręcznej lekkiego klienta (może być wybrany przez lekkiego klienta; nie jest częścią specyfikacji algorytmu) + "diff": 2**14, # Trudność (dostosowywana podczas oceny bloku) + "epochtime": 100000, # Długość epoki w blokach (jak często aktualizowany jest zbiór danych) + "k": 1, # Liczba rodziców węzła + "w": w, # Używane do haszowania potęgowania modularnego + "accesses": 200, # Liczba dostępów do zbioru danych podczas hashimoto + "P": SAFE_PRIME_512 # Bezpieczna liczba pierwsza do haszowania i generowania liczb losowych +} +``` + +W tym przypadku `P` jest liczbą pierwszą wybraną w taki sposób, że `log₂(P)` jest tylko nieznacznie mniejsze od 512, co odpowiada 512 bitom, których używaliśmy do reprezentowania naszych liczb. Należy zauważyć, że w rzeczywistości przechowywana musi być tylko druga połowa DAG, więc de facto zapotrzebowanie na pamięć RAM zaczyna się od 1 GB i rośnie o 441 MB rocznie. + +### Budowanie grafu Dagger {#dagger-graph-building} + +Prymityw budowania grafu Dagger jest zdefiniowany w następujący sposób: + +```python +def produce_dag(params, seed, length): + P = params["P"] + picker = init = pow(sha3(seed), params["w"], P) + o = [init] + for i in range(1, length): + x = picker = (picker * init) % P + for _ in range(params["k"]): + x ^= o[x % i] + o.append(pow(x, params["w"], P)) + return o +``` + +Zasadniczo rozpoczyna on graf jako pojedynczy węzeł, `sha3(seed)`, a stamtąd zaczyna sekwencyjnie dodawać inne węzły w oparciu o losowe poprzednie węzły. Po utworzeniu nowego węzła obliczana jest modularna potęga seeda w celu losowego wyboru niektórych indeksów mniejszych niż `i` (przy użyciu `x % i` powyżej), a wartości węzłów w tych indeksach są używane w obliczeniach do wygenerowania nowej wartości `x`, która jest następnie wprowadzana do małej funkcji dowodu pracy (opartej na XOR) w celu ostatecznego wygenerowania wartości grafu o indeksie `i`. Uzasadnieniem tego konkretnego projektu jest wymuszenie sekwencyjnego dostępu do DAG; następna wartość DAG, do której będzie uzyskiwany dostęp, nie może zostać określona, dopóki bieżąca wartość nie jest znana. Na koniec potęgowanie modularne dalej haszuje wynik. + +Ten algorytm opiera się na kilku wynikach z teorii liczb. Zobacz dyskusję w poniższym dodatku. + +## Ocena lekkiego klienta {#light-client-evaluation} + +Powyższa konstrukcja grafu ma na celu umożliwienie rekonstrukcji każdego węzła w grafie poprzez obliczenie poddrzewa składającego się tylko z niewielkiej liczby węzłów i wymagającego tylko niewielkiej ilości pamięci pomocniczej. Należy pamiętać, że przy k=1 poddrzewo jest tylko łańcuchem wartości prowadzącym do pierwszego elementu w DAG. + +Funkcja obliczeniowa lekkiego klienta dla DAG działa w następujący sposób: + +```python +def quick_calc(params, seed, p): + w, P = params["w"], params["P"] + cache = {} + + def quick_calc_cached(p): + if p in cache: + pass + elif p == 0: + cache[p] = pow(sha3(seed), w, P) + else: + x = pow(sha3(seed), (p + 1) * w, P) + for _ in range(params["k"]): + x ^= quick_calc_cached(x % p) + cache[p] = pow(x, w, P) + return cache[p] + + return quick_calc_cached(p) +``` + +Zasadniczo jest to po prostu przepisanie powyższego algorytmu, który usuwa pętlę obliczania wartości dla całego DAG i zastępuje wcześniejsze wyszukiwanie węzłów wywołaniem rekurencyjnym lub wyszukiwaniem w pamięci podręcznej. Należy pamiętać, że dla `k=1` pamięć podręczna jest niepotrzebna, chociaż dalsza optymalizacja w rzeczywistości wstępnie oblicza kilka pierwszych tysięcy wartości DAG i zachowuje je jako statyczną pamięć podręczną do obliczeń; zobacz dodatek, aby zobaczyć implementację kodu. + +## Podwójny bufor DAG {#double-buffer} + +W pełnym kliencie używany jest [_podwójny bufor_](https://wikipedia.org/wiki/Multiple_buffering) 2 DAG-ów wyprodukowanych według powyższego wzoru. Chodzi o to, że DAG są produkowane co `epochtime` bloków zgodnie z powyższymi parametrami. Zamiast używać najnowszego wyprodukowanego DAG-a, klient używa poprzedniego. Zaletą tego rozwiązania jest to, że pozwala na wymianę DAG-ów w czasie bez konieczności wprowadzania kroku, w którym górnicy muszą nagle ponownie obliczyć wszystkie dane. W przeciwnym razie istnieje ryzyko nagłego, tymczasowego spowolnienia przetwarzania łańcucha w regularnych odstępach czasu i radykalnego zwiększenia centralizacji. Stąd ryzyko ataku 51% w ciągu tych kilku minut przed ponownym obliczeniem wszystkich danych. + +Algorytm używany do generowania zestawu DAG-ów wykorzystywanych do obliczenia pracy dla bloku jest następujący: + +```python +def get_prevhash(n): + from pyethereum.blocks import GENESIS_PREVHASH + from pyethereum import chain_manager + if n <= 0: + return hash_to_int(GENESIS_PREVHASH) + else: + prevhash = chain_manager.index.get_block_by_number(n - 1) + return decode_int(prevhash) + +def get_seedset(params, block): + seedset = {} + seedset["back_number"] = block.number - (block.number % params["epochtime"]) + seedset["back_hash"] = get_prevhash(seedset["back_number"]) + seedset["front_number"] = max(seedset["back_number"] - params["epochtime"], 0) + seedset["front_hash"] = get_prevhash(seedset["front_number"]) + return seedset + +def get_dagsize(params, block): + return params["n"] + (block.number // params["epochtime"]) * params["n_inc"] + +def get_daggerset(params, block): + dagsz = get_dagsize(params, block) + seedset = get_seedset(params, block) + if seedset["front_hash"] <= 0: + # Tylny bufor nie jest możliwy, utwórz tylko przedni bufor + return {"front": {"dag": produce_dag(params, seedset["front_hash"], dagsz), + "block_number": 0}} + else: + return {"front": {"dag": produce_dag(params, seedset["front_hash"], dagsz), + "block_number": seedset["front_number"]}, + "back": {"dag": produce_dag(params, seedset["back_hash"], dagsz), + "block_number": seedset["back_number"]}} +``` + +## Hashimoto {#hashimoto} + +Idea oryginalnego Hashimoto polega na wykorzystaniu blockchain jako zbioru danych, wykonaniu obliczeń, które wybierają N indeksów z blockchain, zebraniu transakcji z tych indeksów, wykonaniu operacji XOR na tych danych i zwróceniu haszu wyniku. Oryginalny algorytm Thaddeusa Dryji, przetłumaczony na język Python dla spójności, jest następujący: + +```python +def orig_hashimoto(prev_hash, merkle_root, list_of_transactions, nonce): + hash_output_A = sha256(prev_hash + merkle_root + nonce) + txid_mix = 0 + for i in range(64): + shifted_A = hash_output_A >> i + transaction = shifted_A % len(list_of_transactions) + txid_mix ^= list_of_transactions[transaction] << i + return txid_mix ^ (nonce << 192) +``` + +Niestety, chociaż Hashimoto jest uważany za trudny pod względem pamięci RAM, opiera się on na 256-bitowej arytmetyce, co wiąże się ze znacznym obciążeniem obliczeniowym. Jednakże Dagger-Hashimoto używa tylko najmniej znaczących 64 bitów podczas indeksowania swojego zbioru danych, aby rozwiązać ten problem. + +```python +def hashimoto(dag, dagsize, params, header, nonce): + m = dagsize / 2 + mix = sha3(encode_int(nonce) + header) + for _ in range(params["accesses"]): + mix ^= dag[m + (mix % 2**64) % m] + return dbl_sha3(mix) +``` + +Użycie podwójnego SHA3 pozwala na formę zerodanych, niemal natychmiastowej weryfikacji wstępnej, weryfikując jedynie, czy została podana poprawna wartość pośrednia. Ta zewnętrzna warstwa dowodu pracy jest bardzo przyjazna dla ASIC i dość słaba, ale istnieje, aby jeszcze bardziej utrudnić ataki DDoS, ponieważ ta niewielka ilość pracy musi zostać wykonana, aby wyprodukować blok, który nie zostanie natychmiast odrzucony. Oto wersja dla lekkiego klienta: + +```python +def quick_hashimoto(seed, dagsize, params, header, nonce): + m = dagsize // 2 + mix = sha3(nonce + header) + for _ in range(params["accesses"]): + mix ^= quick_calc(params, seed, m + (mix % 2**64) % m) + return dbl_sha3(mix) +``` + +## Wydobywanie i weryfikacja {#mining-and-verifying} + +Teraz połączmy to wszystko w algorytm wydobywczy: + +```python +def mine(daggerset, params, block): + from random import randint + nonce = randint(0, 2**64) + while 1: + result = hashimoto(daggerset, get_dagsize(params, block), + params, decode_int(block.prevhash), nonce) + if result * params["diff"] < 2**256: + break + nonce += 1 + if nonce >= 2**64: + nonce = 0 + return nonce +``` + +Oto algorytm weryfikacji: + +```python +def verify(daggerset, params, block, nonce): + result = hashimoto(daggerset, get_dagsize(params, block), + params, decode_int(block.prevhash), nonce) + return result * params["diff"] < 2**256 +``` + +Weryfikacja przyjazna dla lekkiego klienta: + +```python +def light_verify(params, header, nonce): + seedset = get_seedset(params, block) + result = quick_hashimoto(seedset["front_hash"], get_dagsize(params, block), + params, decode_int(block.prevhash), nonce) + return result * params["diff"] < 2**256 +``` + +Należy również zauważyć, że Dagger-Hashimoto nakłada dodatkowe wymagania na nagłówek bloku: + +- Aby weryfikacja dwuwarstwowa działała, nagłówek bloku musi zawierać zarówno nonce, jak i wartość środkową pre-sha3 +- Gdzieś nagłówek bloku musi przechowywać sha3 bieżącego zestawu seedów + +## Dalsza lektura {#further-reading} + +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ + +## Dodatek {#appendix} + +Jak wspomniano powyżej, RNG używany do generowania DAG opiera się na pewnych wynikach z teorii liczb. Po pierwsze, zapewniamy, że RNG Lehmera, który jest podstawą zmiennej `picker`, ma długi okres. Po drugie, pokazujemy, że `pow(x,3,P)` nie zmapuje `x` na `1` lub `P-1`, pod warunkiem, że na początku `x ∈ [2,P-2]`. Na koniec pokazujemy, że `pow(x,3,P)` ma niski wskaźnik kolizji, gdy jest traktowany jako funkcja haszująca. + +### Generator liczb losowych Lehmera {#lehmer-random-number} + +Chociaż funkcja `produce_dag` nie musi generować obiektywnych liczb losowych, potencjalnym zagrożeniem jest to, że `seed**i % P` przyjmuje tylko kilka wartości. Może to dać przewagę górnikom, którzy rozpoznają wzorzec, nad tymi, którzy go nie rozpoznają. + +Aby tego uniknąć, odwołano się do wyniku z teorii liczb. [_Bezpieczna liczba pierwsza_](https://en.wikipedia.org/wiki/Safe_prime) jest zdefiniowana jako liczba pierwsza `P` taka, że `(P-1)/2` jest również liczbą pierwszą. _Rząd_ elementu `x` [grupy multiplikatywnej](https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n) `ℤ/nℤ` jest zdefiniowany jako minimalne `m` takie, że
xᵐ mod P ≡ 1
+Biorąc pod uwagę te definicje, mamy: + +> Obserwacja 1. Niech `x` będzie członkiem grupy multiplikatywnej `ℤ/Pℤ` dla bezpiecznej liczby pierwszej `P`. Jeśli `x mod P ≠ 1 mod P` i `x mod P ≠ P-1 mod P`, to rząd `x` wynosi `P-1` lub `(P-1)/2`. + +_Dowód_. Ponieważ `P` jest bezpieczną liczbą pierwszą, to z [Twierdzenia Lagrange'a][lagrange] wynika, że rząd `x` wynosi `1`, `2`, `(P-1)/2` lub `P-1`. + +Rząd `x` nie może wynosić `1`, ponieważ z małego twierdzenia Fermata mamy: + +
xP-1 mod P ≡ 1
+ +Stąd `x` musi być tożsamością multiplikatywną `ℤ/nℤ`, która jest unikalna. Ponieważ z założenia `x ≠ 1`, nie jest to możliwe. + +Rząd `x` nie może wynosić `2`, chyba że `x = P-1`, ponieważ naruszałoby to pierwszość `P`. + +Z powyższego twierdzenia możemy wywnioskować, że iteracja `(picker * init) % P` będzie miała długość cyklu co najmniej `(P-1)/2`. Dzieje się tak, ponieważ wybraliśmy `P` jako bezpieczną liczbę pierwszą w przybliżeniu równą wyższej potędze dwójki, a `init` znajduje się w przedziale `[2,2**256+1]`. Biorąc pod uwagę wielkość `P`, nigdy nie powinniśmy spodziewać się cyklu z potęgowania modularnego. + +Podczas przypisywania pierwszej komórki w DAG (zmienna oznaczona `init`), obliczamy `pow(sha3(seed) + 2, 3, P)`. Na pierwszy rzut oka nie gwarantuje to, że wynik nie jest ani `1`, ani `P-1`. Jednakże, ponieważ `P-1` jest bezpieczną liczbą pierwszą, mamy następujące dodatkowe zapewnienie, które jest wnioskiem z Obserwacji 1: + +> Obserwacja 2. Niech `x` będzie członkiem grupy multiplikatywnej `ℤ/Pℤ` dla bezpiecznej liczby pierwszej `P` i niech `w` będzie liczbą naturalną. Jeśli `x mod P ≠ 1 mod P` i `x mod P ≠ P-1 mod P`, a także `w mod P ≠ P-1 mod P` i `w mod P ≠ 0 mod P`, to `xʷ mod P ≠ 1 mod P` i `xʷ mod P ≠ P-1 mod P` + +### Potęgowanie modularne jako funkcja haszująca {#modular-exponentiation} + +Dla pewnych wartości `P` i `w` funkcja `pow(x, w, P)` może mieć wiele kolizji. Na przykład `pow(x,9,19)` przyjmuje tylko wartości `{1,18}`. + +Biorąc pod uwagę, że `P` jest liczbą pierwszą, odpowiednie `w` dla funkcji haszującej potęgowania modularnego można wybrać, korzystając z następującego wyniku: + +> Obserwacja 3. Niech `P` będzie liczbą pierwszą; `w` i `P-1` są względnie pierwsze wtedy i tylko wtedy, gdy dla wszystkich `a` i `b` w `ℤ/Pℤ`:
`aʷ mod P ≡ bʷ mod P` wtedy i tylko wtedy, gdy `a mod P ≡ b mod P`
+ +Zatem, biorąc pod uwagę, że `P` jest liczbą pierwszą, a `w` jest względnie pierwsza z `P-1`, mamy, że `|{pow(x, w, P) : x ∈ ℤ}| = P`, co oznacza, że funkcja haszująca ma najniższy możliwy wskaźnik kolizji. + +W szczególnym przypadku, gdy `P` jest bezpieczną liczbą pierwszą, tak jak wybraliśmy, `P-1` ma tylko czynniki 1, 2, `(P-1)/2` i `P-1`. Ponieważ `P` > 7, wiemy, że 3 jest względnie pierwsza z `P-1`, stąd `w=3` spełnia powyższe twierdzenie. + +## Bardziej wydajny algorytm oceny oparty na pamięci podręcznej {#cache-based-evaluation} + +```python +def quick_calc(params, seed, p): + cache = produce_dag(params, seed, params["cache_size"]) + return quick_calc_cached(cache, params, p) + +def quick_calc_cached(cache, params, p): + P = params["P"] + if p < len(cache): + return cache[p] + else: + x = pow(cache[0], p + 1, P) + for _ in range(params["k"]): + x ^= quick_calc_cached(cache, params, x % p) + return pow(x, params["w"], P) + +def quick_hashimoto(seed, dagsize, params, header, nonce): + cache = produce_dag(params, seed, params["cache_size"]) + return quick_hashimoto_cached(cache, dagsize, params, header, nonce) + +def quick_hashimoto_cached(cache, dagsize, params, header, nonce): + m = dagsize // 2 + mask = 2**64 - 1 + mix = sha3(encode_int(nonce) + header) + for _ in range(params["accesses"]): + mix ^= quick_calc_cached(cache, params, m + (mix & mask) % m) + return dbl_sha3(mix) +``` diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md new file mode 100644 index 00000000000..fb9c9a0ca1c --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md @@ -0,0 +1,1022 @@ +--- +title: Ethash +description: "Szczegółowe spojrzenie na algorytm Ethash." +lang: pl +--- + + + + + + Ethash był algorytmem wydobywczym Ethereum opartym na dowodzie pracy. Mechanizm dowodu pracy został już **całkowicie wyłączony**, a zamiast niego sieć Ethereum jest teraz zabezpieczona przy użyciu [dowodu stawki](/developers/docs/consensus-mechanisms/pos/). Przeczytaj więcej o [Połączeniu](/roadmap/merge/), [dowodzie stawki](/developers/docs/consensus-mechanisms/pos/) i [stakingu](/staking/). Ta strona ma jedynie znaczenie historyczne! + + + + +Ethash to zmodyfikowana wersja algorytmu [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto). Dowód pracy Ethash jest [trudny pod względem pamięci](https://wikipedia.org/wiki/Memory-hard_function), co, jak sądzono, miało uczynić algorytm odpornym na układy ASIC. Ostatecznie opracowano układy ASIC dla Ethash, ale wydobycie za pomocą GPU było nadal realną opcją, dopóki dowód pracy nie został wyłączony. Ethash jest nadal używany do wydobywania innych monet w innych sieciach opartych na dowodzie pracy, które nie są sieciami Ethereum. + +## Jak działa Ethash? {#how-does-ethash-work} + +Trudność pod względem pamięci jest osiągana dzięki algorytmowi dowodu pracy, który wymaga wyboru podzbiorów stałego zasobu w zależności od wartości nonce i nagłówka bloku. Ten zasób (o rozmiarze kilku gigabajtów) nazywany jest DAG. DAG jest zmieniany co 30 000 bloków, co jest ~125-godzinnym oknem czasowym nazywanym epoką (około 5,2 dnia), a jego generowanie zajmuje trochę czasu. Ponieważ DAG zależy tylko od wysokości bloku, może on być wstępnie wygenerowany, ale jeśli nie jest, klient musi poczekać do końca tego procesu, aby wyprodukować blok. Jeśli klienci nie generują wstępnie i nie buforują DAG-ów z wyprzedzeniem, sieć może doświadczyć ogromnego opóźnienia bloku przy każdej zmianie epoki. Należy pamiętać, że DAG nie musi być generowany w celu weryfikacji dowodu pracy, co zasadniczo pozwala na weryfikację przy niskim użyciu procesora i małej ilości pamięci. + +Ogólny schemat działania algorytmu jest następujący: + +1. Istnieje **ziarno (seed)**, które można obliczyć dla każdego bloku, skanując nagłówki bloków aż do tego momentu. +2. Z ziarna można obliczyć **16 MB pseudolosowej pamięci podręcznej**. Lekcy klienci przechowują pamięć podręczną. +3. Z pamięci podręcznej możemy wygenerować **zbiór danych o wielkości 1 GB** z tą właściwością, że każdy element w zbiorze danych zależy tylko od niewielkiej liczby elementów z pamięci podręcznej. Pełni klienci i górnicy przechowują zbiór danych. Zbiór danych rośnie liniowo w czasie. +4. Wydobycie polega na pobieraniu losowych fragmentów zbioru danych i haszowaniu ich razem. Weryfikację można przeprowadzić przy niskim zużyciu pamięci, wykorzystując pamięć podręczną do regeneracji potrzebnych fragmentów zbioru danych, dzięki czemu wystarczy przechowywać tylko pamięć podręczną. + +Duży zbiór danych jest aktualizowany raz na 30 000 bloków, więc zdecydowana większość wysiłku górnika polegać będzie na odczytywaniu zbioru danych, a nie na wprowadzaniu do niego zmian. + +## Definicje {#definitions} + +Stosujemy następujące definicje: + +``` +WORD_BYTES = 4 # bajty w słowie +DATASET_BYTES_INIT = 2**30 # bajty w zbiorze danych w momencie genezy +DATASET_BYTES_GROWTH = 2**23 # wzrost zbioru danych na epokę +CACHE_BYTES_INIT = 2**24 # bajty w pamięci podręcznej w momencie genezy +CACHE_BYTES_GROWTH = 2**17 # wzrost pamięci podręcznej na epokę +CACHE_MULTIPLIER=1024 # Rozmiar DAG w stosunku do pamięci podręcznej +EPOCH_LENGTH = 30000 # bloki na epokę +MIX_BYTES = 128 # szerokość miksu +HASH_BYTES = 64 # długość haszu w bajtach +DATASET_PARENTS = 256 # liczba rodziców każdego elementu zbioru danych +CACHE_ROUNDS = 3 # liczba rund w produkcji pamięci podręcznej +ACCESSES = 64 # liczba dostępów w pętli hashimoto +``` + +### Użycie 'SHA3' {#sha3} + +Rozwój Ethereum zbiegł się w czasie z rozwojem standardu SHA3, a +proces standaryzacji wprowadził późną zmianę w dopełnianiu sfinalizowanego algorytmu haszującego, tak że hasze Ethereum +"sha3_256" i "sha3_512" nie są standardowymi haszami sha3, ale wariantem często określanym +jako "Keccak-256" i "Keccak-512" w innych kontekstach. Zobacz dyskusję, np. [tutaj](https://eips.ethereum.org/EIPS/eip-1803), [tutaj](http://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use) lub [tutaj](http://bitcoin.stackexchange.com/questions/42055/what-is-the-approach-to-calculate-an-ethereum-address-from-a-256-bit-private-key/42057#42057). + +Proszę o tym pamiętać, ponieważ hasze „sha3” są przywoływane w poniższym opisie algorytmu. + +## Parametry {#parameters} + +Parametry pamięci podręcznej i zbioru danych Ethash zależą od numeru bloku. Rozmiar pamięci podręcznej i rozmiar zbioru danych rosną liniowo; jednak zawsze bierzemy największą liczbę pierwszą poniżej liniowo rosnącego progu, aby zmniejszyć ryzyko przypadkowych regularności prowadzących do zachowań cyklicznych. + +```python +def get_cache_size(block_number): + sz = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number // EPOCH_LENGTH) + sz -= HASH_BYTES + while not isprime(sz / HASH_BYTES): + sz -= 2 * HASH_BYTES + return sz + +def get_full_size(block_number): + sz = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number // EPOCH_LENGTH) + sz -= MIX_BYTES + while not isprime(sz / MIX_BYTES): + sz -= 2 * MIX_BYTES + return sz +``` + +Tabele wartości rozmiaru zbioru danych i rozmiaru pamięci podręcznej znajdują się w załączniku. + +## Generowanie pamięci podręcznej {#cache-generation} + +Teraz określamy funkcję do tworzenia pamięci podręcznej: + +```python +def mkcache(cache_size, seed): + n = cache_size // HASH_BYTES + + # Sekwencyjnie twórz początkowy zbiór danych + o = [sha3_512(seed)] + for i in range(1, n): + o.append(sha3_512(o[-1])) + + # Użyj wersji randmemohash o niskiej liczbie rund + for _ in range(CACHE_ROUNDS): + for i in range(n): + v = o[i][0] % n + o[i] = sha3_512(map(xor, o[(i-1+n) % n], o[v])) + + return o +``` + +Proces tworzenia pamięci podręcznej obejmuje najpierw sekwencyjne wypełnienie 32 MB pamięci, a następnie wykonanie dwóch przejść algorytmu _RandMemoHash_ autorstwa Sergio Demiana Lernera z pracy [_Strict Memory Hard Hashing Functions_ (2014)](http://www.hashcash.org/papers/memohash.pdf). Wynikiem jest zbiór 524 288 64-bajtowych wartości. + +## Funkcja agregacji danych {#date-aggregation-function} + +W niektórych przypadkach używamy algorytmu inspirowanego [haszem FNV](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) jako niełącznego substytutu dla XOR. Należy zauważyć, że mnożymy liczbę pierwszą przez pełne 32-bitowe wejście, w przeciwieństwie do specyfikacji FNV-1, która z kolei mnoży liczbę pierwszą przez jeden bajt (oktet). + +```python +FNV_PRIME = 0x01000193 + +def fnv(v1, v2): + return ((v1 * FNV_PRIME) ^ v2) % 2**32 +``` + +Należy pamiętać, że chociaż Yellow Paper określa fnv jako v1\*(FNV_PRIME ^ v2), wszystkie obecne implementacje konsekwentnie używają powyższej definicji. + +## Obliczanie pełnego zbioru danych {#full-dataset-calculation} + +Każdy 64-bajtowy element w pełnym zbiorze danych o rozmiarze 1 GB jest obliczany w następujący sposób: + +```python +def calc_dataset_item(cache, i): + n = len(cache) + r = HASH_BYTES // WORD_BYTES + # zainicjuj miks + mix = copy.copy(cache[i % n]) + mix[0] ^= i + mix = sha3_512(mix) + # zastosuj fnv z wieloma losowymi węzłami pamięci podręcznej na podstawie i + for j in range(DATASET_PARENTS): + cache_index = fnv(i ^ j, mix[j % r]) + mix = map(fnv, mix, cache[cache_index % n]) + return sha3_512(mix) +``` + +Zasadniczo łączymy dane z 256 pseudolosowo wybranych węzłów pamięci podręcznej i haszujemy je, aby obliczyć węzeł zbioru danych. Cały zbiór danych jest następnie generowany przez: + +```python +def calc_dataset(full_size, cache): + return [calc_dataset_item(cache, i) for i in range(full_size // HASH_BYTES)] +``` + +## Pętla główna {#main-loop} + +Teraz określimy główną pętlę w stylu „hashimoto”, w której agregujemy dane z pełnego zbioru danych w celu wytworzenia naszej ostatecznej wartości dla konkretnego nagłówka i wartości nonce. W poniższym kodzie `header` reprezentuje _hasz_ SHA3-256 reprezentacji RLP _skróconego_ nagłówka bloku, czyli nagłówka z wyłączeniem pól **mixHash** oraz **nonce**. `nonce` to osiem bajtów 64-bitowej liczby całkowitej bez znaku w porządku big-endian. Zatem `nonce[::-1]` jest ośmiobajtową reprezentacją tej wartości w porządku little-endian: + +```python +def hashimoto(header, nonce, full_size, dataset_lookup): + n = full_size / HASH_BYTES + w = MIX_BYTES // WORD_BYTES + mixhashes = MIX_BYTES / HASH_BYTES + # połącz header+nonce w 64-bajtowe ziarno + s = sha3_512(header + nonce[::-1]) + # rozpocznij miks od powielonego s + mix = [] + for _ in range(MIX_BYTES / HASH_BYTES): + mix.extend(s) + # wmieszaj losowe węzły zbioru danych + for i in range(ACCESSES): + p = fnv(i ^ s[0], mix[i % w]) % (n // mixhashes) * mixhashes + newdata = [] + for j in range(MIX_BYTES / HASH_BYTES): + newdata.extend(dataset_lookup(p + j)) + mix = map(fnv, mix, newdata) + # skompresuj miks + cmix = [] + for i in range(0, len(mix), 4): + cmix.append(fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])) + return { + "mix digest": serialize_hash(cmix), + "result": serialize_hash(sha3_256(s+cmix)) + } + +def hashimoto_light(full_size, cache, header, nonce): + return hashimoto(header, nonce, full_size, lambda x: calc_dataset_item(cache, x)) + +def hashimoto_full(full_size, dataset, header, nonce): + return hashimoto(header, nonce, full_size, lambda x: dataset[x]) +``` + +Zasadniczo utrzymujemy „miks” o szerokości 128 bajtów i wielokrotnie sekwencyjnie pobieramy 128 bajtów z pełnego zbioru danych, używając funkcji `fnv` do połączenia ich z miksem. 128 bajtów dostępu sekwencyjnego jest używane, aby każda runda algorytmu zawsze pobierała pełną stronę z pamięci RAM, minimalizując chybienia w buforze translacji adresów (TLB), których układy ASIC teoretycznie mogłyby uniknąć. + +Jeśli wynik tego algorytmu jest poniżej pożądanego celu, to wartość nonce jest prawidłowa. Należy pamiętać, że dodatkowe zastosowanie `sha3_256` na końcu zapewnia istnienie pośredniej wartości nonce, którą można podać w celu udowodnienia, że wykonano co najmniej niewielką ilość pracy; ta szybka zewnętrzna weryfikacja PoW może być używana do celów ochrony przed atakami DDoS. Służy to również zapewnieniu statystycznej pewności, że wynik jest nieobciążoną, 256-bitową liczbą. + +## Wydobycie {#mining} + +Algorytm wydobycia jest zdefiniowany w następujący sposób: + +```python +def mine(full_size, dataset, header, difficulty): + # dopełnij cel zerami, aby porównać z haszem na tej samej cyfrze + target = zpad(encode_int(2**256 // difficulty), 64)[::-1] + from random import randint + nonce = randint(0, 2**64) + while hashimoto_full(full_size, dataset, header, nonce) > target: + nonce = (nonce + 1) % 2**64 + return nonce +``` + +## Definiowanie haszu ziarna {#seed-hash} + +Aby obliczyć hasz ziarna, który byłby używany do wydobywania na danym bloku, używamy następującego algorytmu: + +```python + def get_seedhash(block): + s = '\x00' * 32 + for i in range(block.number // EPOCH_LENGTH): + s = serialize_hash(sha3_256(s)) + return s +``` + +Należy pamiętać, że w celu płynnego wydobywania i weryfikacji zalecamy wstępne obliczanie przyszłych haszy ziaren i zbiorów danych w osobnym wątku. + +## Dalsza lektura {#further-reading} + +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ + +## Dodatek {#appendix} + +Poniższy kod należy dołączyć na początku, jeśli chcesz uruchomić powyższą specyfikację Pythona jako kod. + +```python +import sha3, copy + +# Zakłada porządek bitów little endian (taki sam jak w architekturach Intela) +def decode_int(s): + return int(s[::-1].encode('hex'), 16) if s else 0 + +def encode_int(s): + a = "%x" % s + return '' if s == 0 else ('0' * (len(a) % 2) + a).decode('hex')[::-1] + +def zpad(s, length): + return s + '\x00' * max(0, length - len(s)) + +def serialize_hash(h): + return ''.join([zpad(encode_int(x), 4) for x in h]) + +def deserialize_hash(h): + return [decode_int(h[i:i+WORD_BYTES]) for i in range(0, len(h), WORD_BYTES)] + +def hash_words(h, sz, x): + if isinstance(x, list): + x = serialize_hash(x) + y = h(x) + return deserialize_hash(y) + +def serialize_cache(ds): + return ''.join([serialize_hash(h) for h in ds]) + +serialize_dataset = serialize_cache + +# funkcja haszująca sha3, zwraca 64 bajty +def sha3_512(x): + return hash_words(lambda v: sha3.sha3_512(v).digest(), 64, x) + +def sha3_256(x): + return hash_words(lambda v: sha3.sha3_256(v).digest(), 32, x) + +def xor(a, b): + return a ^ b + +def isprime(x): + for i in range(2, int(x**0.5)): + if x % i == 0: + return False + return True +``` + +### Rozmiary danych {#data-sizes} + +Poniższe tabele przeglądowe zawierają dane dotyczące rozmiarów danych i pamięci podręcznej dla około 2048 epok. + +```python +def get_datasize(block_number): + return data_sizes[block_number // EPOCH_LENGTH] + +def get_cachesize(block_number): + return cache_sizes[block_number // EPOCH_LENGTH] + +data_sizes = [ +1073739904, 1082130304, 1090514816, 1098906752, 1107293056, +1115684224, 1124070016, 1132461952, 1140849536, 1149232768, +1157627776, 1166013824, 1174404736, 1182786944, 1191180416, +1199568512, 1207958912, 1216345216, 1224732032, 1233124736, +1241513344, 1249902464, 1258290304, 1266673792, 1275067264, +1283453312, 1291844992, 1300234112, 1308619904, 1317010048, +1325397376, 1333787776, 1342176128, 1350561664, 1358954368, +1367339392, 1375731584, 1384118144, 1392507008, 1400897408, +1409284736, 1417673344, 1426062464, 1434451072, 1442839168, +1451229056, 1459615616, 1468006016, 1476394112, 1484782976, +1493171584, 1501559168, 1509948032, 1518337664, 1526726528, +1535114624, 1543503488, 1551892096, 1560278656, 1568669056, +1577056384, 1585446272, 1593831296, 1602219392, 1610610304, +1619000192, 1627386752, 1635773824, 1644164224, 1652555648, +1660943488, 1669332608, 1677721216, 1686109312, 1694497664, +1702886272, 1711274624, 1719661184, 1728047744, 1736434816, +1744829056, 1753218944, 1761606272, 1769995904, 1778382464, +1786772864, 1795157888, 1803550592, 1811937664, 1820327552, +1828711552, 1837102976, 1845488768, 1853879936, 1862269312, +1870656896, 1879048064, 1887431552, 1895825024, 1904212096, +1912601216, 1920988544, 1929379456, 1937765504, 1946156672, +1954543232, 1962932096, 1971321728, 1979707264, 1988093056, +1996487552, 2004874624, 2013262208, 2021653888, 2030039936, +2038430848, 2046819968, 2055208576, 2063596672, 2071981952, +2080373632, 2088762752, 2097149056, 2105539712, 2113928576, +2122315136, 2130700672, 2139092608, 2147483264, 2155872128, +2164257664, 2172642176, 2181035392, 2189426048, 2197814912, +2206203008, 2214587264, 2222979712, 2231367808, 2239758208, +2248145024, 2256527744, 2264922752, 2273312128, 2281701248, +2290086272, 2298476672, 2306867072, 2315251072, 2323639168, +2332032128, 2340420224, 2348808064, 2357196416, 2365580416, +2373966976, 2382363008, 2390748544, 2399139968, 2407530368, +2415918976, 2424307328, 2432695424, 2441084288, 2449472384, +2457861248, 2466247808, 2474637184, 2483026816, 2491414144, +2499803776, 2508191872, 2516582272, 2524970368, 2533359232, +2541743488, 2550134144, 2558525056, 2566913408, 2575301504, +2583686528, 2592073856, 2600467328, 2608856192, 2617240448, +2625631616, 2634022016, 2642407552, 2650796416, 2659188352, +2667574912, 2675965312, 2684352896, 2692738688, 2701130624, +2709518464, 2717907328, 2726293376, 2734685056, 2743073152, +2751462016, 2759851648, 2768232832, 2776625536, 2785017728, +2793401984, 2801794432, 2810182016, 2818571648, 2826959488, +2835349376, 2843734144, 2852121472, 2860514432, 2868900992, +2877286784, 2885676928, 2894069632, 2902451584, 2910843008, +2919234688, 2927622784, 2936011648, 2944400768, 2952789376, +2961177728, 2969565568, 2977951616, 2986338944, 2994731392, +3003120256, 3011508352, 3019895936, 3028287104, 3036675968, +3045063808, 3053452928, 3061837696, 3070228352, 3078615424, +3087003776, 3095394944, 3103782272, 3112173184, 3120562048, +3128944768, 3137339264, 3145725056, 3154109312, 3162505088, +3170893184, 3179280256, 3187669376, 3196056704, 3204445568, +3212836736, 3221224064, 3229612928, 3238002304, 3246391168, +3254778496, 3263165824, 3271556224, 3279944576, 3288332416, +3296719232, 3305110912, 3313500032, 3321887104, 3330273152, +3338658944, 3347053184, 3355440512, 3363827072, 3372220288, +3380608384, 3388997504, 3397384576, 3405774208, 3414163072, +3422551936, 3430937984, 3439328384, 3447714176, 3456104576, +3464493952, 3472883584, 3481268864, 3489655168, 3498048896, +3506434432, 3514826368, 3523213952, 3531603584, 3539987072, +3548380288, 3556763264, 3565157248, 3573545344, 3581934464, +3590324096, 3598712704, 3607098752, 3615488384, 3623877248, +3632265856, 3640646528, 3649043584, 3657430144, 3665821568, +3674207872, 3682597504, 3690984832, 3699367808, 3707764352, +3716152448, 3724541056, 3732925568, 3741318016, 3749706368, +3758091136, 3766481536, 3774872704, 3783260032, 3791650432, +3800036224, 3808427648, 3816815488, 3825204608, 3833592704, +3841981568, 3850370432, 3858755968, 3867147904, 3875536256, +3883920512, 3892313728, 3900702592, 3909087872, 3917478784, +3925868416, 3934256512, 3942645376, 3951032192, 3959422336, +3967809152, 3976200064, 3984588416, 3992974976, 4001363584, +4009751168, 4018141312, 4026530432, 4034911616, 4043308928, +4051695488, 4060084352, 4068472448, 4076862848, 4085249408, +4093640576, 4102028416, 4110413696, 4118805632, 4127194496, +4135583104, 4143971968, 4152360832, 4160746112, 4169135744, +4177525888, 4185912704, 4194303616, 4202691968, 4211076736, +4219463552, 4227855488, 4236246656, 4244633728, 4253022848, +4261412224, 4269799808, 4278184832, 4286578048, 4294962304, +4303349632, 4311743104, 4320130432, 4328521088, 4336909184, +4345295488, 4353687424, 4362073472, 4370458496, 4378852736, +4387238528, 4395630208, 4404019072, 4412407424, 4420790656, +4429182848, 4437571456, 4445962112, 4454344064, 4462738048, +4471119232, 4479516544, 4487904128, 4496289664, 4504682368, +4513068416, 4521459584, 4529846144, 4538232704, 4546619776, +4555010176, 4563402112, 4571790208, 4580174464, 4588567936, +4596957056, 4605344896, 4613734016, 4622119808, 4630511488, +4638898816, 4647287936, 4655675264, 4664065664, 4672451968, +4680842624, 4689231488, 4697620352, 4706007424, 4714397056, +4722786176, 4731173248, 4739562368, 4747951744, 4756340608, +4764727936, 4773114496, 4781504384, 4789894784, 4798283648, +4806667648, 4815059584, 4823449472, 4831835776, 4840226176, +4848612224, 4857003392, 4865391488, 4873780096, 4882169728, +4890557312, 4898946944, 4907333248, 4915722368, 4924110976, +4932499328, 4940889728, 4949276032, 4957666432, 4966054784, +4974438016, 4982831488, 4991221376, 4999607168, 5007998848, +5016386432, 5024763776, 5033164672, 5041544576, 5049941888, +5058329728, 5066717056, 5075107456, 5083494272, 5091883904, +5100273536, 5108662144, 5117048192, 5125436032, 5133827456, +5142215296, 5150605184, 5158993024, 5167382144, 5175769472, +5184157568, 5192543872, 5200936064, 5209324928, 5217711232, +5226102656, 5234490496, 5242877312, 5251263872, 5259654016, +5268040832, 5276434304, 5284819328, 5293209728, 5301598592, +5309986688, 5318374784, 5326764416, 5335151488, 5343542144, +5351929472, 5360319872, 5368706944, 5377096576, 5385484928, +5393871232, 5402263424, 5410650496, 5419040384, 5427426944, +5435816576, 5444205952, 5452594816, 5460981376, 5469367936, +5477760896, 5486148736, 5494536832, 5502925952, 5511315328, +5519703424, 5528089984, 5536481152, 5544869504, 5553256064, +5561645696, 5570032768, 5578423936, 5586811264, 5595193216, +5603585408, 5611972736, 5620366208, 5628750464, 5637143936, +5645528192, 5653921408, 5662310272, 5670694784, 5679082624, +5687474048, 5695864448, 5704251008, 5712641408, 5721030272, +5729416832, 5737806208, 5746194304, 5754583936, 5762969984, +5771358592, 5779748224, 5788137856, 5796527488, 5804911232, +5813300608, 5821692544, 5830082176, 5838468992, 5846855552, +5855247488, 5863636096, 5872024448, 5880411008, 5888799872, +5897186432, 5905576832, 5913966976, 5922352768, 5930744704, +5939132288, 5947522432, 5955911296, 5964299392, 5972688256, +5981074304, 5989465472, 5997851008, 6006241408, 6014627968, +6023015552, 6031408256, 6039796096, 6048185216, 6056574848, +6064963456, 6073351808, 6081736064, 6090128768, 6098517632, +6106906496, 6115289216, 6123680896, 6132070016, 6140459648, +6148849024, 6157237376, 6165624704, 6174009728, 6182403712, +6190792064, 6199176064, 6207569792, 6215952256, 6224345216, +6232732544, 6241124224, 6249510272, 6257899136, 6266287744, +6274676864, 6283065728, 6291454336, 6299843456, 6308232064, +6316620928, 6325006208, 6333395584, 6341784704, 6350174848, +6358562176, 6366951296, 6375337856, 6383729536, 6392119168, +6400504192, 6408895616, 6417283456, 6425673344, 6434059136, +6442444672, 6450837376, 6459223424, 6467613056, 6476004224, +6484393088, 6492781952, 6501170048, 6509555072, 6517947008, +6526336384, 6534725504, 6543112832, 6551500672, 6559888768, +6568278656, 6576662912, 6585055616, 6593443456, 6601834112, +6610219648, 6618610304, 6626999168, 6635385472, 6643777408, +6652164224, 6660552832, 6668941952, 6677330048, 6685719424, +6694107776, 6702493568, 6710882176, 6719274112, 6727662976, +6736052096, 6744437632, 6752825984, 6761213824, 6769604224, +6777993856, 6786383488, 6794770816, 6803158144, 6811549312, +6819937664, 6828326528, 6836706176, 6845101696, 6853491328, +6861880448, 6870269312, 6878655104, 6887046272, 6895433344, +6903822208, 6912212864, 6920596864, 6928988288, 6937377152, +6945764992, 6954149248, 6962544256, 6970928768, 6979317376, +6987709312, 6996093824, 7004487296, 7012875392, 7021258624, +7029652352, 7038038912, 7046427776, 7054818944, 7063207808, +7071595136, 7079980928, 7088372608, 7096759424, 7105149824, +7113536896, 7121928064, 7130315392, 7138699648, 7147092352, +7155479168, 7163865728, 7172249984, 7180648064, 7189036672, +7197424768, 7205810816, 7214196608, 7222589824, 7230975104, +7239367552, 7247755904, 7256145536, 7264533376, 7272921472, +7281308032, 7289694848, 7298088832, 7306471808, 7314864512, +7323253888, 7331643008, 7340029568, 7348419712, 7356808832, +7365196672, 7373585792, 7381973888, 7390362752, 7398750592, +7407138944, 7415528576, 7423915648, 7432302208, 7440690304, +7449080192, 7457472128, 7465860992, 7474249088, 7482635648, +7491023744, 7499412608, 7507803008, 7516192384, 7524579968, +7532967296, 7541358464, 7549745792, 7558134656, 7566524032, +7574912896, 7583300992, 7591690112, 7600075136, 7608466816, +7616854912, 7625244544, 7633629824, 7642020992, 7650410368, +7658794112, 7667187328, 7675574912, 7683961984, 7692349568, +7700739712, 7709130368, 7717519232, 7725905536, 7734295424, +7742683264, 7751069056, 7759457408, 7767849088, 7776238208, +7784626816, 7793014912, 7801405312, 7809792128, 7818179968, +7826571136, 7834957184, 7843347328, 7851732352, 7860124544, +7868512384, 7876902016, 7885287808, 7893679744, 7902067072, +7910455936, 7918844288, 7927230848, 7935622784, 7944009344, +7952400256, 7960786048, 7969176704, 7977565312, 7985953408, +7994339968, 8002730368, 8011119488, 8019508096, 8027896192, +8036285056, 8044674688, 8053062272, 8061448832, 8069838464, +8078227328, 8086616704, 8095006592, 8103393664, 8111783552, +8120171392, 8128560256, 8136949376, 8145336704, 8153726848, +8162114944, 8170503296, 8178891904, 8187280768, 8195669632, +8204058496, 8212444544, 8220834176, 8229222272, 8237612672, +8246000768, 8254389376, 8262775168, 8271167104, 8279553664, +8287944064, 8296333184, 8304715136, 8313108352, 8321497984, +8329885568, 8338274432, 8346663296, 8355052928, 8363441536, +8371828352, 8380217984, 8388606592, 8396996224, 8405384576, +8413772672, 8422161536, 8430549376, 8438939008, 8447326592, +8455715456, 8464104832, 8472492928, 8480882048, 8489270656, +8497659776, 8506045312, 8514434944, 8522823808, 8531208832, +8539602304, 8547990656, 8556378752, 8564768384, 8573154176, +8581542784, 8589933952, 8598322816, 8606705024, 8615099264, +8623487872, 8631876992, 8640264064, 8648653952, 8657040256, +8665430656, 8673820544, 8682209152, 8690592128, 8698977152, +8707374464, 8715763328, 8724151424, 8732540032, 8740928384, +8749315712, 8757704576, 8766089344, 8774480768, 8782871936, +8791260032, 8799645824, 8808034432, 8816426368, 8824812928, +8833199488, 8841591424, 8849976448, 8858366336, 8866757248, +8875147136, 8883532928, 8891923328, 8900306816, 8908700288, +8917088384, 8925478784, 8933867392, 8942250368, 8950644608, +8959032704, 8967420544, 8975809664, 8984197504, 8992584064, +9000976256, 9009362048, 9017752448, 9026141312, 9034530688, +9042917504, 9051307904, 9059694208, 9068084864, 9076471424, +9084861824, 9093250688, 9101638528, 9110027648, 9118416512, +9126803584, 9135188096, 9143581312, 9151969664, 9160356224, +9168747136, 9177134464, 9185525632, 9193910144, 9202302848, +9210690688, 9219079552, 9227465344, 9235854464, 9244244864, +9252633472, 9261021824, 9269411456, 9277799296, 9286188928, +9294574208, 9302965888, 9311351936, 9319740032, 9328131968, +9336516736, 9344907392, 9353296768, 9361685888, 9370074752, +9378463616, 9386849408, 9395239808, 9403629184, 9412016512, +9420405376, 9428795008, 9437181568, 9445570688, 9453960832, +9462346624, 9470738048, 9479121536, 9487515008, 9495903616, +9504289664, 9512678528, 9521067904, 9529456256, 9537843584, +9546233728, 9554621312, 9563011456, 9571398784, 9579788672, +9588178304, 9596567168, 9604954496, 9613343104, 9621732992, +9630121856, 9638508416, 9646898816, 9655283584, 9663675776, +9672061312, 9680449664, 9688840064, 9697230464, 9705617536, +9714003584, 9722393984, 9730772608, 9739172224, 9747561088, +9755945344, 9764338816, 9772726144, 9781116544, 9789503872, +9797892992, 9806282624, 9814670464, 9823056512, 9831439232, +9839833984, 9848224384, 9856613504, 9865000576, 9873391232, +9881772416, 9890162816, 9898556288, 9906940544, 9915333248, +9923721088, 9932108672, 9940496512, 9948888448, 9957276544, +9965666176, 9974048384, 9982441088, 9990830464, 9999219584, +10007602816, 10015996544, 10024385152, 10032774016, 10041163648, +10049548928, 10057940096, 10066329472, 10074717824, 10083105152, +10091495296, 10099878784, 10108272256, 10116660608, 10125049216, +10133437312, 10141825664, 10150213504, 10158601088, 10166991232, +10175378816, 10183766144, 10192157312, 10200545408, 10208935552, +10217322112, 10225712768, 10234099328, 10242489472, 10250876032, +10259264896, 10267656064, 10276042624, 10284429184, 10292820352, +10301209472, 10309598848, 10317987712, 10326375296, 10334763392, +10343153536, 10351541632, 10359930752, 10368318592, 10376707456, +10385096576, 10393484672, 10401867136, 10410262144, 10418647424, +10427039104, 10435425664, 10443810176, 10452203648, 10460589952, +10468982144, 10477369472, 10485759104, 10494147712, 10502533504, +10510923392, 10519313536, 10527702656, 10536091264, 10544478592, +10552867712, 10561255808, 10569642368, 10578032768, 10586423168, +10594805632, 10603200128, 10611588992, 10619976064, 10628361344, +10636754048, 10645143424, 10653531776, 10661920384, 10670307968, +10678696832, 10687086464, 10695475072, 10703863168, 10712246144, +10720639616, 10729026688, 10737414784, 10745806208, 10754190976, +10762581376, 10770971264, 10779356288, 10787747456, 10796135552, +10804525184, 10812915584, 10821301888, 10829692288, 10838078336, +10846469248, 10854858368, 10863247232, 10871631488, 10880023424, +10888412032, 10896799616, 10905188992, 10913574016, 10921964672, +10930352768, 10938742912, 10947132544, 10955518592, 10963909504, +10972298368, 10980687488, 10989074816, 10997462912, 11005851776, +11014241152, 11022627712, 11031017344, 11039403904, 11047793024, +11056184704, 11064570752, 11072960896, 11081343872, 11089737856, +11098128256, 11106514816, 11114904448, 11123293568, 11131680128, +11140065152, 11148458368, 11156845696, 11165236864, 11173624192, +11182013824, 11190402688, 11198790784, 11207179136, 11215568768, +11223957376, 11232345728, 11240734592, 11249122688, 11257511296, +11265899648, 11274285952, 11282675584, 11291065472, 11299452544, +11307842432, 11316231296, 11324616832, 11333009024, 11341395584, +11349782656, 11358172288, 11366560384, 11374950016, 11383339648, +11391721856, 11400117376, 11408504192, 11416893568, 11425283456, +11433671552, 11442061184, 11450444672, 11458837888, 11467226752, +11475611776, 11484003968, 11492392064, 11500780672, 11509169024, +11517550976, 11525944448, 11534335616, 11542724224, 11551111808, +11559500672, 11567890304, 11576277376, 11584667008, 11593056128, +11601443456, 11609830016, 11618221952, 11626607488, 11634995072, +11643387776, 11651775104, 11660161664, 11668552576, 11676940928, +11685330304, 11693718656, 11702106496, 11710496128, 11718882688, +11727273088, 11735660416, 11744050048, 11752437376, 11760824704, +11769216128, 11777604736, 11785991296, 11794381952, 11802770048, +11811157888, 11819548544, 11827932544, 11836324736, 11844713344, +11853100928, 11861486464, 11869879936, 11878268032, 11886656896, +11895044992, 11903433088, 11911822976, 11920210816, 11928600448, +11936987264, 11945375872, 11953761152, 11962151296, 11970543488, +11978928512, 11987320448, 11995708288, 12004095104, 12012486272, +12020875136, 12029255552, 12037652096, 12046039168, 12054429568, +12062813824, 12071206528, 12079594624, 12087983744, 12096371072, +12104759936, 12113147264, 12121534592, 12129924992, 12138314624, +12146703232, 12155091584, 12163481216, 12171864704, 12180255872, +12188643968, 12197034112, 12205424512, 12213811328, 12222199424, +12230590336, 12238977664, 12247365248, 12255755392, 12264143488, +12272531584, 12280920448, 12289309568, 12297694592, 12306086528, +12314475392, 12322865024, 12331253632, 12339640448, 12348029312, +12356418944, 12364805248, 12373196672, 12381580928, 12389969024, +12398357632, 12406750592, 12415138432, 12423527552, 12431916416, +12440304512, 12448692352, 12457081216, 12465467776, 12473859968, +12482245504, 12490636672, 12499025536, 12507411584, 12515801728, +12524190592, 12532577152, 12540966272, 12549354368, 12557743232, +12566129536, 12574523264, 12582911872, 12591299456, 12599688064, +12608074624, 12616463488, 12624845696, 12633239936, 12641631616, +12650019968, 12658407296, 12666795136, 12675183232, 12683574656, +12691960192, 12700350592, 12708740224, 12717128576, 12725515904, +12733906816, 12742295168, 12750680192, 12759071872, 12767460736, +12775848832, 12784236928, 12792626816, 12801014656, 12809404288, +12817789312, 12826181504, 12834568832, 12842954624, 12851345792, +12859732352, 12868122496, 12876512128, 12884901248, 12893289088, +12901672832, 12910067584, 12918455168, 12926842496, 12935232896, +12943620736, 12952009856, 12960396928, 12968786816, 12977176192, +12985563776, 12993951104, 13002341504, 13010730368, 13019115392, +13027506304, 13035895168, 13044272512, 13052673152, 13061062528, +13069446272, 13077838976, 13086227072, 13094613632, 13103000192, +13111393664, 13119782528, 13128157568, 13136559232, 13144945024, +13153329536, 13161724288, 13170111872, 13178502784, 13186884736, +13195279744, 13203667072, 13212057472, 13220445824, 13228832128, +13237221248, 13245610624, 13254000512, 13262388352, 13270777472, +13279166336, 13287553408, 13295943296, 13304331904, 13312719488, +13321108096, 13329494656, 13337885824, 13346274944, 13354663808, +13363051136, 13371439232, 13379825024, 13388210816, 13396605056, +13404995456, 13413380224, 13421771392, 13430159744, 13438546048, +13446937216, 13455326848, 13463708288, 13472103808, 13480492672, +13488875648, 13497269888, 13505657728, 13514045312, 13522435712, +13530824576, 13539210112, 13547599232, 13555989376, 13564379008, +13572766336, 13581154432, 13589544832, 13597932928, 13606320512, +13614710656, 13623097472, 13631477632, 13639874944, 13648264064, +13656652928, 13665041792, 13673430656, 13681818496, 13690207616, +13698595712, 13706982272, 13715373184, 13723762048, 13732150144, +13740536704, 13748926592, 13757316224, 13765700992, 13774090112, +13782477952, 13790869376, 13799259008, 13807647872, 13816036736, +13824425344, 13832814208, 13841202304, 13849591424, 13857978752, +13866368896, 13874754688, 13883145344, 13891533184, 13899919232, +13908311168, 13916692096, 13925085056, 13933473152, 13941866368, +13950253696, 13958643584, 13967032192, 13975417216, 13983807616, +13992197504, 14000582272, 14008973696, 14017363072, 14025752192, +14034137984, 14042528384, 14050918016, 14059301504, 14067691648, +14076083584, 14084470144, 14092852352, 14101249664, 14109635968, +14118024832, 14126407552, 14134804352, 14143188608, 14151577984, +14159968384, 14168357248, 14176741504, 14185127296, 14193521024, +14201911424, 14210301824, 14218685056, 14227067264, 14235467392, +14243855488, 14252243072, 14260630144, 14269021568, 14277409408, +14285799296, 14294187904, 14302571392, 14310961792, 14319353728, +14327738752, 14336130944, 14344518784, 14352906368, 14361296512, +14369685376, 14378071424, 14386462592, 14394848128, 14403230848, +14411627392, 14420013952, 14428402304, 14436793472, 14445181568, +14453569664, 14461959808, 14470347904, 14478737024, 14487122816, +14495511424, 14503901824, 14512291712, 14520677504, 14529064832, +14537456768, 14545845632, 14554234496, 14562618496, 14571011456, +14579398784, 14587789184, 14596172672, 14604564608, 14612953984, +14621341312, 14629724288, 14638120832, 14646503296, 14654897536, +14663284864, 14671675264, 14680061056, 14688447616, 14696835968, +14705228416, 14713616768, 14722003328, 14730392192, 14738784128, +14747172736, 14755561088, 14763947648, 14772336512, 14780725376, +14789110144, 14797499776, 14805892736, 14814276992, 14822670208, +14831056256, 14839444352, 14847836032, 14856222848, 14864612992, +14872997504, 14881388672, 14889775744, 14898165376, 14906553472, +14914944896, 14923329664, 14931721856, 14940109696, 14948497024, +14956887424, 14965276544, 14973663616, 14982053248, 14990439808, +14998830976, 15007216768, 15015605888, 15023995264, 15032385152, +15040768384, 15049154944, 15057549184, 15065939072, 15074328448, +15082715008, 15091104128, 15099493504, 15107879296, 15116269184, +15124659584, 15133042304, 15141431936, 15149824384, 15158214272, +15166602368, 15174991232, 15183378304, 15191760512, 15200154496, +15208542592, 15216931712, 15225323392, 15233708416, 15242098048, +15250489216, 15258875264, 15267265408, 15275654528, 15284043136, +15292431488, 15300819584, 15309208192, 15317596544, 15325986176, +15334374784, 15342763648, 15351151744, 15359540608, 15367929728, +15376318336, 15384706432, 15393092992, 15401481856, 15409869952, +15418258816, 15426649984, 15435037568, 15443425664, 15451815296, +15460203392, 15468589184, 15476979328, 15485369216, 15493755776, +15502146944, 15510534272, 15518924416, 15527311232, 15535699072, +15544089472, 15552478336, 15560866688, 15569254528, 15577642624, +15586031488, 15594419072, 15602809472, 15611199104, 15619586432, +15627975296, 15636364928, 15644753792, 15653141888, 15661529216, +15669918848, 15678305152, 15686696576, 15695083136, 15703474048, +15711861632, 15720251264, 15728636288, 15737027456, 15745417088, +15753804928, 15762194048, 15770582656, 15778971008, 15787358336, +15795747712, 15804132224, 15812523392, 15820909696, 15829300096, +15837691264, 15846071936, 15854466944, 15862855808, 15871244672, +15879634816, 15888020608, 15896409728, 15904799104, 15913185152, +15921577088, 15929966464, 15938354816, 15946743424, 15955129472, +15963519872, 15971907968, 15980296064, 15988684928, 15997073024, +16005460864, 16013851264, 16022241152, 16030629248, 16039012736, +16047406976, 16055794816, 16064181376, 16072571264, 16080957824, +16089346688, 16097737856, 16106125184, 16114514816, 16122904192, +16131292544, 16139678848, 16148066944, 16156453504, 16164839552, +16173236096, 16181623424, 16190012032, 16198401152, 16206790528, +16215177344, 16223567744, 16231956352, 16240344704, 16248731008, +16257117824, 16265504384, 16273898624, 16282281856, 16290668672, +16299064192, 16307449216, 16315842176, 16324230016, 16332613504, +16341006464, 16349394304, 16357783168, 16366172288, 16374561664, +16382951296, 16391337856, 16399726208, 16408116352, 16416505472, +16424892032, 16433282176, 16441668224, 16450058624, 16458448768, +16466836864, 16475224448, 16483613056, 16492001408, 16500391808, +16508779648, 16517166976, 16525555328, 16533944192, 16542330752, +16550719616, 16559110528, 16567497088, 16575888512, 16584274816, +16592665472, 16601051008, 16609442944, 16617832064, 16626218624, +16634607488, 16642996096, 16651385728, 16659773824, 16668163712, +16676552576, 16684938112, 16693328768, 16701718144, 16710095488, +16718492288, 16726883968, 16735272832, 16743661184, 16752049792, +16760436608, 16768827008, 16777214336, 16785599104, 16793992832, +16802381696, 16810768768, 16819151744, 16827542656, 16835934848, +16844323712, 16852711552, 16861101952, 16869489536, 16877876864, +16886265728, 16894653056, 16903044736, 16911431296, 16919821696, +16928207488, 16936592768, 16944987776, 16953375616, 16961763968, +16970152832, 16978540928, 16986929536, 16995319168, 17003704448, +17012096896, 17020481152, 17028870784, 17037262208, 17045649536, +17054039936, 17062426496, 17070814336, 17079205504, 17087592064, +17095978112, 17104369024, 17112759424, 17121147776, 17129536384, +17137926016, 17146314368, 17154700928, 17163089792, 17171480192, +17179864192, 17188256896, 17196644992, 17205033856, 17213423488, +17221811072, 17230198912, 17238588032, 17246976896, 17255360384, +17263754624, 17272143232, 17280530048, 17288918912, 17297309312, +17305696384, 17314085504, 17322475136, 17330863744, 17339252096, +17347640192, 17356026496, 17364413824, 17372796544, 17381190016, +17389583488, 17397972608, 17406360704, 17414748544, 17423135872, +17431527296, 17439915904, 17448303232, 17456691584, 17465081728, +17473468288, 17481857408, 17490247552, 17498635904, 17507022464, +17515409024, 17523801728, 17532189824, 17540577664, 17548966016, +17557353344, 17565741184, 17574131584, 17582519168, 17590907008, +17599296128, 17607687808, 17616076672, 17624455808, 17632852352, +17641238656, 17649630848, 17658018944, 17666403968, 17674794112, +17683178368, 17691573376, 17699962496, 17708350592, 17716739968, +17725126528, 17733517184, 17741898112, 17750293888, 17758673024, +17767070336, 17775458432, 17783848832, 17792236928, 17800625536, +17809012352, 17817402752, 17825785984, 17834178944, 17842563968, +17850955648, 17859344512, 17867732864, 17876119424, 17884511872, +17892900224, 17901287296, 17909677696, 17918058112, 17926451072, +17934843776, 17943230848, 17951609216, 17960008576, 17968397696, +17976784256, 17985175424, 17993564032, 18001952128, 18010339712, +18018728576, 18027116672, 18035503232, 18043894144, 18052283264, +18060672128, 18069056384, 18077449856, 18085837184, 18094225792, +18102613376, 18111004544, 18119388544, 18127781248, 18136170368, +18144558976, 18152947328, 18161336192, 18169724288, 18178108544, +18186498944, 18194886784, 18203275648, 18211666048, 18220048768, +18228444544, 18236833408, 18245220736] + +cache_sizes = [ +16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, +17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, +18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, +19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, +20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, +21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, +22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, +23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, +24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, +25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, +25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, +26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, +27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, +28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, +29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, +30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, +31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, +32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, +33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, +34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, +35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, +36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, +36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, +37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, +38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, +39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, +40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, +41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, +42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, +43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, +44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, +45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, +46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, +47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, +47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, +48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, +49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, +50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, +51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, +52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, +53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, +54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, +55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, +56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, +57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, +58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, +58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, +59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, +60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, +61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, +62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, +63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, +64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, +65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, +66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, +67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, +68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, +69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, +69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, +70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, +71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, +72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, +73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, +74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, +75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, +76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, +77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, +78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, +79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, +80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, +81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, +81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, +82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, +83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, +84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, +85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, +86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, +87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, +88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, +89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, +90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, +91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, +92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, +92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, +93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, +94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, +95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, +96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, +97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, +98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, +99352384, 99482816, 99614272, 99745472, 99876416, 100007104, +100138048, 100267072, 100401088, 100529984, 100662592, 100791872, +100925248, 101056064, 101187392, 101317952, 101449408, 101580608, +101711296, 101841728, 101973824, 102104896, 102235712, 102366016, +102498112, 102628672, 102760384, 102890432, 103021888, 103153472, +103284032, 103415744, 103545152, 103677248, 103808576, 103939648, +104070976, 104201792, 104332736, 104462528, 104594752, 104725952, +104854592, 104988608, 105118912, 105247808, 105381184, 105511232, +105643072, 105774784, 105903296, 106037056, 106167872, 106298944, +106429504, 106561472, 106691392, 106822592, 106954304, 107085376, +107216576, 107346368, 107478464, 107609792, 107739712, 107872192, +108003136, 108131392, 108265408, 108396224, 108527168, 108657344, +108789568, 108920384, 109049792, 109182272, 109312576, 109444928, +109572928, 109706944, 109837888, 109969088, 110099648, 110230976, +110362432, 110492992, 110624704, 110755264, 110886208, 111017408, +111148864, 111279296, 111410752, 111541952, 111673024, 111803456, +111933632, 112066496, 112196416, 112328512, 112457792, 112590784, +112715968, 112852672, 112983616, 113114944, 113244224, 113376448, +113505472, 113639104, 113770304, 113901376, 114031552, 114163264, +114294592, 114425536, 114556864, 114687424, 114818624, 114948544, +115080512, 115212224, 115343296, 115473472, 115605184, 115736128, +115867072, 115997248, 116128576, 116260288, 116391488, 116522944, +116652992, 116784704, 116915648, 117046208, 117178304, 117308608, +117440192, 117569728, 117701824, 117833024, 117964096, 118094656, +118225984, 118357312, 118489024, 118617536, 118749632, 118882112, +119012416, 119144384, 119275328, 119406016, 119537344, 119668672, +119798464, 119928896, 120061376, 120192832, 120321728, 120454336, +120584512, 120716608, 120848192, 120979136, 121109056, 121241408, +121372352, 121502912, 121634752, 121764416, 121895744, 122027072, +122157632, 122289088, 122421184, 122550592, 122682944, 122813888, +122945344, 123075776, 123207488, 123338048, 123468736, 123600704, +123731264, 123861952, 123993664, 124124608, 124256192, 124386368, +124518208, 124649024, 124778048, 124911296, 125041088, 125173696, +125303744, 125432896, 125566912, 125696576, 125829056, 125958592, +126090304, 126221248, 126352832, 126483776, 126615232, 126746432, +126876608, 127008704, 127139392, 127270336, 127401152, 127532224, +127663552, 127794752, 127925696, 128055232, 128188096, 128319424, +128449856, 128581312, 128712256, 128843584, 128973632, 129103808, +129236288, 129365696, 129498944, 129629888, 129760832, 129892288, +130023104, 130154048, 130283968, 130416448, 130547008, 130678336, +130807616, 130939456, 131071552, 131202112, 131331776, 131464384, +131594048, 131727296, 131858368, 131987392, 132120256, 132250816, +132382528, 132513728, 132644672, 132774976, 132905792, 133038016, +133168832, 133299392, 133429312, 133562048, 133692992, 133823296, +133954624, 134086336, 134217152, 134348608, 134479808, 134607296, +134741056, 134872384, 135002944, 135134144, 135265472, 135396544, +135527872, 135659072, 135787712, 135921472, 136052416, 136182848, +136313792, 136444864, 136576448, 136707904, 136837952, 136970048, +137099584, 137232064, 137363392, 137494208, 137625536, 137755712, +137887424, 138018368, 138149824, 138280256, 138411584, 138539584, +138672832, 138804928, 138936128, 139066688, 139196864, 139328704, +139460032, 139590208, 139721024, 139852864, 139984576, 140115776, +140245696, 140376512, 140508352, 140640064, 140769856, 140902336, +141032768, 141162688, 141294016, 141426496, 141556544, 141687488, +141819584, 141949888, 142080448, 142212544, 142342336, 142474432, +142606144, 142736192, 142868288, 142997824, 143129408, 143258944, +143392448, 143523136, 143653696, 143785024, 143916992, 144045632, +144177856, 144309184, 144440768, 144570688, 144701888, 144832448, +144965056, 145096384, 145227584, 145358656, 145489856, 145620928, +145751488, 145883072, 146011456, 146144704, 146275264, 146407232, +146538176, 146668736, 146800448, 146931392, 147062336, 147193664, +147324224, 147455936, 147586624, 147717056, 147848768, 147979456, +148110784, 148242368, 148373312, 148503232, 148635584, 148766144, +148897088, 149028416, 149159488, 149290688, 149420224, 149551552, +149683136, 149814976, 149943616, 150076352, 150208064, 150338624, +150470464, 150600256, 150732224, 150862784, 150993088, 151125952, +151254976, 151388096, 151519168, 151649728, 151778752, 151911104, +152042944, 152174144, 152304704, 152435648, 152567488, 152698816, +152828992, 152960576, 153091648, 153222976, 153353792, 153484096, +153616192, 153747008, 153878336, 154008256, 154139968, 154270912, +154402624, 154533824, 154663616, 154795712, 154926272, 155057984, +155188928, 155319872, 155450816, 155580608, 155712064, 155843392, +155971136, 156106688, 156237376, 156367424, 156499264, 156630976, +156761536, 156892352, 157024064, 157155008, 157284416, 157415872, +157545536, 157677248, 157810496, 157938112, 158071744, 158203328, +158334656, 158464832, 158596288, 158727616, 158858048, 158988992, +159121216, 159252416, 159381568, 159513152, 159645632, 159776192, +159906496, 160038464, 160169536, 160300352, 160430656, 160563008, +160693952, 160822208, 160956352, 161086784, 161217344, 161349184, +161480512, 161611456, 161742272, 161873216, 162002752, 162135872, +162266432, 162397888, 162529216, 162660032, 162790976, 162922048, +163052096, 163184576, 163314752, 163446592, 163577408, 163707968, +163839296, 163969984, 164100928, 164233024, 164364224, 164494912, +164625856, 164756672, 164887616, 165019072, 165150016, 165280064, +165412672, 165543104, 165674944, 165805888, 165936832, 166067648, +166198336, 166330048, 166461248, 166591552, 166722496, 166854208, +166985408, 167116736, 167246656, 167378368, 167508416, 167641024, +167771584, 167903168, 168034112, 168164032, 168295744, 168427456, +168557632, 168688448, 168819136, 168951616, 169082176, 169213504, +169344832, 169475648, 169605952, 169738048, 169866304, 169999552, +170131264, 170262464, 170393536, 170524352, 170655424, 170782016, +170917696, 171048896, 171179072, 171310784, 171439936, 171573184, +171702976, 171835072, 171966272, 172097216, 172228288, 172359232, +172489664, 172621376, 172747712, 172883264, 173014208, 173144512, +173275072, 173407424, 173539136, 173669696, 173800768, 173931712, +174063424, 174193472, 174325696, 174455744, 174586816, 174718912, +174849728, 174977728, 175109696, 175242688, 175374272, 175504832, +175636288, 175765696, 175898432, 176028992, 176159936, 176291264, +176422592, 176552512, 176684864, 176815424, 176946496, 177076544, +177209152, 177340096, 177470528, 177600704, 177731648, 177864256, +177994816, 178126528, 178257472, 178387648, 178518464, 178650176, +178781888, 178912064, 179044288, 179174848, 179305024, 179436736, +179568448, 179698496, 179830208, 179960512, 180092608, 180223808, +180354752, 180485696, 180617152, 180748096, 180877504, 181009984, +181139264, 181272512, 181402688, 181532608, 181663168, 181795136, +181926592, 182057536, 182190016, 182320192, 182451904, 182582336, +182713792, 182843072, 182976064, 183107264, 183237056, 183368384, +183494848, 183631424, 183762752, 183893824, 184024768, 184154816, +184286656, 184417984, 184548928, 184680128, 184810816, 184941248, +185072704, 185203904, 185335616, 185465408, 185596352, 185727296, +185859904, 185989696, 186121664, 186252992, 186383552, 186514112, +186645952, 186777152, 186907328, 187037504, 187170112, 187301824, +187429184, 187562048, 187693504, 187825472, 187957184, 188087104, +188218304, 188349376, 188481344, 188609728, 188743616, 188874304, +189005248, 189136448, 189265088, 189396544, 189528128, 189660992, +189791936, 189923264, 190054208, 190182848, 190315072, 190447424, +190577984, 190709312, 190840768, 190971328, 191102656, 191233472, +191364032, 191495872, 191626816, 191758016, 191888192, 192020288, +192148928, 192282176, 192413504, 192542528, 192674752, 192805952, +192937792, 193068608, 193198912, 193330496, 193462208, 193592384, +193723456, 193854272, 193985984, 194116672, 194247232, 194379712, +194508352, 194641856, 194772544, 194900672, 195035072, 195166016, +195296704, 195428032, 195558592, 195690304, 195818176, 195952576, +196083392, 196214336, 196345792, 196476736, 196607552, 196739008, +196869952, 197000768, 197130688, 197262784, 197394368, 197523904, +197656384, 197787584, 197916608, 198049472, 198180544, 198310208, +198442432, 198573632, 198705088, 198834368, 198967232, 199097792, +199228352, 199360192, 199491392, 199621696, 199751744, 199883968, +200014016, 200146624, 200276672, 200408128, 200540096, 200671168, +200801984, 200933312, 201062464, 201194944, 201326144, 201457472, +201588544, 201719744, 201850816, 201981632, 202111552, 202244032, +202374464, 202505152, 202636352, 202767808, 202898368, 203030336, +203159872, 203292608, 203423296, 203553472, 203685824, 203816896, +203947712, 204078272, 204208192, 204341056, 204472256, 204603328, +204733888, 204864448, 204996544, 205125568, 205258304, 205388864, +205517632, 205650112, 205782208, 205913536, 206044736, 206176192, +206307008, 206434496, 206569024, 206700224, 206831168, 206961856, +207093056, 207223616, 207355328, 207486784, 207616832, 207749056, +207879104, 208010048, 208141888, 208273216, 208404032, 208534336, +208666048, 208796864, 208927424, 209059264, 209189824, 209321792, +209451584, 209582656, 209715136, 209845568, 209976896, 210106432, +210239296, 210370112, 210501568, 210630976, 210763712, 210894272, +211024832, 211156672, 211287616, 211418176, 211549376, 211679296, +211812032, 211942592, 212074432, 212204864, 212334016, 212467648, +212597824, 212727616, 212860352, 212991424, 213120832, 213253952, +213385024, 213515584, 213645632, 213777728, 213909184, 214040128, +214170688, 214302656, 214433728, 214564544, 214695232, 214826048, +214956992, 215089088, 215219776, 215350592, 215482304, 215613248, +215743552, 215874752, 216005312, 216137024, 216267328, 216399296, +216530752, 216661696, 216790592, 216923968, 217054528, 217183168, +217316672, 217448128, 217579072, 217709504, 217838912, 217972672, +218102848, 218233024, 218364736, 218496832, 218627776, 218759104, +218888896, 219021248, 219151936, 219281728, 219413056, 219545024, +219675968, 219807296, 219938624, 220069312, 220200128, 220331456, +220461632, 220592704, 220725184, 220855744, 220987072, 221117888, +221249216, 221378368, 221510336, 221642048, 221772736, 221904832, +222031808, 222166976, 222297536, 222428992, 222559936, 222690368, +222820672, 222953152, 223083968, 223213376, 223345984, 223476928, +223608512, 223738688, 223869376, 224001472, 224132672, 224262848, +224394944, 224524864, 224657344, 224788288, 224919488, 225050432, +225181504, 225312704, 225443776, 225574592, 225704768, 225834176, +225966784, 226097216, 226229824, 226360384, 226491712, 226623424, +226754368, 226885312, 227015104, 227147456, 227278528, 227409472, +227539904, 227669696, 227802944, 227932352, 228065216, 228196288, +228326464, 228457792, 228588736, 228720064, 228850112, 228981056, +229113152, 229243328, 229375936, 229505344, 229636928, 229769152, +229894976, 230030272, 230162368, 230292416, 230424512, 230553152, +230684864, 230816704, 230948416, 231079616, 231210944, 231342016, +231472448, 231603776, 231733952, 231866176, 231996736, 232127296, +232259392, 232388672, 232521664, 232652608, 232782272, 232914496, +233043904, 233175616, 233306816, 233438528, 233569984, 233699776, +233830592, 233962688, 234092224, 234221888, 234353984, 234485312, +234618304, 234749888, 234880832, 235011776, 235142464, 235274048, +235403456, 235535936, 235667392, 235797568, 235928768, 236057152, +236190272, 236322752, 236453312, 236583616, 236715712, 236846528, +236976448, 237108544, 237239104, 237371072, 237501632, 237630784, +237764416, 237895232, 238026688, 238157632, 238286912, 238419392, +238548032, 238681024, 238812608, 238941632, 239075008, 239206336, +239335232, 239466944, 239599168, 239730496, 239861312, 239992384, +240122816, 240254656, 240385856, 240516928, 240647872, 240779072, +240909632, 241040704, 241171904, 241302848, 241433408, 241565248, +241696192, 241825984, 241958848, 242088256, 242220224, 242352064, +242481856, 242611648, 242744896, 242876224, 243005632, 243138496, +243268672, 243400384, 243531712, 243662656, 243793856, 243924544, +244054592, 244187072, 244316608, 244448704, 244580032, 244710976, +244841536, 244972864, 245104448, 245233984, 245365312, 245497792, +245628736, 245759936, 245889856, 246021056, 246152512, 246284224, +246415168, 246545344, 246675904, 246808384, 246939584, 247070144, +247199552, 247331648, 247463872, 247593536, 247726016, 247857088, +247987648, 248116928, 248249536, 248380736, 248512064, 248643008, +248773312, 248901056, 249036608, 249167552, 249298624, 249429184, +249560512, 249692096, 249822784, 249954112, 250085312, 250215488, +250345792, 250478528, 250608704, 250739264, 250870976, 251002816, +251133632, 251263552, 251395136, 251523904, 251657792, 251789248, +251919424, 252051392, 252182464, 252313408, 252444224, 252575552, +252706624, 252836032, 252968512, 253099712, 253227584, 253361728, +253493056, 253623488, 253754432, 253885504, 254017216, 254148032, +254279488, 254410432, 254541376, 254672576, 254803264, 254933824, +255065792, 255196736, 255326528, 255458752, 255589952, 255721408, +255851072, 255983296, 256114624, 256244416, 256374208, 256507712, +256636096, 256768832, 256900544, 257031616, 257162176, 257294272, +257424448, 257555776, 257686976, 257818432, 257949632, 258079552, +258211136, 258342464, 258473408, 258603712, 258734656, 258867008, +258996544, 259127744, 259260224, 259391296, 259522112, 259651904, +259784384, 259915328, 260045888, 260175424, 260308544, 260438336, +260570944, 260700992, 260832448, 260963776, 261092672, 261226304, +261356864, 261487936, 261619648, 261750592, 261879872, 262011968, +262143424, 262274752, 262404416, 262537024, 262667968, 262799296, +262928704, 263061184, 263191744, 263322944, 263454656, 263585216, +263716672, 263847872, 263978944, 264108608, 264241088, 264371648, +264501184, 264632768, 264764096, 264895936, 265024576, 265158464, +265287488, 265418432, 265550528, 265681216, 265813312, 265943488, +266075968, 266206144, 266337728, 266468032, 266600384, 266731072, +266862272, 266993344, 267124288, 267255616, 267386432, 267516992, +267648704, 267777728, 267910592, 268040512, 268172096, 268302784, +268435264, 268566208, 268696256, 268828096, 268959296, 269090368, +269221312, 269352256, 269482688, 269614784, 269745856, 269876416, +270007616, 270139328, 270270272, 270401216, 270531904, 270663616, +270791744, 270924736, 271056832, 271186112, 271317184, 271449536, +271580992, 271711936, 271843136, 271973056, 272105408, 272236352, +272367296, 272498368, 272629568, 272759488, 272891456, 273022784, +273153856, 273284672, 273415616, 273547072, 273677632, 273808448, +273937088, 274071488, 274200896, 274332992, 274463296, 274595392, +274726208, 274857536, 274988992, 275118656, 275250496, 275382208, +275513024, 275643968, 275775296, 275906368, 276037184, 276167872, +276297664, 276429376, 276560576, 276692672, 276822976, 276955072, +277085632, 277216832, 277347008, 277478848, 277609664, 277740992, +277868608, 278002624, 278134336, 278265536, 278395328, 278526784, +278657728, 278789824, 278921152, 279052096, 279182912, 279313088, +279443776, 279576256, 279706048, 279838528, 279969728, 280099648, +280230976, 280361408, 280493632, 280622528, 280755392, 280887104, +281018176, 281147968, 281278912, 281411392, 281542592, 281673152, +281803712, 281935552, 282066496, 282197312, 282329024, 282458816, +282590272, 282720832, 282853184, 282983744, 283115072, 283246144, +283377344, 283508416, 283639744, 283770304, 283901504, 284032576, +284163136, 284294848, 284426176, 284556992, 284687296, 284819264, +284950208, 285081536] +``` diff --git a/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md new file mode 100644 index 00000000000..0ee31eea904 --- /dev/null +++ b/public/content/translations/pl/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md @@ -0,0 +1,42 @@ +--- +title: Algorytmy kopania +description: "Szczegółowe spojrzenie na algorytmy używane do wydobywania Ethereum." +lang: pl +--- + + + + + +proof-of-work nie jest już podstawowym mechanizmem konsensusu Ethereum, co oznacza, że kopanie zostało wyłączone. Zamiast tego, sieć Ethereum jest zabezpieczona przez walidatorów, którzy stakują ETH. Możesz zacząć stakować swoje ETH już dziś. Przeczytaj więcej na The Merge, proof-of-stake, oraz staking. Ta strona ma charakter wyłącznie historyczny. + + + + +Wydobywanie Ethereum używało algorytmu znanego jako Ethash. Podstawowa idea algorytmu polega na tym, że górnik próbuje znaleźć wejście nonce za pomocą obliczeń siłowych, tak aby wynikowy hasz był mniejszy niż próg określony przez obliczoną trudność. Ten poziom trudności może być dynamicznie dostosowywany, co pozwala na tworzenie bloków w regularnych odstępach czasu. + +## Wymagania wstępne {#prerequisites} + +Aby lepiej zrozumieć tę stronę, zalecamy najpierw zapoznanie się z [konsensusem proof-of-work](/developers/docs/consensus-mechanisms/pow) i [wydobywaniem](/developers/docs/consensus-mechanisms/pow/mining). + +## Dagger Hashimoto {#dagger-hashimoto} + +Dagger Hashimoto był prekursorem algorytmu badawczego do wydobywania Ethereum, który został zastąpiony przez Ethash. Był to amalgamat dwóch różnych algorytmów: Dagger i Hashimoto. Była to tylko implementacja badawcza i została zastąpiona przez Ethash w momencie uruchomienia sieci głównej Ethereum. + +[Dagger](http://www.hashcash.org/papers/dagger.html) polega na generowaniu [skierowanego grafu acyklicznego](https://en.wikipedia.org/wiki/Directed_acyclic_graph), którego losowe fragmenty są razem haszowane. Podstawową zasadą jest to, że każdy nonce wymaga tylko niewielkiej części dużego, całkowitego drzewa danych. Ponowne obliczanie poddrzewa dla każdego nonce jest zbyt kosztowne dla wydobywania — stąd potrzeba przechowywania drzewa — ale jest w porządku w przypadku weryfikacji wartości pojedynczego nonce. Dagger został zaprojektowany jako alternatywa dla istniejących algorytmów, takich jak Scrypt, które są trudne pamięciowo, ale trudne do zweryfikowania, gdy ich trudność pamięciowa wzrasta do prawdziwie bezpiecznych poziomów. Jednakże Dagger był podatny na akcelerację sprzętową pamięci współdzielonej i został porzucony na rzecz innych kierunków badań. + +[Hashimoto](http://diyhpl.us/%7Ebryan/papers2/bitcoin/meh/hashimoto.pdf) to algorytm, który dodaje odporność na ASIC poprzez bycie ograniczonym przez operacje wejścia/wyjścia (I/O bound) (tzn. odczyty z pamięci są czynnikiem ograniczającym w procesie wydobycia). Teoria głosi, że pamięć RAM jest bardziej dostępna niż moc obliczeniowa; badania warte miliardy dolarów już zajmowały się optymalizacją pamięci RAM dla różnych przypadków użycia, które często obejmują wzorce dostępu bliskie losowemu (stąd „pamięć o dostępie swobodnym”). W rezultacie istniejąca pamięć RAM jest prawdopodobnie umiarkowanie bliska optymalnej do oceny algorytmu. Hashimoto używa blockchaina jako źródła danych, jednocześnie spełniając warunki (1) i (3) powyżej. + +Dagger-Hashimoto używał zmodyfikowanych wersji algorytmów Dagger i Hashimoto. Różnica między Dagger Hashimoto a Hashimoto polega na tym, że zamiast używać blockchaina jako źródła danych, Dagger Hashimoto używa niestandardowego zestawu danych, który jest aktualizowany na podstawie danych z bloku co N bloków. Zestaw danych jest generowany przy użyciu algorytmu Dagger, co pozwala na wydajne obliczanie podzbioru specyficznego dla każdego nonce dla algorytmu weryfikacji lekkiego klienta. Różnica między Dagger Hashimoto a Dagger polega na tym, że w przeciwieństwie do oryginalnego Daggera zbiór danych używany do odpytywania bloku jest częściowo stały i aktualizowany tylko w określonych odstępach czasu (np. raz w tygodniu). Oznacza to, że część wysiłku związanego z generowaniem zbioru danych jest bliska zeru, więc argumenty Sergio Lernera dotyczące przyspieszenia pamięci współdzielonej stają się znikome. + +Więcej o [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto). + +## Ethash {#ethash} + +Ethash był algorytmem wydobywczym, który był faktycznie używany w prawdziwej sieci głównej Ethereum w ramach przestarzałej już architektury proof-of-work. Ethash był w rzeczywistości nową nazwą nadaną określonej wersji Dagger-Hashimoto po tym, jak algorytm został znacznie zaktualizowany, jednocześnie dziedzicząc podstawowe zasady swojego poprzednika. Sieć główna Ethereum używała tylko Ethash — Dagger Hashimoto był wersją badawczo-rozwojową (R&D) algorytmu wydobywczego, który został zastąpiony, zanim rozpoczęto wydobywanie w sieci głównej Ethereum. + +[Więcej o Ethash](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash). + +## Dalsza lektura {#further-reading} + +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ diff --git a/public/content/translations/pl/developers/docs/dapps/index.md b/public/content/translations/pl/developers/docs/dapps/index.md index 81d8b01ac0f..00b0e26168b 100644 --- a/public/content/translations/pl/developers/docs/dapps/index.md +++ b/public/content/translations/pl/developers/docs/dapps/index.md @@ -1,96 +1,96 @@ --- -title: Wprowadzenie do zdecentralizowanych aplikacji +title: Wprowadzenie techniczne do dapek description: lang: pl --- -Zdecentralizowana aplikacja (dapp) to aplikacja zbudowana na zdecentralizowanej sieci, która łączy [inteligentny kontrakt](/developers/docs/smart-contracts/) i frontendowy interfejs użytkownika. Pamiętaj, że inteligentne kontrakty Ethereum są dostępne i przejrzyste – jak otwarte API – aby aplikacja dapp mogła nawet zawierać inteligentny kontrakt, który ktoś inny napisał. +Zdecentralizowana aplikacja (dapp) to aplikacja zbudowana w zdecentralizowanej sieci, która łączy [smart kontrakt](/developers/docs/smart-contracts/) i frontendowy interfejs użytkownika. Pamiętaj, że inteligentne kontrakty Ethereum są dostępne i przejrzyste – jak otwarte API – aby aplikacja dapp mogła nawet zawierać inteligentny kontrakt, który ktoś inny napisał. -## Warunki wstępne {#prerequisites} +## Wymagania wstępne {#prerequisites} -Zanim dowiesz się więcej o zdecentralizowanych aplikacjach, radzimy zapoznać się z podstawami [blockchain](/developers/docs/intro-to-ethereum/) oraz przeczytać o sieci Ethereum oraz o jej zdecentralizowanym charakterze. +Zanim zaczniesz uczyć się o dapkach, powinieneś zapoznać się z [podstawami blockchaina](/developers/docs/intro-to-ethereum/) i przeczytać o sieci Ethereum oraz o tym, jak jest ona zdecentralizowana. -## Definicja dapp {#definition-of-a-dapp} +## Definicja dapki {#definition-of-a-dapp} Dapp ma swój kod backend uruchomiony w zdecentralizowanej sieci peer-to-peer. Porównaj to z aplikacją, w której kod backendu jest uruchomiony na scentralizowanych serwerach. -Dapp może mieć kod frontend i interfejsy użytkownika napisane w dowolnym języku (tak jak aplikacja), który może wywoływać do swojego backendu. Co więcej, jej frontend może być hostowany w zdecentralizowanej pamięci masowej, takiej jak [IPFS](https://ipfs.io/). +Dapka może mieć kod frontendowy i interfejsy użytkownika napisane w dowolnym języku (tak jak aplikacja), które umożliwiają wywołania do jej backendu. Ponadto jej frontend może być hostowany w zdecentralizowanej pamięci masowej, takiej jak [IPFS](https://ipfs.io/). -- **Zdecentralizowane**, tzn. działają na Ethereum, otwartej publicznej zdecentralizowanej platformie, na której żadna osoba ani grupa nie sprawuje kontroli -- **Deterministyczne**, tzn. wykonują tę samą funkcję niezależnie od środowiska, w którym są wykonywane. -- **Kompletność Turinga**, tzn. mogą wykonać dowolną czynność, jeśli posiadają wymagane zasoby -- **Odizolowane**, tzn. są realizowane w wirtualnym środowisku zwanym maszyną wirtualną Ethereum, więc jeśli inteligentny kontrakt zawiera błąd, nie zaburzy to normalnego funkcjonowania sieci blockchain +- **Zdecentralizowane** – dapki działają na Ethereum, otwartej, publicznej, zdecentralizowanej platformie, na której żadna osoba ani grupa nie sprawuje kontroli. +- **Deterministyczne** – dapki wykonują tę samą funkcję niezależnie od środowiska, w którym są uruchamiane. +- **Kompletne w sensie Turinga** – dapki mogą wykonać dowolne działanie, pod warunkiem posiadania wymaganych zasobów. +- **Izolowane** – dapki są wykonywane w wirtualnym środowisku znanym jako Wirtualna Maszyna Ethereum, więc jeśli smart kontrakt będzie miał błąd, nie zakłóci to normalnego funkcjonowania sieci blockchain. -### O inteligentnych kontraktach {#on-smart-contracts} +### O smart kontraktach {#on-smart-contracts} -Aby wprowadzić dapps, musimy wprowadzić inteligentne kontrakty – backend dapps z powodu braku lepszego terminu. Szczegółowe informacje znajdują się w naszej części o [inteligentnych kontraktach](/developers/docs/smart-contracts/). +Aby wprowadzić dapps, musimy wprowadzić inteligentne kontrakty – backend dapps z powodu braku lepszego terminu. Aby uzyskać szczegółowy przegląd, przejdź do naszej sekcji o [smart kontraktach](/developers/docs/smart-contracts/). Inteligentny kontrakt to kod, który znajduje się na blockchainie Ethereum i działa dokładnie tak, jak zaprogramowano. Po wdrożeniu inteligentnych kontraktów w sieci nie można ich zmienić. Aplikacje mogą być zdecentralizowane, ponieważ są kontrolowane przez logikę zapisaną w kontrakcie, a nie przez osobę prywatną czy firmę. Oznacza to również, że trzeba bardzo uważnie projektować kontrakty i dokładnie je testować. -## Korzyści z rozwoju dapp {#benefits-of-dapp-development} +## Zalety tworzenia dapek {#benefits-of-dapp-development} -- **Zero przestojów** – Po wdrożeniu inteligentnego kontraktu na blockchainie sieć jako całość zawsze będzie w stanie obsługiwać klientów, którzy chcą wchodzić w interakcję z kontraktem. Złośliwe podmioty nie mogą zatem uruchamiać ataków typu „denial-of-service” ukierunkowanych na poszczególne aplikacje. -- **Prywatność** – nie musisz podawać rzeczywistej tożsamości, aby wdrożyć aplikację lub korzystać z niej. -- **Odporność na cenzurę** – żaden pojedynczy podmiot w sieci nie może zablokować użytkownikom możliwości przesyłania transakcji, wdrażania aplikacji lub odczytywania danych z blockchaina. +- **Zero przestojów** – gdy smart kontrakt zostanie wdrożony w blockchainie, sieć jako całość zawsze będzie w stanie obsługiwać klientów, którzy chcą wejść w interakcję z kontraktem. Dlatego złośliwe podmioty nie mogą przeprowadzać ataków typu „odmowa usługi” (denial-of-service) wymierzonych w poszczególne dapki. +- **Prywatność** – nie musisz podawać swojej prawdziwej tożsamości, aby wdrożyć dapką lub wejść z nią w interakcję. +- **Odporność na cenzurę** – żaden pojedynczy podmiot w sieci nie może uniemożliwić użytkownikom przesyłania transakcji, wdrażania dapek ani odczytywania danych z blockchaina. - **Pełna integralność danych** – dane przechowywane w blockchainie są niezmienne i niepodważalne dzięki prymitywom kryptograficznym. Złośliwe podmioty nie mogą tworzyć transakcji ani innych danych, które zostały już podane do wiadomości publicznej. -- **Obliczenie niewymagające zaufania/weryfikowalne zachowanie** – Inteligentne kontrakty mogą być analizowane i mają gwarancję realizacji w przewidywalny sposób bez konieczności ufania organowi centralnemu. Nie dotyczy to tradycyjnych modeli; na przykład, gdy korzystamy z systemów bankowości internetowej, musimy ufać, że instytucje finansowe nie będą nadużywać naszych danych finansowych, ingerować w zapisy ani nie zostaną zhakowane. +- **Obliczenia niewymagające zaufania/weryfikowalne zachowanie** – smart kontrakty można analizować i mieć gwarancję, że wykonają się w przewidywalny sposób, bez konieczności ufania organowi centralnemu. Nie jest to prawdą w tradycyjnych modelach; na przykład, gdy korzystamy z systemów bankowości internetowej, musimy ufać, że instytucje finansowe nie będą niewłaściwie wykorzystywać naszych danych finansowych, ingerować w zapisy ani nie zostaną zhakowane. -## Wady rozwoju dapp {#drawbacks-of-dapp-development} +## Wady tworzenia dapek {#drawbacks-of-dapp-development} -- **Utrzymanie** – Zdecentralizowane aplikacje mogą być trudniejsze do utrzymania, ponieważ kod i dane publikowane w blockchainie są trudniejsze do modyfikacji. Deweloperom jest trudno dokonywać aktualizacji swoich zdecentralizowanych aplikacji (lub podstawowych danych przechowywanych przez dapp) po ich wdrożeniu, nawet jeśli zostaną zidentyfikowane błędy lub zagrożenia bezpieczeństwa w starej wersji. -- **Koszty ogólne wydajności** – Koszty ogólne są ogromne, a skalowanie jest naprawdę trudne. Aby osiągnąć poziom bezpieczeństwa, integralności, przejrzystości i niezawodności, do którego dąży Ethereum, każdy węzeł prowadzi i przechowuje każdą transakcję. Ponadto konsensus proof-of-stake również wymaga czasu. -- **Zatłoczenie sieci** – Kiedy jedna zdecentralizowana aplikacja używa zbyt wielu zasobów obliczeniowych, cała sieć zostaje zablokowana. Obecnie sieć jest w stanie przetwarzać tylko około 10-15 transakcji na sekundę; jeżeli transakcje są wysyłane szybciej, pula niepotwierdzonych transakcji może szybko wzrosnąć. -- **Doświadczenia użytkownika** – Tworzenie przyjaznych dla użytkownika doświadczeń może być trudniejsze, ponieważ przeciętny użytkownik końcowy może uznać, że skonfigurowanie stosu narzędzi niezbędnych do interakcji z blockchainem w naprawdę bezpieczny sposób to zbyt trudne zadanie. -- **Centralizacja** – Przyjazne dla użytkownika i programisty rozwiązania zbudowane na bazowej warstwie Ethereum mogą i tak ostatecznie przybrać formę podobną do scentralizowanych usług. Na przykład takie usługi mogą przechowywać klucze lub inne poufne informacje po stronie serwera, zapewniać frontend za pomocą scentralizowanego serwera lub uruchamiać ważną logikę biznesową na scentralizowanym serwerze przed zapisaniem w blockchainie. Centralizacja eliminuje wiele (jeśli nie wszystkie) przewagi blockchainu nad tradycyjnym modelem. +- **Utrzymanie** – dapki mogą być trudniejsze w utrzymaniu, ponieważ kod i dane opublikowane w blockchainie są trudniejsze do zmodyfikowania. Deweloperom jest trudno dokonywać aktualizacji swoich zdecentralizowanych aplikacji (lub podstawowych danych przechowywanych przez dapp) po ich wdrożeniu, nawet jeśli zostaną zidentyfikowane błędy lub zagrożenia bezpieczeństwa w starej wersji. +- **Narzut wydajnościowy** – występuje ogromny narzut wydajnościowy, a skalowanie jest naprawdę trudne. Aby osiągnąć poziom bezpieczeństwa, integralności, przejrzystości i niezawodności, do którego dąży Ethereum, każdy węzeł prowadzi i przechowuje każdą transakcję. Ponadto konsensus proof-of-stake również wymaga czasu. +- **Przeciążenie sieci** – gdy jedna dapka zużywa zbyt wiele zasobów obliczeniowych, cała sieć ulega spowolnieniu. Obecnie sieć jest w stanie przetwarzać tylko około 10-15 transakcji na sekundę; jeżeli transakcje są wysyłane szybciej, pula niepotwierdzonych transakcji może szybko wzrosnąć. +- **Doświadczenie użytkownika** – projektowanie przyjaznych dla użytkownika doświadczeń może być trudniejsze, ponieważ przeciętny użytkownik końcowy może uznać za zbyt trudne skonfigurowanie stosu narzędzi niezbędnego do interakcji z blockchainem w naprawdę bezpieczny sposób. +- **Centralizacja** – przyjazne dla użytkownika i deweloperów rozwiązania zbudowane na warstwie bazowej Ethereum i tak mogą w końcu wyglądać jak scentralizowane usługi. Na przykład takie usługi mogą przechowywać klucze lub inne poufne informacje po stronie serwera, zapewniać frontend za pomocą scentralizowanego serwera lub uruchamiać ważną logikę biznesową na scentralizowanym serwerze przed zapisaniem w blockchainie. Centralizacja eliminuje wiele (jeśli nie wszystkie) przewagi blockchainu nad tradycyjnym modelem. -## Jesteś raczej wzrokowcem? {#visual-learner} +## Jesteś raczej wzrokowcem? Dla wzrokowców {#visual-learner} -## Narzędzia do tworzenia zdecentralizowanych aplikacji {#dapp-tools} +## Narzędzia do tworzenia dapek {#dapp-tools} -**Scaffold-ETH _— Szybko eksperymentuj z Solidity używając frontendu, który dostosowuje się do Twojego inteligentnego kontraktu._** +**Scaffold-ETH _- Szybko eksperymentuj z Solidity, używając frontendu, który dostosowuje się do Twojego smart kontraktu._** - [GitHub](https://github.com/scaffold-eth/scaffold-eth-2) -- [Przykładowy dapp](https://punkwallet.io/) +- [Przykładowa dapka](https://punkwallet.io/) -**Create Eth App _— Twórz aplikacje oparte na Ethereum za pomocą jednego polecenia._** +**Create Eth App _- Twórz aplikacje oparte na Ethereum za pomocą jednego polecenia._** - [GitHub](https://github.com/paulrberg/create-eth-app) -**One Click Dapp _— Narzędzie FOSS do generowania frontendów zdecentralizowanych aplikacji z [ABI](/glossary/#abi)._** +**One Click Dapp _- Narzędzie FOSS do generowania frontendów dla dapek na podstawie [ABI](/glossary/#abi)._** - [oneclickdapp.com](https://oneclickdapp.com) - [GitHub](https://github.com/oneclickdapp/oneclickdapp-v1) -**Etherflow _— Narzędzie FOSS dla deweloperów Ethereum do testowania ich węzła i tworzenia oraz debugowania wywołań RPC z przeglądarki._** +**Etherflow _- Narzędzie FOSS dla deweloperów Ethereum do testowania węzłów oraz tworzenia i debugowania wywołań RPC z poziomu przeglądarki._** - [etherflow.quiknode.io](https://etherflow.quiknode.io/) - [GitHub](https://github.com/abunsen/etherflow) -**thirdweb _— SDK w każdym języku, inteligentne kontrakty, narzędzia i infrastruktura do rozwoju web3._** +**thirdweb _- Zestawy SDK we wszystkich językach, smart kontrakty, narzędzia i infrastruktura do rozwoju web3._** - [Strona główna](https://thirdweb.com/) - [Dokumentacja](https://portal.thirdweb.com/) - [GitHub](https://github.com/thirdweb-dev/) -**Crossmint _ — platforma programistyczna Web3 klasy korporacyjnej służąca do wdrażania inteligentnych kontraktów, umożliwiania płatności kartą kredytową i płatności międzyłańcuchami oraz wykorzystywania API do tworzenia, udostępniania, sprzedawania, przechowywania oraz edytowania NFT._** +**Crossmint _- Platforma programistyczna web3 klasy korporacyjnej do wdrażania smart kontraktów, włączania płatności kartami kredytowymi i międzyłańcuchowych oraz używania API do tworzenia, dystrybucji, sprzedaży, przechowywania i edytowania NFT._** - [crossmint.com](https://www.crossmint.com) - [Dokumentacja](https://docs.crossmint.com) - [Discord](https://discord.com/invite/crossmint) -## Dodatkowo przeczytaj {#further-reading} +## Dalsza lektura {#further-reading} -- [Przeglądaj zdecentralizowane aplikacje](/apps) -- [Architektura aplikacji Web 3.0](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) — _Preethi Kasireddy_ -- [Przewodnik z 2021 r. po zdecentralizowanych aplikacjach](https://limechain.tech/blog/what-are-dapps-the-2021-guide/) — _LimeChain_ -- [Czym są zdecentralizowane aplikacje?](https://www.gemini.com/cryptopedia/decentralized-applications-defi-dapps) — _Gemini_ -- [Popularne zdecentralizowane aplikacje](https://www.alchemy.com/dapps) — _Alchemy_ +- [Przeglądaj dapki](/apps) +- [Architektura aplikacji Web 3.0](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) – _Preethi Kasireddy_ +- [Przewodnik po aplikacjach zdecentralizowanych 2021](https://limechain.tech/blog/what-are-dapps-the-2021-guide/) - _LimeChain_ +- [Czym są aplikacje zdecentralizowane?](https://www.gemini.com/cryptopedia/decentralized-applications-defi-dapps) - _Gemini_ +- [Popularne dapki](https://www.alchemy.com/dapps) - _Alchemy_ -_Wiesz o zasobach społecznościowych, które Ci pomogły? Wyedytuj tę stronę i dodaj je!_ +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ -## Tematy powiązane {#related-topics} +## Powiązane tematy {#related-topics} - [Wprowadzenie do stosu Ethereum](/developers/docs/ethereum-stack/) -- [Frameworki programistyczne](/developers/docs/frameworks/) +- [Frameworki deweloperskie](/developers/docs/frameworks/) diff --git a/public/content/translations/pl/developers/docs/data-and-analytics/block-explorers/index.md b/public/content/translations/pl/developers/docs/data-and-analytics/block-explorers/index.md index 07c6f49dd83..b5456a94362 100644 --- a/public/content/translations/pl/developers/docs/data-and-analytics/block-explorers/index.md +++ b/public/content/translations/pl/developers/docs/data-and-analytics/block-explorers/index.md @@ -1,278 +1,254 @@ --- -title: Eksploratory bloków -description: Wprowadzenie do eksploratorów bloków, portalu do świata danych blockchain, w którym możesz wyszukiwać informacje o transakcjach, kontach, kontraktach i nie tylko. +title: "Eksploratory bloków" +description: "Wprowadzenie do eksploratorów bloków, portalu do świata danych blockchain, w którym możesz wyszukiwać informacje o transakcjach, kontach, kontraktach i nie tylko." lang: pl sidebarDepth: 3 --- -Eksploratory bloków są twoim portalem do danych Ethereum. Możesz ich użyć, aby zobaczyć dane w czasie rzeczywistym o blokach, transakcjach, górnikach, kontach i innych aktywnościach w łańcuchu dostaw. +Eksploratory bloków są twoim portalem do danych Ethereum. Można używać ich do śledzenia w czasie rzeczywistym danych o blokach, transakcjach, walidatorach, kontach oraz innych aktywnościach na łańcuchu. -## Warunki wstępne {#prerequisites} +## Wymagania wstępne {#prerequisites} Powinieneś zrozumieć podstawowe pojęcia Ethereum, abyś mógł zrozumieć dane, które daje Ci eksplorator bloków. Zacznij od [wprowadzenia do Ethereum](/developers/docs/intro-to-ethereum/). ## Usługi {#services} -- [Etherscan](https://etherscan.io/) – _dostępne również w języku chińskim, koreańskim, rosyjskim i japońskim_ -- [Etherchain](https://www.etherchain.org/) -- [Ethplorer](https://ethplorer.io/) -- [Blockchair](https://blockchair.com/ethereum) – _dostępne również w języku hiszpańskim, francuskim, włoskim, niderlandzkim, portugalskim, rosyjskim, chińskim i farsi_ +- [Etherscan](https://etherscan.io/) – _Dostępny również w języku chińskim, koreańskim, rosyjskim i japońskim_ +- [3xpl](https://3xpl.com/ethereum) +- [Beaconcha.in](https://beaconcha.in/) +- [Blockchair](https://blockchair.com/ethereum) – _Dostępny również w języku hiszpańskim, francuskim, włoskim, holenderskim, portugalskim, rosyjskim, chińskim i perskim_ - [Blockscout](https://eth.blockscout.com/) +- [Chainlens](https://www.chainlens.com/) +- [Eksplorator bloków DexGuru](https://ethereum.dex.guru/) +- [Etherchain](https://www.etherchain.org/) +- [Ethplorer](https://ethplorer.io/) – _Dostępny również w języku chińskim, hiszpańskim, francuskim, tureckim, rosyjskim, koreańskim i wietnamskim_ +- [EthVM](https://www.ethvm.com/) - [OKLink](https://www.oklink.com/eth) +- [Ethseer](https://ethseer.io) -## Dane {#data} - -Ethereum jest zgodnie z projektem przezroczyste, więc wszystko jest możliwe do zweryfikowania. Eksploratory bloków zapewniają interfejs do uzyskania tych informacji. Dotyczy to zarówno głównej sieci Ethereum, jak i sieci testowych, jeśli potrzebujesz tych danych. - -Oto podsumowanie typów danych, które możesz uzyskać z eksploratora bloków. +## Narzędzia open source {#open-source-tools} -### Bloki {#blocks} +- [Otterscan](https://otterscan.io/) +- [lazy-etherscan](https://github.com/woxjro/lazy-etherscan) -Nowe bloki są dodawane do Ethereum co ~12 sekund (może się to wahać), istnieje niemal stały strumień danych, które zostają dodane do eksploratorów bloków. Bloki zawierają wiele ważnych danych, które mogą okazać się przydatne: +## Dane {#data} -**Standardowe dane** +Ethereum jest zgodnie z projektem przezroczyste, więc wszystko jest możliwe do zweryfikowania. Eksploratory bloków zapewniają interfejs do uzyskania tych informacji. Dotyczy to zarówno głównej sieci Ethereum, jak i sieci testowych, jeśli potrzebujesz tych danych. Dane są podzielone na dane wykonania i dane konsensusu. Dane wykonania odnoszą się do transakcji, które zostały zrealizowane w określonym bloku. Dane konsensusu odnoszą się do samych bloków i walidatorów, którzy je zaproponowali. -- Wysokość bloku – numer i długość blockchaina (w blokach) przy tworzeniu bieżącego bloku. -- Znacznik czasu – czas, w którym górnik wydobył blok. -- Transakcje – liczba transakcji objętych blokiem. -- Górnik – adres górnika, który wydobył blok. -- Nagroda – kwota ETH przyznana górnikowi za dodanie bloku (standardowa nagroda 2ETH + wszelkie opłaty transakcyjne z transakcji zawartych w bloku). -- Trudność – trudności związane z wydobyciem bloku. -- Rozmiar – rozmiar danych w obrębie bloku (mierzony w bajtach). -- Zużyty gaz – całkowita ilość jednostek gazu wykorzystanych w transakcjach w bloku. -- Limit emisji gazu – całkowite limity gazu określone w transakcjach w bloku. -- Dodatkowe dane – wszelkie dodatkowe dane zawarte przez górnika w bloku. +Oto podsumowanie typów danych, które możesz uzyskać z eksploratora bloków. -**Zaawansowane dane** +### Dane wykonania {#execution-data} -- Hash – skrót kryptograficzny reprezentujący nagłówek bloku (unikalny identyfikator bloku). -- Hash nadrzędny – skrót bloku, który pojawił się przed bieżącym blokiem. -- Sha3Uncles – łączny skrót wszystkich bloków-wujów danego bloku nadrzędnego. -- StateRoot – główny hash drzewa Merkle, który przechowuje cały stan systemu. -- Nonce – wartość używana do wykazania proof-of-work dla bloku przez górnika. +Nowe bloki są dodawane do Ethereum co 12 sekund (chyba że wnioskodawca bloku przegapi swoją kolej), więc eksploratory bloków otrzymują niemal ciągły strumień danych. Bloki zawierają wiele ważnych danych, które mogą okazać się przydatne: -**Bloki-wuje** +**Dane standardowe** -Bloki-wuje powstają, gdy dwóch górników tworzy bloki niemal w tym samym czasie - tylko jeden blok może być potwierdzony przez węzły. Nie są one uwzględniane, ale nadal otrzymują nagrodę za pracę. +- Wysokość bloku — numer i długość blockchaina (w blokach) w chwili utworzenia bieżącego bloku +- Znacznik czasowy — czas zaproponowania bloku +- Transakcje — liczba transakcji zawartych w bloku +- Odbiorca opłaty — adres, który otrzymał napiwki z transakcji od opłat za gaz +- Nagroda za blok — kwota w ETH przyznana walidatorowi, który zaproponował blok +- Rozmiar — rozmiar danych w bloku (mierzony w bajtach) +- Zużyty gaz — całkowita ilość jednostek gazu zużyta przez transakcje w bloku +- Limit gazu — całkowite limity gazu określone przez transakcje w bloku +- Opłata podstawowa za gaz — minimalny mnożnik wymagany do uwzględnienia transakcji w bloku +- Spalone opłaty — ile ETH spalono w bloku +- Dodatkowe dane — wszystkie dodatkowe dane, które programista dołączyć do bloku -Eksploratory bloków dostarczają informacji o blokach-wujach, takie jak: +**Dane zaawansowane** -- Numer bloku-wuja. -- Czas jego wystąpienia. -- Wysokość bloku, na którym zostały utworzone. -- Kto wydobył. -- Nagroda ETH. +- Hash — skrót kryptograficzny reprezentujący nagłówek bloku (unikalny identyfikator bloku) +- Hash nadrzędny — skrót bloku, który pojawił się przed bieżącym blokiem +- StateRoot — główny hash drzewa Merkle, który przechowuje cały stan systemu -### Paliwo {#gas} +### Gaz {#gas} -Eksploratory bloków nie tylko dostarczą Ci danych o zużyciu gazu w transakcjach i blokach, ale niektóre z nich podadzą Ci informacje o aktualnych cenach gazu w sieci. Pomoże to zrozumieć użycie sieci, przesłać bezpieczne transakcje i nadmiernie nie wydawać pieniędzy na gaz. Poszukaj API, które pomogą Ci uzyskać te informacje w interfejsie Twojego produktu. Dane odnoszące się do danego gazu obejmują: +Eksploratory bloków nie tylko dostarczą Ci danych o zużyciu gazu w transakcjach i blokach — niektóre z nich podadzą Ci też informacje o aktualnych cenach gazu w sieci. Pomoże Ci to zrozumieć wykorzystanie sieci, dokonywać bezpiecznych transakcji i nie wydawać zbyt dużo na gaz. Poszukaj interfejsów API, które pomogą Ci uzyskać te informacje w interfejsie Twojego produktu. Dane zależne od gazu obejmują: -- Szacunkowe jednostki gazu potrzebne do bezpiecznej, ale wolnej transakcji (+ szacowana cena i czas trwania). -- Szacowane jednostki gazu potrzebne do średniej transakcji (+ szacunkowa cena i czas trwania). -- Szacowane jednostki gazu potrzebne do szybkiej transakcji (+ szacunkowa cena i czas trwania). -- Średni czas potwierdzenia w oparciu o cenę gazu. -- Kontrakty, które zużywają gaz – innymi słowy popularne produkty, które widzą wiele zastosowań w sieci. -- Konta wydające gaz – innymi słowy częstych użytkowników sieci. +- Szacunkowa liczba jednostek gazu potrzebna do bezpiecznej, ale powolnej transakcji (+ szacowana cena i czas trwania) +- Szacowana liczba jednostek gazu potrzebna do przeciętnej transakcji (+ szacunkowa cena i czas trwania) +- Szacowana liczba jednostek gazu potrzebna do szybkiej transakcji (+ szacunkowa cena i czas trwania) +- Średni czas potwierdzenia w zależności od ceny gazu +- Kontrakty, które zużywają gaz — innymi słowy popularne produkty, które mają wiele zastosowań w sieci +- Konta wydające gaz — innymi słowy, regularni użytkownicy sieci ### Transakcje {#transactions} -Eksploratory bloków stały się powszechnym miejscem, w którym ludzie mogą śledzić postęp swoich transakcji. Dzieje się tak, ponieważ poziom szczegółowości, który możesz uzyskać zapewnia dodatkową pewność. Dane transakcji obejmują: +Eksploratory bloków stały się popularnym miejscem, w którym ludzie mogą śledzić postęp swoich transakcji. Dzieje się tak, ponieważ możliwy do uzyskania poziom szczegółowości zapewnia dodatkową pewność. Dane transakcji obejmują: -**Standardowe dane** +**Dane standardowe** -- Skrót transakcji – skrót generowany po złożeniu transakcji. -- Status – wskazanie, czy transakcja jest w toku, nie powiodła się, czy też zakończyła się sukcesem. -- Blok– blok, w którym uwzględniono transakcję. -- Znacznik czasu – czas, w którym górnik wydobywał transakcję. -- Od – adres konta, które przeprowadziło transakcję. -- Adres odbiorcy lub inteligentnego kontraktu, z którym transakcja wchodzi w interakcje. -- Przesłane tokeny – lista tokenów, które zostały przekazane jako część transakcji. -- Wartość – całkowita przekazywana wartość ETH. -- Opłata transakcyjna – kwota zapłacona górnikowi w celu przetworzenia transakcji (obliczona na podstawie ceny gazu\*użytego gazu). +- Hash transakcji — skrót generowany po przesłaniu transakcji +- Status — wskazanie, czy transakcja jest w toku, nie powiodła się, czy też zakończyła się sukcesem +- Blok — blok, w którym uwzględniono transakcję +- Znacznik czasu — dokładny czas włączenia transakcji do bloku zaproponowanego przez walidatora +- Od — adres konta, które przesłało transakcję +- Do — adres odbiorcy lub inteligentnego kontraktu, z którym transakcja wchodzi w interakcję +- Przesłane tokeny — lista tokenów, które zostały przekazane w ramach transakcji +- Wartość — całkowita przekazywana wartość w ETH +- Opłata transakcyjna — kwota zapłacone walidatorowi w celu przetworzenia transakcji (obliczona tak: cena gazu\*użyty gaz) -**Zaawansowane dane** +**Dane zaawansowane** -- Limit gazu – maksymalna liczba jednostek gazu, jaką może zużyć dana transakcja. -- Zużyty gaz – faktyczna ilość gazu zużytego w ramach transakcji. -- Cena gazu – cena ustalona za jednostkę gazu. -- Nonce – numer transakcji dla adresu `od` (pamiętaj, że zaczyna się on od 0, więc nonce `100` byłby faktycznie 101. transakcją zgłoszoną przez to konto. -- Dane wejściowe – wszelkie dodatkowe informacje wymagane przez transakcję. +- Limit gazu — maksymalna liczba jednostek gazu, jaką może zużyć dana transakcja +- Zużyty gaz — faktyczna ilość jednostek gazu zużyta w ramach transakcji +- Cena gazu — ustalona cena jednostki gazu +- Nonce – numer transakcji dla adresu `from` (pamiętaj, że zaczyna się od 0, więc nonce o wartości `100` byłby w rzeczywistości 101. transakcją wysłaną przez to konto) +- Dane wejściowe — wszelkie dodatkowe informacje wymagane przez transakcję ### Konta {#accounts} -Istnieje mnóstwo danych, które możesz uzyskać na temat konta. Dlatego często zaleca się używanie wielu kont, aby Twoje aktywa i wartość nie były łatwe do śledzenia. Istnieją również pewne rozwiązania, które sprawią, że transakcje i operacje na kontach będą bardziej prywatne. Oto dane, które są dostępne dla kont: +Jest mnóstwo danych, które możesz uzyskać na temat konta. Dlatego często zalecane jest używanie wielu kont, aby utrudnić śledzenie Twoich aktywów i wartości. Dostępne są również pewne rozwiązania, dzięki którym transakcje i operacje na kontach będą bardziej prywatne. Oto dostępne dane kont: **Konta użytkowników** -- Adres konta – publiczny adres, na który możesz wysyłać środki. -- Saldo ETH – kwota ETH powiązana z tym kontem. -- Całkowita wartość ETH – wartość ETH. -- Tokeny – tokeny powiązane z kontem i ich wartość. -- Historia transakcji – lista wszystkich transakcji, w których to konto było nadawcą lub odbiorcą. +- Adres konta — publiczny adres, na który możesz wysyłać środki +- Saldo ETH — kwota ETH powiązana z danym kontem +- Całkowita wartość ETH — wartość ETH +- Tokeny — tokeny powiązane z kontem i ich wartość +- Historia transakcji — lista wszystkich transakcji, w których to konto było nadawcą lub odbiorcą **Inteligentne kontrakty** -Konta inteligentnych kontraktów mają wszystkie dane, które będzie mieć konto użytkownika, ale niektóre eksploratory bloków będą również wyświetlać pewne informacje o kodzie. Przykłady: +Konta inteligentnych kontraktów zawierają wszystkie dane, które zawiera konto użytkownika, ale niektóre eksploratory bloków będą również wyświetlać pewne informacje o kodzie. Przykłady: -- Twórca kontraktu – adres, który wdrożył kontrakt w sieci głównej. -- Transakcja utworzenia – transakcja, która obejmowała wdrożenie do sieci głównej. -- Kod źródłowy – kod solidity lub vyper inteligentnego kontraktu. -- ABI (Application Binary Interface) kontraktu – wywołania wykonywane przez umowę oraz otrzymane dane. -- Kod tworzenia kontraktu – skompilowany kod bajtowy inteligentnego kontraktu – utworzony podczas kompilacji inteligentnego kontraktu napisanego w Solidity lub Vyper itp. -- Wydarzenia kontraktu – historia metod wywołanych w inteligentnym kontrakcie. Zasadniczo sposób na sprawdzenie, w jaki sposób i jak często kontrakt jest wykorzystywany. +- Twórca kontraktu — adres, który wdrożył kontrakt w sieci głównej +- Transakcja utworzenia — transakcja, która obejmowała wdrożenie w sieci głównej +- Kod źródłowy — kod Solidity lub Vyper inteligentnego kontraktu +- ABI (Application Binary Interface) kontraktu — wywołania wykonywane przez kontrakt oraz otrzymane dane +- Kod tworzenia kontraktu — skompilowany kod bajtowy inteligentnego kontraktu, tworzony podczas kompilacji inteligentnego kontraktu napisanego w Solidity lub Vyper itd. +- Zdarzenia kontraktu — historia metod wywołanych w inteligentnym kontrakcie; zasadniczo jest to sposób sprawdzenia, w jaki sposób kontrakt jest używany i jak często ### Tokeny {#tokens} -Token jest rodzajem kontraktu, więc będzie mieć dane podobne do inteligentnego kontraktu. Ponieważ jednak tokeny mają wartość i mogą być przedmiotem obrotu, mają dodatkowe punkty danych: +Token jest typem kontraktu, więc będzie mieć dane podobne do inteligentnego kontraktu. Tokeny mają jednak wartość i mogą być przedmiotem obrotu, mają więc dodatkowe punkty danych: -- Typ – czy są one standardem ERC-20, ERC-721 czy innym standardem tokenów. -- Cena – jeśli są ERC-20, będą miały bieżącą wartość rynkową. -- Pułap rynkowy – jeśli są ERC-20, będą miały pułap rynkowy (obliczony na podstawie ceny\*całkowitej podaży). -- Całkowita podaż – liczba tokenów znajdujących się w obiegu. -- Posiadacze – liczba adresów, które posiadają token. -- Transfery – ile razy token został przeniesiony pomiędzy rachunkami. -- Historia transakcji – historia wszystkich transakcji zawierających token. -- Adres kontraktu – adres tokenu, który został wysłany do sieci głównej. -- Miejsca dziesiętne – tokeny ERC-20 są podzielne i mają miejsca dziesiętne. +- Typ — czy są one tokenami standardu ERC-20, ERC-721, czy też innego standardu tokenów +- Cena — jeśli są tokenami ERC-20, będą mieć bieżącą wartość rynkową +- Kapitalizacja rynkowa — jeśli są tokenami ERC-20, będą mieć kapitalizację rynkową (obliczoną na podstawie ceny \ \*całkowitej podaży) +- Całkowita podaż — liczba tokenów znajdujących się w obiegu +- Posiadacze — liczba adresów, które posiadają token +- Transfery — ile razy token został przeniesiony między kontami +- Historia transakcji — historia wszystkich transakcji zawierających token +- Adres kontraktu — adres tokena, który został wdrożony w sieci głównej +- Miejsca dziesiętne — tokeny ERC-20 są podzielne i mają miejsca dziesiętne ### Sieć {#network} -Oczywiście są pewne dane, które mówią o stanie sieci. Są one dość specyficzne dla mechanizmu konsensusu proof-of-work Ethereum. Gdy Ethereum przejdzie do Eth2, niektóre z tych danych będą zbędne - -- Trudność – aktualna trudność w wydobyciu. -- Częstotliwość haszowania – oszacowanie liczby hashów generowanych przez górników Ethereum próbujących rozwiązać bieżący blok Ethereum lub dowolny blok. -- Suma transakcji – liczba transakcji od czasu utworzenia Ethereum. -- Transakcje na sekundę – liczba transakcji możliwa do przetworzenia w ciągu sekundy. -- Cena ETH – bieżąca wycena 1 ETH. -- Całkowita podaż ETH – liczba ETH w obiegu – pamiętaj, że nowy ETH powstaje dzięki utworzeniu każdego bloku w formie nagród za bloki. -- Pułap rynkowy – obliczenie ceny\*podaży. - -## Dane Eth2 {#consensus-layer-data} +Niektóre dane bloków dotyczą kondycji Ethereum w bardziej holistycznym ujęciu. -Ulepszenia Eth2 są nadal w fazie rozwoju, ale warto wspomnieć o niektórych punktach danych, które eksplorery będą mogły Ci dostarczyć. W rzeczywistości wszystkie te dane są obecnie dostępne dla sieci testowych. +- Suma transakcji — liczba transakcji od czasu utworzenia Ethereum +- Transakcje na sekundę — liczba transakcji, które można przetworzyć w ciągu sekundy +- Cena ETH — bieżąca wycena 1 ETH +- Całkowita podaż ETH — liczba ETH w obiegu. Pamiętaj, że nowy ETH powstaje dzięki utworzeniu każdego bloku w postaci nagród za bloki +- Kapitalizacja rynkowa — obliczenie ceny\*podaży -Jeśli brak Ci wiedzy o Eth2, sprawdź [nasz przegląd ulepszeń Eth2](/roadmap/). +## Dane warstwy konsensusu {#consensus-layer-data} ### Epoka {#epoch} -Pierwsza aktualizacja Eth2, łańcuch śledzący Eth2, stworzy komitety walidatorów, które są losowo przydzielane na koniec każdej epoki (co 6,4 minuty) ze względów bezpieczeństwa. Dane dotyczące epoki obejmują: +Ze względów bezpieczeństwa pod koniec każdej epoki (co 6,4 minuty) tworzone są losowe komitety walidatorów. Dane dotyczące epoki obejmują: -- Numer epoki. -- Status końcowy – czy epoka została ukończona (Tak/Nie). -- Czas – czas zakończenia epoki. -- Poświadczenie – liczba poświadczeń w epoce (głosy za blokami w czasie). -- Depozyty – liczba depozytów ETH zawartych w epoce (walidatorzy muszą zestakować ETH, aby stać się walidatorami). -- Ograniczenia – liczba kar nałożonych na wnioskodawców bloków lub poświadczających. -- Udział w głosowaniu – ilość zestakowanego ETH użyta do poświadczenia bloków. -- Walidatory – liczba walidatorów aktywnych dla epoki. -- Średni bilans walidatora – średni bilans dla aktywnych walidatorów. -- Sloty – liczba slotów w epoce (sloty zawierają jeden ważny blok). +- Numer epoki +- Status końcowy — czy epoka została ukończona (Tak/Nie) +- Czas — czas zakończenia epoki +- Poświadczenia — liczba poświadczeń w epoce (głosy za blokami w slotach) +- Depozyty — liczba depozytów ETH zawartych w epoce (walidatorzy muszą zestakować ETH, aby stać się walidatorami) +- Cięcia — liczba kar nałożonych na proponentów bloków lub poświadczających +- Udział w głosowaniu — ilość zestakowanego ETH użyta do poświadczenia bloków +- Walidatorzy — liczba aktywnych walidatorów epoki +- Średnie saldo walidatora — średnie saldo aktywnych walidatorów +- Sloty — liczba slotów w epoce (sloty zawierają jeden ważny blok) ### Slot {#slot} -Sloty to możliwości tworzenia bloków, dane dostępne dla każdego slotu obejmują: - -- Epoka – epoka, w której slot jest ważny. -- Numer slotu. -- Status – status slotu (zaproponowany/pominięty). -- Czas – znacznik czasowy slotu. -- Proponujący – walidator, który zaproponował blok do slotu. -- Block root — główne drzewo haszujące BeaconBlock. -- Root nadrzędny — skrót bloku, który pojawił się wcześniej. -- Root stanu — główne drzewo haszujące BeaconState. -- Podpis. -- Ujawnienie randao. -- Graffiti – proponujący blok może uwzględnić 32-bajtową wiadomość w propozycji bloku. -- Dane ETH1. - - Hasz bloku. - - Liczba wpłat. - - Root wpłaty. -- Poświadczenia – liczba poświadczeń bloku w tym slocie. -- Depozyty – liczba depozytów w tym slocie. -- Dobrowolne wyjścia — liczba walidatorów, którzy opuścili slot. -- Ograniczenia – liczba kar nałożonych na wnioskodawców bloków lub poświadczających. -- Głosy - walidatorzy, którzy głosowali za blokiem w tym slocie. +Sloty to możliwości tworzenia bloków, dane dostępne w przypadku każdego slotu obejmują: + +- Epoka — epoka, w której slot jest ważny +- Numer slotu +- Status — status slotu (zaproponowany/pominięty) +- Czas — znacznik czasowy slotu +- Proponujący — walidator, który zaproponował blok do slotu +- Block root — główne drzewo haszujące BeaconBlock +- Root nadrzędny — skrót bloku, który pojawił się wcześniej +- Root stanu — główne drzewo haszujące BeaconState +- Podpis +- Ujawnienie ranDAO +- Graffiti — proponent bloku może zawrzeć 32-bajtową wiadomość w propozycji bloku +- Dane wykonania + - Hash bloku + - Liczba depozytów + - Root depozytu +- Poświadczenia — liczba poświadczeń bloku w tym slocie +- Depozyty — liczba depozytów w tym slocie +- Dobrowolne wyjścia — liczba walidatorów, którzy opuścili slot +- Cięcia — liczba kar nałożonych na proponentów bloków lub poświadczających +- Głosy — walidatorzy, którzy głosowali za blokiem w danym slocie ### Bloki {#blocks-1} -W Eth2 bloki działają inaczej, ponieważ górnicy są zastępowani przez walidatorów, a łańcuch śledzący wprowadza sloty i epoki do Ethereum. Więc oznacza to nowe dane! +Proof-of stake dzieli czas na sloty i epoki. Oznacza to nowe dane! -- Proponujący – walidator, który został wybrany algorytmicznie do zaproponowania nowego bloku. -- Epoka – epoka, w której zaproponowano blok. -- Slot – slot, w którym zaproponowano blok. -- Poświadczenia – liczba poświadczeń zawartych w slocie. Poświadczenia są jak głosy wskazujące, że blok jest gotowy do przejścia do łańcucha śledzącego. +- Proponujący — walidator, który został wybrany algorytmicznie do zaproponowania nowego bloku +- Epoka — epoka, w której zaproponowano blok +- Slot — slot, w którym zaproponowano blok +- Poświadczenia — liczba poświadczeń zawartych w slocie. Poświadczenia są jak głosy wskazujące, że blok jest gotowy do przekazania do łańcucha śledzącego ### Walidatorzy {#validators} Walidatorzy są odpowiedzialni za proponowanie bloków i poświadczanie ich w slotach. -- Numer walidatora – niepowtarzalny numer, który reprezentuje walidatora. -- Bieżące saldo – saldo walidatora, w tym nagrody. -- Efektywna równowaga – saldo walidatora, które jest wykorzystywane do stawkowania. -- Dochody – nagrody lub kary otrzymane przez walidatora. -- Status – czy walidator jest obecnie online i aktywny, czy nie. -- Skuteczność poświadczenia – średni czas potrzebny na włączenie poświadczeń walidatora do łańcucha. -- Kwalifikowalność do aktywacji – data (i epoka), kiedy walidator stał się dostępny do zatwierdzenia. -- Aktywne od – data (i epoka), kiedy walidator stał się aktywny. -- Proponowane bloki – blok zaproponowany przez walidatora. -- Poświadczenia – poświadczenia przedstawione przez walidatora. -- Depozyty – adres „od”, hash transakcji, numeru bloku, znacznik czasu, kwota i status depozytu zestakowanego przez walidatora. +- Numer walidatora — niepowtarzalny numer, który reprezentuje walidatora +- Bieżące saldo — saldo walidatora, w tym nagrody +- Efektywne saldo — saldo walidatora, które jest używane do stakowania +- Dochody — nagrody lub kary otrzymane przez walidatora +- Status — wskazuje, czy walidator jest obecnie online i czy jest aktywny +- Skuteczność poświadczenia — średni czas potrzebny na włączenie poświadczeń walidatora do łańcucha +- Kwalifikowalność do aktywacji — data (i epoka), kiedy walidator stał się dostępny do walidacji +- Aktywny od — data (i epoka), kiedy walidator stał się aktywny +- Proponowane bloki — blok zaproponowany przez walidatora +- Poświadczenia — poświadczenia przedstawione przez walidatora +- Depozyty — adres „od”, hash transakcji, numer bloku, znacznik czasu, kwota i status depozytu zestakowanego przez walidatora ### Poświadczenia {#attestations} -Poświadczenia to głosy za włączeniem bloków do łańcucha. Ich dane odnoszą się do zapisu poświadczenia i walidatorów poświadczających +Poświadczenia to głosy „za” włączeniem bloków do łańcucha. Ich dane odnoszą się do zapisu poświadczenia i walidatorów poświadczających -- Slot – slot, w którym odbyło się poświadczenie. -- Indeks komitetu – indeks komitetu w danym slocie. -- Bity agregacji – zagregowane poświadczenia wszystkich walidatorów uczestniczących w poświadczeniu. -- Walidatorzy – walidatorzy, którzy dostarczyli poświadczenia. -- Beacon block root – wskazuje na blok poświadczany przez walidatorów. -- Źródło – wskazuje na ostatnią uzasadnioną epokę. -- Cel – wskazuje na na ostatnią granicę epoki. -- Podpis. +- Slot — slot, w którym odbyło się poświadczenie +- Indeks komitetu — indeks komitetu w danym slocie +- Bity agregacji — zagregowane poświadczenia wszystkich walidatorów uczestniczących w poświadczeniu +- Walidatorzy — walidatorzy, którzy dostarczyli poświadczenia +- Root bloku śledzącego — wskazuje na blok poświadczany przez walidatorów +- Źródło — wskazuje na ostatnią uzasadnioną epokę +- Cel — wskazuje na granicę najnowszej epoki +- Podpis ### Sieć {#network-1} -Dane najwyższego poziomu Eth2 obejmują: +Dane najwyższego poziomu warstwy konsensusu obejmują: -- Bieżąca epoka. -- Bieżący slot. -- Aktywni walidatorzy – liczba aktywnych walidatorów. -- Oczekujący walidatorzy – liczba walidatorów oczekujących na aktywność. -- Zestakowane ETH – ilość ETH zestakowana w sieci. -- Średni bilans – średni bilans ETH walidatorów. +- Bieżąca epoka +- Bieżący slot +- Aktywni walidatorzy — liczba aktywnych walidatorów +- Walidatorzy oczekujący — liczba walidatorów oczekujących na aktywowanie +- Zestakowane ETH — ilość ETH zestakowana w sieci +- Średnie saldo — średnie saldo walidatorów w ETH ## Eksploratory bloków {#block-explorers} -- [Etherscan](https://etherscan.io/) – eksplorator bloków, którego możesz użyć do pobrania danych dla głównej sieci Ethereum i sieci testowej Sepolia. -- [3xpl](https://3xpl.com/ethereum) – eksplorator Ethereum typu open source bez reklam, pozwalający na pobieranie własnych zestawów danych. -- [Beaconcha.in](https://beaconcha.in/) – eksplorator bloków open source dla sieci głównej Ethereum i sieci testowej Sepolia. -- [Blockchair](https://blockchair.com/ethereum) – najbardziej prywatny eksplorator Ethereum. Także do sortowania i filtrowania danych (mempool). -- [Etherchain](https://www.etherchain.org/) – eksplorator bloków dla głównej sieci Ethereum. -- [Ethplorer](https://ethplorer.io/) – eksplorator bloków z naciskiem na tokeny dla głównej sieci Ethereum i sieci testowej Sepolia. -- [Rantom](https://rantom.app/) – otwarty i przyjazny dla użytkownika eksplorator transakcji NFT i DeFi dla bardziej szczegółowego wglądu. -- [Ethernow](https://www.ethernow.xyz/) – eksplorator transakcji w czasie rzeczywistym, który pozwala zobaczyć warstwę pre-chain głównej sieci Ethereum. -- [Otterscan](https://otterscan.io/) – alternatywny eksplorator bloków typu open source dla Ethereum. -- [Blockscout](https://eth.blockscout.com/) – koncentruje się na następujących sieciach: - - xDai – mądre połączenie technologii stablecoin DAI MakerDAO, a także technologii łańcucha bocznego POA i tokenbridge. - - POA – łańcuch boczny i autonomiczna sieć zabezpieczona przez grupę zaufanych walidatorów. Wszyscy walidatorzy w sieci są notariuszami Stanów Zjednoczonych, a ich informacje są publicznie dostępne. - - POA Sokol Testnet. - - ARTIS – blockchain zgodny z Ethereum. - - [LUKSO L14](https://blockscout.com/lukso/l14) – L14 pełni funkcję pierwszej sieci testowej, aby umożliwić społeczności LUKSO budowę i przetestowanie wspólnej infrastruktury. - - qDai. - -## Eksploratory bloków Eth2 {#beacon-chain-block-explorers} - -- [https://beaconcha.in/](https://beaconcha.in/) -- [https://beaconscan.com/](https://beaconscan.com/) +- [Etherscan](https://etherscan.io/) – eksplorator bloków, którego można użyć do pobierania danych z sieci głównej Ethereum i sieci testowej +- [3xpl](https://3xpl.com/ethereum) – wolny od reklam, open-source'owy eksplorator Ethereum, który umożliwia pobieranie zestawów danych +- [Beaconcha.in](https://beaconcha.in/) – eksplorator bloków open source dla sieci głównej Ethereum i sieci testowej +- [Blockchair](https://blockchair.com/ethereum) – najbardziej prywatny eksplorator Ethereum. Także do sortowania i filtrowania danych (mempool) +- [Etherchain](https://www.etherchain.org/) – eksplorator bloków dla sieci głównej Ethereum +- [Ethplorer](https://ethplorer.io/) – eksplorator bloków skoncentrowany na tokenach dla sieci głównej Ethereum i sieci testowej Kovan ## Dalsza lektura {#further-reading} -_Znasz jakieś zasoby społeczności, które Ci pomogły? Wyedytuj tę stronę i dodaj je!_ +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ ## Powiązane tematy {#related-topics} -- [Wydobywanie](/developers/docs/consensus-mechanisms/pow/mining/) - [Transakcje](/developers/docs/transactions/) - [Konta](/developers/docs/accounts/) - [Sieci](/developers/docs/networks/) diff --git a/public/content/translations/pl/developers/docs/data-and-analytics/index.md b/public/content/translations/pl/developers/docs/data-and-analytics/index.md index 68cc6abbbf9..ec8a1dfba7c 100644 --- a/public/content/translations/pl/developers/docs/data-and-analytics/index.md +++ b/public/content/translations/pl/developers/docs/data-and-analytics/index.md @@ -1,35 +1,72 @@ --- title: Dane i analityka -description: Jak uzyskać analizy i dane on-chain do wykorzystania w Twoich aplikacjach zdecentralizowanych +description: "Jak pozyskać analizy na łańcuchu oraz dane do wykorzystania w dapkach" lang: pl --- ## Wprowadzenie {#Introduction} -W miarę wzrostu wykorzystania sieci coraz więcej cennych informacji będzie znajdować się w danych on-chain. W miarę szybkiego wzrostu ilości danych, obliczanie i agregowanie tych informacji w celu tworzenia raportów lub napędzania aplikacji dapp może stać się czasochłonnym i skomplikowanym przedsięwzięciem. +W miarę rozrastania się sieci Ethereum coraz więcej wartościowych informacji będzie istniało pośród danych na łańcuchu. W miarę szybkiego wzrostu ilości danych obliczanie i agregowanie tych informacji w celu tworzenia raportów lub napędzania zdecentralizowanych aplikacji może stać się czasochłonnym i skomplikowanym przedsięwzięciem. -Wykorzystanie istniejących dostawców danych może przyspieszyć rozwój, dać dokładniejsze wyniki i zmniejszyć nakłady na bieżącą konserwację. Umożliwi to zespołowi skupienie się na podstawowej funkcjonalności dostarczanej przez projekt. +Wykorzystanie istniejących dostawców danych może przyspieszyć rozwój, zapewnić dokładniejsze wyniki i zmniejszyć bieżące koszty utrzymania. Umożliwi to zespołowi skupienie się na podstawowej funkcjonalności dostarczanej przez projekt. -## Warunki wstępne {#prerequisites} +## Wymagania wstępne {#prerequisites} -Musisz rozumieć koncepcję leżącą u podstaw [eksploratorów bloków](/developers/docs/data-and-analytics/block-explorers/), aby lepiej orientować się w kwestiach używania ich w kontekście analizy danych. Dodatkowo, zapoznaj się z koncepcją [indeksu](/glossary/#index), aby zrozumieć korzyści, jakie indeksy dodają do projektu systemu. +Należy rozumieć podstawową koncepcję [eksploratorów bloków](/developers/docs/data-and-analytics/block-explorers/), aby lepiej zrozumieć ich zastosowanie w kontekście analityki danych. Ponadto należy zapoznać się z pojęciem [indeksu](/glossary/#index), aby zrozumieć korzyści, jakie wnosi on do projektu systemu. -W zakresie podstaw architektury, zrozumienie, czym są [API](https://www.wikipedia.org/wiki/API) i [REST](https://www.wikipedia.org/wiki/Representational_state_transfer), nawet teoretycznie. +W kwestii podstaw architektury, zrozumienie czym są [API](https://www.wikipedia.org/wiki/API) i [REST](https://www.wikipedia.org/wiki/Representational_state_transfer), nawet w teorii. -## Graph {#the-graph} +## Eksploratory bloków {#block-explorers} -[Graph Network](https://thegraph.com/) jest zdecentralizowanym protokołem do porządkowania danych blockchainu. Zamiast budować i zarządzać scentralizowanymi magazynami danych w celu agregacji danych on-chain, dzięki The Graph deweloperzy mogą tworzyć bezserwerowe aplikacje, które działają w całości na infrastrukturze publicznej. +Wiele [eksploratorów bloków](/developers/docs/data-and-analytics/block-explorers/) oferuje bramki [API](https://www.wikipedia.org/wiki/API) [RESTful](https://www.wikipedia.org/wiki/Representational_state_transfer), które zapewnią programistom wgląd w dane czasu rzeczywistego na temat bloków, transakcji, walidatorów, kont i innych działań w łańcuchu. -Za pomocą [GraphQL](https://graphql.org/), deweloperzy mogą korzystać z każdego otwartego API, znanego jako sub-graph, aby uzyskać niezbędne informacje, które są potrzebne do napędzania ich aplikacji zdecentralizowanych. Dzięki zapytaniom do tych indeksowanych sub-graphów, raporty i aplikacje dapp nie tylko uzyskują korzyści związane z wydajnością i skalowalnością, ale także wbudowaną dokładność zapewnianą przez konsensus sieciowy. W miarę jak do sieci dodawane są nowe ulepszenia i/lub sub-graphy, Twoje projekty mogą szybko iterować, aby wykorzystać te ulepszenia. +Programiści mogą następnie przetwarzać i przekształcać te dane, aby zapewnić swoim użytkownikom unikalny wgląd i interakcje z [blockchainem](/glossary/#blockchain). Na przykład [Etherscan](https://etherscan.io) i [Blockscout](https://eth.blockscout.com) dostarczają dane dotyczące wykonania i konsensusu dla każdego 12-sekundowego slotu. -## Eksplorator bloków {#block-explorers} +## The Graph {#the-graph} -Wiele [eksploratorów bloków](/developers/docs/data-and-analytics/block-explorers/) oferuje bramy [RESTful](https://www.wikipedia.org/wiki/Representational_state_transfer) [API](https://www.wikipedia.org/wiki/API) zapewniające deweloperom widoczność w czasie rzeczywistym danych dotyczących bloków, transakcji, górników, kont i innych aktywności on-chain. +[The Graph](https://thegraph.com/) to protokół indeksujący, który zapewnia łatwy sposób odpytywania danych z blockchaina za pomocą otwartych interfejsów API, znanych jako podgrafy. -Programiści mogą następnie przetwarzać i przekształcać te dane, aby umożliwić użytkownikom unikalne informacje i interakcje z [blockchainem](/glossary/#blockchain). +Za pomocą The Graph, programiści mogą czerpać korzyści z: + +- Zdecentralizowane indeksowanie: Umożliwia indeksowanie danych blockchain z pomocą wielu podmiotów, tym samym eliminując potencjalne pojedyncze punkty awarii +- Zapytania GraphQL: Dostarcza potężny interfejs GraphQL do zapytań indeksowanych danych, sprawiając, że pozyskanie danych jest super proste +- Dostosowywanie: Definiowanie własnej logiki przekształcania i przechowywania danych z blockchaina oraz ponowne wykorzystywanie podgrafów opublikowanych przez innych programistów w sieci The Graph Network. + +Należy postępować zgodnie z tym przewodnikiem [szybkiego startu](https://thegraph.com/docs/en/quick-start/), aby utworzyć, wdrożyć i odpytać podgraf w ciągu 5 minut. + +## Różnorodność klientów {#client-diversity} + +[Różnorodność klientów](/developers/docs/nodes-and-clients/client-diversity/) jest ważna dla ogólnego stanu sieci Ethereum, ponieważ zapewnia odporność na błędy i exploity. Obecnie istnieje kilka pulpitów nawigacyjnych dotyczących różnorodności klientów, w tym [clientdiversity.org](https://clientdiversity.org/), [rated.network](https://www.rated.network), [supermajority.info](https://supermajority.info//) i [Ethernodes](https://ethernodes.org/). + +## Dune Analytics {#dune-analytics} + +[Dune Analytics](https://dune.com/) wstępnie przetwarza dane blockchaina w tabele relacyjnej bazy danych (DuneSQL), pozwala użytkownikom odpytywać dane blockchaina za pomocą SQL i tworzyć pulpity nawigacyjne na podstawie wyników zapytań. Dane on-chain są zorganizowane w 4 surowych tabelach: `blocks`, `transactions`, (event) `logs` oraz (call) `traces`. Popularne kontrakty i protokoły zostały rozszyfrowane, a każdy z nich posiada własny zestaw tabel wydarzeń i wywołań. Te tabele wydarzeń i wywołań są dalej przetwarzane i organizowane w tabele abstrakcji według rodzaju protokołów, na przykład dex, pożyczki, stablecoiny itp. + +## SQD {#sqd} + +[SQD](https://sqd.dev/) to zdecentralizowana, hiperskalowalna platforma danych zoptymalizowana pod kątem zapewniania wydajnego, niewymagającego zezwoleń dostępu do dużych ilości danych. Aktualnie przedstawia dane historyczne z łańcucha takie jak rejestry zdarzeń, potwierdzenia transakcji, ślady, różnice stanu dla każdej transakcji. SQD oferuje skuteczny zestaw narzędzi do tworzenia niestandardowych procesów pozyskiwania i przetwarzania danych, osiągając prędkość indeksowania sięgającą 150 tysięcy bloków na sekundę. + +Aby zacząć, należy odwiedzić [dokumentację](https://docs.sqd.dev/) lub zobaczyć [przykłady EVM](https://github.com/subsquid-labs/squid-evm-examples), aby dowiedzieć się, co można zbudować za pomocą SQD. + +## SubQuery Network {#subquery-network} + +[SubQuery](https://subquery.network/) to wiodący indeksator danych, który zapewnia programistom szybkie, niezawodne, zdecentralizowane i dostosowane interfejsy API dla ich projektów web3. SubQuery wspomaga pracę programistów z ponad 165 ekosystemów (włącznie z Ethereum) za pomocą bogatych indeksowanych danych, które wykorzystać można do tworzenia intuicyjnych i pochłaniających doświadczeń dla użytkowników. Sieć SubQuery zasila twoje niepowstrzymane apki zdecentralizowaną i odporną infrastrukturą sieciową. Zestawu blockchainowych narzędzi programistycznych SubQuery użyjesz do stworzenia aplikacji przyszłości web3 bez poświęcania czasu na tworzenie niestandardowego backendu do przetwarzania danych. + +Aby rozpocząć, należy odwiedzić [przewodnik szybkiego startu Ethereum](https://academy.subquery.network/quickstart/quickstart_chains/ethereum-gravatar.html), aby w ciągu kilku minut rozpocząć indeksowanie danych z blockchaina Ethereum w lokalnym środowisku Docker do celów testowych, przed uruchomieniem w [usłudze zarządzanej SubQuery](https://managedservice.subquery.network/) lub w [zdecentralizowanej sieci SubQuery](https://app.subquery.network/dashboard). + +## Język zapytań EVM {#evm-query-language} + +Język zapytań do EVM (EQL) jest podobnym do SQL językiem zaprojektowanym, aby stosować zapytania do łańcuchów EVM (Wirtualnej Maszyny Ethereum). Nadrzędnym celem EQL jest obsługa złożonych zapytań relacyjnych dotyczących najważniejszych obywateli EVM (bloków, kont i transakcji) dając jednocześnie programistom i badaczom ergonomiczną składnię do codziennego użytku. Za pomocą EQL programiści mogą pozyskać dane blockchain, używając składni podobnej do SQL i wykluczając potrzebę użycia skomplikowanego kodu szablonowego. EQL wspiera standardowe żądania dotyczące danych blockchain (np. uzyskanie informacji o nonce danego konta i jego saldzie na Ethereum lub zdobycie aktualnego rozmiaru bloku i znacznika czasu) i ciągle rozszerza wsparcie o bardziej złożone żądania i zestawy funkcji. ## Dalsza lektura {#further-reading} -- [Przegląd Graph Network](https://thegraph.com/docs/en/about) -- [Graph Query Playground](https://thegraph.com/explorer/subgraph/graphprotocol/graph-network-mainnet?version=current) -- [Przykłady kodu API w EtherScan](https://etherscan.io/apis#contracts) +- [Badanie danych kryptograficznych I: Architektury przepływu danych](https://web.archive.org/web/20250125012042/https://research.2077.xyz/exploring-crypto-data-1-data-flow-architectures) +- [Omówienie Graph Network](https://thegraph.com/docs/en/about/) +- [Piaskownica zapytań Graph](https://thegraph.com/explorer/subgraph/graphprotocol/graph-network-mainnet?version=current) +- [Przykłady kodu API na Etherscanie](https://etherscan.io/apis#contracts) +- [Dokumentacja API na Blockscout](https://docs.blockscout.com/devs/apis) +- [Beaconcha.in – eksplorator łańcucha śledzącego](https://beaconcha.in) +- [Podstawy Dune](https://docs.dune.com/#dune-basics) +- [Przewodnik szybkiego startu SubQuery dla Ethereum](https://academy.subquery.network/indexer/quickstart/quickstart_chains/ethereum-gravatar.html) +- [Omówienie sieci SQD](https://docs.sqd.dev/) +- [Język zapytań EVM](https://eql.sh/blog/alpha-release-notes) diff --git a/public/content/translations/pl/developers/docs/data-availability/blockchain-data-storage-strategies/index.md b/public/content/translations/pl/developers/docs/data-availability/blockchain-data-storage-strategies/index.md new file mode 100644 index 00000000000..91afe4f7ce2 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-availability/blockchain-data-storage-strategies/index.md @@ -0,0 +1,118 @@ +--- +title: Strategie przechowywania danych blockchainu +description: "Istnieje kilka sposobów przechowywania danych za pomocą blockchaina. W tym artykule porównamy różne strategie, ich koszty i kompromisy, a także wymagania dotyczące ich bezpiecznego stosowania." +lang: pl +--- + +Istnieje wiele sposobów przechowywania informacji bezpośrednio w blockchainie lub w sposób zabezpieczony przez blockchain: + +- Bloby EIP-4844 +- Calldata +- Offchain z mechanizmami L1 +- „Kod” kontraktu +- Zdarzenia +- Przechowywanie EVM + +Wybór metody zależy od kilku kryteriów: + +- Źródło informacji. Informacje w calldata nie mogą pochodzić bezpośrednio z samego blockchaina. +- Miejsce docelowe informacji. Calldata jest dostępna tylko w transakcji, która ją zawiera. Zdarzenia nie są w ogóle dostępne onchain. +- Jakie utrudnienia są dopuszczalne? Komputery, które uruchamiają pełny node, mogą wykonać więcej operacji przetwarzania niż lekki klient w aplikacji działającej w przeglądarce. +- Czy konieczne jest ułatwienie dostępu do informacji z każdego node'a? +- Wymagania dotyczące bezpieczeństwa. + +## Wymagania dotyczące bezpieczeństwa {#security-requirements} + +Ogólnie rzecz biorąc, bezpieczeństwo informacji składa się z trzech atrybutów: + +- _Poufność_, nieautoryzowane podmioty nie mogą odczytywać informacji. Jest to ważne w wielu przypadkach, ale nie w tym. _W blockchainie nie ma tajemnic_. Blockchainy działają, ponieważ każdy może zweryfikować przejścia stanów, więc niemożliwe jest ich użycie do bezpośredniego przechowywania tajemnic. Istnieją sposoby na przechowywanie poufnych informacji w blockchainie, ale wszystkie opierają się na pewnym komponencie offchain do przechowywania co najmniej klucza. + +- _Integralność_, informacja jest poprawna, nie może być zmieniana przez nieautoryzowane podmioty ani w nieautoryzowany sposób (na przykład transfer [tokenów ERC-20](https://eips.ethereum.org/EIPS/eip-20#events) bez zdarzenia `Transfer`). W blockchainie każdy node weryfikuje każdą zmianę stanu, co zapewnia integralność. + +- _Dostępność_, informacja jest dostępna dla każdego autoryzowanego podmiotu. W blockchainie jest to zazwyczaj osiągane poprzez udostępnienie informacji na każdym [pełnym nodzie](https://ethereum.org/developers/docs/nodes-and-clients#full-node). + +Wszystkie te różne rozwiązania charakteryzują się doskonałą integralnością, ponieważ hasze są publikowane na L1. Mają one jednak różne gwarancje dostępności. + +## Wymagania wstępne {#prerequisites} + +Należy dobrze rozumieć [podstawy blockchaina](/developers/docs/intro-to-ethereum/). Na tej stronie zakłada się również, że czytelnik jest zaznajomiony z [blokami](/developers/docs/blocks/), [transakcjami](/developers/docs/transactions/) i innymi powiązanymi tematami. + +## Bloby EIP-4844 {#eip-4844-blobs} + +Począwszy od [hardforka Dencun](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md), blockchain Ethereum zawiera [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), który dodaje do Ethereum bloby danych o ograniczonym czasie życia (początkowo około [18 dni](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/p2p-interface.md#configuration)). Te bloby są wyceniane oddzielnie od [gazu wykonawczego](/developers/docs/gas), chociaż używają podobnego mechanizmu. Są tanim sposobem na publikowanie tymczasowych danych. + +Głównym przypadkiem użycia blobów EIP-4844 jest publikowanie transakcji przez pakiety zbiorcze. [Optymistyczne pakiety zbiorcze](/developers/docs/scaling/optimistic-rollups) muszą publikować transakcje na swoich blockchainach. Transakcje te muszą być dostępne dla każdego w [okresie wyzwania](https://docs.optimism.io/connect/resources/glossary#challenge-period), aby umożliwić [walidatorom](https://docs.optimism.io/connect/resources/glossary#validator) naprawienie błędu, jeśli [sekwencer](https://docs.optimism.io/connect/resources/glossary#sequencer) pakietu zbiorczego opublikuje nieprawidłowy state root. + +Jednakże, gdy okres wyzwania minie, a state root zostanie sfinalizowany, pozostałym celem znajomości tych transakcji jest replikacja bieżącego stanu łańcucha. Ten stan jest również dostępny z node'ów łańcucha, przy czym wymagane jest o wiele mniej przetwarzania. Tak więc informacje o transakcjach powinny być nadal przechowywane w kilku miejscach, takich jak [eksploratory bloków](/developers/docs/data-and-analytics/block-explorers), ale nie ma potrzeby płacić za poziom odporności na cenzurę, jaki zapewnia Ethereum. + +[Pakiety zbiorcze o wiedzy zerowej](/developers/docs/scaling/zk-rollups/#data-availability) również publikują swoje dane transakcyjne, aby umożliwić innym node'om replikację istniejącego stanu i weryfikację dowodów ważności, ale jest to znowu wymóg krótkoterminowy. + +W momencie pisania tego tekstu publikacja w EIP-4844 kosztuje jeden wei (10-18 ETH) za bajt, co jest znikomą kwotą w porównaniu z [21 000 jednostek gazu wykonawczego, które kosztuje każda transakcja, w tym transakcja publikująca bloby](https://eth.blockscout.com/tx/0xf6cfaf0431c73dd1d96369a5e6707d64f463ccf477a4131265397f1d81466929?tab=index). Aktualną cenę EIP-4844 można zobaczyć na [blobscan.com](https://blobscan.com/blocks). + +Oto adresy, pod którymi można zobaczyć bloby opublikowane przez niektóre znane pakiety zbiorcze. + +| Pakiet zbiorczy | Adres skrzynki pocztowej | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | +| [Optimism](https://www.optimism.io/) | [`0xFF00000000000000000000000000000000000010`](https://blobscan.com/address/0xFF00000000000000000000000000000000000010) | +| [Arbitrum](https://arbitrum.io/) | [`0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6`](https://blobscan.com/address/0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6) | +| [Base](https://base.org/) | [`0xFF00000000000000000000000000000000008453`](https://blobscan.com/address/0xFF00000000000000000000000000000000008453) | + +## Calldata {#calldata} + +Calldata odnosi się do bajtów wysyłanych w ramach transakcji. Jest ona przechowywana jako część trwałego zapisu blockchaina w bloku, który zawiera daną transakcję. + +Jest to najtańsza metoda trwałego umieszczania danych w blockchainie. Koszt za bajt wynosi 4 jednostki gazu wykonawczego (jeśli bajt jest zerowy) lub 16 jednostek gazu (dla każdej innej wartości). Jeśli dane są skompresowane, co jest standardową praktyką, to każda wartość bajtu jest równie prawdopodobna, więc średni koszt wynosi około 15,95 jednostek gazu na bajt. + +W chwili pisania tego tekstu ceny wynoszą 12 gwei/gaz i 2300 $/ETH, co oznacza, że koszt wynosi około 45 centów za kilobajt. Ponieważ była to najtańsza metoda przed EIP-4844, jest to metoda, której pakiety zbiorcze używały do przechowywania informacji o transakcjach, które muszą być dostępne dla [wyzwań dotyczących błędów](https://docs.optimism.io/stack/protocol/overview#fault-proofs), ale nie muszą być dostępne bezpośrednio onchain. + +Oto adresy, pod którymi można zobaczyć transakcje opublikowane przez niektóre znane pakiety zbiorcze. + +| Pakiet zbiorczy | Adres skrzynki pocztowej | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| [Optimism](https://www.optimism.io/) | [`0xFF00000000000000000000000000000000000010`](https://eth.blockscout.com/address/0xFF00000000000000000000000000000000000010) | +| [Arbitrum](https://arbitrum.io/) | [`0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6`](https://eth.blockscout.com/address/0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6) | +| [Base](https://base.org/) | [`0xFF00000000000000000000000000000000008453`](https://eth.blockscout.com/address/0xFF00000000000000000000000000000000008453) | + +## Offchain z mechanizmami L1 {#offchain-with-l1-mechs} + +W zależności od kompromisów w zakresie bezpieczeństwa, może być dopuszczalne umieszczenie informacji w innym miejscu i użycie mechanizmu, który zapewni dostępność danych w razie potrzeby. Aby to zadziałało, muszą być spełnione dwa wymagania: + +1. Opublikuj [hasz](https://en.wikipedia.org/wiki/Cryptographic_hash_function) danych w blockchainie, zwany _zobowiązaniem wejściowym_. Może to być pojedyncze 32-bajtowe słowo, więc nie jest to drogie. Dopóki zobowiązanie wejściowe jest dostępne, integralność jest zapewniona, ponieważ nie jest wykonalne znalezienie innych danych, które haszowałyby się do tej samej wartości. Więc jeśli zostaną podane nieprawidłowe dane, można to wykryć. + +2. Posiadanie mechanizmu, który zapewnia dostępność. Na przykład w [Redstone](https://redstone.xyz/docs/what-is-redstone) każdy node może zgłosić wyzwanie dostępności. Jeśli sekwencer nie odpowie onchain przed upływem terminu, zobowiązanie wejściowe jest odrzucane, więc informacja jest uważana za nigdy nieopublikowaną. + +Jest to dopuszczalne w przypadku optymistycznego pakietu zbiorczego, ponieważ już polegamy na istnieniu co najmniej jednego uczciwego weryfikatora dla state root. Taki uczciwy weryfikator upewni się również, że ma dane do przetwarzania bloków i zgłosi wyzwanie dostępności, jeśli informacja nie będzie dostępna offchain. Ten typ optymistycznego pakietu zbiorczego nazywa się [plasma](/developers/docs/scaling/plasma/). + +## Kod kontraktu {#contract-code} + +Informacje, które trzeba zapisać tylko raz, nigdy nie są nadpisywane i muszą być dostępne onchain, mogą być przechowywane jako kod kontraktu. Oznacza to, że tworzymy „inteligentny kontrakt” z danymi, a następnie używamy [`EXTCODECOPY`](https://www.evm.codes/#3c?fork=shanghai) do odczytania informacji. Zaletą jest to, że kopiowanie kodu jest stosunkowo tanie. + +Oprócz kosztu rozszerzenia pamięci, `EXTCODECOPY` kosztuje 2600 jednostek gazu za pierwszy dostęp do kontraktu (kiedy jest „zimny”) i 100 jednostek gazu za kolejne kopie z tego samego kontraktu plus 3 jednostki gazu za 32-bajtowe słowo. W porównaniu z calldata, która kosztuje 15,95 za bajt, jest to tańsze, zaczynając od około 200 bajtów. Na podstawie [wzoru na koszty rozszerzenia pamięci](https://www.evm.codes/about#memoryexpansion), o ile nie potrzeba więcej niż 4 MB pamięci, koszt rozszerzenia pamięci jest mniejszy niż koszt dodania calldata. + +Oczywiście jest to tylko koszt _odczytu_ danych. Utworzenie kontraktu kosztuje około 32 000 jednostek gazu + 200 jednostek gazu/bajt. Ta metoda jest ekonomiczna tylko wtedy, gdy te same informacje muszą być odczytywane wielokrotnie w różnych transakcjach. + +Kod kontraktu może być bezsensowny, o ile nie zaczyna się od `0xEF`. Kontrakty zaczynające się od `0xEF` są interpretowane jako [format obiektu Ethereum](https://notes.ethereum.org/@ipsilon/evm-object-format-overview), który ma znacznie surowsze wymagania. + +## Zdarzenia {#events} + +[Zdarzenia](https://docs.alchemy.com/docs/solidity-events) są emitowane przez inteligentne kontrakty i odczytywane przez oprogramowanie offchain. +Ich zaletą jest to, że kod offchain może nasłuchiwać zdarzeń. Koszt to [gaz](https://www.evm.codes/#a0?fork=cancun), 375 plus 8 jednostek gazu za bajt danych. Przy 12 gwei/gaz i 2300 $/ETH, przekłada się to na jednego centa plus 22 centy za kilobajt. + +## Przechowywanie {#storage} + +Inteligentne kontrakty mają dostęp do [trwałego przechowywania](https://docs.alchemy.com/docs/smart-contract-storage-layout#what-is-storage-memory). Jest ono jednak bardzo drogie. Zapisanie 32-bajtowego słowa do wcześniej pustego slotu pamięci może [kosztować 22 100 jednostek gazu](https://www.evm.codes/#55?fork=cancun). Przy 12 gwei/gaz i 2300 $/ETH, daje to około 61 centów za operację zapisu, czyli 19,5 dolara za kilobajt. + +Jest to najdroższa forma przechowywania w Ethereum. + +## Podsumowanie {#summary} + +Poniższa tabela podsumowuje różne opcje, ich zalety i wady. + +| Typ przechowywania | Źródło danych | Gwarancja dostępności | Dostępność onchain | Dodatkowe ograniczenia | +| -------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | --------------------------------------------------------------- | +| Bloby EIP-4844 | Offchain | Gwarancja Ethereum na [~18 dni](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/p2p-interface.md#configuration) | Dostępny jest tylko hasz | | +| Calldata | Offchain | Gwarancja Ethereum na zawsze (część blockchaina) | Dostępne tylko w przypadku zapisu do kontraktu i w tej transakcji | | +| Offchain z mechanizmami L1 | Offchain | Gwarancja „jednego uczciwego weryfikatora” w okresie wyzwania | Tylko hasz | Gwarantowane przez mechanizm wyzwania, tylko w okresie wyzwania | +| Kod kontraktu | Onchain lub offchain | Gwarancja Ethereum na zawsze (część blockchaina) | Tak | Zapisywany pod „losowy” adres, nie może zaczynać się od `0xEF` | +| Zdarzenia | Onchain | Gwarancja Ethereum na zawsze (część blockchaina) | Nie | | +| Przechowywanie | Onchain | Gwarancja Ethereum na zawsze (część blockchaina i obecnego stanu do momentu nadpisania) | Tak | | diff --git a/public/content/translations/pl/developers/docs/data-availability/index.md b/public/content/translations/pl/developers/docs/data-availability/index.md new file mode 100644 index 00000000000..d0d7e8ba081 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-availability/index.md @@ -0,0 +1,84 @@ +--- +title: "Dostępność danych" +description: "Przegląd problemów i rozwiązań związanych z dostępnością danych w Ethereum" +lang: pl +--- + +„Nie ufaj, weryfikuj” to popularna maksyma w Ethereum. Ideą jest, aby węzeł mógł samodzielnie zweryfikować poprawność otrzymywanych informacji, wykonując wszystkie transakcje z bloków otrzymanych od peerów, aby upewnić się, że proponowane zmiany dokładnie odpowiadają tym obliczonym niezależnie przez węzeł. Oznacza to, że węzły nie muszą ufać, że nadawcy bloku są uczciwi. Nie jest to możliwe, jeśli brakuje danych. + +**Dostępność danych** odnosi się do pewności, jaką użytkownik może mieć co do tego, że dane wymagane do zweryfikowania bloku są rzeczywiście dostępne dla wszystkich uczestników sieci. W przypadku pełnych węzłów w warstwie 1 Ethereum jest to stosunkowo proste; pełny węzeł pobiera kopię wszystkich danych z każdego bloku – dane _muszą_ być dostępne, aby pobieranie było możliwe. Blok z brakującymi danymi zostałby odrzucony, a nie dodany do blockchaina. Jest to „dostępność danych on-chain” i jest to cecha monolitycznych blockchainów. Pełnych węzłów nie da się oszukać, aby zaakceptowały nieprawidłowe transakcje, ponieważ same pobierają i wykonują każdą transakcję. Jednakże w przypadku modułowych blockchainów, rollupów warstwy 2 i lekkich klientów krajobraz dostępności danych jest bardziej złożony i wymaga bardziej zaawansowanych procedur weryfikacyjnych. + +## Wymagania wstępne {#prerequisites} + +Należy dobrze rozumieć [podstawy technologii blockchain](/developers/docs/intro-to-ethereum/), a zwłaszcza [mechanizmy konsensusu](/developers/docs/consensus-mechanisms/). Ta strona zakłada również, że czytelnik jest zaznajomiony z [blokami](/developers/docs/blocks/), [transakcjami](/developers/docs/transactions/), [węzłami](/developers/docs/nodes-and-clients/), [rozwiązaniami skalującymi](/developers/docs/scaling/) i innymi istotnymi tematami. + +## Problem dostępności danych {#the-data-availability-problem} + +Problem dostępności danych to potrzeba udowodnienia całej sieci, że podsumowana forma niektórych danych transakcji dodawanych do blockchaina rzeczywiście reprezentuje zestaw prawidłowych transakcji, ale bez wymagania od wszystkich węzłów pobierania wszystkich danych. Pełne dane transakcji są niezbędne do niezależnej weryfikacji bloków, ale wymaganie od wszystkich węzłów pobierania wszystkich danych transakcji stanowi barierę dla skalowania. Rozwiązania problemu dostępności danych mają na celu zapewnienie uczestnikom sieci, którzy sami nie pobierają i nie przechowują danych, wystarczających gwarancji, że pełne dane transakcji zostały udostępnione do weryfikacji. + +[Lekkie węzły](/developers/docs/nodes-and-clients/light-clients) i [rollupy warstwy 2](/developers/docs/scaling) są ważnymi przykładami uczestników sieci, którzy wymagają silnych gwarancji dostępności danych, ale nie mogą sami pobierać i przetwarzać danych transakcji. Unikanie pobierania danych transakcji jest tym, co sprawia, że lekkie węzły są „lekkie” i pozwala rollupom być skutecznymi rozwiązaniami skalującymi. + +Dostępność danych jest również kluczową kwestią dla przyszłych [„bezstanowych”](/roadmap/statelessness) klientów Ethereum, którzy nie muszą pobierać i przechowywać danych o stanie, aby weryfikować bloki. Klienci bezstanowi nadal muszą mieć pewność, że dane są _gdzieś_ dostępne i że zostały poprawnie przetworzone. + +## Rozwiązania problemu dostępności danych {#data-availability-solutions} + +### Próbkowanie dostępności danych (DAS) {#data-availability-sampling} + +Próbkowanie dostępności danych (DAS) to sposób, w jaki sieć może sprawdzić, czy dane są dostępne, nie obciążając zbytnio żadnego pojedynczego węzła. Każdy węzeł (w tym węzły niestakujące) pobiera niewielki, losowo wybrany podzbiór wszystkich danych. Pomyślne pobranie próbek potwierdza z dużą pewnością, że wszystkie dane są dostępne. Opiera się to na kodowaniu wymazującym danych, które rozszerza dany zestaw danych o nadmiarowe informacje (odbywa się to poprzez dopasowanie funkcji znanej jako _wielomian_ do danych i obliczenie wartości tego wielomianu w dodatkowych punktach). Pozwala to w razie potrzeby na odzyskanie oryginalnych danych z danych nadmiarowych. Konsekwencją tego tworzenia danych jest to, że jeśli _jakakolwiek_ część oryginalnych danych jest niedostępna, będzie brakować _połowy_ rozszerzonych danych! Ilość próbek danych pobieranych przez każdy węzeł można dostosować tak, aby było _niezwykle_ prawdopodobne, że będzie brakować co najmniej jednego z fragmentów danych próbkowanych przez każdego klienta, _jeśli_ faktycznie dostępna jest mniej niż połowa danych. + +DAS będzie używane do zapewnienia, że operatorzy rollupów udostępniają swoje dane transakcyjne po wdrożeniu [pełnego Dankshardingu](/roadmap/danksharding/#what-is-danksharding). Węzły Ethereum będą losowo próbkować dane transakcyjne dostarczone w obiektach blob, używając wyjaśnionego powyżej schematu nadmiarowości, aby upewnić się, że wszystkie dane istnieją. Tę samą technikę można by również zastosować, aby zapewnić, że producenci bloków udostępniają wszystkie swoje dane bezpiecznym lekkim klientom. Podobnie, w ramach [separacji proponującego od budowniczego](/roadmap/pbs), tylko budowniczy bloku byłby zobowiązany do przetworzenia całego bloku – inni walidatorzy dokonywaliby weryfikacji za pomocą próbkowania dostępności danych. + +### Komitety ds. dostępności danych {#data-availability-committees} + +Komitety ds. dostępności danych (DAC) to zaufane podmioty, które zapewniają lub poświadczają dostępność danych. Komitety DAC mogą być używane zamiast, [lub w połączeniu z](https://hackmd.io/@vbuterin/sharding_proposal#Why-not-use-just-committees-and-not-DAS) DAS. Gwarancje bezpieczeństwa zapewniane przez komitety zależą od konkretnej konfiguracji. Na przykład Ethereum wykorzystuje losowo wybrane podzbiory walidatorów do poświadczania dostępności danych dla lekkich węzłów. + +Komitety DAC są również używane przez niektóre validium. DAC to zaufany zestaw węzłów, który przechowuje kopie danych w trybie offline. Komitet DAC jest zobowiązany do udostępnienia danych w przypadku sporu. Członkowie komitetu DAC publikują również poświadczenia on-chain, aby udowodnić, że wspomniane dane są rzeczywiście dostępne. Niektóre validium zastępują komitety DAC systemem walidatorów opartym na dowodzie stawki (PoS). W tym przypadku każdy może zostać walidatorem i przechowywać dane w trybie off-chain. Muszą jednak zapewnić „zabezpieczenie” (bond), które jest zdeponowane w inteligentnym kontrakcie. W przypadku złośliwego zachowania, takiego jak wstrzymywanie danych przez walidatora, zabezpieczenie może zostać obcięte (slashing). Komitety ds. dostępności danych oparte na dowodzie stawki są znacznie bezpieczniejsze niż zwykłe komitety DAC, ponieważ bezpośrednio motywują do uczciwego zachowania. + +## Dostępność danych i lekkie węzły {#data-availability-and-light-nodes} + +[Lekkie węzły](/developers/docs/nodes-and-clients/light-clients) muszą weryfikować poprawność otrzymywanych nagłówków bloków bez pobierania danych bloku. Ceną tej „lekkości” jest niemożność niezależnej weryfikacji nagłówków bloków poprzez ponowne lokalne wykonanie transakcji w taki sam sposób, w jaki robią to pełne węzły. + +Lekkie węzły Ethereum ufają losowym zestawom 512 walidatorów, którzy zostali przypisani do _komitetu synchronizacyjnego_. Komitet synchronizacyjny działa jako DAC, który sygnalizuje lekkim klientom za pomocą podpisu kryptograficznego, że dane w nagłówku są prawidłowe. Każdego dnia komitet synchronizacyjny jest odświeżany. Każdy nagłówek bloku informuje lekkie węzły, którzy walidatorzy mają podpisać _następny_ blok, więc nie mogą one zostać oszukane i zaufać złośliwej grupie udającej prawdziwy komitet synchronizacyjny. + +Co się jednak stanie, jeśli atakującemu _uda się_ przekazać złośliwy nagłówek bloku lekkim klientom i przekonać ich, że został on podpisany przez uczciwy komitet synchronizacyjny? W takim przypadku atakujący mógłby zawrzeć nieprawidłowe transakcje, a lekki klient zaakceptowałby je na ślepo, ponieważ nie sprawdza on niezależnie wszystkich zmian stanu podsumowanych w nagłówku bloku. Aby się przed tym zabezpieczyć, lekki klient może używać dowodów oszustwa. + +Dowody oszustwa działają w ten sposób, że pełny węzeł, widząc nieprawidłowe przejście stanu rozgłaszane w sieci, może szybko wygenerować mały fragment danych, który wykaże, że proponowane przejście stanu nie mogło powstać z danego zestawu transakcji, i rozgłosić te dane do peerów. Lekkie węzły mogłyby odebrać te dowody oszustwa i użyć ich do odrzucenia nieprawidłowych nagłówków bloków, zapewniając, że pozostaną na tym samym uczciwym łańcuchu co pełne węzły. + +Wymaga to, aby pełne węzły miały dostęp do pełnych danych transakcji. Atakujący, który rozgłasza nieprawidłowy nagłówek bloku, a także nie udostępnia danych transakcji, byłby w stanie uniemożliwić pełnym węzłom generowanie dowodów oszustwa. Pełne węzły mogłyby zasygnalizować ostrzeżenie o nieprawidłowym bloku, ale nie mogłyby poprzeć swojego ostrzeżenia dowodem, ponieważ dane potrzebne do jego wygenerowania nie zostały udostępnione! + +Rozwiązaniem tego problemu dostępności danych jest DAS. Lekkie węzły pobierają bardzo małe, losowe fragmenty pełnych danych o stanie i używają próbek do weryfikacji, czy pełny zestaw danych jest dostępny. Rzeczywiste prawdopodobieństwo błędnego założenia pełnej dostępności danych po pobraniu N losowych fragmentów można obliczyć ([dla 100 fragmentów szansa wynosi 10^-30](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html), czyli jest niewiarygodnie małe). + +Nawet w tym scenariuszu ataki polegające na wstrzymaniu zaledwie kilku bajtów mogłyby pozostać niezauważone przez klientów wysyłających losowe żądania danych. Kodowanie wymazujące naprawia to poprzez rekonstrukcję małych brakujących fragmentów danych, które można wykorzystać do sprawdzenia proponowanych zmian stanu. Dowód oszustwa można by następnie skonstruować przy użyciu zrekonstruowanych danych, uniemożliwiając lekkim węzłom akceptowanie nieprawidłowych nagłówków. + +**Uwaga:** DAS i dowody oszustwa nie zostały jeszcze wdrożone dla lekkich klientów Ethereum opartych na dowodzie stawki, ale znajdują się w planie działania i najprawdopodobniej przyjmą formę dowodów opartych na ZK-SNARK. Dzisiejsze lekkie klienty polegają na pewnej formie komitetu DAC: weryfikują tożsamość członków komitetu synchronizacyjnego, a następnie ufają otrzymywanym podpisanym nagłówkom bloków. + +## Dostępność danych i rollupy warstwy 2 {#data-availability-and-layer-2-rollups} + +[Rozwiązania skalujące warstwy 2](/layer-2/), takie jak [rollupy](/glossary/#rollups), zmniejszają koszty transakcji i zwiększają przepustowość Ethereum poprzez przetwarzanie transakcji w trybie off-chain. Transakcje rollup są kompresowane i publikowane w Ethereum w partiach. Partie reprezentują tysiące pojedynczych transakcji off-chain w ramach jednej transakcji w Ethereum. Zmniejsza to przeciążenie w warstwie podstawowej i obniża opłaty dla użytkowników. + +Jednakże zaufanie do transakcji „podsumowujących” publikowanych w Ethereum jest możliwe tylko wtedy, gdy proponowana zmiana stanu może być niezależnie zweryfikowana i potwierdzona jako wynik zastosowania wszystkich pojedynczych transakcji off-chain. Jeśli operatorzy rollupów nie udostępnią danych transakcji do tej weryfikacji, mogliby wysyłać nieprawidłowe dane do Ethereum. + +[Rollupy optymistyczne](/developers/docs/scaling/optimistic-rollups/) publikują skompresowane dane transakcji w Ethereum i czekają przez pewien czas (zazwyczaj 7 dni), aby umożliwić niezależnym weryfikatorom sprawdzenie danych. Jeśli ktoś zidentyfikuje problem, może wygenerować dowód oszustwa i użyć go do zakwestionowania rollupu. Spowodowałoby to wycofanie zmian w łańcuchu i pominięcie nieprawidłowego bloku. Jest to możliwe tylko wtedy, gdy dane są dostępne. Obecnie istnieją dwa sposoby, w jakie rollupy optymistyczne publikują dane transakcji w L1. Niektóre rollupy udostępniają dane na stałe jako `CALLDATA`, które na stałe pozostają w łańcuchu (on-chain). Wraz z wdrożeniem EIP-4844 niektóre rollupy zamiast tego publikują swoje dane transakcyjne w tańszej pamięci masowej blob. Nie jest to pamięć trwała. Niezależni weryfikatorzy muszą odpytywać obiekty blob i zgłaszać swoje zastrzeżenia w ciągu ok. 18 dni, zanim dane zostaną usunięte z warstwy 1 Ethereum. Dostępność danych jest gwarantowana przez protokół Ethereum tylko w tym krótkim, stałym oknie czasowym. Po tym czasie staje się to obowiązkiem innych podmiotów w ekosystemie Ethereum. Każdy węzeł może zweryfikować dostępność danych za pomocą DAS, tzn. pobierając małe, losowe próbki danych z obiektu blob. + +[Rollupy o zerowej wiedzy (ZK)](/developers/docs/scaling/zk-rollups) nie muszą publikować danych transakcji, ponieważ [dowody ważności o zerowej wiedzy](/glossary/#zk-proof) gwarantują poprawność przejść stanów. Jednakże dostępność danych nadal stanowi problem, ponieważ nie możemy zagwarantować funkcjonalności rollupu ZK (ani wchodzić z nim w interakcje) bez dostępu do jego danych o stanie. Na przykład użytkownicy nie mogą poznać swoich sald, jeśli operator wstrzymuje szczegóły dotyczące stanu rollupu. Nie mogą również wykonywać aktualizacji stanu, używając informacji zawartych w nowo dodanym bloku. + +## Dostępność danych a odzyskiwalność danych {#data-availability-vs-data-retrievability} + +Dostępność danych różni się od odzyskiwalności danych. Dostępność danych to zapewnienie, że pełne węzły były w stanie uzyskać dostęp i zweryfikować pełny zestaw transakcji powiązanych z określonym blokiem. Niekoniecznie oznacza to, że dane są dostępne na zawsze. + +Odzyskiwalność danych to zdolność węzłów do pobierania _informacji historycznych_ z blockchaina. Te dane historyczne nie są potrzebne do weryfikacji nowych bloków, są wymagane tylko do synchronizacji pełnych węzłów od bloku genezy lub obsługi określonych żądań historycznych. + +Podstawowy protokół Ethereum dotyczy przede wszystkim dostępności danych, a nie ich odzyskiwalności. Odzyskiwalność danych może być zapewniona przez niewielką populację węzłów archiwalnych prowadzonych przez strony trzecie lub może być rozproszona w całej sieci przy użyciu zdecentralizowanej pamięci masowej, takiej jak [Portal Network](https://www.ethportal.net/). + +## Dalsza lektura {#further-reading} + +- [O co chodzi z dostępnością danych?](https://medium.com/blockchain-capital-blog/wtf-is-data-availability-80c2c95ded0f) +- [Czym jest dostępność danych?](https://coinmarketcap.com/academy/article/what-is-data-availability) +- [Wprowadzenie do kontroli dostępności danych](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html) +- [Wyjaśnienie propozycji shardingu i DAS](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) +- [Uwagi na temat dostępności danych i kodowania wymazującego](https://github.com/ethereum/research/wiki/A-note-on-data-availability-and-erasure-coding#can-an-attacker-not-circumvent-this-scheme-by-releasing-a-full-unavailable-block-but-then-only-releasing-individual-bits-of-data-as-clients-query-for-them) +- [Komitety ds. dostępności danych.](https://medium.com/starkware/data-availability-e5564c416424) +- [Komitety ds. dostępności danych oparte na dowodzie stawki.](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) +- [Rozwiązania problemu odzyskiwalności danych](https://notes.ethereum.org/@vbuterin/data_sharding_roadmap#Who-would-store-historical-data-under-sharding) +- [Dostępność danych, czyli jak rollupy nauczyły się nie martwić i pokochały Ethereum](https://web.archive.org/web/20250515194659/https://web.archive.org/web/20241108192208/https://research.2077.xyz/data-availability-or-how-rollups-learned-to-stop-worrying-and-love-ethereum) +- [EIP-7623: Zwiększenie kosztu Calldata](https://web.archive.org/web/20250515194659/https://research.2077.xyz/eip-7623-increase-calldata-cost) diff --git a/public/content/translations/pl/developers/docs/data-structures-and-encoding/index.md b/public/content/translations/pl/developers/docs/data-structures-and-encoding/index.md new file mode 100644 index 00000000000..68556aa0621 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-structures-and-encoding/index.md @@ -0,0 +1,32 @@ +--- +title: Struktura i kodowanie danych +description: "Przegląd podstawowych struktur danych Ethereum." +lang: pl +sidebarDepth: 2 +--- + +Ethereum tworzy, przechowuje i przesyła duże ilości danych. Dane te muszą być sformatowane w ustandaryzowany i wydajny pod względem pamięci sposób, aby umożliwić każdemu [uruchomienie węzła](/run-a-node/) na stosunkowo skromnym sprzęcie klasy konsumenckiej. Aby to osiągnąć, w stosie Ethereum używanych jest kilka specyficznych struktur danych. + +## Wymagania wstępne {#prerequisites} + +Należy zrozumieć podstawy Ethereum i [oprogramowania klienckiego](/developers/docs/nodes-and-clients/). Zalecana jest znajomość warstwy sieciowej i [białej księgi Ethereum](/whitepaper/). + +## Struktury danych {#data-structures} + +### Drzewa Patricia Merkle {#patricia-merkle-tries} + +Drzewa Patricia Merkle to struktury, które kodują pary klucz-wartość w deterministyczne i kryptograficznie uwierzytelnione drzewo. Są one szeroko stosowane w warstwie wykonawczej Ethereum. + +[Więcej o drzewach Patricia Merkle](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) + +### Recursive Length Prefix {#recursive-length-prefix} + +Recursive Length Prefix (RLP) to metoda serializacji szeroko stosowana w warstwie wykonawczej Ethereum. + +[Więcej o RLP](/developers/docs/data-structures-and-encoding/rlp) + +### Simple Serialize {#simple-serialize} + +Simple Serialize (SSZ) to dominujący format serializacji w warstwie konsensusu Ethereum ze względu na jego zgodność z merkelizacją. + +[Więcej o SSZ](/developers/docs/data-structures-and-encoding/ssz) diff --git a/public/content/translations/pl/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md b/public/content/translations/pl/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md new file mode 100644 index 00000000000..062cc0b3207 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md @@ -0,0 +1,266 @@ +--- +title: Drzewo Merkle Patricia +description: Wprowadzenie do drzewa Merkle Patricia. +lang: pl +sidebarDepth: 2 +--- + +Stan Ethereum (całość wszystkich kont, sald i inteligentnych kontraktów) jest zakodowany w specjalnej wersji struktury danych, znanej w informatyce jako drzewo Merkle. Struktura ta jest przydatna w wielu zastosowaniach w kryptografii, ponieważ tworzy weryfikowalną relację między wszystkimi pojedynczymi fragmentami danych splątanymi w drzewie, co skutkuje pojedynczą wartością **korzenia**, która może być użyta do udowodnienia różnych kwestii dotyczących danych. + +Struktura danych Ethereum to „zmodyfikowane drzewo Merkle-Patricia”, nazwane tak, ponieważ czerpie niektóre cechy z PATRICIA (ang. Practical Algorithm To Retrieve Information Coded in Alphanumeric) i ponieważ jest zaprojektowana do wydajnego odzyskiwania (ang. re**trie**val) danych, które składają się na stan Ethereum. + +Drzewo Merkle-Patricia jest deterministyczne i weryfikowalne kryptograficznie: jedynym sposobem na wygenerowanie korzenia stanu jest obliczenie go z każdego pojedynczego elementu stanu, a identyczność dwóch stanów można łatwo udowodnić, porównując hasz korzenia i hasze, które do niego doprowadziły (_dowód Merklego_). I odwrotnie, nie ma sposobu na stworzenie dwóch różnych stanów o tym samym haszu korzenia, a każda próba modyfikacji stanu za pomocą różnych wartości spowoduje powstanie innego haszu korzenia stanu. Teoretycznie struktura ta zapewnia „święty Graal” wydajności `O(log(n))` dla operacji wstawiania, wyszukiwania i usuwania. + +W niedalekiej przyszłości Ethereum planuje migrację do struktury [drzewa Verkle](/roadmap/verkle-trees), co otworzy wiele nowych możliwości przyszłych ulepszeń protokołu. + +## Wymagania wstępne {#prerequisites} + +Aby lepiej zrozumieć tę stronę, pomocna będzie podstawowa znajomość [haszy](https://en.wikipedia.org/wiki/Hash_function), [drzew Merklego](https://en.wikipedia.org/wiki/Merkle_tree), [drzew prefiksowych (tries)](https://en.wikipedia.org/wiki/Trie) i [serializacji](https://en.wikipedia.org/wiki/Serialization). Ten artykuł rozpoczyna się od opisu podstawowego [drzewa pozycyjnego (radix)](https://en.wikipedia.org/wiki/Radix_tree), a następnie stopniowo wprowadza modyfikacje niezbędne dla bardziej zoptymalizowanej struktury danych Ethereum. + +## Podstawowe drzewa pozycyjne {#basic-radix-tries} + +W podstawowym drzewie pozycyjnym każdy węzeł wygląda następująco: + +``` + [i_0, i_1 ... i_n, wartość] +``` + +Gdzie `i_0 ... `i_n`reprezentują symbole alfabetu (często binarnego lub szesnastkowego),`wartość`jest wartością końcową w węźle, a wartości w`i_0, i_1 ...` `i_n`slotach są albo`NULL`, albo wskaźnikami (w naszym przypadku haszami) do innych węzłów. Tworzy to podstawowy magazyn `(klucz, wartość)`. + +Załóżmy, że chcesz użyć struktury danych drzewa pozycyjnego do utrwalenia porządku w zbiorze par klucz-wartość. Aby znaleźć wartość aktualnie przypisaną do klucza `dog` w drzewie, należy najpierw przekonwertować `dog` na litery alfabetu (co daje `64 6f 67`), a następnie zejść w dół drzewa, podążając tą ścieżką, aż do znalezienia wartości. Oznacza to, że zaczynasz od wyszukania haszu korzenia w płaskiej bazie danych klucz/wartość, aby znaleźć węzeł główny drzewa. Jest on reprezentowany jako tablica kluczy wskazujących na inne węzły. Użyjesz wartości o indeksie `6` jako klucza i wyszukasz ją w płaskiej bazie danych klucz/wartość, aby uzyskać węzeł o jeden poziom niżej. Następnie wybierz indeks `4`, aby wyszukać następną wartość, potem indeks `6` i tak dalej, aż po przejściu ścieżki: `korzeń -> 6 -> 4 -> 6 -> 15 -> 6 -> 7`, odszukasz wartość węzła i zwrócisz wynik. + +Istnieje różnica między wyszukiwaniem czegoś w „drzewie” a podstawową płaską „bazą danych” klucz/wartość. Oba definiują układy klucz/wartość, ale podstawowa baza danych może wykonać tradycyjne 1-etapowe wyszukiwanie klucza. Wyszukanie klucza w drzewie wymaga wielokrotnego wyszukiwania w podstawowej bazie danych, aby dotrzeć do ostatecznej wartości opisanej powyżej. Aby wyeliminować niejednoznaczność, będziemy nazywać to drugie `ścieżką`. + +Operacje aktualizacji i usuwania dla drzew pozycyjnych można zdefiniować w następujący sposób: + +```python + def update(node_hash, path, value): + curnode = db.get(node_hash) if node_hash else [NULL] * 17 + newnode = curnode.copy() + if path == "": + newnode[-1] = value + else: + newindex = update(curnode[path[0]], path[1:], value) + newnode[path[0]] = newindex + db.put(hash(newnode), newnode) + return hash(newnode) + + def delete(node_hash, path): + if node_hash is NULL: + return NULL + else: + curnode = db.get(node_hash) + newnode = curnode.copy() + if path == "": + newnode[-1] = NULL + else: + newindex = delete(curnode[path[0]], path[1:]) + newnode[path[0]] = newindex + + if all(x is NULL for x in newnode): + return NULL + else: + db.put(hash(newnode), newnode) + return hash(newnode) +``` + +Drzewo pozycyjne „Merkle” jest zbudowane przez łączenie węzłów przy użyciu deterministycznie generowanych kryptograficznych skrótów haszujących. To adresowanie treści (w bazie danych klucz/wartość `klucz == keccak256(rlp(wartość))`) zapewnia kryptograficzną gwarancję integralności przechowywanych danych. Jeśli hasz korzenia danego drzewa jest publicznie znany, każdy, kto ma dostęp do danych bazowych liści, może skonstruować dowód, że drzewo zawiera daną wartość w określonej ścieżce, podając hasze każdego węzła łączącego określoną wartość z korzeniem drzewa. + +Atakujący nie może przedstawić dowodu na parę `(ścieżka, wartość)`, która nie istnieje, ponieważ hasz korzenia jest ostatecznie oparty na wszystkich haszach znajdujących się pod nim. Każda modyfikacja bazowa zmieniłaby hasz korzenia. Można myśleć o haszu jako o skompresowanej reprezentacji informacji strukturalnych o danych, zabezpieczonej przez ochronę przeciwobrazu funkcji haszującej. + +Będziemy odnosić się do jednostki atomowej drzewa pozycyjnego (np. pojedynczego znaku szesnastkowego lub 4-bitowej liczby binarnej) jako „półbajtu”. Podczas przechodzenia ścieżki po jednym półbajcie na raz, jak opisano powyżej, węzły mogą odnosić się maksymalnie do 16 potomków, ale zawierają element `wartość`. Dlatego reprezentujemy je jako tablicę o długości 17. Nazywamy te 17-elementowe tablice „węzłami gałęzi”. + +## Drzewo Merkle Patricia {#merkle-patricia-trees} + +Drzewa pozycyjne mają jedno poważne ograniczenie: są nieefektywne. Jeśli chcesz przechować jedno powiązanie `(ścieżka, wartość)`, gdzie ścieżka, podobnie jak w Ethereum, ma 64 znaki długości (liczba półbajtów w `bytes32`), będziemy potrzebować ponad kilobajt dodatkowej przestrzeni na przechowanie jednego poziomu na znak, a każde wyszukiwanie lub usuwanie zajmie pełne 64 kroki. Drzewo Patricia wprowadzone w dalszej części rozwiązuje ten problem. + +### Optymalizacja {#optimization} + +Węzeł w drzewie Merkle Patricia jest jednym z następujących: + +1. `NULL` (reprezentowany jako pusty ciąg znaków) +2. `gałąź` 17-elementowy węzeł `[ v0 ...` `v15, vt ]` +3. `liść` 2-elementowy węzeł `[ zakodowanaŚcieżka, wartość ]` +4. `rozszerzenie` 2-elementowy węzeł `[ zakodowanaŚcieżka, klucz ]` + +Przy ścieżkach o długości 64 znaków nieuniknione jest, że po przejściu przez kilka pierwszych warstw drzewa dotrzemy do węzła, w którym przez przynajmniej część drogi w dół nie istnieje żadna rozbieżna ścieżka. Aby uniknąć konieczności tworzenia do 15 rzadkich węzłów `NULL` wzdłuż ścieżki, skracamy drogę, tworząc węzeł `rozszerzenia` w formie `[ zakodowanaŚcieżka, klucz ]`, gdzie `zakodowanaŚcieżka` zawiera „częściową ścieżkę” do pominięcia (używając kompaktowego kodowania opisanego poniżej), a `klucz` służy do następnego wyszukiwania w bazie danych. + +W przypadku węzła `liścia`, który może być oznaczony flagą w pierwszym półbajcie `zakodowanejŚcieżki`, ścieżka koduje wszystkie fragmenty ścieżek poprzednich węzłów i możemy bezpośrednio wyszukać `wartość`. + +Powyższa optymalizacja wprowadza jednak niejednoznaczność. + +Podczas przechodzenia ścieżek w półbajtach możemy skończyć z nieparzystą liczbą półbajtów do przejścia, ale ponieważ wszystkie dane są przechowywane w formacie `bajtów`. Nie jest możliwe rozróżnienie, na przykład, półbajtu `1` od półbajtów `01` (oba muszą być przechowywane jako `<01>`). Aby określić nieparzystą długość, częściowa ścieżka jest poprzedzona flagą. + +### Specyfikacja: Kompaktowe kodowanie sekwencji szesnastkowej z opcjonalnym terminatorem {#specification} + +Oznaczanie zarówno _nieparzystej vs. parzystej pozostałej długości częściowej ścieżki_, jak i _węzła liścia vs. rozszerzenia_, jak opisano powyżej, znajduje się w pierwszym półbajcie częściowej ścieżki dowolnego 2-elementowego węzła. Skutkują one następującymi: + +| znak hex | bity | częściowy typ węzła | długość ścieżki | +| -------- | ---- | ---------------------------------- | --------------- | +| 0 | 0000 | rozszerzenie | parzysta | +| 1 | 0001 | rozszerzenie | nieparzysta | +| 2 | 0010 | kończący (liść) | parzysta | +| 3 | 0011 | kończący (liść) | nieparzysta | + +Dla parzystej pozostałej długości ścieżki (`0` lub `2`) zawsze następuje kolejny `0` „dopełniający” półbajt. + +```python + def compact_encode(hexarray): + term = 1 if hexarray[-1] == 16 else 0 + if term: + hexarray = hexarray[:-1] + oddlen = len(hexarray) % 2 + flags = 2 * term + oddlen + if oddlen: + hexarray = [flags] + hexarray + else: + hexarray = [flags] + [0] + hexarray + # hexarray now has an even length whose first nibble is the flags. + o = "" + for i in range(0, len(hexarray), 2): + o += chr(16 * hexarray[i] + hexarray[i + 1]) + return o +``` + +Przykłady: + +```python + > [1, 2, 3, 4, 5, ...] + '11 23 45' + > [0, 1, 2, 3, 4, 5, ...] + '00 01 23 45' + > [0, f, 1, c, b, 8, 10] + '20 0f 1c b8' + > [f, 1, c, b, 8, 10] + '3f 1c b8' +``` + +Oto rozszerzony kod do pobierania węzła w drzewie Merkle Patricia: + +```python + def get_helper(node_hash, path): + if path == []: + return node_hash + if node_hash == "": + return "" + curnode = rlp.decode(node_hash if len(node_hash) < 32 else db.get(node_hash)) + if len(curnode) == 2: + (k2, v2) = curnode + k2 = compact_decode(k2) + if k2 == path[: len(k2)]: + return get(v2, path[len(k2) :]) + else: + return "" + elif len(curnode) == 17: + return get_helper(curnode[path[0]], path[1:]) + + def get(node_hash, path): + path2 = [] + for i in range(len(path)): + path2.push(int(ord(path[i]) / 16)) + path2.push(ord(path[i]) % 16) + path2.push(16) + return get_helper(node_hash, path2) +``` + +### Przykładowe drzewo {#example-trie} + +Załóżmy, że chcemy mieć drzewo zawierające cztery pary ścieżka/wartość `('do', 'verb')`, `('dog', 'puppy')`, `('doge', 'coins')`, `('horse', 'stallion')`. + +Najpierw konwertujemy zarówno ścieżki, jak i wartości na `bajty`. Poniżej, rzeczywiste reprezentacje bajtowe dla _ścieżek_ są oznaczone przez `<>`, chociaż _wartości_ są nadal pokazane jako ciągi znaków, oznaczone przez `''`, dla łatwiejszego zrozumienia (one również w rzeczywistości byłyby `bajtami`): + +``` + <64 6f> : 'verb' + <64 6f 67> : 'puppy' + <64 6f 67 65> : 'coins' + <68 6f 72 73 65> : 'stallion' +``` + +Teraz budujemy takie drzewo z następującymi parami klucz/wartość w podstawowej bazie danych: + +``` + rootHash: [ <16>, hashA ] + hashA: [ <>, <>, <>, <>, hashB, <>, <>, <>, [ <20 6f 72 73 65>, 'stallion' ], <>, <>, <>, <>, <>, <>, <>, <> ] + hashB: [ <00 6f>, hashC ] + hashC: [ <>, <>, <>, <>, <>, <>, hashD, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'verb' ] + hashD: [ <17>, [ <>, <>, <>, <>, <>, <>, [ <35>, 'coins' ], <>, <>, <>, <>, <>, <>, <>, <>, <>, 'puppy' ] ] +``` + +Gdy jeden węzeł jest przywoływany wewnątrz innego węzła, to, co jest dołączane, to `keccak256(rlp.encode(node))`, jeśli `len(rlp.encode(node)) >= 32`, w przeciwnym razie `node`, gdzie `rlp.encode` to funkcja kodowania [RLP](/developers/docs/data-structures-and-encoding/rlp). + +Należy pamiętać, że podczas aktualizacji drzewa należy zapisać parę klucz/wartość `(keccak256(x), x)` w trwałej tabeli przeglądowej, _jeśli_ nowo utworzony węzeł ma długość >= 32. Jeśli jednak węzeł jest krótszy, nie trzeba niczego przechowywać, ponieważ funkcja f(x) = x jest odwracalna. + +## Drzewa w Ethereum {#tries-in-ethereum} + +Wszystkie drzewa Merklego w warstwie wykonawczej Ethereum wykorzystują drzewo Merkle Patricia. + +Z nagłówka bloku pochodzą 3 korzenie z 3 takich drzew. + +1. stateRoot +2. transactionsRoot +3. receiptsRoot + +### Drzewo stanu {#state-trie} + +Istnieje jedno globalne drzewo stanu, które jest aktualizowane za każdym razem, gdy klient przetwarza blok. W nim `ścieżka` to zawsze: `keccak256(adresEthereum)`, a `wartość` to zawsze: `rlp(kontoEthereum)`. Dokładniej, `konto` Ethereum to 4-elementowa tablica `[nonce,balance,storageRoot,codeHash]`. W tym momencie warto zauważyć, że ten `storageRoot` jest korzeniem innego drzewa Patricia: + +### Drzewo przechowywania {#storage-trie} + +Drzewo przechowywania to miejsce, w którym znajdują się _wszystkie_ dane kontraktu. Dla każdego konta istnieje oddzielne drzewo przechowywania. Aby pobrać wartości na określonych pozycjach przechowywania pod danym adresem, wymagany jest adres przechowywania, pozycja całkowita przechowywanych danych w magazynie oraz identyfikator bloku. Można je następnie przekazać jako argumenty do `eth_getStorageAt` zdefiniowanego w API JSON-RPC, np. aby pobrać dane ze slotu 0 przechowywania dla adresu `0x295a70b2de5e3953354a6a8344e616ed314d7251`: + +```bash +curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545 + +{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000004d2"} + +``` + +Pobieranie innych elementów z magazynu jest nieco bardziej skomplikowane, ponieważ najpierw należy obliczyć pozycję w drzewie przechowywania. Pozycja jest obliczana jako hasz `keccak256` adresu i pozycji w magazynie, oba dopełnione z lewej strony zerami do długości 32 bajtów. Na przykład pozycja danych w slocie 1 przechowywania dla adresu `0x391694e7e0b0cce554cb130d723a9d27458f9298` to: + +```python +keccak256(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001")) +``` + +W konsoli Geth można to obliczyć w następujący sposób: + +``` +> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001" +undefined +> web3.sha3(key, {"encoding": "hex"}) +"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9" +``` + +`Ścieżka` jest zatem `keccak256(<6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9>)`. Można to teraz wykorzystać do pobrania danych z drzewa przechowywania, tak jak poprzednio: + +```bash +curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", "latest"], "id": 1}' localhost:8545 + +{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000162e"} +``` + +Uwaga: `storageRoot` dla konta Ethereum jest domyślnie pusty, jeśli nie jest to konto kontraktu. + +### Drzewo transakcji {#transaction-trie} + +Dla każdego bloku istnieje osobne drzewo transakcji, przechowujące pary `(klucz, wartość)`. Ścieżka tutaj to: `rlp(indeksTransakcji)`, która reprezentuje klucz odpowiadający wartości określonej przez: + +```python +if legacyTx: + value = rlp(tx) +else: + value = TxType | encode(tx) +``` + +Więcej informacji na ten temat można znaleźć w dokumentacji [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718). + +### Drzewo potwierdzeń {#receipts-trie} + +Każdy blok ma własne drzewo potwierdzeń. `Ścieżka` tutaj to: `rlp(indeksTransakcji)`. `indeksTransakcji` to jego indeks w bloku, w którym został zawarty. Drzewo potwierdzeń nigdy nie jest aktualizowane. Podobnie jak w drzewie transakcji, istnieją bieżące i starsze potwierdzenia. Aby wyszukać określone potwierdzenie w drzewie potwierdzeń, wymagany jest indeks transakcji w jej bloku, ładunek potwierdzenia oraz typ transakcji. Zwrócone potwierdzenie może być typu `Receipt`, który jest zdefiniowany jako konkatenacja `TransactionType` i `ReceiptPayload` lub może być typu `LegacyReceipt`, który jest zdefiniowany jako `rlp([status, cumulativeGasUsed, logsBloom, logs])`. + +Więcej informacji na ten temat można znaleźć w dokumentacji [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718). + +## Dalsza lektura {#further-reading} + +- [Zmodyfikowane drzewo Merkle Patricia — jak Ethereum zapisuje stan](https://medium.com/codechain/modified-merkle-patricia-trie-how-ethereum-saves-a-state-e6d7555078dd) +- [Merkling w Ethereum](https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/) +- [Zrozumieć drzewo Ethereum](https://easythereentropy.wordpress.com/2014/06/04/understanding-the-ethereum-trie/) diff --git a/public/content/translations/pl/developers/docs/data-structures-and-encoding/rlp/index.md b/public/content/translations/pl/developers/docs/data-structures-and-encoding/rlp/index.md new file mode 100644 index 00000000000..eae5e659ee6 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-structures-and-encoding/rlp/index.md @@ -0,0 +1,163 @@ +--- +title: "Serializacja prefiksem o rekursywnej długości (RLP)" +description: Definicja kodowania RLP w warstwie wykonawczej Ethereum. +lang: pl +sidebarDepth: 2 +--- + +Serializacja przy użyciu prefiksu o rekursywnej długości (RLP) jest szeroko stosowana w klientach wykonawczych Ethereum. RLP standaryzuje przesyłanie danych pomiędzy węzłami w formacie oszczędzającym miejsce. Celem RLP jest kodowanie dowolnie zagnieżdżonych tablic danych binarnych oraz RLP jest główną metodą kodowania wykorzystywaną do serializacji obiektów w warstwie wykonawczej Ethereum. Głównym celem RLP jest kodowanie struktury; z wyjątkiem dodatnich liczb całkowitych, RLP oddelegowuje kodowanie specyficznych typów danych (np. ciągów znaków, liczb zmiennoprzecinkowych) do protokołów wyższego rzędu. Dodatnie liczby całkowite muszą być reprezentowane w postaci binarnej big endian bez zer wiodących (w ten sposób wartość całkowita zero jest równoważna pustej tablicy bajtów). Deserializowane dodatnie liczby całkowite z wiodącymi zerami powinny być traktowane jako nieprawidłowe przez dowolny protokół wyższego rzędu wykorzystujący RLP. + +Więcej informacji w [żółtej księdze Ethereum (Dodatek B)](https://ethereum.github.io/yellowpaper/paper.pdf#page=19). + +Aby użyć RLP do zakodowania słownika, zaleca się dwie następujące kanoniczne formy: + +- użyj `[[k1,v1],[k2,v2]...]` z kluczami w porządku leksykograficznym +- użycie kodowania wyższego poziomu drzewa Patricia, tak jak robi to Ethereum + +## Definicja {#definition} + +Funkcja kodowania RLP przyjmuje jeden element. Element zdefiniowany jest w następujący sposób: + +- ciąg znaków (tzn. tablica bajtów) jest elementem +- lista elementów jest elementem +- dodatnia liczba całkowita jest elementem + +Dla przykładu wszystko, co poniżej jest elementem: + +- pusty ciąg znaków; +- ciąg znaków zawierający słowo „cat”; +- lista zawierająca dowolną ilość ciągów znaków; +- oraz bardziej złożone struktury danych, takie jak `["cat", ["puppy", "cow"], "horse", [[]], "pig", [""], "sheep"]`. +- liczba `100` + +Zauważ, że w kontekście reszty tej strony „ciąg znaków” oznacza „określoną liczbę bajtów danych binarnych”; nie są używane żadne specjalne kodowania i nie jest implikowana żadna wiedza na temat zawartości ciągów znaków (z wyjątkiem tego, co jest wymagane przez regułę przeciwko nieminimalnym dodatnim liczbom całkowitym). + +Kodowanie RLP definiuje się w następujący sposób: + +- Dla dodatniej liczby całkowitej: jest ona konwertowana na najkrótszą tablicę bajtów, której interpretacja w postaci big endian odpowiada tej liczbie całkowitej, a następnie kodowana jako ciąg znaków zgodnie z poniższymi zasadami. +- Dla pojedynczego bajtu, którego wartość znajduje się w zakresie `[0x00, 0x7f]` (dziesiętnie `[0, 127]`), ten bajt jest swoim własnym kodowaniem RLP. +- W przeciwnym razie, jeśli ciąg znaków ma 0-55 bajtów długości, kodowanie RLP składa się z pojedynczego bajtu o wartości **0x80** (dzies. 128) plus długość ciągu, po której następuje sam ciąg. Zakres pierwszego bajtu wynosi więc `[0x80, 0xb7]` (dzies. `[128, 183]`). +- Jeśli ciąg znaków ma więcej niż 55 bajtów, kodowanie RLP składa się z pojedynczego bajtu o wartości **0xb7** (dzies. 183) plus długość w bajtach długości ciągu w postaci binarnej, po której następuje długość ciągu, a po niej sam ciąg. Na przykład ciąg znaków o długości 1024 bajtów byłby zakodowany jako `\xb9\x04\x00` (dzies. `185, 4, 0`), po którym następuje ciąg. Tutaj, `0xb9` (183 + 2 = 185) jako pierwszy bajt, po którym następują 2 bajty `0x0400` (dzies. 1024) oznaczające długość właściwego ciągu. Zakres pierwszego bajtu wynosi więc `[0xb8, 0xbf]` (dzies. `[184, 191]`). +- Jeśli ciąg znaków ma długość 2^64 bajtów lub większą, nie może zostać zakodowany. +- Jeśli całkowity ładunek listy (tzn. łączna długość wszystkich jej elementów zakodowanych w RLP) ma 0-55 bajtów długości, kodowanie RLP składa się z pojedynczego bajtu o wartości **0xc0** plus długość ładunku, po którym następuje konkatenacja kodowań RLP poszczególnych elementów. Zakres pierwszego bajtu wynosi więc `[0xc0, 0xf7]` (dzies. `[192, 247]`). +- Jeśli całkowity ładunek listy ma więcej niż 55 bajtów, kodowanie RLP składa się z pojedynczego bajtu o wartości **0xf7** plus długość w bajtach długości ładunku w postaci binarnej, po której następuje długość ładunku, a następnie konkatenacja kodowań RLP poszczególnych elementów. Zakres pierwszego bajtu wynosi więc `[0xf8, 0xff]` (dzies. `[248, 255]`). + +W kodzie wygląda to tak: + +```python +def rlp_encode(input): + if isinstance(input,str): + if len(input) == 1 and ord(input) < 0x80: + return input + return encode_length(len(input), 0x80) + input + elif isinstance(input, list): + output = '' + for item in input: + output += rlp_encode(item) + return encode_length(len(output), 0xc0) + output + +def encode_length(L, offset): + if L < 56: + return chr(L + offset) + elif L < 256**8: + BL = to_binary(L) + return chr(len(BL) + offset + 55) + BL + raise Exception("zbyt długie dane wejściowe") + +def to_binary(x): + if x == 0: + return '' + return to_binary(int(x / 256)) + chr(x % 256) +``` + +## Przykłady {#examples} + +- ciąg znaków „dog” = [ 0x83, 'd', 'o', 'g' ] +- lista [ "cat", "dog" ] = `[ 0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' ]` +- pusty ciąg znaków ('null') = `[ 0x80 ]` +- pusta lista = `[ 0xc0 ]` +- liczba całkowita 0 = `[ 0x80 ]` +- bajt '\\x00' = `[ 0x00 ]` +- bajt '\\x0f' = `[ 0x0f ]` +- bajty '\\x04\\x00' = `[ 0x82, 0x04, 0x00 ]` +- the [reprezentacja teoriomnogościowa](http://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers) of three, `[ [], [[]], [ [], [[]] ] ] = [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ]` +- ciąg znaków "Lorem ipsum dolor sit amet, consectetur adipisicing elit" = `[ 0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't' ]` + +## Dekodowanie RLP {#rlp-decoding} + +Zgodnie z zasadami i procesem kodowania RLP, dane wejściowe dla dekodowania RLP są traktowane jako tablica danych binarnych. Proces dekodowania RLP jest następujący: + +1. zgodnie z pierwszym bajtem (tzn. prefiksem) danych wejściowych i dekodowaniem typu danych, długości rzeczywistych danych i przesunięcia; + +2. zgodnie z typem oraz przesunięciem danych, następuje dekodowanie danych z uwzględnieniem reguły minimalnego kodowania dla dodatnich liczb całkowitych; + +3. następnie kontynuuje się dekodowanie pozostałej części danych wejściowych; + +Wśród nich zasady dekodowania typów oraz przesunięcia danych są następujące: + +1. dane są ciągiem znaków, jeśli zakres pierwszego bajtu (tzn. prefiksu) wynosi [0x00, 0x7f], a sam ciąg jest dokładnie tym pierwszym bajtem; + +2. dane są ciągiem znaków, jeśli zakres pierwszego bajtu wynosi [0x80, 0xb7], a za pierwszym bajtem znajduje się ciąg znaków o długości równej pierwszemu bajtowi minus 0x80; + +3. dane są ciągiem znaków, jeśli zakres pierwszego bajtu wynosi [0xb8, 0xbf], a długość ciągu, której długość w bajtach jest równa pierwszemu bajtowi minus 0xb7, znajduje się za pierwszym bajtem, a za długością znajduje się sam ciąg; + +4. dane są listą, jeśli zakres pierwszego bajtu wynosi [0xc0, 0xf7], a za pierwszym bajtem znajduje się konkatenacja kodowań RLP wszystkich elementów listy, których łączny ładunek jest równy pierwszemu bajtowi minus 0xc0; + +5. dane są listą, jeśli zakres pierwszego bajtu wynosi [0xf8, 0xff], a za pierwszym bajtem znajduje się łączny ładunek listy, której długość jest równa pierwszemu bajtowi minus 0xf7, a po łącznym ładunku listy następuje konkatenacja kodowań RLP wszystkich elementów listy; + +W kodzie wygląda to tak: + +```python +def rlp_decode(input): + if len(input) == 0: + return + output = '' + (offset, dataLen, type) = decode_length(input) + if type is str: + output = instantiate_str(substr(input, offset, dataLen)) + elif type is list: + output = instantiate_list(substr(input, offset, dataLen)) + output += rlp_decode(substr(input, offset + dataLen)) + return output + +def decode_length(input): + length = len(input) + if length == 0: + raise Exception("puste dane wejściowe") + prefix = ord(input[0]) + if prefix <= 0x7f: + return (0, 1, str) + elif prefix <= 0xb7 and length > prefix - 0x80: + strLen = prefix - 0x80 + return (1, strLen, str) + elif prefix <= 0xbf and length > prefix - 0xb7 and length > prefix - 0xb7 + to_integer(substr(input, 1, prefix - 0xb7)): + lenOfStrLen = prefix - 0xb7 + strLen = to_integer(substr(input, 1, lenOfStrLen)) + return (1 + lenOfStrLen, strLen, str) + elif prefix <= 0xf7 and length > prefix - 0xc0: + listLen = prefix - 0xc0; + return (1, listLen, list) + elif prefix <= 0xff and length > prefix - 0xf7 and length > prefix - 0xf7 + to_integer(substr(input, 1, prefix - 0xf7)): + lenOfListLen = prefix - 0xf7 + listLen = to_integer(substr(input, 1, lenOfListLen)) + return (1 + lenOfListLen, listLen, list) + raise Exception("dane wejściowe niezgodne z formą kodowania RLP") + +def to_integer(b): + length = len(b) + if length == 0: + raise Exception("puste dane wejściowe") + elif length == 1: + return ord(b[0]) + return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256 +``` + +## Dalsza lektura {#further-reading} + +- [RLP w Ethereum](https://medium.com/coinmonks/data-structure-in-ethereum-episode-1-recursive-length-prefix-rlp-encoding-decoding-d1016832f919) +- [Ethereum od podszewki: RLP](https://medium.com/coinmonks/ethereum-under-the-hood-part-3-rlp-decoding-df236dc13e58) +- Coglio, A. (2020 r.). Prefiks o rekursywnej długości Ethereum w ACL2. preprint arXiv:2009.13769.](https://arxiv.org/abs/2009.13769) + +## Powiązane tematy {#related-topics} + +- [drzewo Patricia Merkle](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) diff --git a/public/content/translations/pl/developers/docs/data-structures-and-encoding/ssz/index.md b/public/content/translations/pl/developers/docs/data-structures-and-encoding/ssz/index.md new file mode 100644 index 00000000000..951f6f48896 --- /dev/null +++ b/public/content/translations/pl/developers/docs/data-structures-and-encoding/ssz/index.md @@ -0,0 +1,150 @@ +--- +title: Prosta serializacja +description: "Wyjaśnienie formatu SSZ Ethereum." +lang: pl +sidebarDepth: 2 +--- + +**Prosta serializacja (SSZ)** to metoda serializacji stosowana w łańcuchu Beacon Chain. Zastępuje ona serializację RLP używaną na warstwie wykonawczej wszędzie w warstwie konsensusu, z wyjątkiem protokołu odnajdywania peerów. Aby dowiedzieć się więcej o serializacji RLP, zobacz [Prefiks o rekurencyjnej długości (RLP)](/developers/docs/data-structures-and-encoding/rlp/). SSZ zostało zaprojektowane tak, aby było deterministyczne, a także aby umożliwiało wydajne tworzenie drzew Merkle'a. SSZ można postrzegać jako składające się z dwóch komponentów: schematu serializacji i schematu tworzenia drzew Merkle'a, który jest zaprojektowany do wydajnej pracy z serializowaną strukturą danych. + +## Jak działa SSZ? {#how-does-ssz-work} + +### Serializacja {#serialization} + +SSZ to schemat serializacji, który nie jest samoopisujący się – zamiast tego opiera się na schemacie, który musi być znany z góry. Celem serializacji SSZ jest przedstawienie obiektów o dowolnej złożoności jako ciągów bajtów. Jest to bardzo prosty proces dla "typów podstawowych". Element jest po prostu konwertowany na bajty szesnastkowe. Typy podstawowe obejmują: + +- liczby całkowite bez znaku +- Wartości logiczne + +W przypadku złożonych typów "złożonych" serializacja jest bardziej skomplikowana, ponieważ typ złożony zawiera wiele elementów, które mogą mieć różne typy, różne rozmiary lub jedno i drugie. Gdy wszystkie te obiekty mają stałe długości (tzn. rozmiar elementów będzie zawsze stały niezależnie od ich rzeczywistych wartości), serializacja jest po prostu konwersją każdego elementu w typie złożonym uporządkowanym w ciągi bajtów w formacie little-endian. Te ciągi bajtów są ze sobą łączone. Zserializowany obiekt ma reprezentację listy bajtów elementów o stałej długości w tej samej kolejności, w jakiej występują w obiekcie zdeserializowanym. + +W przypadku typów o zmiennej długości rzeczywiste dane są zastępowane wartością "przesunięcia" na pozycji tego elementu w zserializowanym obiekcie. Rzeczywiste dane są dodawane do sterty na końcu zserializowanego obiektu. Wartość przesunięcia jest indeksem początku rzeczywistych danych na stercie, działając jako wskaźnik do odpowiednich bajtów. + +Poniższy przykład ilustruje, jak działa przesunięcie dla kontenera z elementami o stałej i zmiennej długości: + +```Rust + + struct Dummy { + + number1: u64, + number2: u64, + vector: Vec, + number3: u64 + } + + dummy = Dummy{ + + number1: 37, + number2: 55, + vector: vec![1,2,3,4], + number3: 22, + } + + serialized = ssz.serialize(dummy) + +``` + +`serialized` miałoby następującą strukturę (tutaj dopełnione tylko do 4 bitów, w rzeczywistości do 32 bitów, z zachowaniem reprezentacji `int` dla przejrzystości): + +``` +[37, 0, 0, 0, 55, 0, 0, 0, 16, 0, 0, 0, 22, 0, 0, 0, 1, 2, 3, 4] +------------ ----------- ----------- ----------- ---------- + | | | | | + number1 number2 przesunięcie dla number3 wartość dla + vector vector + +``` + +podzielone na wiersze dla przejrzystości: + +``` +[ + 37, 0, 0, 0, # kodowanie little-endian dla `number1`. + 55, 0, 0, 0, # kodowanie little-endian dla `number2`. + 16, 0, 0, 0, # „Przesunięcie”, które wskazuje, gdzie zaczyna się wartość `vector` (little-endian 16). + 22, 0, 0, 0, # kodowanie little-endian dla `number3`. + 1, 2, 3, 4, # Rzeczywiste wartości w `vector`. +] +``` + +To wciąż uproszczenie – liczby całkowite i zera na powyższych schematach byłyby w rzeczywistości przechowywane jako listy bajtów, w ten sposób: + +``` +[ + 10100101000000000000000000000000 # kodowanie little-endian dla `number1` + 10110111000000000000000000000000 # kodowanie little-endian dla `number2`. + 10010000000000000000000000000000 # „Przesunięcie”, które wskazuje, gdzie zaczyna się wartość `vector` (little-endian 16). + 10010110000000000000000000000000 # kodowanie little-endian dla `number3`. + 10000001100000101000001110000100 # Rzeczywista wartość pola `bytes`. +] +``` + +Tak więc rzeczywiste wartości dla typów o zmiennej długości są przechowywane na stercie na końcu zserializowanego obiektu, a ich przesunięcia są przechowywane na właściwych pozycjach na uporządkowanej liście pól. + +Istnieją również pewne szczególne przypadki, które wymagają specjalnego traktowania, takie jak typ `BitList`, który wymaga dodania ograniczenia długości podczas serializacji i usunięcia go podczas deserializacji. Pełne szczegóły są dostępne w [specyfikacji SSZ](https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md). + +### Deserializacja {#deserialization} + +Aby zdeserializować ten obiekt, wymagany jest schemat. Schemat definiuje precyzyjny układ zserializowanych danych, tak aby każdy konkretny element mógł zostać zdeserializowany z bloba bajtów w jakiś znaczący obiekt z elementami o odpowiednim typie, wartości, rozmiarze i pozycji. To schemat informuje deserializator, które wartości są rzeczywistymi wartościami, a które przesunięciami. Wszystkie nazwy pól znikają, gdy obiekt jest serializowany, ale są ponownie tworzone podczas deserializacji zgodnie ze schematem. + +Zobacz interaktywny opis na [ssz.dev](https://www.ssz.dev/overview). + +## Tworzenie drzewa Merkle'a {#merkleization} + +Ten zserializowany obiekt SSZ może być następnie przekształcony w drzewo Merkle'a – to znaczy przekształcony w reprezentację tych samych danych w postaci drzewa Merkle'a. Najpierw określa się liczbę 32-bajtowych fragmentów w zserializowanym obiekcie. Są to "liście" drzewa. Całkowita liczba liści musi być potęgą liczby 2, aby haszowanie liści ostatecznie dało pojedynczy korzeń drzewa haszującego. Jeśli tak nie jest, dodawane są dodatkowe liście zawierające 32 bajty zer. Schematycznie: + +``` + korzeń drzewa haszującego + / \ + / \ + / \ + / \ + hasz liści hasz liści + 1 i 2 3 i 4 + / \ / \ + / \ / \ + / \ / \ + liść1 liść2 liść3 liść4 +``` + +Istnieją również przypadki, w których liście drzewa nie rozkładają się naturalnie równomiernie w taki sposób, jak w powyższym przykładzie. Na przykład liść 4 może być kontenerem z wieloma elementami, które wymagają dodania dodatkowej "głębokości" do drzewa Merkle'a, tworząc nierówne drzewo. + +Zamiast odnosić się do tych elementów drzewa jako liść X, węzeł X itd., możemy nadać im uogólnione indeksy, zaczynając od korzenia = 1 i licząc od lewej do prawej na każdym poziomie. Jest to uogólniony indeks wyjaśniony powyżej. Każdy element na zserializowanej liście ma uogólniony indeks równy `2**depth + idx`, gdzie idx jest jego pozycją indeksowaną od zera w zserializowanym obiekcie, a głębokość jest liczbą poziomów w drzewie Merkle'a, którą można określić jako logarytm o podstawie dwa z liczby elementów (liści). + +## Indeksy uogólnione {#generalized-indices} + +Uogólniony indeks to liczba całkowita, która reprezentuje węzeł w binarnym drzewie Merkle'a, gdzie każdy węzeł ma uogólniony indeks `2 ** depth + index in row`. + +``` + 1 --głębokość = 0 2**0 + 0 = 1 + 2 3 --głębokość = 1 2**1 + 0 = 2, 2**1+1 = 3 + 4 5 6 7 --głębokość = 2 2**2 + 0 = 4, 2**2 + 1 = 5... + +``` + +Ta reprezentacja daje indeks węzła dla każdego fragmentu danych w drzewie Merkle'a. + +## Wielodowody {#multiproofs} + +Podanie listy uogólnionych indeksów reprezentujących określony element pozwala nam zweryfikować go względem korzenia drzewa haszującego. Ten korzeń jest naszą akceptowaną wersją rzeczywistości. Wszelkie dane, które otrzymujemy, mogą być zweryfikowane względem tej rzeczywistości poprzez wstawienie ich we właściwe miejsce w drzewie Merkle'a (określone przez ich uogólniony indeks) i obserwowanie, że korzeń pozostaje stały. W specyfikacji [tutaj](https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#merkle-multiproofs) znajdują się funkcje, które pokazują, jak obliczyć minimalny zbiór węzłów wymaganych do zweryfikowania zawartości określonego zbioru uogólnionych indeksów. + +Na przykład, aby zweryfikować dane o indeksie 9 w poniższym drzewie, potrzebujemy haszu danych o indeksach 8, 9, 5, 3, 1. +Hasz (8,9) powinien być równy haszowi (4), który jest haszowany z 5, aby utworzyć 2, który jest haszowany z 3, aby utworzyć korzeń drzewa 1. Gdyby dla 9 podano nieprawidłowe dane, korzeń by się zmienił – wykrylibyśmy to i nie udałoby się zweryfikować gałęzi. + +``` +* = dane wymagane do wygenerowania dowodu + + 1* + 2 3* + 4 5* 6 7 +8* 9* 10 11 12 13 14 15 + +``` + +## Dalsza lektura {#further-reading} + +- [Modernizacja Ethereum: SSZ](https://eth2book.info/altair/part2/building_blocks/ssz) +- [Modernizacja Ethereum: tworzenie drzewa Merkle'a](https://eth2book.info/altair/part2/building_blocks/merkleization) +- [Implementacje SSZ](https://github.com/ethereum/consensus-specs/issues/2138) +- [Kalkulator SSZ](https://simpleserialize.com/) +- [SSZ.dev](https://www.ssz.dev/) From 36434371a87dd3255ed433898f362f0b4fe21128 Mon Sep 17 00:00:00 2001 From: Joshua <62268199+minimalsm@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:08:06 +0000 Subject: [PATCH 2/9] i18n(pl): translation import part 07 of 13 (23 files) --- .../pl/developers/docs/storage/index.md | 211 ++- .../pl/developers/docs/transactions/index.md | 114 +- .../pl/developers/docs/web2-vs-web3/index.md | 36 +- .../pl/developers/docs/wrapped-eth/index.md | 6 +- .../index.md | 2 +- .../index.md | 300 ++++ .../tutorials/all-you-can-cache/index.md | 867 +++++++++ .../developers/tutorials/app-plasma/index.md | 1255 ++++++++++++++ .../index.md | 59 +- .../index.md | 585 +++++++ .../index.md | 68 +- .../index.md | 372 ++++ .../index.md | 144 ++ .../index.md | 129 ++ .../erc-721-vyper-annotated-code/index.md | 713 ++++++++ .../tutorials/erc20-annotated-code/index.md | 873 ++++++++++ .../erc20-with-safety-rails/index.md | 217 +++ .../tutorials/ethereum-for-web2-auth/index.md | 886 ++++++++++ .../index.md | 122 +- .../index.md | 102 ++ .../index.md | 1543 +++++++++++++++++ .../hello-world-smart-contract/index.md | 367 ++++ .../index.md | 34 +- 23 files changed, 8772 insertions(+), 233 deletions(-) create mode 100644 public/content/translations/pl/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md create mode 100644 public/content/translations/pl/developers/tutorials/all-you-can-cache/index.md create mode 100644 public/content/translations/pl/developers/tutorials/app-plasma/index.md create mode 100644 public/content/translations/pl/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md create mode 100644 public/content/translations/pl/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md create mode 100644 public/content/translations/pl/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md create mode 100644 public/content/translations/pl/developers/tutorials/eip-1271-smart-contract-signatures/index.md create mode 100644 public/content/translations/pl/developers/tutorials/erc-721-vyper-annotated-code/index.md create mode 100644 public/content/translations/pl/developers/tutorials/erc20-annotated-code/index.md create mode 100644 public/content/translations/pl/developers/tutorials/erc20-with-safety-rails/index.md create mode 100644 public/content/translations/pl/developers/tutorials/ethereum-for-web2-auth/index.md create mode 100644 public/content/translations/pl/developers/tutorials/guide-to-smart-contract-security-tools/index.md create mode 100644 public/content/translations/pl/developers/tutorials/hello-world-smart-contract-fullstack/index.md create mode 100644 public/content/translations/pl/developers/tutorials/hello-world-smart-contract/index.md diff --git a/public/content/translations/pl/developers/docs/storage/index.md b/public/content/translations/pl/developers/docs/storage/index.md index 2f378ffa99d..8f5de13b87e 100644 --- a/public/content/translations/pl/developers/docs/storage/index.md +++ b/public/content/translations/pl/developers/docs/storage/index.md @@ -1,35 +1,216 @@ --- -title: Zdecentralizowana pamięć -description: Przegląd tego, czym jest zdecentralizowana pamięć i dostępne narzędzia do integracji z integracji z aplikacjami dapp. +title: "Zdecentralizowana pamięć" +description: "Przegląd tego, czym jest zdecentralizowana pamięć masowa i dostępne narzędzia do integracji z dappką." lang: pl -incomplete: true -isOutdated: true --- -W przeciwieństwie do centralnie zlokalizowanego serwera obsługiwanego przez jedną firmę lub organizację, zdecentralizowane systemy pamięci masowej składają się z sieci peer-to-peer użytkowników-operatorów, którzy posiadają część ogólnych danych, tworząc odporny system przechowywania i udostępniania plików. +W przeciwieństwie do scentralizowanego serwera zarządzanego przez konkretną firmę lub organizację, systemy pamięci zdecentralizowanej składają się z sieci peer-to-peer, w której operatorami są użytkownicy, którzy przechowują część danych, tworząc odporny system współdzielenia pamięci masowej. Mogą one występować w aplikacjach opartych na technologii blockchain lub innych sieciach peer-to-peer. + +Samo Ethereum może być używane jako zdecentralizowany system pamięci masowej i jest nim w zakresie przechowywania kodu wszystkich inteligentnych kontraktów. Ethereum jednakże nie zostało stworzone z myślą o przechowywaniu dużych ilości danych. Łańcuch stale rośnie, ale w chwili pisania tego tekstu łańcuch Ethereum ma rozmiar około 500 GB – 1 TB ([w zależności od klienta](https://etherscan.io/chartsync/chaindefault)), a każdy węzeł w sieci musi być w stanie przechować wszystkie te dane. Jeśli łańcuch miałby rozrosnąć się do większych rozmiarów (powiedzmy 5 TB), mogłoby to być niewykonalne dla części z węzłów. Ponadto koszt wdrożenia tak dużej ilości danych w sieci Mainnet byłby zaporowo wysoki ze względu na opłaty za [gaz](/developers/docs/gas). + +W związku z tymi ograniczeniami potrzebne są inne łańcuchy lub metody przechowywania dużych ilości danych w sposób zdecentralizowany. + +Rozważając różne opcje zdecentralizowanej pamięci masowej (dStorage), użytkownik powinien pamiętać o kilku kwestiach. + +- Mechanizm trwałości / struktura zachęt +- Egzekwowanie odpowiedniego przechowywania danych +- Decentralizacja +- Konsensus + +## Mechanizm trwałości / struktura zachęt {#persistence-mechanism} + +### Oparte na blockchainie {#blockchain-based} + +Jeśli element danych ma przetrwać na zawsze, trzeba skorzystać z mechanizmu trwałości danych. W przykładzie Ethereum mechanizm trwałości oparty jest na założeniu, że cały łańcuch musi być zawarty na każdym węźle sieci. Nowe fragmenty danych dołączane są do końca łańcucha, więc rośnie on nieustannie, tworząc potrzebę replikacji całości zamieszczonych na nim danych przez każdy z węzłów. + +Jest to znane jako trwałość **oparta na blockchainie**. + +Problem z trwałością opartą na blockchainie polega na tym, że łańcuch mógłby stać się zbyt duży, aby można było realnie utrzymywać i przechowywać wszystkie dane (np. [wiele źródeł](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/) szacuje, że Internet wymaga ponad 40 zetabajtów pojemności magazynowej). + +Blockchain musi mieć również jakiś rodzaj struktury zachęt. Za trwałość opartą na blockchainie przewidziana jest opłata dla walidatora. Kiedy dane dołączone są do łańcucha, walidatorowi płaci się za ich dodanie. + +Platformy z trwałością opartą o blockchain: + +- Ethereum +- [Arweave](https://www.arweave.org/) + +### Oparta na kontrakcie {#contract-based} + +**Trwałość oparta na kontrakcie** opiera się na założeniu, że dane nie mogą być replikowane przez każdy węzeł i przechowywane na zawsze, a zamiast tego muszą być utrzymywane za pomocą umów kontraktowych. Są to porozumienia zawarte pomiędzy wieloma węzłami, które zobowiązały się przechowywać fragment danych przez pewien okres. Muszą być zwrócone lub odnowione, kiedy się wyczerpią, aby utrzymać trwałość danych. + +W większości przypadków, zamiast przechowywać całość danych na łańcuchu, hasz lokalizacji danych jest na nim przechowywany. Dzięki temu cały łańcuch nie musi być skalowany, aby utrzymać wszystkie dane. + +Platformy z trwałością opartą na kontrakcie: + +- [Filecoin](https://docs.filecoin.io/basics/what-is-filecoin) +- [Skynet](https://sia.tech/) +- [Storj](https://storj.io/) +- [Züs](https://zus.network/) +- [Crust Network](https://crust.network) +- [Swarm](https://www.ethswarm.org/) +- [4EVERLAND](https://www.4everland.org/) + +### Dodatkowe uwagi {#additional-consideration} + +IPFS jest rozproszonym systemem przechowywania i dostępu do plików, stron internetowych, aplikacji oraz danych. Nie ma wbudowanego schematu zachęt, ale może, zamiast tego być używany z każdym wspomnianym powyżej rozwiązaniem motywacyjnym, aby zapewnić dłuższą trwałość. Inną metodą utrwalania danych w IPFS jest współpraca z usługą przypinania, która "przypnie" Twoje dane za ciebie. Możesz nawet uruchomić własny węzeł IPFS i przyczynić się do utrwalania własnych danych oraz danych innych osób całkowicie za darmo! + +- [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/) +- [Pinata](https://www.pinata.cloud/) _(usługa przypinania IPFS)_ +- [web3.storage](https://web3.storage/) _(usługa przypinania dla IPFS/Filecoin)_ +- [Infura](https://infura.io/product/ipfs) _(usługa przypinania IPFS)_ +- [IPFS Scan](https://ipfs-scan.io) _(eksplorator przypinania IPFS)_ +- [4EVERLAND](https://www.4everland.org/) _(usługa przypinania IPFS)_ +- [Filebase](https://filebase.com) _(usługa przypinania IPFS)_ +- [Spheron Network](https://spheron.network/) _(usługa przypinania dla IPFS/Filecoin)_ + +SWARM to zdecentralizowana metoda przechowywania i dystrybucji danych z systemem zachęt za przechowywanie i wyrocznią cen wynajmu pamięci. + +## Przechowywanie danych {#data-retention} + +Aby zachować dane, system musi mieć jakiś mechanizm ich zachowania. + +### Mechanizm wyzwań {#challenge-mechanism} + +Jednym z najpopularniejszych sposób na upewnienie się, że dane są zachowane, jest zastosowanie kryptograficznego wyzwania, które jest przedstawiane węzłowi, aby upewnić się, że wciąż ma dane. Prostym przykładem jest dowód dostępu od Arweave. Przedstawiają węzłowi wyzwanie, aby sprawdzić, czy posiada dane w najnowszym bloku oraz losowo wybranym bloku z przeszłości. Jeśli węzeł nie potrafi odpowiedzieć, zostaje ukarany. + +Typy zdecentralizowanej pamięci z mechanizmami wyzwań: + +- Züs +- Skynet +- Arweave +- Filecoin +- Sieć Crust +- 4EVERLAND + +### Decentralizacja {#decentrality} + +Nie ma świetnych narzędzi, by zmierzyć poziom decentralizacji platform, ale ogólnie rzecz biorąc, warto używać narzędzi, które nie używają potwierdzania tożsamości użytkownika. W ten sposób dostarczają one dowodu na to, że nie są scentralizowane. + +Zdecentralizowane narzędzia bez KYC: + +- Skynet +- Arweave +- Filecoin +- IPFS - Inter-Planetarny System Plików jest to zdecentralizowana pamięć i system nawiązywania plików w Ethereum +- Ethereum +- Sieć Crust +- 4EVERLAND + +### Konsensus {#consensus} + +Większość z tych narzędzi ma własną wersję [mechanizmu konsensusu](/developers/docs/consensus-mechanisms/), ale generalnie opierają się one na [**dowodzie pracy (PoW)**](/developers/docs/consensus-mechanisms/pow/) lub [**dowodzie stawki (PoS)**](/developers/docs/consensus-mechanisms/pos/). + +Oparte na proof-of-work: + +- Skynet +- Arweave + +Oparte na proof-of-stake: + +- Ethereum +- Filecoin +- Züs +- Sieć Crust ## Powiązane narzędzia {#related-tools} -**IPFS -** **_InterPlanetary File System to zdecentralizowany system przechowywania i odwoływania się do plików dla Ethereum. _** +**IPFS - _InterPlanetary File System to zdecentralizowany system przechowywania i odwoływania się do plików dla Ethereum._** -- [ipfs.io](https://ipfs.io/) +- [Ipfs.io](https://ipfs.io/) - [Dokumentacja](https://docs.ipfs.io/) - [GitHub](https://github.com/ipfs/ipfs) -**Swarm —** **platforma rozproszonej pamięci masowej i usługa dystrybucji treści dla stosu web3 Ethereum.** +**Storj DCS - _Bezpieczna, prywatna i kompatybilna z S3 zdecentralizowana chmurowa pamięć masowa obiektów dla deweloperów._** + +- [Storj.io](https://storj.io/) +- [Dokumentacja](https://docs.storj.io/) +- [GitHub](https://github.com/storj/storj) + +**Sia - _Wykorzystuje kryptografię do stworzenia niewymagającego zaufania rynku chmurowej pamięci masowej, pozwalając kupującym i sprzedającym na bezpośrednie przeprowadzanie transakcji._** + +- [Skynet.net](https://sia.tech/) +- [Dokumentacja](https://docs.sia.tech/) +- [GitHub](https://github.com/SiaFoundation/) + +**Filecoin - _Filecoin został stworzony przez ten sam zespół, który stoi za IPFS To warstwa wyposażona w zachęty oparta na ideałach IPFS._** + +- [Filecoin.io](https://filecoin.io/) +- [Dokumentacja](https://docs.filecoin.io/) +- [GitHub](https://github.com/filecoin-project/) + +**Arweave - _Arweave to platforma zdecentralizowanej pamięci masowej (dStorage) do przechowywania danych._** + +- [Arweave.org](https://www.arweave.org/) +- [Dokumentacja](https://docs.arweave.org/info/) +- [Arweave](https://github.com/ArweaveTeam/arweave/) + +**Züs - _Züs to platforma dStorage typu proof-of-stake (dowód stawki) z shardingiem i blobberami._** + +- [zus.network](https://zus.network/) +- [Dokumentacja](https://docs.zus.network/zus-docs/) +- [GitHub](https://github.com/0chain/) + +**Crust Network - _Crust to platforma zdecentralizowanej pamięci masowej (dStorage) działająca na bazie IPFS._** -- [Swarm](https://ethersphere.github.io/swarm-home/) -- [GitHub](https://github.com/ethersphere/swarm) +- [Crust.network](https://crust.network) +- [Dokumentacja](https://wiki.crust.network) +- [GitHub](https://github.com/crustio) -**OrbitDB —** **zdecentralizowana baza danych peer-to-peer oparta na IPFS.** +**Swarm - _Rozproszona platforma pamięci masowej i usługa dystrybucji treści dla stosu web3 Ethereum._** -- [Dokumentacja](https://github.com/orbitdb/field-manual) -- [GitHub](https://github.com/orbitdb/orbit-db) +- [EthSwarm.org](https://www.ethswarm.org/) +- [Dokumentacja](https://docs.ethswarm.org/) +- [GitHub](https://github.com/ethersphere/) + +**OrbitDB - _Zdecentralizowana baza danych peer-to-peer działająca na IPFS._** + +- [OrbitDB.org](https://orbitdb.org/) +- [Dokumentacja](https://github.com/orbitdb/field-manual/) +- [GitHub](https://github.com/orbitdb/orbit-db/) + +**Aleph.im - _Zdecentralizowany projekt chmurowy (baza danych, przechowywanie plików, moc obliczeniowa i DID). Unikalne połączenie technologi peer-to-peer na łańcuchu i poza nim. IPFS i kompatybilność wielołańcuchowa._** + +- [Aleph.im](https://aleph.cloud/) +- [Dokumentacja](https://docs.aleph.cloud/) +- [GitHub](https://github.com/aleph-im/) + +**Ceramic - _Kontrolowana przez użytkownika baza danych IPFS do przechowywania danych dla bogatych w dane i angażujących aplikacji._** + +- [Ceramic.network](https://ceramic.network/) +- [Dokumentacja](https://developers.ceramic.network/) +- [GitHub](https://github.com/ceramicnetwork/js-ceramic/) + +**Filebase - _Kompatybilna z S3 zdecentralizowana pamięć masowa i geo-redundantna usługa przypinania IPFS. Wszystkie pliki przesłane do IPFS przez Filebase są automatycznie przypinane do infrastruktury Filebase z potrójną replikacją na całym świecie._** + +- [Filebase.com](https://filebase.com/) +- [Dokumentacja](https://docs.filebase.com/) +- [GitHub](https://github.com/filebase) + +**4EVERLAND - _Platforma chmury obliczeniowej Web 3.0, która integruje podstawowe funkcje przechowywania, obliczeń i sieci, jest kompatybilna z S3 i zapewnia synchroniczne przechowywanie danych w zdecentralizowanych sieciach pamięci masowej, takich jak IPFS i Arweave._** + +- [4everland.org](https://www.4everland.org/) +- [Dokumentacja](https://docs.4everland.org/) +- [GitHub](https://github.com/4everland) + +**Kaleido - _Platforma typu blockchain jako usługa (BaaS) z węzłami IPFS dostępnymi na jedno kliknięcie._** + +- [Kaleido](https://kaleido.io/) +- [Dokumentacja](https://docs.kaleido.io/kaleido-services/ipfs/) +- [GitHub](https://github.com/kaleido-io) + +**Spheron Network - _Spheron to platforma jako usługa (PaaS) zaprojektowana dla dappek, które chcą uruchamiać swoje aplikacje na zdecentralizowanej infrastrukturze z najlepszą wydajnością. Zapewnia od ręki moc obliczeniową, zdecentralizowaną pamięć masową, CDN i hosting stron internetowych._** + +- [spheron.network](https://spheron.network/) +- [Dokumentacja](https://docs.spheron.network/) +- [GitHub](https://github.com/spheronFdn) ## Dalsza lektura {#further-reading} -_Znasz jakieś zasoby społeczności, które Ci pomogły? Wyedytuj tę stronę i dodaj je!_ +- [Czym jest zdecentralizowana pamięć masowa?](https://coinmarketcap.com/academy/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ +- [Obalamy pięć popularnych mitów na temat zdecentralizowanej pamięci masowej](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ + +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ ## Powiązane tematy {#related-topics} -- [Frameworki programistyczne](/developers/docs/frameworks/) +- [Frameworki deweloperskie](/developers/docs/frameworks/) diff --git a/public/content/translations/pl/developers/docs/transactions/index.md b/public/content/translations/pl/developers/docs/transactions/index.md index e3df3c50bbc..1db03e7ef48 100644 --- a/public/content/translations/pl/developers/docs/transactions/index.md +++ b/public/content/translations/pl/developers/docs/transactions/index.md @@ -1,20 +1,21 @@ --- title: Transakcje -description: Przegląd transakcji Ethereum – sposób działania, struktury danych i metody ich wysyłania za pośrednictwem aplikacji. +description: "Przegląd transakcji Ethereum – sposób działania, struktury danych i metody ich wysyłania za pośrednictwem aplikacji." lang: pl --- Transakcje to podpisane kryptograficznie instrukcje od kont. Konto inicjuje transakcję, aby zaktualizować stan sieci Ethereum. Najprostszą transakcją jest przeniesienie ETH z jednego konta na drugie. -## Warunki wstępne {#prerequisites} +## Wymagania wstępne {#prerequisites} -Aby lepiej zrozumieć tę stronę, zalecamy najpierw przeczytanie rozdziału o [kontach](/developers/docs/accounts/) oraz naszym [wprowadzeniu do Ethereum](/developers/docs/intro-to-ethereum/). +Aby lepiej zrozumieć tę stronę, zalecamy najpierw przeczytanie rozdziału [Konta](/developers/docs/accounts/) oraz naszego [wprowadzenia do Ethereum](/developers/docs/intro-to-ethereum/). ## Czym jest transakcja? {#whats-a-transaction} Transakcja Ethereum odnosi się do działania zainicjowanego przez konto zewnętrzne, czyli takie, które jest zarządzane przez człowieka, a nie przez kontrakt. Na przykład, jeśli Bob wysyła Alice 1 ETH, na koncie Boba musi się pojawić obciążenie, a na koncie Alice uznanie. Ta zmiana stanu ma miejsce w ramach transakcji. -![Schemat pokazujący transakcję powodującą zmianę stanu](./tx.png) _Diagram zaadaptowany z [Ilustrowanego Ethereum EVM](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![Diagram pokazujący, jak transakcja powoduje zmianę stanu](./tx.png) +_Diagram zaadaptowany z [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ Transakcje, które zmieniają stan EVM, muszą być rozesłane do całej sieci. Każdy węzeł może rozesłać prośbę o wykonanie transakcji na EVM; po tym wydarzeniu walidator wykona transakcję i roześle powstałą zmianę stanu do reszty sieci. @@ -22,17 +23,17 @@ Transakcje wymagają opłaty i muszą być uwzględnione w ważnym bloku. Aby up Przesłana transakcja zawiera następujące informacje: -- `from` — adres nadawcy, który będzie podpisywać transakcję. Będzie to konto zewnętrzne, ponieważ konta kontraktowe nie mogą wysyłać transakcji -- `to` — adres odbiorcy (jeśli jest to konto zewnętrzne, to transakcja przekaże wartość. Natomiast jeśli jest to konto kontraktowe to, transakcja wykona kod kontraktu) -- `signature` — identyfikator nadawcy. Jest on generowany, kiedy klucz prywatny nadawcy podpisuje transakcję i potwierdza, że nadawca autoryzował tę transakcję -- `nonce` — sekwencyjnie zwiększający się licznik, który wskazuje na numer transakcji konta -- `value` — kwota ETH do przesłania od nadawcy do odbiorcy (wyrażona w WEI, gdzie 1 ETH jest równy 1e+18wei) -- `input data` — opcjonalne pole do umieszczania dowolnych danych -- `gasLimit` — maksymalna ilość jednostek gazu, które mogą zostać zużyte w trakcie transakcji. [EVM](/developers/docs/evm/opcodes) określa, ile jednostek gazu wymaga każdy krok obliczeniowy -- `maxPriorityFeePerGas` — maksymalna cena zużytego gazu, która zostanie uwzględniona jako napiwek dla walidatora -- `maxFeePerGas` — maksymalna opłata za jednostkę gazu, jaką użytkownik jest w stanie zapłacić za transakcję (w tym `baseFeePerGas` i `maxPriorityFeePerGas`) +- `from` – adres nadawcy, który podpisze transakcję. To jest konto z zewnętrznym właścicielem, ponieważ inteligentne kontrakty nie mają możliwości wysyłania transakcji +- `to` – adres odbiorcy (jeśli jest to konto należące do zewnętrznego właściciela, transakcja przekaże wartość. Natomiast jeśli jest to konto kontraktowe to, transakcja wykona kod kontraktu) +- `signature` – identyfikator nadawcy. Jest on generowany, kiedy klucz prywatny nadawcy podpisuje transakcję i potwierdza, że nadawca autoryzował tę transakcję +- `nonce` – sekwencyjnie zwiększający się licznik, który wskazuje na numer transakcji z konta +- `value` – kwota ETH do przesłania od nadawcy do odbiorcy (wyrażona w WEI, gdzie 1 ETH jest równy 1e+18wei) +- `input data` – opcjonalne pole do umieszczania dowolnych danych +- `gasLimit` – maksymalna ilość jednostek gazu, które mogą zostać zużyte przez transakcję. [EVM](/developers/docs/evm/opcodes) określa, ile jednostek gazu wymaga każdy krok obliczeniowy +- `maxPriorityFeePerGas` – maksymalna cena zużytego gazu, która zostanie uwzględniona jako napiwek dla walidatora +- `maxFeePerGas` – maksymalna opłata za jednostkę gazu, jaką użytkownik jest w stanie zapłacić za transakcję (w tym `baseFeePerGas` i `maxPriorityFeePerGas`) -Gaz jest odniesieniem do obliczeń wymaganych do przetworzenia transakcji przez walidatora. Użytkownicy muszą zapłacić opłatę za to obliczenie. `gasLimit` i `maxPriorityFeePerGas` określają maksymalną opłatę transakcyjną płaconą walidatorowi. [Więcej na temat gazu](/developers/docs/gas/). +Gaz jest odniesieniem do obliczeń wymaganych do przetworzenia transakcji przez walidatora. Użytkownicy muszą zapłacić opłatę za to obliczenie. `gasLimit` i `maxPriorityFeePerGas` określają maksymalną opłatę transakcyjną płaconą walidatorowi. [Więcej o gazie](/developers/docs/gas/). Obiekt transakcji będzie wyglądał mniej więcej w ten sposób: @@ -99,22 +100,26 @@ Przykładowa odpowiedź: } ``` -- `raw` jest podpisaną transakcją w zakodowanym formacie [prefiksu o rekursywnej długości (RLP)](/developers/docs/data-structures-and-encoding/rlp) -- `tx` jest podpisaną transakcją w formacie JSON +- `raw` to podpisana transakcja w formie zakodowanej za pomocą [prefiksu o rekursywnej długości (RLP)](/developers/docs/data-structures-and-encoding/rlp) +- `tx` to podpisana transakcja w formacie JSON Dzięki hashowi podpisu można udowodnić kryptograficznie, że transakcja pochodzi od nadawcy i została przesłana do sieci. ### Pole danych {#the-data-field} -Zdecydowana większość transakcji uzyskuje dostęp do kontraktu z konta zewnętrznego. Większość kontraktów jest napisana w Solidity i interpretuje swoje pole danych zgodnie z [binarnym interfejsem aplikacji (ABI)](/glossary/#abi). +Zdecydowana większość transakcji uzyskuje dostęp do kontraktu z konta zewnętrznego. +Większość kontraktów jest napisana w Solidity i interpretuje swoje pole danych zgodnie z [binarnym interfejsem aplikacji (ABI)](/glossary/#abi). -Pierwsze cztery bajty określają, które funkcje mają zostać wywołane, korzystając z hasha nazwy funkcji i jej argumentów. Możesz czasami zidentyfikować funkcję z selektora korzystając z [tej bazy danych](https://www.4byte.directory/signatures/). +Pierwsze cztery bajty określają, które funkcje mają zostać wywołane, korzystając z hasha nazwy funkcji i jej argumentów. +Czasami można zidentyfikować funkcję na podstawie selektora, korzystając z [tej bazy danych](https://www.4byte.directory/signatures/). -Reszta danych wywoławczych to argumenty, [zakodowane zgodnie ze specyfikacją ABI](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). +Reszta danych wywołania to argumenty, [zakodowane zgodnie ze specyfikacją ABI](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). -Spójrzmy dla przykładu na [tę transakcję](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1). Kliknij **Click to show more**, aby zobaczyć dane wywoławcze. +Spójrzmy na przykład na [tę transakcję](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1). +Użyj **Click to see More**, aby zobaczyć dane wywołania. -Selektorem funkcji jest `0xa9059cbb`. Istnieje kilka [znanych funkcji z tym podpisem](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb). W tym przypadku [kod źródłowy kontraktu](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code) został opublikowany na Etherscan, więc wiemy, że funkcją jest `transfer(address,uint256)`. +Selektor funkcji to `0xa9059cbb`. Istnieje kilka [znanych funkcji z tym podpisem](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb). +W tym przypadku [kod źródłowy kontraktu](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code) został przesłany do Etherscan, więc wiemy, że funkcja to `transfer(address,uint256)`. Reszta danych to: @@ -123,7 +128,9 @@ Reszta danych to: 000000000000000000000000000000000000000000000000000000003b0559f4 ``` -Zgodnie ze specyfikacją ABI wartości całkowite (takie jak adresy, które są 20-bajtowymi wartościami całkowitymi) wyświetlają się w ABI jako 32-bajtowe słowa, uzupełnione zerami z przodu. Wiemy więc, że adres `to` wygląda tak [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279). Wartość `value` wynosi 0x3b0559f4 = 990206452. +Zgodnie ze specyfikacją ABI wartości całkowite (takie jak adresy, które są 20-bajtowymi wartościami całkowitymi) wyświetlają się w ABI jako 32-bajtowe słowa, uzupełnione zerami z przodu. +Więc wiemy, że adres `to` to [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279). +Wartość `value` wynosi 0x3b0559f4 = 990206452. ## Rodzaje transakcji {#types-of-transactions} @@ -133,11 +140,11 @@ W Ethereum istnieje kilka różnych rodzajów transakcji: - Transakcje wdrożenia kontraktu: transakcja bez adresu „to”, w którym pole danych jest wykorzystywane dla kodu kontraktu. - Wykonanie kontraktu: transakcja, która wchodzi w interakcję z wdrożonym inteligentnym kontraktem. W tym przypadku adres „to” jest adresem inteligentnego kontraktu. -### Na temat gazu {#on-gas} +### O gazie {#on-gas} Jak już wspomniano, wykonanie transakcji kosztuje [gaz](/developers/docs/gas/). Proste transakcje transferu wymagają 21 000 jednostek gazu. -A więc, aby Bob mógł wysłać Alice 1 ETH przy `baseFeePerGas` wynoszącym 190 gwei i `maxPriorityFeePerGas` wynoszącym 10 gwei, Bob będzie musiał zapłacić następującą opłatę: +Aby Bob mógł wysłać Alice 1 ETH przy `baseFeePerGas` wynoszącym 190 gwei i `maxPriorityFeePerGas` wynoszącym 10 gwei, Bob będzie musiał zapłacić następującą opłatę: ``` (190 + 10) * 21 000 = 4 200 000 gwei @@ -145,16 +152,16 @@ A więc, aby Bob mógł wysłać Alice 1 ETH przy `baseFeePerGas` wynoszącym 19 0,0042 ETH ``` -Konto Boba zostanie obciążone kwotą **1,0042 ETH** (1 ETH dla Alice + 0,0042 ETH w opłatach za gaz) +Konto Boba zostanie obciążone kwotą **-1,0042 ETH** (1 ETH dla Alice + 0,0042 ETH w opłatach za gaz) -Konto Alicji zostanie zasilone kwotą **1,0 ETH** +Konto Alice zostanie zasilone kwotą **+1,0 ETH** -Podstawowa opłata wynosząca **0,00399 ETH** zostanie spalona +Podstawowa opłata zostanie spalona **-0,00399 ETH** -Walidator zatrzyma napiwek wynoszący **0,000210 ETH** +Walidator zatrzyma napiwek **+0,000210 ETH** - -![Schemat pokazujący, w jaki sposób zwracany jest niewykorzystany gaz](./gas-tx.png) _Schemat zaadaptowany z [Ilustracja Ethereum EVM](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![Diagram pokazujący, jak zwracany jest niewykorzystany gaz](./gas-tx.png) +_Diagram zaadaptowany z [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ Gaz niewykorzystany w transakcji jest zwracany na konto użytkownika. @@ -162,60 +169,65 @@ Gaz niewykorzystany w transakcji jest zwracany na konto użytkownika. Gaz jest wymagany dla każdej transakcji wiążącej się z inteligentnym kontraktem. -Inteligentne kontrakty mogą również zawierać funkcje takie jak [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) czy [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions), które nie zmieniają stanu kontraktu. W związku z tym wywoływanie tych funkcji z konta zewnętrznego nie będzie wymagało żadnego gazu. Podstawowym wywołaniem RPC dla takiego scenariusza jest [`eth_call`](/developers/docs/apis/json-rpc#eth_call) +Inteligentne kontrakty mogą również zawierać funkcje znane jako [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) lub [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions), które nie zmieniają stanu kontraktu. W związku z tym wywoływanie tych funkcji z konta zewnętrznego nie będzie wymagało żadnego gazu. Podstawowe wywołanie RPC dla tego scenariusza to [`eth_call`](/developers/docs/apis/json-rpc#eth_call). -W przeciwieństwie do dostępu przy użyciu `eth_call`, funkcje `view` czy `pure` są również często wywoływane wewnętrznie (tj. z samego kontraktu lub od innego kontraktu) co już wymaga gazu. +W przeciwieństwie do dostępu przy użyciu `eth_call`, funkcje `view` lub `pure` są również często wywoływane wewnętrznie (tj. z samego kontraktu lub z innego kontraktu), co już kosztuje gaz. -## Cykl życiowy transakcji {#transaction-lifecycle} +## Cykl życia transakcji {#transaction-lifecycle} Po przesłaniu transakcji dzieją się następujące wydarzenia: -1. Hash transakcji zostaje kryptograficznie wygenerowany: `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` +1. Hasz transakcji jest generowany kryptograficznie: + `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` 2. Transakcja zostaje następnie rozgłoszona do sieci i dodawana do puli transakcji składającej się z wszystkich innych oczekujących transakcji w sieci. 3. Walidator musi wybrać Twoją transakcję i uwzględnić ją w bloku, aby ją zweryfikować transakcję i uznać ją za „udaną”. -4. W miarę upływu czasu blok zawierający Twoją transakcję zostanie zaktualizowany do kategorii „uzasadniony”, a następnie „sfinalizowany”. Aktualizacje te znacznie zwiększają pewność, że Twoja transakcja zakończyła się sukcesem i nie będzie można jej zmienić. Po „sfinalizowaniu” bloku mógłby on zostać zmieniony tylko przez atak na poziomie sieci, który kosztowałby miliardy dolarów. +4. W miarę upływu czasu blok zawierający Twoją transakcję zostanie zaktualizowany do kategorii „uzasadniony”, a następnie „sfinalizowany”. Te aktualizacje dają znacznie + większą pewność, że Twoja transakcja zakończyła się sukcesem i nigdy nie zostanie zmieniona. Gdy blok zostanie „sfinalizowany”, może zostać zmieniony + jedynie przez atak na poziomie sieci, który kosztowałby wiele miliardów dolarów. -## Demo wizualne {#a-visual-demo} +## Demonstracja wizualna {#a-visual-demo} Zobacz, jak Austin opowiada o transakcjach, gazie i kopaniu. -## Typed Transaction Envelope {#typed-transaction-envelope} +## Typowana koperta transakcji {#typed-transaction-envelope} -Ethereum pierwotnie miało jeden format transakcji. Każda transakcja zawierała nonce, cenę gazu, limit gazu, adres docelowy, wartość, dane, v, r oraz s. Pola te są [zakodowane w RLP](/developers/docs/data-structures-and-encoding/rlp/), aby wyglądały mniej więcej tak: +Ethereum pierwotnie miało jeden format transakcji. Każda transakcja zawierała nonce, cenę gazu, limit gazu, adres docelowy, wartość, dane, v, r oraz s. Pola te są [kodowane za pomocą RLP](/developers/docs/data-structures-and-encoding/rlp/), aby wyglądały mniej więcej tak: `RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` -Ethereum wyewoluowało i wspiera wiele rodzajów transakcji, zezwalając na wdrażanie nowych funkcji takich jak listy dostępu i [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), bez wpływania na starsze formaty transakcji. +Ethereum ewoluowało, aby obsługiwać wiele typów transakcji, co pozwala na wdrażanie nowych funkcji, takich jak listy dostępu i [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), bez wpływu na starsze formaty transakcji. -[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) jest tym, co umożliwia takie zachowanie. Transakcję są interpretowane jako: +[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) to propozycja, która pozwala na takie zachowanie. Transakcję są interpretowane jako: `TransactionType || TransactionPayload` Gdzie pola są definiowane jako: -- `TransactionType` — liczba z zakresu od 0 do 0x7f, zapewniająca w sumie 128 możliwych rodzajów transakcji. -- `TransactionPayload` — dowolna tablica bajtów zdefiniowana przez rodzaj transakcji. +- `TransactionType` – liczba z zakresu od 0 do 0x7f, co daje w sumie 128 możliwych typów transakcji. +- `TransactionPayload` – dowolna tablica bajtów zdefiniowana przez typ transakcji. -Na podstawie wartości `TransactionType`, transakcje mogą być definiowane jako: +Na podstawie wartości `TransactionType` transakcję można sklasyfikować jako: -1. **Transakcje typu 0 (starsze):** oryginalny format transakcji używany od samego początku Ethereum. Nie zawierają funkcji z [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), takich jak dynamiczne obliczenia opłat za gaz czy list dostępu do inteligentnych kontraktów. Starsze transakcje nie mają określonego prefiksu wskazującego na ich typ w ich serializowanej formie, począwszy od bajtu `0xf8` przy użyciu kodowania [prefiksu o rekursywnej długości (RLP)](/developers/docs/data-structures-and-encoding/rlp). Wartość TransactionType dla tych transakcji wynosi `0x0`. +1. **Transakcje typu 0 (starsze):** oryginalny format transakcji używany od samego początku Ethereum. Nie obejmują one funkcji z [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), takich jak dynamiczne obliczanie opłat za gaz czy listy dostępu do inteligentnych kontraktów. Starsze transakcje nie mają określonego prefiksu wskazującego na ich typ w postaci serializowanej, zaczynając od bajtu `0xf8` przy użyciu kodowania [prefiksu o rekursywnej długości (RLP)](/developers/docs/data-structures-and-encoding/rlp). Wartość TransactionType dla tych transakcji wynosi `0x0`. -2. **Transakcje typu 1:** wprowadzone w [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) jako część [uaktualnienia Berlin](/ethereum-forks/#berlin) sieci Ethereum transakcje te zawierają parametr `accessList`. Ta lista określa adresy i klucze przechowywania, do których transakcja oczekuje dostępu, potencjalnie pomagając zmniejszyć koszty [gazu](/developers/docs/gas/) złożonych transakcji wykorzystujących inteligentne kontrakty. Zmiany rynku opłat EIP-1559 nie są uwzględnione w transakcjach typu 1. Transakcje typu 1 zawierają również parametr `yParity`, który może wynosić zarówno `0x0` jak i `0x1`, wskazując na parzystość wartości y podpisu secp256k1. Są identyfikowane przez początkowy bajt `0x01`, a ich wartość TransactionType wynosi `0x1`. +2. **Transakcje typu 1:** wprowadzone w [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) jako część [aktualizacji Berlin](/ethereum-forks/#berlin) sieci Ethereum; transakcje te zawierają parametr `accessList`. Ta lista określa adresy i klucze przechowywania, do których transakcja oczekuje dostępu, potencjalnie pomagając zmniejszyć koszty [gazu](/developers/docs/gas/) złożonych transakcji wykorzystujących inteligentne kontrakty. Zmiany rynku opłat EIP-1559 nie są uwzględnione w transakcjach typu 1. Transakcje typu 1 zawierają również parametr `yParity`, który może wynosić `0x0` lub `0x1`, wskazując parzystość wartości y podpisu secp256k1. Są one identyfikowane przez początkowy bajt `0x01`, a ich wartość TransactionType wynosi `0x1`. -3. **Transakcje typu 2**, powszechnie określane jako transakcje EIP-1559, to transakcje wprowadzone w [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), w ramach [uaktualnienia London](/ethereum-forks/#london) sieci Ethereum. Stały się one standardowym rodzajem transakcji w sieci Ethereum. Transakcje te wprowadziły nowy mechanizm rynku opłat, który poprawia przewidywalność, rozdzielając opłaty transakcyjne na opłatę podstawową oraz opłatę priorytetową. Zaczynają się bajtem `0x02` i zawierają takie pola jak `maxPriorityFeePerGas` i `maxFeePerGas`. Transakcje typu 2 są teraz domyślnymi, ze względu na ich elastyczność i wydajność, są szczególnie preferowanie podczas okresów dużego przeciążenia sieci ze względu na zdolność pomagania użytkownikom w zarządzaniu opłatami transakcyjnymi w bardziej przewidywalny sposób. Wartość TransactionType dla tych transakcji wynosi `0x2`. +3. **Transakcje typu 2**, powszechnie określane jako transakcje EIP-1559, to transakcje wprowadzone w [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) w ramach [aktualizacji London](/ethereum-forks/#london) sieci Ethereum. Stały się one standardowym rodzajem transakcji w sieci Ethereum. Transakcje te wprowadziły nowy mechanizm rynku opłat, który poprawia przewidywalność, rozdzielając opłaty transakcyjne na opłatę podstawową oraz opłatę priorytetową. Zaczynają się od bajtu `0x02` i zawierają pola takie jak `maxPriorityFeePerGas` i `maxFeePerGas`. Transakcje typu 2 są teraz domyślnymi, ze względu na ich elastyczność i wydajność, są szczególnie preferowanie podczas okresów dużego przeciążenia sieci ze względu na zdolność pomagania użytkownikom w zarządzaniu opłatami transakcyjnymi w bardziej przewidywalny sposób. Wartość TransactionType dla tych transakcji wynosi `0x2`. +4. **Transakcje typu 3 (Blob)** zostały wprowadzone w [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) jako część [aktualizacji Dencun](/ethereum-forks/#dencun) sieci Ethereum. Te transakcje zostały zaprojektowane w celu wydajniejszej obsługi danych "blob" (duże obiekty binarne), co przynosi szczególną korzyść drugim warstwom poprzez zapewnienie im możliwości przesyłania danych do głównej sieci Ethereum niższym kosztem. Transakcje typu blob zawierają dodatkowe pola, takie jak `blobVersionedHashes`, `maxFeePerBlobGas` i `blobGasPrice`. Zaczynają się od bajtu `0x03`, a ich wartość TransactionType wynosi `0x3`. Transakcje blob wprowadzają znaczący rozwój do kwestii dostępności danych i możliwości skalowania Ethereum. +5. **Transakcje typu 4** zostały wprowadzone w [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) jako część [aktualizacji Pectra](/roadmap/pectra/) Ethereum. Transakcje te są zaprojektowane tak, aby były kompatybilne w przód z abstrakcją konta. Pozwalają one kontom EOA na tymczasowe zachowywanie się jak konta inteligentnych kontraktów, bez naruszania ich pierwotnej funkcjonalności. Zawierają one parametr `authorization_list`, który określa inteligentny kontrakt, któremu EOA deleguje swoje uprawnienia. Po transakcji pole kodu EOA będzie zawierało adres delegowanego inteligentnego kontraktu. -## Dodatkowo przeczytaj {#further-reading} +## Dalsza lektura {#further-reading} -- [EIP-2718: Typed Transaction Envelope](https://eips.ethereum.org/EIPS/eip-2718) +- [EIP-2718: Typowana koperta transakcji](https://eips.ethereum.org/EIPS/eip-2718) -_Znasz jakieś zasoby społeczności, które Ci pomogły? Wyedytuj tę stronę i dodaj je!_ +_Znasz jakieś zasoby społeczności, które Ci pomogły? Edytuj tę stronę i dodaj je!_ ## Powiązane tematy {#related-topics} - [Konta](/developers/docs/accounts/) -- [Maszyna wirtualna Ethereum (EVM)](/developers/docs/evm/) -- [Paliwo](/developers/docs/gas/) +- [Wirtualna Maszyna Ethereum (EVM)](/developers/docs/evm/) +- [Gaz](/developers/docs/gas/) diff --git a/public/content/translations/pl/developers/docs/web2-vs-web3/index.md b/public/content/translations/pl/developers/docs/web2-vs-web3/index.md index a355d4260a7..7264144840b 100644 --- a/public/content/translations/pl/developers/docs/web2-vs-web3/index.md +++ b/public/content/translations/pl/developers/docs/web2-vs-web3/index.md @@ -1,6 +1,6 @@ --- -title: Web2 vs Web3 -description: +title: "Web2 w porównaniu z Web3" +description: "Porównaj scentralizowane usługi Web2 ze zdecentralizowanymi aplikacjami Web3 opartymi na technologii blockchain Ethereum." lang: pl --- @@ -27,12 +27,12 @@ Wielu deweloperów Web3 zdecydowało się budować zdecentralizowane aplikacje z To nie oznacza, że wszystkie usługi należy przekształcić w zdecentralizowane aplikacje. Te przykłady ilustrują główne różnice między usługami web2 i web3. -## Ograniczenia sieci Web3 {#web3-limitations} +## Ograniczenia Web3 {#web3-limitations} Web3 ma teraz pewne ograniczenia: - Skalowalność — transakcje są wolniejsze w web3, ponieważ są zdecentralizowane. Zmiany stanu, jak płatności, muszą być przetwarzane przez węzeł i propagowane w całej sieci. -- UX — interakcja z aplikacjami web3 może wymagać dodatkowych kroków, oprogramowania i edukacji. Może to stanowić przeszkodę w akceptacji. +- UX – interakcja z aplikacjami web3 może wymagać dodatkowych kroków, oprogramowania i edukacji. Może to stanowić przeszkodę w akceptacji. - Dostępność — brak integracji z nowoczesnymi przeglądarkami internetowymi sprawia, że web3 jest mniej dostępna dla większości użytkowników. - Koszt — większość udanych zdecentralizowanych aplikacji umieszcza bardzo małe części swojego kodu w blockchainie, ponieważ jest to kosztowne. @@ -40,23 +40,23 @@ Web3 ma teraz pewne ograniczenia: W tabeli poniżej wymieniono pewne zalety i wady scentralizowanych i zdecentralizowanych sieci cyfrowych. -| Systemy scentralizowane | Systemy zdecentralizowane | -| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Niska średnica sieci (wszyscy uczestnicy są podłączeni do organu centralnego); informacja jest szybko rozsyłana, ponieważ rozsyłanie jest prowadzone przez organ centralny z wieloma zasobami obliczeniowymi. | Najodleglejsi uczestnicy sieci mogą być znacznie odsunięci od siebie. Informacje nadawane z jednej strony sieci mogą potrzebować dużo czasu, aby dotrzeć do drugiej strony. | -| Zazwyczaj wyższa wydajność (większa przepustowość, mniej całkowitych kosztów zasobów obliczeniowych) i łatwiejsze do wdrożenia. | Zwykle niższa wydajność (mniejsza przepustowość, więcej całkowitych zasobów obliczeniowych wydatkowanych) i bardziej skomplikowana do wdrożenia. | -| W przypadku sprzecznych danych rozwiązanie jest jasne i łatwe: ostatecznym źródłem prawdy jest organ centralny. | Protokół (często złożony) jest potrzebny do rozstrzygania sporów, jeśli współuczestnicy zgłaszają sprzeczne roszczenia co do stanu danych, które mają być zsynchronizowane. | -| Pojedynczy punkt awarii: złośliwe podmioty mogą być w stanie zniszczyć sieć poprzez atak na organ centralny. | Brak pojedynczego punktu awarii: sieć może nadal funkcjonować, nawet jeśli duża część uczestników zostanie zaatakowana/wyeliminowana. | +| Systemy scentralizowane | Systemy zdecentralizowane | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Niska średnica sieci (wszyscy uczestnicy są podłączeni do organu centralnego); informacja jest szybko rozsyłana, ponieważ rozsyłanie jest prowadzone przez organ centralny z wieloma zasobami obliczeniowymi. | Najodleglejsi uczestnicy sieci mogą być znacznie odsunięci od siebie. Informacje nadawane z jednej strony sieci mogą potrzebować dużo czasu, aby dotrzeć do drugiej strony. | +| Zazwyczaj wyższa wydajność (większa przepustowość, mniej całkowitych kosztów zasobów obliczeniowych) i łatwiejsze do wdrożenia. | Zwykle niższa wydajność (mniejsza przepustowość, więcej całkowitych zasobów obliczeniowych wydatkowanych) i bardziej skomplikowana do wdrożenia. | +| W przypadku sprzecznych danych rozwiązanie jest jasne i łatwe: ostatecznym źródłem prawdy jest organ centralny. | Protokół (często złożony) jest potrzebny do rozstrzygania sporów, jeśli współuczestnicy zgłaszają sprzeczne roszczenia co do stanu danych, które mają być zsynchronizowane. | +| Pojedynczy punkt awarii: złośliwe podmioty mogą być w stanie zniszczyć sieć poprzez atak na organ centralny. | Brak pojedynczego punktu awarii: sieć może nadal funkcjonować, nawet jeśli duża część uczestników zostanie zaatakowana/wyeliminowana. | | Koordynacja między uczestnikami sieci jest znacznie łatwiejsza i jest prowadzona przez organ centralny. Organ centralny może zmusić uczestników sieci do przyjmowania aktualizacji, aktualizacji protokołów itp., przy bardzo niewielkim sprzeciwie. | Koordynacja jest często trudna, ponieważ żaden przedstawiciel nie ma ostatecznego głosu w decyzjach dotyczących sieci, modernizacji protokołów itp. W najgorszym przypadku sieć jest podatna na rozpad, gdy dochodzi do nieporozumień dotyczących zmian w protokole. | -| Organ centralny może cenzurować dane, potencjalnie oddzielić części sieci od interakcji z resztą sieci. | Cenzura jest o wiele trudniejsza, ponieważ informacje mogą rozprzestrzeniać się w sieci na wiele sposobów. | -| Udział w sieci jest kontrolowany przez organ centralny. | Każdy może uczestniczyć w sieci; nie ma „stróżów” Najlepiej byłoby, gdyby koszty uczestnictwa były bardzo niskie. | +| Organ centralny może cenzurować dane, potencjalnie oddzielić części sieci od interakcji z resztą sieci. | Cenzura jest o wiele trudniejsza, ponieważ informacje mogą rozprzestrzeniać się w sieci na wiele sposobów. | +| Udział w sieci jest kontrolowany przez organ centralny. | Każdy może uczestniczyć w sieci; nie ma „stróżów” Najlepiej byłoby, gdyby koszty uczestnictwa były bardzo niskie. | Zauważ, że są to ogólne wzorce, które mogą nie występować w każdej sieci. Ponadto w rzeczywistości stopień, w jakim sieć jest scentralizowana/zdecentralizowana, leży w spektrum; żadna sieć nie jest całkowicie scentralizowana lub całkowicie zdecentralizowana. ## Dalsza lektura {#further-reading} -- [Czym jest Web3](/web3/) — _ethereum.org_ -- [Architektura aplikacji Web 3.0](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) — _Preethi Kasireddy_ -- [Znaczenie decentralizacji](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _6 lutego 2017 r. — Vitalik Buterin_ -- [Dlaczego decentralizacja ma znaczenie](https://medium.com/s/story/why-decentralization-matters-5e3f79f7638e) _18 lutego 2018 r. — Chris Dixon_ -- [Czym jest Web 3.0 i dlaczego ma znaczenie](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _31 grudnia 2019 r. — Max Mersch and Richard Muirhead_ -- [Dlaczego potrzebujemy Web 3.0](https://medium.com/@gavofyork/why-we-need-web-3-0-5da4f2bf95ab) _12 września 2018 r. — Gavin Wood_ +- [Czym jest Web3?](/web3/) - _ethereum.org_ +- [Architektura aplikacji Web 3.0](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) – _Preethi Kasireddy_ +- [Znaczenie decentralizacji](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _6 lutego 2017 - Vitalik Buterin_ +- [Dlaczego decentralizacja ma znaczenie](https://onezero.medium.com/why-decentralization-matters-5e3f79f7638e) _18 lutego 2018 - Chris Dixon_ +- [Czym jest Web 3.0 i dlaczego ma znaczenie](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _31 grudnia 2019 - Max Mersch i Richard Muirhead_ +- [Dlaczego potrzebujemy Web 3.0](https://gavofyork.medium.com/why-we-need-web-3-0-5da4f2bf95ab) _12 września 2018 - Gavin Wood_ diff --git a/public/content/translations/pl/developers/docs/wrapped-eth/index.md b/public/content/translations/pl/developers/docs/wrapped-eth/index.md index 3c433d81a87..ed1708af44e 100644 --- a/public/content/translations/pl/developers/docs/wrapped-eth/index.md +++ b/public/content/translations/pl/developers/docs/wrapped-eth/index.md @@ -1,6 +1,6 @@ --- title: Czym jest Wrapped Ether (WETH) -description: Wprowadzenie do Wrapped Ether (WETH) — kompatybilny z ERC-20 owijacz (wrapper) dla etheru (ETH). +description: "Wprowadzenie do Wrapped Ether (WETH) — kompatybilny z ERC-20 owijacz (wrapper) dla etheru (ETH)." lang: pl --- @@ -35,19 +35,16 @@ Możesz odwinąć WETH do ETH używając inteligentnego kontraktu WETH. Możesz Płacisz opłaty za gaz za owinięcie lub rozwinięcie ETH przy użyciu kontraktu WETH. - WETH generalnie uważa się za bezpieczne, ponieważ jest oparte na prostym i przetestowanym inteligentnym kontrakcie. Kontrakt WETH został również formalnie zweryfikowany, co jest największym standardem bezpieczeństwa dla inteligentnych kontraktów na Ethereum. - Oprócz [kanonicznej implementacji WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) opisanej na tej stronie istnieją również jej inne warianty. Mogą to być własne tokeny stworzone przez twórców aplikacji lub wersje wyemitowane na innych blockchainach i mogą one się inaczej zachowywać lub mieć różne zabezpieczenia. **Zawsze sprawdzaj dokładnie informacje o tokenie, aby wiedzieć, z jaką implementacją WETH masz do czynienia.** - @@ -55,7 +52,6 @@ Oprócz [kanonicznej implementacji WETH](https://etherscan.io/token/0xc02aaa39b2 - [Sieć główna Ethereum](https://etherscan.io/token/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) - [Arbitrum](https://arbiscan.io/token/0x82af49447d8a07e3bd95bd0d56f35241523fbab1) - [Optimism](https://optimistic.etherscan.io/token/0x4200000000000000000000000000000000000006) - ## Further reading {#further-reading} diff --git a/public/content/translations/pl/developers/tutorials/Waffle-hello-world-with-buidler-tutorial/index.md b/public/content/translations/pl/developers/tutorials/Waffle-hello-world-with-buidler-tutorial/index.md index 46d9bcb7696..016814fb6a6 100644 --- a/public/content/translations/pl/developers/tutorials/Waffle-hello-world-with-buidler-tutorial/index.md +++ b/public/content/translations/pl/developers/tutorials/Waffle-hello-world-with-buidler-tutorial/index.md @@ -1,6 +1,6 @@ --- title: "Samouczek Waffle „powiedz Hello World” za pomocą hardhat i ethers" -description: Stwórz swój pierwszy projekt Waffle za pomocą hardhat i ethers.js +description: "Stwórz swój pierwszy projekt Waffle za pomocą hardhat i ethers.js" author: "MiZiet" tags: - "waffle" diff --git a/public/content/translations/pl/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md b/public/content/translations/pl/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md new file mode 100644 index 00000000000..34fc6d29707 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md @@ -0,0 +1,300 @@ +--- +title: "Wprowadzenie do Ethereum dla programistów Pythona, część 1" +description: "Wprowadzenie do tworzenia aplikacji na Ethereum, szczególnie przydatne dla osób znających język programowania Python" +author: Marc Garreau +lang: pl +tags: [ "python", "web3.py" ] +skill: beginner +published: 2020-09-08 +source: Snake charmers +sourceUrl: https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/ +--- + +Słyszałeś więc o tym całym Ethereum i jesteś gotów, by zanurzyć się w króliczej norze? Ten post szybko omówi podstawy technologii blockchain, a następnie pozwoli Ci na interakcję z symulowanym węzłem Ethereum – odczytywanie danych bloków, sprawdzanie sald kont i wysyłanie transakcji. Po drodze podkreślimy różnice między tradycyjnymi sposobami tworzenia aplikacji a tym nowym, zdecentralizowanym paradygmatem. + +## Wymagania (nieobowiązkowe) {#soft-prerequisites} + +Ten post ma być przystępny dla szerokiego grona deweloperów. Użyte zostaną [narzędzia Pythona](/developers/docs/programming-languages/python/), ale są one tylko nośnikiem dla idei – nie ma problemu, jeśli nie jesteś deweloperem Pythona. Poczynię jednak kilka założeń na temat tego, co już wiesz, abyśmy mogli szybko przejść do fragmentów specyficznych dla Ethereum. + +Założenia: + +- Potrafisz poruszać się w terminalu, +- Napisałeś kilka linijek kodu w Pythonie, +- Masz zainstalowaną wersję Pythona 3.6 lub nowszą na swoim komputerze (zdecydowanie zalecane jest użycie [środowiska wirtualnego](https://realpython.com/effective-python-environment/#virtual-environments)), oraz +- używałeś `pip`, instalatora pakietów Pythona. + Jeszcze raz, jeśli któreś z tych założeń jest nieprawdziwe lub nie planujesz odtwarzać kodu z tego artykułu, prawdopodobnie i tak bez problemu sobie poradzisz. + +## Blockchain w skrócie {#blockchains-briefly} + +Istnieje wiele sposobów na opisanie Ethereum, ale w jego sercu leży blockchain. Blockchainy składają się z serii bloków, więc zacznijmy od tego. W najprostszych słowach, każdy blok w blockchainie Ethereum to tylko trochę metadanych i lista transakcji. W formacie JSON wygląda to mniej więcej tak: + +```json +{ + "number": 1234567, + "hash": "0xabc123...", + "parentHash": "0xdef456...", + ..., + "transactions": [...] +} +``` + +Każdy [blok](/developers/docs/blocks/) ma odniesienie do bloku, który był przed nim; `parentHash` to po prostu hasz poprzedniego bloku. + +Uwaga: Ethereum regularnie używa funkcji haszujących do tworzenia wartości o stałym rozmiarze („haszy”). Hasze odgrywają ważną rolę w Ethereum, ale na razie możesz bezpiecznie myśleć o nich jako o unikalnych identyfikatorach. + +![Diagram przedstawiający blockchain, w tym dane wewnątrz każdego bloku](./blockchain-diagram.png) + +_Blockchain to w zasadzie lista połączona; każdy blok ma odniesienie do poprzedniego bloku._ + +Ta struktura danych nie jest niczym nowym, ale zasady (tj. protokoły peer-to-peer), które rządzą siecią, już tak. Nie ma centralnego organu; sieć peerów musi współpracować, aby utrzymać sieć i konkurować, aby zdecydować, które transakcje zostaną uwzględnione w następnym bloku. Więc kiedy chcesz wysłać pieniądze do znajomego, musisz rozgłosić tę transakcję w sieci, a następnie poczekać, aż zostanie ona uwzględniona w nadchodzącym bloku. + +Jedynym sposobem, w jaki blockchain może zweryfikować, że pieniądze zostały faktycznie wysłane od jednego użytkownika do drugiego, jest użycie waluty natywnej dla tego blockchaina (tj. stworzonej i zarządzanej przez niego). W Ethereum waluta ta nazywa się ether, a blockchain Ethereum zawiera jedyny oficjalny rejestr sald kont. + +## Nowy paradygmat {#a-new-paradigm} + +Ten nowy zdecentralizowany stos technologiczny dał początek nowym narzędziom deweloperskim. Takie narzędzia istnieją w wielu językach programowania, ale my będziemy patrzeć przez pryzmat Pythona. Powtórzmy: nawet jeśli Python nie jest Twoim ulubionym językiem, nie powinno być problemu ze śledzeniem treści. + +Deweloperzy Pythona, którzy chcą wejść w interakcję z Ethereum, prawdopodobnie sięgną po [Web3.py](https://web3py.readthedocs.io/). Web3.py to biblioteka, która znacznie upraszcza sposób łączenia się z węzłem Ethereum, a następnie wysyłania i odbierania z niego danych. + +Uwaga: „Węzeł Ethereum” i „klient Ethereum” są używane zamiennie. W obu przypadkach odnosi się to do oprogramowania, które uruchamia uczestnik sieci Ethereum. To oprogramowanie może odczytywać dane bloków, otrzymywać aktualizacje, gdy nowe bloki są dodawane do łańcucha, rozgłaszać nowe transakcje i nie tylko. Technicznie rzecz biorąc, klient to oprogramowanie, a węzeł to komputer, na którym działa to oprogramowanie. + +[Klienci Ethereum](/developers/docs/nodes-and-clients/) mogą być skonfigurowani tak, aby byli osiągalni przez [IPC](https://wikipedia.org/wiki/Inter-process_communication), HTTP lub Websockets, więc Web3.py będzie musiało odzwierciedlać tę konfigurację. Web3.py odnosi się do tych opcji połączenia jako **dostawcy** (providers). Będziesz musiał wybrać jednego z trzech dostawców, aby połączyć instancję Web3.py ze swoim węzłem. + +![Diagram pokazujący, jak web3.py używa IPC do połączenia Twojej aplikacji z węzłem Ethereum](./web3py-and-nodes.png) + +_Skonfiguruj węzeł Ethereum i Web3.py do komunikacji za pomocą tego samego protokołu, np. IPC na tym diagramie._ + +Gdy Web3.py jest poprawnie skonfigurowane, możesz zacząć wchodzić w interakcję z blockchainem. Oto kilka przykładów użycia Web3.py jako zapowiedź tego, co nadchodzi: + +```python +# odczytaj dane bloku: +w3.eth.get_block('latest') + +# wyślij transakcję: +w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...}) +``` + +## Instalacja {#installation} + +W tym przewodniku będziemy pracować tylko w interpreterze Pythona. Nie będziemy tworzyć żadnych katalogów, plików, klas ani funkcji. + +Uwaga: w poniższych przykładach polecenia, które zaczynają się od `$`, są przeznaczone do uruchomienia w terminalu. (Nie wpisuj znaku `$`, on tylko oznacza początek linii.) + +Najpierw zainstaluj [IPython](https://ipython.org/), aby uzyskać przyjazne dla użytkownika środowisko do eksploracji. IPython oferuje między innymi uzupełnianie tabulatorem, co znacznie ułatwia sprawdzenie, co jest możliwe w Web3.py. + +```bash +pip install ipython +``` + +Web3.py jest publikowane pod nazwą `web3`. Zainstaluj go w ten sposób: + +```bash +pip install web3 +``` + +Jeszcze jedno – później będziemy symulować blockchain, co wymaga kilku dodatkowych zależności. Możesz je zainstalować za pomocą: + +```bash +pip install 'web3[tester]' +``` + +Wszystko gotowe! + +Uwaga: Pakiet `web3[tester]` działa z Pythonem do wersji 3.10.xx + +## Uruchomienie piaskownicy {#spin-up-a-sandbox} + +Otwórz nowe środowisko Pythona, uruchamiając `ipython` w terminalu. Jest to porównywalne z uruchomieniem `python`, ale z większą liczbą dodatków. + +```bash +ipython +``` + +Spowoduje to wydrukowanie informacji o wersjach Pythona i IPythona, których używasz, a następnie powinieneś zobaczyć monit oczekujący na dane wejściowe: + +```python +In [1]: +``` + +Patrzysz teraz na interaktywną powłokę Pythona. Zasadniczo jest to piaskownica do zabawy. Jeśli dotarłeś tak daleko, czas zaimportować Web3.py: + +```python +In [1]: from web3 import Web3 +``` + +## Wprowadzenie do modułu Web3 {#introducing-the-web3-module} + +Oprócz tego, że jest bramą do Ethereum, moduł [Web3](https://web3py.readthedocs.io/en/stable/overview.html#base-api) oferuje kilka wygodnych funkcji. Przyjrzyjmy się kilku z nich. + +W aplikacji Ethereum często będziesz musiał konwertować nominały walut. Moduł Web3 udostępnia do tego celu kilka metod pomocniczych: [from_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.from_wei) i [to_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.to_wei). + + +Uwaga: Komputery są notorycznie złe w obsłudze arytmetyki dziesiętnej. Aby obejść ten problem, deweloperzy często przechowują kwoty w dolarach jako centy. Na przykład przedmiot o cenie 5,99 USD może być przechowywany w bazie danych jako 599. + +Podobny wzorzec jest używany podczas obsługi transakcji w etherze. Jednak zamiast dwóch miejsc po przecinku, ether ma ich 18! Najmniejszy nominał etheru nazywa się wei, więc jest to wartość określana podczas wysyłania transakcji. + +1 ether = 1000000000000000000 wei + +1 wei = 0,000000000000000001 ether + + + +Spróbuj przekonwertować niektóre wartości na wei i z wei. Zauważ, że [istnieją nazwy dla wielu nominałów](https://web3py.readthedocs.io/en/stable/troubleshooting.html#how-do-i-convert-currency-denominations) pomiędzy etherem a wei. Jednym z bardziej znanych jest **gwei**, ponieważ często w ten sposób przedstawiane są opłaty transakcyjne. + +```python +In [2]: Web3.to_wei(1, 'ether') +Out[2]: 1000000000000000000 + +In [3]: Web3.from_wei(500000000, 'gwei') +Out[3]: Decimal('0.5') +``` + +Inne metody narzędziowe w module Web3 obejmują konwertery formatu danych (np. [`toHex`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toHex)), pomocników adresów (np. [`isAddress`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.isAddress)) i funkcje haszujące (np. [`keccak`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.keccak)). Wiele z nich zostanie omówionych w dalszej części serii. Aby wyświetlić wszystkie dostępne metody i właściwości, skorzystaj z autouzupełniania w IPython, wpisując `Web3`. i naciskając dwukrotnie klawisz tabulacji po kropce. + +## Porozmawiaj z łańcuchem {#talk-to-the-chain} + +Metody pomocnicze są świetne, ale przejdźmy do blockchaina. Następnym krokiem jest skonfigurowanie Web3.py do komunikacji z węzłem Ethereum. Tutaj mamy możliwość korzystania z dostawców IPC, HTTP lub Websocket. + +Nie będziemy podążać tą ścieżką, ale przykład kompletnego przepływu pracy z użyciem dostawcy HTTP może wyglądać mniej więcej tak: + +- Pobierz węzeł Ethereum, np. [Geth](https://geth.ethereum.org/). +- Uruchom Geth w jednym oknie terminala i poczekaj, aż zsynchronizuje się z siecią. Domyślny port HTTP to `8545`, ale można go skonfigurować. +- Poinstruuj Web3.py, aby połączyło się z węzłem przez HTTP na `localhost:8545`. + `w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))` +- Użyj instancji `w3`, aby wejść w interakcję z węzłem. + +Chociaż jest to jeden z „prawdziwych” sposobów, proces synchronizacji trwa godzinami i jest niepotrzebny, jeśli chcesz tylko środowiska programistycznego. Web3.py udostępnia w tym celu czwartego dostawcę, **EthereumTesterProvider**. Ten dostawca testowy łączy się z symulowanym węzłem Ethereum z luźnymi uprawnieniami i fałszywą walutą do zabawy. + +![Diagram pokazujący EthereumTesterProvider łączący Twoją aplikację web3.py z symulowanym węzłem Ethereum](./ethereumtesterprovider.png) + +_EthereumTesterProvider łączy się z symulowanym węzłem i jest przydatny do szybkich środowisk programistycznych._ + +Ten symulowany węzeł nazywa się [eth-tester](https://github.com/ethereum/eth-tester) i zainstalowaliśmy go jako część polecenia `pip install web3[tester]`. Konfiguracja Web3.py do używania tego dostawcy testowego jest tak prosta, jak: + +```python +In [4]: w3 = Web3(Web3.EthereumTesterProvider()) +``` + +Teraz jesteś gotowy, aby surfować po łańcuchu! To nie jest coś, co ludzie mówią. Właśnie to wymyśliłem. Zróbmy szybką wycieczkę. + +## Szybka wycieczka {#the-quick-tour} + +Po pierwsze, sprawdzenie poprawności: + +```python +In [5]: w3.is_connected() +Out[5]: True +``` + +Ponieważ używamy dostawcy testowego, nie jest to bardzo wartościowy test, ale jeśli się nie powiedzie, prawdopodobnie wpisałeś coś źle podczas tworzenia instancji zmiennej `w3`. Sprawdź dwukrotnie, czy uwzględniłeś wewnętrzne nawiasy, tj. `Web3.EthereumTesterProvider()`. + +## Przystanek wycieczki nr 1: [konta](/developers/docs/accounts/) {#tour-stop-1-accounts} + +Dla wygody dostawca testowy stworzył kilka kont i załadował je testowym etherem. + +Najpierw zobaczmy listę tych kont: + +```python +In [6]: w3.eth.accounts +Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', + '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', + '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...] +``` + +Jeśli uruchomisz to polecenie, powinieneś zobaczyć listę dziesięciu ciągów znaków, które zaczynają się od `0x`. Każdy z nich to **adres publiczny** i pod pewnymi względami jest analogiczny do numeru konta w rachunku bieżącym. Podałbyś ten adres komuś, kto chciałby wysłać ci ether. + +Jak wspomniano, dostawca testowy wstępnie załadował każde z tych kont pewną ilością testowego etheru. Sprawdźmy, ile jest na pierwszym koncie: + +```python +In [7]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[7]: 1000000000000000000000000 +``` + +To mnóstwo zer! Zanim pójdziesz śmiejąc się do fałszywego banku, przypomnij sobie wcześniejszą lekcję o nominałach walut. Wartości etheru są reprezentowane w najmniejszym nominale, wei. Przelicz to na ether: + +```python +In [8]: w3.from_wei(1000000000000000000000000, 'ether') +Out[8]: Decimal('1000000') +``` + +Milion testowego etheru — całkiem nieźle. + +## Przystanek wycieczki nr 2: dane bloku {#tour-stop-2-block-data} + +Rzućmy okiem na stan tego symulowanego blockchaina: + +```python +In [9]: w3.eth.get_block('latest') +Out[9]: AttributeDict({ + 'number': 0, + 'hash': HexBytes('0x9469878...'), + 'parentHash': HexBytes('0x0000000...'), + ... + 'transactions': [] +}) +``` + +Zwracanych jest wiele informacji o bloku, ale warto zwrócić uwagę na kilka rzeczy: + +- Numer bloku to zero — niezależnie od tego, jak dawno skonfigurowałeś dostawcę testowego. W przeciwieństwie do prawdziwej sieci Ethereum, która dodaje nowy blok co 12 sekund, ta symulacja będzie czekać, aż dasz jej coś do zrobienia. +- `transactions` to pusta lista z tego samego powodu: jeszcze nic nie zrobiliśmy. Ten pierwszy blok to **pusty blok**, tylko po to, aby rozpocząć łańcuch. +- Zauważ, że `parentHash` to tylko garść pustych bajtów. Oznacza to, że jest to pierwszy blok w łańcuchu, znany również jako **blok genezy**. + +## Przystanek wycieczki nr 3: [transakcje](/developers/docs/transactions/) {#tour-stop-3-transactions} + +Utknęliśmy na bloku zero, dopóki nie pojawi się oczekująca transakcja, więc stwórzmy jedną. Wyślij kilka testowych etherów z jednego konta na drugie: + +```python +In [10]: tx_hash = w3.eth.send_transaction({ + 'from': w3.eth.accounts[0], + 'to': w3.eth.accounts[1], + 'value': w3.to_wei(3, 'ether'), + 'gas': 21000 +}) +``` + +Jest to zazwyczaj moment, w którym czeka się kilka sekund na dołączenie transakcji do nowego bloku. Pełny proces wygląda mniej więcej tak: + +1. Prześlij transakcję i zachowaj jej hasz. Dopóki blok zawierający transakcję nie zostanie utworzony i rozgłoszony, transakcja jest „oczekująca”. + `tx_hash = w3.eth.send_transaction({ … })` +2. Poczekaj, aż transakcja zostanie uwzględniona w bloku: + `w3.eth.wait_for_transaction_receipt(tx_hash)` +3. Kontynuuj logikę aplikacji. Aby wyświetlić pomyślną transakcję: + `w3.eth.get_transaction(tx_hash)` + +Nasze symulowane środowisko natychmiast doda transakcję w nowym bloku, dzięki czemu możemy od razu ją wyświetlić: + +```python +In [11]: w3.eth.get_transaction(tx_hash) +Out[11]: AttributeDict({ + 'hash': HexBytes('0x15e9fb95dc39...'), + 'blockNumber': 1, + 'transactionIndex': 0, + 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', + 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', + 'value': 3000000000000000000, + ... +}) +``` + +Zobaczysz tutaj kilka znajomych szczegółów: pola `from`, `to` i `value` powinny pasować do danych wejściowych naszego wywołania `send_transaction`. Inną uspokajającą informacją jest to, że transakcja ta została uwzględniona jako pierwsza (`'transactionIndex': 0`) w bloku numer 1. + +Możemy również łatwo zweryfikować powodzenie tej transakcji, sprawdzając salda dwóch zaangażowanych kont. Trzy ethery powinny zostać przeniesione z jednego konta na drugie. + +```python +In [12]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[12]: 999996999979000000000000 + +In [13]: w3.eth.get_balance(w3.eth.accounts[1]) +Out[13]: 1000003000000000000000000 +``` + +To drugie wygląda dobrze! Saldo wzrosło z 1 000 000 do 1 000 003 etherów. Ale co stało się z pierwszym kontem? Wygląda na to, że straciło nieco więcej niż trzy ethery. Niestety, nic w życiu nie jest za darmo, a korzystanie z publicznej sieci Ethereum wymaga wynagrodzenia innych za ich rolę wspierającą. Niewielka opłata transakcyjna została odjęta od konta, które przesłało transakcję – ta opłata to ilość spalonego gazu (21000 jednostek gazu za transfer ETH) pomnożona przez opłatę podstawową, która zmienia się w zależności od aktywności sieci, plus napiwek, który trafia do walidatora, który włącza transakcję do bloku. + +Więcej o [gazie](/developers/docs/gas/#post-london) + +Uwaga: W sieci publicznej opłaty transakcyjne są zmienne w zależności od zapotrzebowania w sieci i tego, jak szybko chcesz, aby transakcja została przetworzona. Jeśli interesuje Cię szczegółowe omówienie sposobu obliczania opłat, zobacz mój wcześniejszy post o tym, jak transakcje są włączane do bloku. + +## Chwila oddechu {#and-breathe} + +Siedzimy nad tym już chwilę, więc to wydaje się dobrym miejscem na przerwę. Królicza nora ciągnie się dalej, a my będziemy kontynuować eksplorację w drugiej części tej serii. Nadchodzące koncepcje: łączenie się z prawdziwym węzłem, inteligentne kontrakty i tokeny. Masz dodatkowe pytania? Daj mi znać! Twoja opinia wpłynie na to, w jakim kierunku pójdziemy dalej. Prośby mile widziane na [Twitterze](https://twitter.com/wolovim). diff --git a/public/content/translations/pl/developers/tutorials/all-you-can-cache/index.md b/public/content/translations/pl/developers/tutorials/all-you-can-cache/index.md new file mode 100644 index 00000000000..7c8a1f4745c --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/all-you-can-cache/index.md @@ -0,0 +1,867 @@ +--- +title: "Wszystko, co możesz zbuforować" +description: "Dowiedz się, jak tworzyć i używać kontraktu buforującego w celu uzyskania tańszych transakcji w pakietach zbiorczych" +author: Ori Pomerantz +tags: [ "warstwa 2", "buforowanie", "przechowywanie" ] +skill: intermediate +published: 2022-09-15 +lang: pl +--- + +Podczas korzystania z pakietów zbiorczych koszt jednego bajtu w transakcji jest znacznie wyższy niż koszt slotu pamięci. Dlatego sensowne jest buforowanie jak największej ilości informacji w łańcuchu. + +W tym artykule dowiesz się, jak stworzyć i używać kontraktu buforującego w taki sposób, aby każda wartość parametru, która prawdopodobnie będzie używana wielokrotnie, została zbuforowana i była dostępna do użycia (po pierwszym razie) przy użyciu znacznie mniejszej liczby bajtów, oraz jak napisać kod poza łańcuchem, który korzysta z tej pamięci podręcznej. + +Jeśli chcesz pominąć artykuł i po prostu zobaczyć kod źródłowy, [jest on tutaj](https://github.com/qbzzt/20220915-all-you-can-cache). Stos programistyczny to [Foundry](https://getfoundry.sh/introduction/installation/). + +## Ogólny projekt {#overall-design} + +Dla uproszczenia założymy, że wszystkie parametry transakcji to `uint256` o długości 32 bajtów. Gdy otrzymamy transakcję, będziemy analizować każdy parametr w następujący sposób: + +1. Jeśli pierwszy bajt to `0xFF`, weź następne 32 bajty jako wartość parametru i zapisz ją w pamięci podręcznej. + +2. Jeśli pierwszy bajt to `0xFE`, weź następne 32 bajty jako wartość parametru, ale _nie_ zapisuj jej w pamięci podręcznej. + +3. Dla każdej innej wartości weź cztery górne bity jako liczbę dodatkowych bajtów, a dolne cztery bity jako najbardziej znaczące bity klucza pamięci podręcznej. Oto kilka przykładów: + + | Bajty w calldata | Klucz pamięci podręcznej | + | :--------------- | -----------------------: | + | 0x0F | 0x0F | + | 0x10,0x10 | 0x10 | + | 0x12,0xAC | 0x02AC | + | 0x2D,0xEA, 0xD6 | 0x0DEAD6 | + +## Manipulacja pamięcią podręczną {#cache-manipulation} + +Pamięć podręczna jest zaimplementowana w [`Cache.sol`](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol). Przejdźmy przez niego linia po linii. + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + + +contract Cache { + + bytes1 public constant INTO_CACHE = 0xFF; + bytes1 public constant DONT_CACHE = 0xFE; +``` + +Te stałe służą do interpretacji specjalnych przypadków, w których podajemy wszystkie informacje i chcemy je zapisać w pamięci podręcznej lub nie. Zapisywanie do pamięci podręcznej wymaga dwóch operacji [`SSTORE`](https://www.evm.codes/#55) w wcześniej nieużywanych slotach pamięci kosztem 22100 jednostek gazu każda, dlatego jest to opcjonalne. + +```solidity + + mapping(uint => uint) public val2key; +``` + +[Odwzorowanie](https://www.geeksforgeeks.org/solidity/solidity-mappings/) pomiędzy wartościami a ich kluczami. Ta informacja jest niezbędna do zakodowania wartości przed wysłaniem transakcji. + +```solidity + // Lokalizacja n ma wartość dla klucza n+1, ponieważ musimy zachować + // zero jako "nie w pamięci podręcznej". + uint[] public key2val; +``` + +Możemy użyć tablicy do mapowania kluczy na wartości, ponieważ to my przypisujemy klucze i dla uproszczenia robimy to sekwencyjnie. + +```solidity + function cacheRead(uint _key) public view returns (uint) { + require(_key <= key2val.length, "Odczyt niezainicjowanego wpisu w pamięci podręcznej"); + return key2val[_key-1]; + } // cacheRead +``` + +Odczytaj wartość z pamięci podręcznej. + +```solidity + // Zapisz wartość w pamięci podręcznej, jeśli jeszcze jej tam nie ma + // Funkcja publiczna tylko po to, aby umożliwić działanie testu + function cacheWrite(uint _value) public returns (uint) { + // Jeśli wartość jest już w pamięci podręcznej, zwróć bieżący klucz + if (val2key[_value] != 0) { + return val2key[_value]; + } +``` + +Nie ma sensu umieszczać tej samej wartości w pamięci podręcznej więcej niż raz. Jeśli wartość już istnieje, po prostu zwróć istniejący klucz. + +```solidity + // Ponieważ 0xFE jest przypadkiem specjalnym, największy klucz, jaki może pomieścić pamięć podręczna, to + // 0x0D, po którym następuje 15 wartości 0xFF. Jeśli długość pamięci podręcznej jest już tak + // duża, zakończ błędem. + // 1 2 3 4 5 6 7 8 9 A B C D E F + require(key2val.length+1 < 0x0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, + "przepełnienie pamięci podręcznej"); +``` + +Nie sądzę, abyśmy kiedykolwiek uzyskali tak dużą pamięć podręczną (około 1,8\*1037 wpisów, co wymagałoby około 1027 TB do przechowywania). Jednak jestem na tyle stary, że pamiętam ["640 kB powinno zawsze wystarczyć"](https://quoteinvestigator.com/2011/09/08/640k-enough/). Ten test jest bardzo tani. + +```solidity + // Zapisz wartość, używając następnego klucza + val2key[_value] = key2val.length+1; +``` + +Dodaj wyszukiwanie wsteczne (od wartości do klucza). + +```solidity + key2val.push(_value); +``` + +Dodaj wyszukiwanie w przód (od klucza do wartości). Ponieważ przypisujemy wartości sekwencyjnie, możemy po prostu dodać ją po ostatniej wartości w tablicy. + +```solidity + return key2val.length; + } // cacheWrite +``` + +Zwróć nową długość `key2val`, która jest komórką, w której przechowywana jest nowa wartość. + +```solidity + function _calldataVal(uint startByte, uint length) + private pure returns (uint) +``` + +Ta funkcja odczytuje wartość z calldata o dowolnej długości (do 32 bajtów, czyli rozmiaru słowa). + +```solidity + { + uint _retVal; + + require(length < 0x21, + "Limit długości _calldataVal to 32 bajty"); + require(length + startByte <= msg.data.length, + "_calldataVal próbuje odczytać poza calldatasize"); +``` + +Ta funkcja jest wewnętrzna, więc jeśli reszta kodu jest napisana poprawnie, te testy nie są wymagane. Jednak nie kosztują wiele, więc równie dobrze możemy je mieć. + +```solidity + assembly { + _retVal := calldataload(startByte) + } +``` + +Ten kod jest w języku [Yul](https://docs.soliditylang.org/en/v0.8.16/yul.html). Odczytuje 32-bajtową wartość z calldata. Działa to nawet wtedy, gdy calldata kończy się przed `startByte+32`, ponieważ niezainicjowana przestrzeń w EVM jest uważana za zerową. + +```solidity + _retVal = _retVal >> (256-length*8); +``` + +Niekoniecznie chcemy wartości 32-bajtowej. To usuwa nadmiarowe bajty. + +```solidity + return _retVal; + } // _calldataVal + + + // Odczytaj pojedynczy parametr z calldata, zaczynając od _fromByte + function _readParam(uint _fromByte) internal + returns (uint _nextByte, uint _parameterValue) + { +``` + +Odczytaj pojedynczy parametr z calldata. Zauważ, że musimy zwrócić nie tylko odczytaną wartość, ale także lokalizację następnego bajtu, ponieważ parametry mogą mieć długość od 1 do 33 bajtów. + +```solidity + // Pierwszy bajt mówi nam, jak interpretować resztę + uint8 _firstByte; + + _firstByte = uint8(_calldataVal(_fromByte, 1)); +``` + +Solidity próbuje zredukować liczbę błędów, zabraniając potencjalnie niebezpiecznych [niejawnych konwersji typów](https://docs.soliditylang.org/en/v0.8.16/types.html#implicit-conversions). Degradacja, na przykład z 256 bitów do 8 bitów, musi być jawna. + +```solidity + + // Odczytaj wartość, ale nie zapisuj jej w pamięci podręcznej + if (_firstByte == uint8(DONT_CACHE)) + return(_fromByte+33, _calldataVal(_fromByte+1, 32)); + + // Odczytaj wartość i zapisz ją w pamięci podręcznej + if (_firstByte == uint8(INTO_CACHE)) { + uint _param = _calldataVal(_fromByte+1, 32); + cacheWrite(_param); + return(_fromByte+33, _param); + } + + // Jeśli dotarliśmy tutaj, oznacza to, że musimy odczytać z pamięci podręcznej + + // Liczba dodatkowych bajtów do odczytania + uint8 _extraBytes = _firstByte / 16; +``` + +Weź dolny [półbajt (nibble)](https://en.wikipedia.org/wiki/Nibble) i połącz go z pozostałymi bajtami, aby odczytać wartość z pamięci podręcznej. + +```solidity + uint _key = (uint256(_firstByte & 0x0F) << (8*_extraBytes)) + + _calldataVal(_fromByte+1, _extraBytes); + + return (_fromByte+_extraBytes+1, cacheRead(_key)); + + } // _readParam + + + // Odczytaj n parametrów (funkcje wiedzą, ilu parametrów oczekują) + function _readParams(uint _paramNum) internal returns (uint[] memory) { +``` + +Moglibyśmy pobrać liczbę parametrów z samych danych wywołania (calldata), ale funkcje, które nas wywołują, wiedzą, ilu parametrów oczekują. Łatwiej jest pozwolić, aby to one nam o tym powiedziały. + +```solidity + // Parametry, które odczytujemy + uint[] memory params = new uint[](_paramNum); + + // Parametry zaczynają się od 4 bajtu, przed nim jest sygnatura funkcji + uint _atByte = 4; + + for(uint i=0; i<_paramNum; i++) { + (_atByte, params[i]) = _readParam(_atByte); + } +``` + +Odczytuj parametry, aż uzyskasz potrzebną liczbę. Jeśli wykroczymy poza koniec calldata, `_readParams` cofnie wywołanie. + +```solidity + + return(params); + } // readParams + + // Do testowania _readParams, przetestuj odczyt czterech parametrów + function fourParam() public + returns (uint256,uint256,uint256,uint256) + { + uint[] memory params; + params = _readParams(4); + return (params[0], params[1], params[2], params[3]); + } // fourParam +``` + +Jedną z wielkich zalet Foundry jest to, że pozwala na pisanie testów w Solidity ([zobacz Testowanie pamięci podręcznej poniżej](#testing-the-cache)). To znacznie ułatwia testy jednostkowe. Jest to funkcja, która odczytuje cztery parametry i zwraca je, aby test mógł zweryfikować ich poprawność. + +```solidity + // Pobierz wartość, zwróć bajty, które ją zakodują (używając pamięci podręcznej, jeśli to możliwe) + function encodeVal(uint _val) public view returns(bytes memory) { +``` + +`encodeVal` to funkcja, którą kod offchain (poza łańcuchem) wywołuje, aby pomóc w tworzeniu calldata korzystających z pamięci podręcznej. Otrzymuje pojedynczą wartość i zwraca bajty, które ją kodują. Ta funkcja jest funkcją typu `view`, więc nie wymaga transakcji, a wywołana z zewnątrz nie zużywa gazu. + +```solidity + uint _key = val2key[_val]; + + // Wartości nie ma jeszcze w pamięci podręcznej, więc dodaj ją + if (_key == 0) + return bytes.concat(INTO_CACHE, bytes32(_val)); +``` + +W [EVM](/developers/docs/evm/) cała niezainicjowana pamięć masowa jest traktowana jako zera. Więc jeśli szukamy klucza dla wartości, której tam nie ma, otrzymujemy zero. W takim przypadku bajty, które ją kodują, to `INTO_CACHE` (więc zostanie zbuforowana następnym razem), a po nich rzeczywista wartość. + +```solidity + // Jeśli klucz jest <0x10, zwróć go jako pojedynczy bajt + if (_key < 0x10) + return bytes.concat(bytes1(uint8(_key))); +``` + +Pojedyncze bajty są najłatwiejsze. Używamy po prostu [`bytes.concat`](https://docs.soliditylang.org/en/v0.8.16/types.html#the-functions-bytes-concat-and-string-concat), aby zamienić typ `bytes` na tablicę bajtów o dowolnej długości. Pomimo nazwy działa dobrze, gdy jest zaopatrzona w tylko jeden argument. + +```solidity + // Wartość dwubajtowa, zakodowana jako 0x1vvv + if (_key < 0x1000) + return bytes.concat(bytes2(uint16(_key) | 0x1000)); +``` + +Gdy mamy klucz mniejszy niż 163, możemy go wyrazić w dwóch bajtach. Najpierw konwertujemy `_key`, która jest wartością 256-bitową, na wartość 16-bitową i używamy logicznego LUB, aby dodać liczbę dodatkowych bajtów do pierwszego bajtu. Następnie zamieniamy ją na wartość `bytes2`, którą można przekonwertować na `bytes`. + +```solidity + // Prawdopodobnie istnieje sprytny sposób na wykonanie następujących linii jako pętli, + // ale jest to funkcja widoku, więc optymalizuję pod kątem czasu programisty i + // prostoty. + + if (_key < 16*256**2) + return bytes.concat(bytes3(uint24(_key) | (0x2 * 16 * 256**2))); + if (_key < 16*256**3) + return bytes.concat(bytes4(uint32(_key) | (0x3 * 16 * 256**3))); + . + . + . + if (_key < 16*256**14) + return bytes.concat(bytes15(uint120(_key) | (0xE * 16 * 256**14))); + if (_key < 16*256**15) + return bytes.concat(bytes16(uint128(_key) | (0xF * 16 * 256**15))); +``` + +Pozostałe wartości (3 bajty, 4 bajty itp.) są obsługiwane w ten sam sposób, tylko z różnymi rozmiarami pól. + +```solidity + // Jeśli dotarliśmy tutaj, coś jest nie tak. + revert("Błąd w encodeVal, nie powinno się zdarzyć"); +``` + +Jeśli tu dotrzemy, oznacza to, że otrzymaliśmy klucz, który nie jest mniejszy niż 16\*25615. Ale `cacheWrite` ogranicza klucze, więc nie możemy nawet dojść do 14\*25616 (co miałoby pierwszy bajt 0xFE, więc wyglądałoby jak `DONT_CACHE`). Ale niewiele nas kosztuje dodanie testu na wypadek, gdyby przyszły programista wprowadził błąd. + +```solidity + } // encodeVal + +} // Cache +``` + +### Testowanie pamięci podręcznej {#testing-the-cache} + +Jedną z zalet Foundry jest to, że [pozwala pisać testy w Solidity](https://getfoundry.sh/forge/tests/overview/), co ułatwia pisanie testów jednostkowych. Testy dla klasy `Cache` są [tutaj](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/Cache.t.sol). Ponieważ kod testowy jest powtarzalny, jak to zwykle bywa z testami, w tym artykule wyjaśniono tylko interesujące części. + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; + + +// Należy uruchomić `forge test -vv` dla konsoli. +import "forge-std/console.sol"; +``` + +To tylko standardowy kod, który jest niezbędny do użycia pakietu testowego i `console.log`. + +```solidity +import "src/Cache.sol"; +``` + +Musimy znać kontrakt, który testujemy. + +```solidity +contract CacheTest is Test { + Cache cache; + + function setUp() public { + cache = new Cache(); + } +``` + +Funkcja `setUp` jest wywoływana przed każdym testem. W tym przypadku po prostu tworzymy nową pamięć podręczną, aby nasze testy nie wpływały na siebie nawzajem. + +```solidity + function testCaching() public { +``` + +Testy to funkcje, których nazwy zaczynają się od `test`. Ta funkcja sprawdza podstawową funkcjonalność pamięci podręcznej, zapisując wartości i ponownie je odczytując. + +```solidity + for(uint i=1; i<5000; i++) { + cache.cacheWrite(i*i); + } + + for(uint i=1; i<5000; i++) { + assertEq(cache.cacheRead(i), i*i); +``` + +W ten sposób przeprowadza się rzeczywiste testowanie za pomocą [funkcji `assert...`](https://getfoundry.sh/reference/forge-std/std-assertions/). W tym przypadku sprawdzamy, czy wartość, którą zapisaliśmy, jest tą samą, którą odczytaliśmy. Możemy zignorować wynik `cache.cacheWrite`, ponieważ wiemy, że klucze pamięci podręcznej są przypisywane liniowo. + +```solidity + } + } // testCaching + + + // Zapisz tę samą wartość wiele razy, upewnij się, że klucz pozostaje + // taki sam + function testRepeatCaching() public { + for(uint i=1; i<100; i++) { + uint _key1 = cache.cacheWrite(i); + uint _key2 = cache.cacheWrite(i); + assertEq(_key1, _key2); + } +``` + +Najpierw zapisujemy każdą wartość do pamięci podręcznej dwukrotnie i upewniamy się, że klucze są takie same (co oznacza, że drugi zapis tak naprawdę nie miał miejsca). + +```solidity + for(uint i=1; i<100; i+=3) { + uint _key = cache.cacheWrite(i); + assertEq(_key, i); + } + } // testRepeatCaching +``` + +Teoretycznie może istnieć błąd, który nie wpływa na kolejne zapisy w pamięci podręcznej. Dlatego tutaj wykonujemy kilka zapisów, które nie są następujące po sobie i widzimy, że wartości nadal nie są nadpisywane. + +```solidity + // Odczytaj uint z bufora pamięci (aby upewnić się, że otrzymamy z powrotem parametry, + // które wysłaliśmy) + function toUint256(bytes memory _bytes, uint256 _start) internal pure + returns (uint256) +``` + +Odczytaj 256-bitowe słowo z bufora `bytes memory`. Ta funkcja narzędziowa pozwala nam zweryfikować, czy otrzymujemy poprawne wyniki, gdy uruchamiamy wywołanie funkcji, która używa pamięci podręcznej. + +```solidity + { + require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); + uint256 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x20), _start)) + } +``` + +Yul nie obsługuje struktur danych poza `uint256`, więc gdy odwołujesz się do bardziej zaawansowanej struktury danych, takiej jak bufor pamięci `_bytes`, otrzymujesz adres tej struktury. Solidity przechowuje wartości `bytes memory` jako 32-bajtowe słowo, które zawiera długość, po której następują rzeczywiste bajty, więc aby uzyskać bajt o numerze `_start`, musimy obliczyć `_bytes+32+_start`. + +```solidity + + return tempUint; + } // toUint256 + + // Sygnatura funkcji dla fourParams(), dzięki uprzejmości + // https://www.4byte.directory/signatures/?bytes4_signature=0x3edc1e6d + bytes4 constant FOUR_PARAMS = 0x3edc1e6d; + + // Po prostu kilka stałych wartości, aby zobaczyć, czy otrzymujemy poprawne wartości z powrotem + uint256 constant VAL_A = 0xDEAD60A7; + uint256 constant VAL_B = 0xBEEF; + uint256 constant VAL_C = 0x600D; + uint256 constant VAL_D = 0x600D60A7; +``` + +Kilka stałych, których potrzebujemy do testowania. + +```solidity + function testReadParam() public { +``` + +Wywołaj `fourParams()`, funkcję, która używa `readParams`, aby przetestować, czy potrafimy poprawnie odczytać parametry. + +```solidity + address _cacheAddr = address(cache); + bool _success; + bytes memory _callInput; + bytes memory _callOutput; +``` + +Nie możemy użyć normalnego mechanizmu ABI do wywołania funkcji przy użyciu pamięci podręcznej, więc musimy użyć niskopoziomowego mechanizmu [`
.call()`](https://docs.soliditylang.org/en/v0.8.16/types.html#members-of-addresses). Mechanizm ten przyjmuje na wejściu `bytes memory`, a na wyjściu zwraca to samo (oraz wartość logiczną). + +```solidity + // Pierwsze wywołanie, pamięć podręczna jest pusta + _callInput = bytes.concat( + FOUR_PARAMS, +``` + +Użyteczne jest, aby ten sam kontrakt obsługiwał zarówno funkcje buforowane (dla wywołań bezpośrednio z transakcji), jak i niebuforowane (dla wywołań z innych inteligentnych kontraktów). Aby to zrobić, musimy nadal polegać na mechanizmie Solidity do wywoływania poprawnej funkcji, zamiast umieszczać wszystko w [funkcji `fallback`](https://docs.soliditylang.org/en/v0.8.16/contracts.html#fallback-function). Dzięki temu kompozycyjność staje się o wiele łatwiejsza. Pojedynczy bajt w większości przypadków wystarczyłby do zidentyfikowania funkcji, więc marnujemy trzy bajty (16\*3=48 jednostek gazu). Jednak w chwili, gdy to piszę, te 48 jednostek gazu kosztuje 0,07 centa, co jest rozsądnym kosztem prostszego, mniej podatnego na błędy kodu. + +```solidity + // Pierwsza wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), + bytes32(VAL_A), +``` + +Pierwsza wartość: flaga informująca, że jest to pełna wartość, która musi zostać zapisana w pamięci podręcznej, a następnie 32 bajty wartości. Pozostałe trzy wartości są podobne, z wyjątkiem tego, że `VAL_B` nie jest zapisywana do pamięci podręcznej, a `VAL_C` jest zarówno trzecim, jak i czwartym parametrem. + +```solidity + . + . + . + ); + (_success, _callOutput) = _cacheAddr.call(_callInput); +``` + +To tutaj faktycznie wywołujemy kontrakt `Cache`. + +```solidity + assertEq(_success, true); +``` + +Oczekujemy, że wywołanie się powiedzie. + +```solidity + assertEq(cache.cacheRead(1), VAL_A); + assertEq(cache.cacheRead(2), VAL_C); +``` + +Zaczynamy z pustą pamięcią podręczną, a następnie dodajemy `VAL_A`, a po niej `VAL_C`. Spodziewalibyśmy się, że pierwszy będzie miał klucz 1, a drugi 2. + +``` + assertEq(toUint256(_callOutput,0), VAL_A); + assertEq(toUint256(_callOutput,32), VAL_B); + assertEq(toUint256(_callOutput,64), VAL_C); + assertEq(toUint256(_callOutput,96), VAL_C); +``` + +Dane wyjściowe to cztery parametry. Tutaj weryfikujemy, czy są poprawne. + +```solidity + // Drugie wywołanie, możemy użyć pamięci podręcznej + _callInput = bytes.concat( + FOUR_PARAMS, + + // Pierwsza wartość w pamięci podręcznej + bytes1(0x01), +``` + +Klucze pamięci podręcznej poniżej 16 to tylko jeden bajt. + +```solidity + // Druga wartość, nie dodawaj jej do pamięci podręcznej + cache.DONT_CACHE(), + bytes32(VAL_B), + + // Trzecia i czwarta wartość, ta sama wartość + bytes1(0x02), + bytes1(0x02) + ); + . + . + . + } // testReadParam +``` + +Testy po wywołaniu są identyczne jak te po pierwszym wywołaniu. + +```solidity + function testEncodeVal() public { +``` + +Ta funkcja jest podobna do `testReadParam`, z wyjątkiem tego, że zamiast jawnie pisać parametry, używamy `encodeVal()`. + +```solidity + . + . + . + _callInput = bytes.concat( + FOUR_PARAMS, + cache.encodeVal(VAL_A), + cache.encodeVal(VAL_B), + cache.encodeVal(VAL_C), + cache.encodeVal(VAL_D) + ); + . + . + . + assertEq(_callInput.length, 4+1*4); + } // testEncodeVal +``` + +Jedynym dodatkowym testem w `testEncodeVal()` jest weryfikacja, czy długość `_callInput` jest prawidłowa. Dla pierwszego wywołania jest to 4+33\*4. Dla drugiego, gdzie każda wartość jest już w pamięci podręcznej, wynosi ona 4+1\*4. + +```solidity + // Przetestuj encodeVal, gdy klucz ma więcej niż jeden bajt + // Maksymalnie trzy bajty, ponieważ wypełnienie pamięci podręcznej do czterech bajtów trwa + // zbyt długo. + function testEncodeValBig() public { + // Umieść pewną liczbę wartości w pamięci podręcznej. + // Aby uprościć sprawę, użyj klucza n dla wartości n. + for(uint i=1; i<0x1FFF; i++) { + cache.cacheWrite(i); + } +``` + +Powyższa funkcja `testEncodeVal` zapisuje tylko cztery wartości do pamięci podręcznej, więc [część funkcji, która zajmuje się wartościami wielobajtowymi](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol#L144-L171), nie jest sprawdzana. Ale ten kod jest skomplikowany i podatny na błędy. + +Pierwsza część tej funkcji to pętla, która po kolei zapisuje do pamięci podręcznej wszystkie wartości od 1 do 0x1FFF, dzięki czemu będziemy w stanie zakodować te wartości i wiedzieć, dokąd trafią. + +```solidity + . + . + . + + _callInput = bytes.concat( + FOUR_PARAMS, + cache.encodeVal(0x000F), // Jeden bajt 0x0F + cache.encodeVal(0x0010), // Dwa bajty 0x1010 + cache.encodeVal(0x0100), // Dwa bajty 0x1100 + cache.encodeVal(0x1000) // Trzy bajty 0x201000 + ); +``` + +Przetestuj wartości jedno-, dwu- i trzybajtowe. Nie testujemy dalej, ponieważ zapisanie wystarczającej liczby wpisów na stosie (co najmniej 0x10000000, czyli około ćwierć miliarda) zajęłoby zbyt dużo czasu. + +```solidity + . + . + . + . + } // testEncodeValBig + + + // Przetestuj, że przy zbyt małym buforze otrzymamy revert + function testShortCalldata() public { +``` + +Przetestuj, co się stanie w nietypowym przypadku, gdy nie ma wystarczającej liczby parametrów. + +```solidity + . + . + . + (_success, _callOutput) = _cacheAddr.call(_callInput); + assertEq(_success, false); + } // testShortCalldata +``` + +Ponieważ następuje wycofanie, wynikiem, który powinniśmy otrzymać, jest `fałsz`. + +``` + // Wywołanie z kluczami pamięci podręcznej, których tam nie ma + function testNoCacheKey() public { + . + . + . + _callInput = bytes.concat( + FOUR_PARAMS, + + // Pierwsza wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), + bytes32(VAL_A), + + // Druga wartość + bytes1(0x0F), + bytes2(0x1234), + bytes11(0xA10102030405060708090A) + ); +``` + +Ta funkcja otrzymuje cztery całkowicie prawidłowe parametry, z wyjątkiem tego, że pamięć podręczna jest pusta, więc nie ma tam żadnych wartości do odczytania. + +```solidity + . + . + . + // Przetestuj, że przy zbyt długim buforze wszystko działa poprawnie + function testLongCalldata() public { + address _cacheAddr = address(cache); + bool _success; + bytes memory _callInput; + bytes memory _callOutput; + + // Pierwsze wywołanie, pamięć podręczna jest pusta + _callInput = bytes.concat( + FOUR_PARAMS, + + // Pierwsza wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), bytes32(VAL_A), + + // Druga wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), bytes32(VAL_B), + + // Trzecia wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), bytes32(VAL_C), + + // Czwarta wartość, dodaj ją do pamięci podręcznej + cache.INTO_CACHE(), bytes32(VAL_D), + + // I jeszcze jedna wartość „na szczęście” + bytes4(0x31112233) + ); +``` + +Ta funkcja wysyła pięć wartości. Wiemy, że piąta wartość jest ignorowana, ponieważ nie jest prawidłowym wpisem w pamięci podręcznej, co spowodowałoby wycofanie transakcji, gdyby nie została uwzględniona. + +```solidity + (_success, _callOutput) = _cacheAddr.call(_callInput); + assertEq(_success, true); + . + . + . + } // testLongCalldata + +} // CacheTest + +``` + +## Przykładowa aplikacja {#a-sample-app} + +Pisanie testów w Solidity jest bardzo dobre, ale ostatecznie dapka musi być w stanie przetwarzać żądania spoza łańcucha, aby być użyteczną. Ten artykuł pokazuje, jak używać buforowania w dapce z `WORM`, co oznacza „Write Once, Read Many” (zapisz raz, czytaj wiele razy). Jeśli klucz nie jest jeszcze zapisany, można do niego zapisać wartość. Jeśli klucz jest już zapisany, następuje wycofanie transakcji. + +### Kontrakt {#the-contract} + +[To jest kontrakt](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/WORM.sol). W dużej mierze powtarza to, co zrobiliśmy już z `Cache` i `CacheTest`, więc omówimy tylko interesujące części. + +```solidity +import "./Cache.sol"; + +contract WORM is Cache { +``` + +Najłatwiejszym sposobem na użycie `Cache` jest odziedziczenie go w naszym własnym kontrakcie. + +```solidity + function writeEntryCached() external { + uint[] memory params = _readParams(2); + writeEntry(params[0], params[1]); + } // writeEntryCached +``` + +Ta funkcja jest podobna do `fourParam` w `CacheTest` powyżej. Ponieważ nie przestrzegamy specyfikacji ABI, najlepiej nie deklarować żadnych parametrów w funkcji. + +```solidity + // Ułatwienie wywoływania nas + // Sygnatura funkcji dla writeEntryCached(), dzięki uprzejmości + // https://www.4byte.directory/signatures/?bytes4_signature=0xe4e4f2d3 + bytes4 constant public WRITE_ENTRY_CACHED = 0xe4e4f2d3; +``` + +Kod zewnętrzny, który wywołuje `writeEntryCached`, będzie musiał ręcznie zbudować dane wywołania (calldata), zamiast używać `worm.writeEntryCached`, ponieważ nie przestrzegamy specyfikacji ABI. Posiadanie tej stałej wartości po prostu ułatwia pisanie. + +Należy pamiętać, że chociaż definiujemy `WRITE_ENTRY_CACHED` jako zmienną stanu, aby odczytać ją z zewnątrz, należy użyć funkcji pobierającej dla niej, `worm.WRITE_ENTRY_CACHED()`. + +```solidity + function readEntry(uint key) public view + returns (uint _value, address _writtenBy, uint _writtenAtBlock) +``` + +Funkcja odczytu jest typu `view`, więc nie wymaga transakcji i nie kosztuje gazu. W rezultacie nie ma korzyści z używania pamięci podręcznej dla parametru. W przypadku funkcji `view` najlepiej jest używać standardowego mechanizmu, który jest prostszy. + +### Kod testowy {#the-testing-code} + +[To jest kod testowy dla kontraktu](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/WORM.t.sol). Ponownie, spójrzmy tylko na to, co jest interesujące. + +```solidity + function testWReadWrite() public { + worm.writeEntry(0xDEAD, 0x60A7); + + vm.expectRevert(bytes("entry already written")); + worm.writeEntry(0xDEAD, 0xBEEF); +``` + +[To (`vm.expectRevert`)](https://book.getfoundry.sh/cheatcodes/expect-revert#expectrevert) to sposób, w jaki w teście Foundry określamy, że następne wywołanie powinno zakończyć się niepowodzeniem, oraz podajemy przyczynę niepowodzenia. Dotyczy to sytuacji, gdy używamy składni `.()` zamiast budować dane wywołania (calldata) i wywoływać kontrakt przy użyciu interfejsu niskiego poziomu (`.call()` itp.). + +```solidity + function testReadWriteCached() public { + uint cacheGoat = worm.cacheWrite(0x60A7); +``` + +Tutaj wykorzystujemy fakt, że `cacheWrite` zwraca klucz pamięci podręcznej. Nie jest to coś, czego spodziewalibyśmy się używać w produkcji, ponieważ `cacheWrite` zmienia stan, a zatem może być wywoływane tylko podczas transakcji. Transakcje nie mają wartości zwracanych; jeśli mają wyniki, to te wyniki powinny być emitowane jako zdarzenia. Zatem wartość zwracana przez `cacheWrite` jest dostępna tylko z kodu onchain, a kod onchain nie potrzebuje buforowania parametrów. + +```solidity + (_success,) = address(worm).call(_callInput); +``` + +W ten sposób mówimy Solidity, że chociaż `.call()` ma dwie wartości zwracane, interesuje nas tylko pierwsza. + +```solidity + (_success,) = address(worm).call(_callInput); + assertEq(_success, false); +``` + +Ponieważ używamy funkcji niskiego poziomu `
.call()`, nie możemy użyć `vm.expectRevert()` i musimy sprawdzić wartość logiczną powodzenia, którą otrzymujemy z wywołania. + +```solidity + event EntryWritten(uint indexed key, uint indexed value); + + . + . + . + + _callInput = bytes.concat( + worm.WRITE_ENTRY_CACHED(), worm.encodeVal(a), worm.encodeVal(b)); + vm.expectEmit(true, true, false, false); + emit EntryWritten(a, b); + (_success,) = address(worm).call(_callInput); +``` + +W ten sposób w Foundry weryfikujemy, czy kod [poprawnie emituje zdarzenie](https://getfoundry.sh/reference/cheatcodes/expect-emit/). + +### Klient {#the-client} + +Jedną rzeczą, której nie dostajesz w testach Solidity, jest kod JavaScript, który możesz wyciąć i wkleić do własnej aplikacji. Aby napisać ten kod, wdrożyłem WORM w [Optimism Goerli](https://community.optimism.io/docs/useful-tools/networks/#optimism-goerli), nowej sieci testowej [Optimism](https://www.optimism.io/). Znajduje się pod adresem [`0xd34335b1d818cee54e3323d3246bd31d94e6a78a`](https://goerli-optimism.etherscan.io/address/0xd34335b1d818cee54e3323d3246bd31d94e6a78a). + +[Kod JavaScript dla klienta można zobaczyć tutaj](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/javascript/index.js). Aby go użyć: + +1. Sklonuj repozytorium git: + + ```sh + git clone https://github.com/qbzzt/20220915-all-you-can-cache.git + ``` + +2. Zainstaluj niezbędne pakiety: + + ```sh + cd javascript + yarn + ``` + +3. Skopiuj plik konfiguracyjny: + + ```sh + cp .env.example .env + ``` + +4. Edytuj `.env` dla swojej konfiguracji: + + | Parametr | Wartość | + | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | MNEMONIC | Mnemonic dla konta, które ma wystarczająco dużo ETH, aby opłacić transakcję. [Darmowe ETH dla sieci Optimism Goerli można uzyskać tutaj](https://optimismfaucet.xyz/). | + | OPTIMISM_GOERLI_URL | URL do Optimism Goerli. Publiczny punkt końcowy, `https://goerli.optimism.io`, ma ograniczenia szybkości, ale jest wystarczający do tego, czego tutaj potrzebujemy | + +5. Uruchom `index.js`. + + ```sh + node index.js + ``` + + Ta przykładowa aplikacja najpierw zapisuje wpis do WORM, wyświetlając dane wywołania (calldata) i link do transakcji na Etherscan. Następnie odczytuje ten wpis i wyświetla używany klucz oraz wartości we wpisie (wartość, numer bloku i autor). + +Większość klienta to normalny JavaScript Dapp. Dlatego ponownie przejdziemy tylko przez interesujące części. + +```javascript +. +. +. +const main = async () => { + const func = await worm.WRITE_ENTRY_CACHED() + + // Za każdym razem potrzebny jest nowy klucz + const key = await worm.encodeVal(Number(new Date())) +``` + +W danym slocie można zapisać tylko raz, więc używamy znacznika czasu, aby upewnić się, że nie używamy ponownie slotów. + +```javascript +const val = await worm.encodeVal("0x600D") + +// Zapisz wpis +const calldata = func + key.slice(2) + val.slice(2) +``` + +Ethers oczekuje, że dane wywołania będą ciągiem szesnastkowym, `0x` po którym następuje parzysta liczba cyfr szesnastkowych. Ponieważ zarówno `key`, jak i `val` zaczynają się od `0x`, musimy usunąć te nagłówki. + +```javascript +const tx = await worm.populateTransaction.writeEntryCached() +tx.data = calldata + +sentTx = await wallet.sendTransaction(tx) +``` + +Podobnie jak w przypadku kodu testowego Solidity, nie możemy normalnie wywołać funkcji buforowanej. Zamiast tego musimy użyć mechanizmu niższego poziomu. + +```javascript + . + . + . + // Odczytaj właśnie zapisany wpis + const realKey = '0x' + key.slice(4) // usuń flagę FF + const entryRead = await worm.readEntry(realKey) + . + . + . +``` + +Do odczytywania wpisów możemy użyć normalnego mechanizmu. Nie ma potrzeby używania buforowania parametrów z funkcjami `view`. + +## Wnioski {#conclusion} + +Kod w tym artykule jest dowodem słuszności koncepcji, jego celem jest ułatwienie zrozumienia pomysłu. W przypadku systemu gotowego do produkcji można zaimplementować dodatkowe funkcje: + +- Obsługuj wartości, które nie są `uint256`. Na przykład ciągi znaków. +- Zamiast globalnej pamięci podręcznej, można mieć mapowanie między użytkownikami a pamięciami podręcznymi. Różni użytkownicy używają różnych wartości. +- Wartości używane dla adresów różnią się od tych używanych do innych celów. Może mieć sens posiadanie oddzielnej pamięci podręcznej tylko dla adresów. +- Obecnie klucze pamięci podręcznej działają na zasadzie algorytmu „kto pierwszy, ten ma najmniejszy klucz”. Pierwsze szesnaście wartości można wysłać jako pojedynczy bajt. Następne 4080 wartości można wysłać jako dwa bajty. Następny około milion wartości to trzy bajty itd. System produkcyjny powinien utrzymywać liczniki użycia wpisów w pamięci podręcznej i reorganizować je tak, aby szesnaście _najczęściej używanych_ wartości miało jeden bajt, następne 4080 najczęściej używanych wartości dwa bajty itd. + + Jest to jednak potencjalnie niebezpieczna operacja. Wyobraź sobie następującą sekwencję zdarzeń: + + 1. Noam Naiwny wywołuje `encodeVal`, aby zakodować adres, na który chce wysłać tokeny. Ten adres jest jednym z pierwszych używanych w aplikacji, więc zakodowana wartość to 0x06. Jest to funkcja `view`, a nie transakcja, więc jest to sprawa między Noamem a węzłem, którego używa, i nikt inny o tym nie wie. + + 2. Owen Właściciel uruchamia operację zmiany kolejności pamięci podręcznej. Bardzo niewiele osób faktycznie używa tego adresu, więc jest on teraz zakodowany jako 0x201122. Innej wartości, 1018, przypisano 0x06. + + 3. Noam Naiwny wysyła swoje tokeny na 0x06. Trafiają na adres `0x0000000000000000000000000de0b6b3a7640000`, a ponieważ nikt nie zna klucza prywatnego do tego adresu, po prostu tam utknęły. Noam _nie jest zadowolony_. + + Istnieją sposoby rozwiązania tego problemu i powiązanego z nim problemu transakcji znajdujących się w mempoolu podczas zmiany kolejności pamięci podręcznej, ale trzeba być tego świadomym. + +Pokazałem tutaj buforowanie na przykładzie Optimism, ponieważ jestem pracownikiem Optimism i jest to pakiet zbiorczy, który znam najlepiej. Ale powinno to działać z każdym pakietem zbiorczym, który pobiera minimalny koszt za przetwarzanie wewnętrzne, tak że w porównaniu zapisywanie danych transakcji do L1 jest głównym wydatkiem. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). + diff --git a/public/content/translations/pl/developers/tutorials/app-plasma/index.md b/public/content/translations/pl/developers/tutorials/app-plasma/index.md new file mode 100644 index 00000000000..3865dc71520 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/app-plasma/index.md @@ -0,0 +1,1255 @@ +--- +title: "Napisz specyficzną dla aplikacji plasmę, która zachowuje prywatność" +description: "W tym samouczku zbudujemy na wpół tajny bank na depozyty. Bank jest scentralizowanym komponentem; zna saldo każdego użytkownika. Jednakże informacje te nie są przechowywane w łańcuchu. Zamiast tego bank publikuje hasz stanu. Za każdym razem, gdy dochodzi do transakcji, bank publikuje nowy hasz wraz z dowodem o zerowej wiedzy, że posiada podpisaną transakcję, która zmienia stan hasza na nowy. Po przeczytaniu tego samouczka zrozumiesz nie tylko, jak używać dowodów o zerowej wiedzy, ale także dlaczego ich używać i jak robić to bezpiecznie." +author: Ori Pomerantz +tags: [ "zerowej-wiedzy", "serwer", "offchain", "prywatność" ] +skill: advanced +lang: pl +published: 2025-10-15 +--- + +## Wprowadzenie {#introduction} + +W przeciwieństwie do [rollupów](/developers/docs/scaling/zk-rollups/), [plasmy](/developers/docs/scaling/plasma) używają sieci głównej Ethereum do zapewnienia integralności, ale nie dostępności. W tym artykule napiszemy aplikację, która zachowuje się jak plasma, z Ethereum gwarantującym integralność (brak nieautoryzowanych zmian), ale nie dostępność (scentralizowany komponent może ulec awarii i wyłączyć cały system). + +Aplikacja, którą tu napiszemy, to bank chroniący prywatność. Różne adresy mają konta z saldami i mogą wysyłać pieniądze (ETH) na inne konta. Bank publikuje hasze stanu (konta i ich salda) oraz transakcje, ale faktyczne salda przechowuje poza łańcuchem, gdzie mogą pozostać prywatne. + +## Projekt {#design} + +To nie jest system gotowy do produkcji, ale narzędzie dydaktyczne. W związku z tym został napisany z kilkoma upraszczającymi założeniami. + +- Stała pula kont. Istnieje określona liczba kont, a każde konto należy do z góry określonego adresu. To sprawia, że system jest znacznie prostszy, ponieważ trudno jest obsługiwać struktury danych o zmiennym rozmiarze w dowodach o zerowej wiedzy. W przypadku systemu gotowego do produkcji możemy użyć [korzenia Merkle'a](/developers/tutorials/merkle-proofs-for-offline-data-integrity/) jako hasza stanu i dostarczyć dowody Merkle'a dla wymaganych sald. + +- Przechowywanie w pamięci. W systemie produkcyjnym musimy zapisywać wszystkie salda kont na dysku, aby zachować je w przypadku ponownego uruchomienia. Tutaj jest w porządku, jeśli informacje zostaną po prostu utracone. + +- Tylko przelewy. System produkcyjny wymagałby sposobu na wpłacanie aktywów do banku i ich wypłacanie. Ale celem jest tu tylko zilustrowanie koncepcji, więc ten bank jest ograniczony do przelewów. + +### Dowody o zerowej wiedzy {#zero-knowledge-proofs} + +Na poziomie podstawowym dowód o zerowej wiedzy pokazuje, że dowodzący zna pewne dane, _Daneprywatne_ takie, że istnieje relacja _Relacja_ między pewnymi danymi publicznymi, _Danepubliczne_, a _Danymiprywatnymi_. Weryfikator zna _Relację_ i _Danepubliczne_. + +Aby zachować prywatność, potrzebujemy, aby stany i transakcje były prywatne. Ale aby zapewnić integralność, potrzebujemy, aby [hasz kryptograficzny](https://en.wikipedia.org/wiki/Cryptographic_hash_function) stanów był publiczny. Aby udowodnić osobom przesyłającym transakcje, że te transakcje rzeczywiście miały miejsce, musimy również publikować hasze transakcji. + +W większości przypadków _Daneprywatne_ są danymi wejściowymi do programu dowodu o zerowej wiedzy, a _Danepubliczne_ są danymi wyjściowymi. + +Te pola w _Danychprywatnych_: + +- _Stann_, stary stan +- _Stann+1_, nowy stan +- _Transakcja_, transakcja, która zmienia stary stan na nowy. Ta transakcja musi zawierać następujące pola: + - _Adres docelowy_, który otrzymuje przelew + - _Kwota_ przelewu + - _Nonce_, aby zapewnić, że każda transakcja może zostać przetworzona tylko raz. + Adres źródłowy nie musi znajdować się w transakcji, ponieważ można go odzyskać z podpisu. +- _Podpis_, podpis upoważniający do wykonania transakcji. W naszym przypadku jedynym adresem upoważnionym do wykonania transakcji jest adres źródłowy. Ponieważ nasz system o zerowej wiedzy działa w taki sposób, oprócz podpisu Ethereum potrzebujemy również klucza publicznego konta. + +Oto pola w _Danychpublicznych_: + +- _Hasz(Stann)_ hasz starego stanu +- _Hasz(Stann+1)_ hasz nowego stanu +- _Hasz(Transakcja)_ hasz transakcji, która zmienia stan ze _Stanun_ na _Stann+1_. + +Relacja sprawdza kilka warunków: + +- Hasze publiczne są rzeczywiście poprawnymi haszami dla pól prywatnych. +- Transakcja, po zastosowaniu do starego stanu, skutkuje nowym stanem. +- Podpis pochodzi z adresu źródłowego transakcji. + +Ze względu na właściwości funkcji haszujących kryptograficznie, udowodnienie tych warunków wystarczy, aby zapewnić integralność. + +### Struktury danych {#data-structures} + +Podstawową strukturą danych jest stan przechowywany przez serwer. Dla każdego konta serwer śledzi saldo konta i [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce), używany do zapobiegania [atakom typu replay](https://en.wikipedia.org/wiki/Replay_attack). + +### Komponenty {#components} + +Ten system wymaga dwóch komponentów: + +- _Serwer_, który odbiera transakcje, przetwarza je i publikuje hasze w łańcuchu wraz z dowodami o zerowej wiedzy. +- _Inteligentny kontrakt_, który przechowuje hasze i weryfikuje dowody o zerowej wiedzy, aby zapewnić, że przejścia stanów są prawidłowe. + +### Przepływ danych i sterowania {#flows} + +Są to sposoby, w jakie różne komponenty komunikują się w celu dokonania przelewu z jednego konta na drugie. + +1. Przeglądarka internetowa przesyła podpisaną transakcję z prośbą o przelew z konta podpisującego na inne konto. + +2. Serwer weryfikuje, czy transakcja jest prawidłowa: + + - Podpisujący ma konto w banku z wystarczającym saldem. + - Odbiorca ma konto w banku. + +3. Serwer oblicza nowy stan, odejmując przelaną kwotę od salda podpisującego i dodając ją do salda odbiorcy. + +4. Serwer oblicza dowód o zerowej wiedzy, że zmiana stanu jest prawidłowa. + +5. Serwer przesyła do Ethereum transakcję, która zawiera: + + - Nowy hasz stanu + - Hasz transakcji (aby nadawca transakcji wiedział, że została przetworzona) + - Dowód o zerowej wiedzy, który udowadnia, że przejście do nowego stanu jest prawidłowe + +6. Inteligentny kontrakt weryfikuje dowód o zerowej wiedzy. + +7. Jeśli dowód o zerowej wiedzy jest poprawny, inteligentny kontrakt wykonuje następujące czynności: + - Zaktualizuj bieżący hasz stanu na nowy hasz stanu + - Wyemituj wpis w dzienniku z nowym haszem stanu i haszem transakcji + +### Narzędzia {#tools} + +Do kodu po stronie klienta użyjemy [Vite](https://vite.dev/), [React](https://react.dev/), [Viem](https://viem.sh/) i [Wagmi](https://wagmi.sh/). Są to standardowe narzędzia branżowe; jeśli ich nie znasz, możesz skorzystać z [tego samouczka](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/). + +Większość serwera jest napisana w JavaScript przy użyciu [Node](https://nodejs.org/en). Część dotycząca zerowej wiedzy jest napisana w [Noir](https://noir-lang.org/). Potrzebujemy wersji `1.0.0-beta.10`, więc po [zainstalowaniu Noir zgodnie z instrukcją](https://noir-lang.org/docs/getting_started/quick_start), uruchom: + +``` +noirup -v 1.0.0-beta.10 +``` + +Blockchain, którego używamy, to `anvil`, lokalny blockchain testowy, który jest częścią [Foundry](https://getfoundry.sh/introduction/installation). + +## Implementacja {#implementation} + +Ponieważ jest to złożony system, wdrożymy go etapami. + +### Etap 1 - Ręczna zerowa wiedza {#stage-1} + +W pierwszym etapie podpiszemy transakcję w przeglądarce, a następnie ręcznie podamy informacje do dowodu o zerowej wiedzy. Kod zerowej wiedzy oczekuje, że otrzyma te informacje w pliku `server/noir/Prover.toml` (udokumentowane [tutaj](https://noir-lang.org/docs/getting_started/project_breakdown#provertoml-1)). + +Aby zobaczyć to w działaniu: + +1. Upewnij się, że masz zainstalowane [Node](https://nodejs.org/en/download) i [Noir](https://noir-lang.org/install). Najlepiej zainstalować je w systemie UNIX, takim jak macOS, Linux lub [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). + +2. Pobierz kod etapu 1 i uruchom serwer WWW, aby obsługiwać kod klienta. + + ```sh + git clone https://github.com/qbzzt/250911-zk-bank.git -b 01-manual-zk + cd 250911-zk-bank + cd client + npm install + npm run dev + ``` + + Powodem, dla którego potrzebujesz tutaj serwera WWW, jest to, że aby zapobiec niektórym rodzajom oszustw, wiele portfeli (takich jak MetaMask) nie akceptuje plików serwowanych bezpośrednio z dysku + +3. Otwórz przeglądarkę z portfelem. + +4. W portfelu wprowadź nową frazę dostępu. Pamiętaj, że spowoduje to usunięcie istniejącej frazy dostępu, więc _upewnij się, że masz kopię zapasową_. + + Fraza dostępu to `test test test test test test test test test test test junk`, domyślna fraza testowa dla anvil. + +5. Przejdź do [kodu po stronie klienta](http://localhost:5173/). + +6. Połącz się z portfelem i wybierz konto docelowe oraz kwotę. + +7. Kliknij **Podpisz** i podpisz transakcję. + +8. Pod nagłówkiem **Prover.toml** znajdziesz tekst. Zastąp `server/noir/Prover.toml` tym tekstem. + +9. Wykonaj dowód o zerowej wiedzy. + + ```sh + cd ../server/noir + nargo execute + ``` + + Dane wyjściowe powinny być podobne do + + ``` + ori@CryptoDocGuy:~/noir/250911-zk-bank/server/noir$ nargo execute + + [zkBank] Circuit witness successfully solved + [zkBank] Witness saved to target/zkBank.gz + [zkBank] Circuit output: (0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b, 0x0cfc0a67cb7308e4e9b254026b54204e34f6c8b041be207e64c5db77d95dd82d, 0x450cf9da6e180d6159290554ae3d8787, 0x6d8bc5a15b9037e52fb59b6b98722a85) + ``` + +10. Porównaj dwie ostatnie wartości z haszem widocznym w przeglądarce internetowej, aby sprawdzić, czy komunikat jest poprawnie haszowany. + +#### `server/noir/Prover.toml` {#server-noir-prover-toml} + +[Ten plik](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml) pokazuje format informacji oczekiwany przez Noir. + +```toml +message="send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 500 finney (milliEth) 0 " +``` + +Komunikat jest w formacie tekstowym, co ułatwia użytkownikowi jego zrozumienie (co jest konieczne przy podpisywaniu) i parsowanie przez kod Noir. Kwota jest podawana w finneyach, aby z jednej strony umożliwić przelewy ułamkowe, a z drugiej strony być łatwo czytelna. Ostatnia liczba to [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce). + +Ciąg ma 100 znaków długości. Dowody o zerowej wiedzy nie radzą sobie dobrze z danymi o zmiennym rozmiarze, więc często konieczne jest uzupełnianie danych. + +```toml +pubKeyX=["0x83",...,"0x75"] +pubKeyY=["0x35",...,"0xa5"] +signature=["0xb1",...,"0x0d"] +``` + +Te trzy parametry to tablice bajtów o stałym rozmiarze. + +```toml +[[accounts]] +address="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance=100_000 +nonce=0 + +[[accounts]] +address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +balance=100_000 +nonce=0 +``` + +W ten sposób określa się tablicę struktur. Dla każdego wpisu określamy adres, saldo (w milliETH, czyli [finney](https://cryptovalleyjournal.com/glossary/finney/)) oraz następną wartość nonce. + +#### `client/src/Transfer.tsx` {#client-src-transfer-tsx} + +[Ten plik](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/client/src/Transfer.tsx) implementuje przetwarzanie po stronie klienta i generuje plik `server/noir/Prover.toml` (ten, który zawiera parametry zerowej wiedzy). + +Oto wyjaśnienie ciekawszych części. + +```tsx +export default attrs => { +``` + +Ta funkcja tworzy komponent React `Transfer`, który inne pliki mogą importować. + +```tsx + const accounts = [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65", + ] +``` + +Są to adresy kont, adresy utworzone przez `test ...` frazę dostępu `test junk`. Jeśli chcesz używać własnych adresów, po prostu zmodyfikuj tę definicję. + +```tsx + const account = useAccount() + const wallet = createWalletClient({ + transport: custom(window.ethereum!) + }) +``` + +Te [hooki Wagmi](https://wagmi.sh/react/api/hooks) pozwalają nam uzyskać dostęp do biblioteki [viem](https://viem.sh/) i portfela. + +```tsx + const message = `send ${toAccount} ${ethAmount*1000} finney (milliEth) ${nonce}`.padEnd(100, " ") +``` + +To jest komunikat, uzupełniony spacjami. Za każdym razem, gdy jedna ze zmiennych [`useState`](https://react.dev/reference/react/useState) się zmienia, komponent jest ponownie rysowany, a `message` jest aktualizowany. + +```tsx + const sign = async () => { +``` + +Ta funkcja jest wywoływana, gdy użytkownik kliknie przycisk **Podpisz**. Komunikat jest aktualizowany automatycznie, ale podpis wymaga zatwierdzenia przez użytkownika w portfelu i nie chcemy o to prosić, jeśli nie jest to konieczne. + +```tsx + const signature = await wallet.signMessage({ + account: fromAccount, + message, + }) +``` + +Poproś portfel o [podpisanie komunikatu](https://viem.sh/docs/accounts/local/signMessage). + +```tsx + const hash = hashMessage(message) +``` + +Pobierz hasz komunikatu. Pomocne jest dostarczenie go użytkownikowi do debugowania (kodu Noir). + +```tsx + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +[Pobierz klucz publiczny](https://viem.sh/docs/utilities/recoverPublicKey). Jest to wymagane dla funkcji [Noir `ecrecover`](https://github.com/colinnielsen/ecrecover-noir). + +```tsx + setSignature(signature) + setHash(hash) + setPubKey(pubKey) +``` + +Ustaw zmienne stanu. Zrobienie tego powoduje ponowne narysowanie komponentu (po wyjściu z funkcji `sign`) i pokazuje użytkownikowi zaktualizowane wartości. + +```tsx + let proverToml = ` +``` + +Tekst dla `Prover.toml`. + +```tsx +message="${message}" + +pubKeyX=${hexToArray(pubKey.slice(4,4+2*32))} +pubKeyY=${hexToArray(pubKey.slice(4+2*32))} +``` + +Viem dostarcza nam klucz publiczny w postaci 65-bajtowego ciągu szesnastkowego. Pierwszy bajt to `0x04`, znacznik wersji. Następnie 32 bajty dla `x` klucza publicznego, a potem 32 bajty dla `y` klucza publicznego. + +Jednak Noir oczekuje, że otrzyma te informacje jako dwie tablice bajtów, jedną dla `x` i jedną dla `y`. Łatwiej jest to parsować tutaj po stronie klienta, niż jako część dowodu o zerowej wiedzy. + +Należy zauważyć, że jest to ogólnie dobra praktyka w dowodach o zerowej wiedzy. Kod wewnątrz dowodu o zerowej wiedzy jest kosztowny, więc każde przetwarzanie, które można wykonać poza dowodem o zerowej wiedzy, _powinno_ być wykonane poza nim. + +```tsx +signature=${hexToArray(signature.slice(2,-2))} +``` + +Podpis jest również dostarczany jako 65-bajtowy ciąg szesnastkowy. Jednak ostatni bajt jest potrzebny tylko do odzyskania klucza publicznego. Ponieważ klucz publiczny zostanie już dostarczony do kodu Noir, nie potrzebujemy go do weryfikacji podpisu, a kod Noir go nie wymaga. + +```tsx +${accounts.map(accountInProverToml).reduce((a,b) => a+b, "")} +` +``` + +Podaj konta. + +```tsx + setProverToml(proverToml) + } + + return ( + <> +

Przelew

+``` + +To jest format HTML (a dokładniej [JSX](https://react.dev/learn/writing-markup-with-jsx)) komponentu. + +#### `server/noir/src/main.nr` {#server-noir-src-main-nr} + +[Ten plik](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/src/main.nr) to faktyczny kod o zerowej wiedzy. + +``` +use std::hash::pedersen_hash; +``` + +[Hasz Pedersena](https://rya-sge.github.io/access-denied/2024/05/07/pedersen-hash-function/) jest dostarczany ze [standardową biblioteką Noir](https://noir-lang.org/docs/noir/standard_library/cryptographic_primitives/hashes#pedersen_hash). Dowody o zerowej wiedzy często używają tej funkcji haszującej. Jest znacznie łatwiejszy do obliczenia wewnątrz [obwodów arytmetycznych](https://rareskills.io/post/arithmetic-circuit) w porównaniu ze standardowymi funkcjami haszującymi. + +``` +use keccak256::keccak256; +use dep::ecrecover; +``` + +Te dwie funkcje to biblioteki zewnętrzne, zdefiniowane w [`Nargo.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Nargo.toml). Są dokładnie tym, na co wskazują ich nazwy: funkcją, która oblicza [hasz keccak256](https://emn178.github.io/online-tools/keccak_256.html) oraz funkcją, która weryfikuje podpisy Ethereum i odzyskuje adres Ethereum osoby podpisującej. + +``` +global ACCOUNT_NUMBER : u32 = 5; +``` + +Noir jest inspirowany językiem [Rust](https://www.rust-lang.org/). Zmienne domyślnie są stałymi. W ten sposób definiujemy globalne stałe konfiguracyjne. W szczególności `ACCOUNT_NUMBER` to liczba kont, które przechowujemy. + +Typy danych o nazwie `u` to ta liczba bitów, bez znaku. Jedyne obsługiwane typy to `u8`, `u16`, `u32`, `u64` i `u128`. + +``` +global FLAT_ACCOUNT_FIELDS : u32 = 2; +``` + +Ta zmienna jest używana do haszowania Pedersena kont, jak wyjaśniono poniżej. + +``` +global MESSAGE_LENGTH : u32 = 100; +``` + +Jak wyjaśniono powyżej, długość komunikatu jest stała. Jest ona określona tutaj. + +``` +global ASCII_MESSAGE_LENGTH : [u8; 3] = [0x31, 0x30, 0x30]; +global HASH_BUFFER_SIZE : u32 = 26+3+MESSAGE_LENGTH; +``` + +[Podpisy EIP-191](https://eips.ethereum.org/EIPS/eip-191) wymagają bufora z 26-bajtowym prefiksem, po którym następuje długość komunikatu w ASCII, a na końcu sam komunikat. + +``` +struct Account { + balance: u128, + address: Field, + nonce: u32, +} +``` + +Informacje, które przechowujemy o koncie. [`Pole`](https://noir-lang.org/docs/noir/concepts/data_types/fields) to liczba, zazwyczaj do 253 bitów, która może być używana bezpośrednio w [obwodzie arytmetycznym](https://rareskills.io/post/arithmetic-circuit), który implementuje dowód o zerowej wiedzy. Tutaj używamy `Pola` do przechowywania 160-bitowego adresu Ethereum. + +``` +struct TransferTxn { + from: Field, + to: Field, + amount: u128, + nonce: u32 +} +``` + +Informacje, które przechowujemy dla transakcji przelewu. + +``` +fn flatten_account(account: Account) -> [Field; FLAT_ACCOUNT_FIELDS] { +``` + +Definicja funkcji. Parametrem jest informacja o `Koncie`. Wynikiem jest tablica zmiennych `Pole`, której długość to `FLAT_ACCOUNT_FIELDS` + +``` + let flat = [ + account.address, + ((account.balance << 32) + account.nonce.into()).into(), + ]; +``` + +Pierwszą wartością w tablicy jest adres konta. Druga zawiera zarówno saldo, jak i nonce. Wywołania `.into()` zmieniają liczbę na typ danych, którym musi być. `account.nonce` to wartość `u32`, ale aby dodać ją do `account.balance << 32`, wartości `u128`, musi to być `u128`. To jest pierwsze `.into()`. Drugi konwertuje wynik `u128` na `Pole`, aby zmieścił się w tablicy. + +``` + flat +} +``` + +W Noir funkcje mogą zwracać wartość tylko na końcu (nie ma wcześniejszego zwrotu). Aby określić wartość zwracaną, należy ją obliczyć tuż przed nawiasem zamykającym funkcję. + +``` +fn flatten_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] { +``` + +Ta funkcja zamienia tablicę kont na tablicę `Pól`, która może być użyta jako dane wejściowe do hasza Petersena. + +``` + let mut flat: [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] = [0; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER]; +``` + +W ten sposób określa się zmienną mutowalną, czyli _nie_ stałą. Zmienne w Noir muszą zawsze mieć wartość, więc inicjalizujemy tę zmienną samymi zerami. + +``` + for i in 0..ACCOUNT_NUMBER { +``` + +To jest pętla `for`. Należy zauważyć, że granice są stałymi. Pętle w Noir muszą mieć granice znane w czasie kompilacji. Powodem jest to, że obwody arytmetyczne nie obsługują kontroli przepływu. Podczas przetwarzania pętli `for` kompilator po prostu umieszcza kod wewnątrz niej wielokrotnie, raz dla każdej iteracji. + +``` + let fields = flatten_account(accounts[i]); + for j in 0..FLAT_ACCOUNT_FIELDS { + flat[i*FLAT_ACCOUNT_FIELDS + j] = fields[j]; + } + } + + flat +} + +fn hash_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> Field { + pedersen_hash(flatten_accounts(accounts)) +} +``` + +Wreszcie doszliśmy do funkcji, która haszuje tablicę kont. + +``` +fn find_account(accounts: [Account; ACCOUNT_NUMBER], address: Field) -> u32 { + let mut account : u32 = ACCOUNT_NUMBER; + + for i in 0..ACCOUNT_NUMBER { + if accounts[i].address == address { + account = i; + } + } +``` + +Ta funkcja znajduje konto o określonym adresie. Ta funkcja byłaby strasznie nieefektywna w standardowym kodzie, ponieważ iteruje po wszystkich kontach, nawet po znalezieniu adresu. + +Jednak w dowodach o zerowej wiedzy nie ma kontroli przepływu. Jeśli kiedykolwiek będziemy musieli sprawdzić warunek, musimy go sprawdzać za każdym razem. + +Podobna rzecz dzieje się z instrukcjami `if`. Instrukcja `if` w powyższej pętli jest tłumaczona na te instrukcje matematyczne. + +_wynikwarunku = konta[i].adres == adres_ // jeden, jeśli są równe, zero w przeciwnym razie + +_kontonowe = wynikwarunku\*i + (1-wynikwarunku)\*kontostare_ + +```rust + assert (account < ACCOUNT_NUMBER, f"{address} nie ma konta"); + + account +} +``` + +Funkcja [`assert`](https://noir-lang.org/docs/dev/noir/concepts/assert) powoduje awarię dowodu o zerowej wiedzy, jeśli asercja jest fałszywa. W tym przypadku, jeśli nie możemy znaleźć konta z odpowiednim adresem. Aby zgłosić adres, używamy [ciągu formatującego](https://noir-lang.org/docs/noir/concepts/data_types/strings#format-strings). + +```rust +fn apply_transfer_txn(accounts: [Account; ACCOUNT_NUMBER], txn: TransferTxn) -> [Account; ACCOUNT_NUMBER] { +``` + +Ta funkcja stosuje transakcję przelewu i zwraca nową tablicę kont. + +```rust + let from = find_account(accounts, txn.from); + let to = find_account(accounts, txn.to); + + let (txnFrom, txnAmount, txnNonce, accountNonce) = + (txn.from, txn.amount, txn.nonce, accounts[from].nonce); +``` + +Nie możemy uzyskać dostępu do elementów struktury wewnątrz ciągu formatującego w Noir, więc tworzymy użyteczną kopię. + +```rust + assert (accounts[from].balance >= txn.amount, + f"{txnFrom} nie ma {txnAmount} finney"); + + assert (accounts[from].nonce == txn.nonce, + f"Transakcja ma nonce {txnNonce}, ale oczekuje się, że konto użyje {accountNonce}"); +``` + +Są to dwa warunki, które mogą unieważnić transakcję. + +```rust + let mut newAccounts = accounts; + + newAccounts[from].balance -= txn.amount; + newAccounts[from].nonce += 1; + newAccounts[to].balance += txn.amount; + + newAccounts +} +``` + +Utwórz nową tablicę kont, a następnie ją zwróć. + +```rust +fn readAddress(messageBytes: [u8; MESSAGE_LENGTH]) -> Field +``` + +Ta funkcja odczytuje adres z komunikatu. + +```rust +{ + let mut result : Field = 0; + + for i in 7..47 { +``` + +Adres ma zawsze 20 bajtów (czyli 40 cyfr szesnastkowych) długości i zaczyna się od znaku nr 7. + +```rust + result *= 0x10; + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + result += (messageBytes[i]-48).into(); + } + if messageBytes[i] >= 65 & messageBytes[i] <= 70 { // A-F + result += (messageBytes[i]-65+10).into() + } + if messageBytes[i] >= 97 & messageBytes[i] <= 102 { // a-f + result += (messageBytes[i]-97+10).into() + } + } + + result +} + +fn readAmountAndNonce(messageBytes: [u8; MESSAGE_LENGTH]) -> (u128, u32) +``` + +Odczytaj kwotę i nonce z komunikatu. + +```rust +{ + let mut amount : u128 = 0; + let mut nonce: u32 = 0; + let mut stillReadingAmount: bool = true; + let mut lookingForNonce: bool = false; + let mut stillReadingNonce: bool = false; +``` + +W komunikacie pierwsza liczba po adresie to kwota finney (czyli tysięczna ETH) do przelania. Druga liczba to nonce. Każdy tekst między nimi jest ignorowany. + +```rust + for i in 48..MESSAGE_LENGTH { + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + let digit = (messageBytes[i]-48); + + if stillReadingAmount { + amount = amount*10 + digit.into(); + } + + if lookingForNonce { // Właśnie to znaleźliśmy + stillReadingNonce = true; + lookingForNonce = false; + } + + if stillReadingNonce { + nonce = nonce*10 + digit.into(); + } + } else { + if stillReadingAmount { + stillReadingAmount = false; + lookingForNonce = true; + } + if stillReadingNonce { + stillReadingNonce = false; + } + } + } + + (amount, nonce) +} +``` + +Zwracanie [krotki](https://noir-lang.org/docs/noir/concepts/data_types/tuples) to sposób Noir na zwracanie wielu wartości z funkcji. + +```rust +fn readTransferTxn(message: str) -> TransferTxn +{ + let mut txn: TransferTxn = TransferTxn { from: 0, to: 0, amount:0, nonce:0 }; + let messageBytes = message.as_bytes(); + + txn.to = readAddress(messageBytes); + let (amount, nonce) = readAmountAndNonce(messageBytes); + txn.amount = amount; + txn.nonce = nonce; + + txn +} +``` + +Ta funkcja konwertuje komunikat na bajty, a następnie konwertuje kwoty na `TransferTxn`. + +```rust +// Odpowiednik hashMessage Viem +// https://viem.sh/docs/utilities/hashMessage#hashmessage +fn hashMessage(message: str) -> [u8;32] { +``` + +Mogliśmy użyć hasza Pedersena dla kont, ponieważ są one haszowane tylko wewnątrz dowodu o zerowej wiedzy. Jednak w tym kodzie musimy sprawdzić podpis komunikatu, który jest generowany przez przeglądarkę. W tym celu musimy postępować zgodnie z formatem podpisywania Ethereum w [EIP 191](https://eips.ethereum.org/EIPS/eip-191). Oznacza to, że musimy utworzyć połączony bufor ze standardowym prefiksem, długością komunikatu w ASCII i samym komunikatem, a następnie użyć standardowego dla Ethereum keccak256 do jego haszowania. + +```rust + // prefiks ASCII + let prefix_bytes = [ + 0x19, // \x19 + 0x45, // 'E' + 0x74, // 't' + 0x68, // 'h' + 0x65, // 'e' + 0x72, // 'r' + 0x65, // 'e' + 0x75, // 'u' + 0x6D, // 'm' + 0x20, // ' ' + 0x53, // 'S' + 0x69, // 'i' + 0x67, // 'g' + 0x6E, // 'n' + 0x65, // 'e' + 0x64, // 'd' + 0x20, // ' ' + 0x4D, // 'M' + 0x65, // 'e' + 0x73, // 's' + 0x73, // 's' + 0x61, // 'a' + 0x67, // 'g' + 0x65, // 'e' + 0x3A, // ':' + 0x0A // '\n' + ]; +``` + +Aby uniknąć przypadków, w których aplikacja prosi użytkownika o podpisanie komunikatu, który może być użyty jako transakcja lub w innym celu, EIP 191 określa, że wszystkie podpisane komunikaty zaczynają się od znaku 0x19 (nie jest to prawidłowy znak ASCII), po którym następuje `Ethereum Signed Message:` i nowa linia. + +```rust + let mut buffer: [u8; HASH_BUFFER_SIZE] = [0u8; HASH_BUFFER_SIZE]; + for i in 0..26 { + buffer[i] = prefix_bytes[i]; + } + + let messageBytes : [u8; MESSAGE_LENGTH] = message.as_bytes(); + + if MESSAGE_LENGTH <= 9 { + for i in 0..1 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+1] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 10 & MESSAGE_LENGTH <= 99 { + for i in 0..2 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+2] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 100 { + for i in 0..3 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+3] = messageBytes[i]; + } + } + + assert(MESSAGE_LENGTH < 1000, "Komunikaty, których długość przekracza trzy cyfry, nie są obsługiwane"); +``` + +Obsługuj komunikaty o długości do 999 i zakończ niepowodzeniem, jeśli jest większa. Dodałem ten kod, mimo że długość komunikatu jest stała, ponieważ ułatwia to jego zmianę. W systemie produkcyjnym prawdopodobnie po prostu założyłbyś, że `MESSAGE_LENGTH` nie zmienia się ze względu na lepszą wydajność. + +```rust + keccak256::keccak256(buffer, HASH_BUFFER_SIZE) +} +``` + +Użyj standardowej funkcji Ethereum `keccak256`. + +```rust +fn signatureToAddressAndHash( + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64] + ) -> (Field, Field, Field) // adres, pierwsze 16 bajtów hasza, ostatnie 16 bajtów hasza +{ +``` + +Ta funkcja weryfikuje podpis, co wymaga hasza komunikatu. Następnie dostarcza nam adres, który go podpisał, oraz hasz komunikatu. Hasz komunikatu jest dostarczany w dwóch wartościach `Pole`, ponieważ są one łatwiejsze w użyciu w pozostałej części programu niż tablica bajtów. + +Musimy użyć dwóch wartości `Pole`, ponieważ obliczenia na polach są wykonywane [modulo](https://en.wikipedia.org/wiki/Modulo) dużej liczby, ale ta liczba jest zwykle mniejsza niż 256 bitów (w przeciwnym razie trudno byłoby wykonać te obliczenia w EVM). + +```rust + let hash = hashMessage(message); + + let mut (hash1, hash2) = (0,0); + + for i in 0..16 { + hash1 = hash1*256 + hash[31-i].into(); + hash2 = hash2*256 + hash[15-i].into(); + } +``` + +Określ `hash1` i `hash2` jako zmienne mutowalne i zapisz w nich hasz bajt po bajcie. + +```rust + ( + ecrecover::ecrecover(pubKeyX, pubKeyY, signature, hash), +``` + +Jest to podobne do [`ecrecover` w Solidity](https://docs.soliditylang.org/en/v0.8.30/cheatsheet.html#mathematical-and-cryptographic-functions), z dwiema ważnymi różnicami: + +- Jeśli podpis nie jest prawidłowy, wywołanie kończy się niepowodzeniem `assert`, a program jest przerywany. +- Chociaż klucz publiczny można odzyskać z podpisu i hasza, jest to przetwarzanie, które można wykonać zewnętrznie, a zatem nie warto go robić wewnątrz dowodu o zerowej wiedzy. Jeśli ktoś spróbuje nas tu oszukać, weryfikacja podpisu zakończy się niepowodzeniem. + +```rust + hash1, + hash2 + ) +} + +fn main( + accounts: [Account; ACCOUNT_NUMBER], + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64], + ) -> pub ( + Field, // Hasz starej tablicy kont + Field, // Hasz nowej tablicy kont + Field, // Pierwsze 16 bajtów hasza komunikatu + Field, // Ostatnie 16 bajtów hasza komunikatu + ) +``` + +Wreszcie dochodzimy do funkcji `main`. Musimy udowodnić, że mamy transakcję, która prawidłowo zmienia hasz kont ze starej wartości na nową. Musimy również udowodnić, że ma ona ten konkretny hasz transakcji, aby osoba, która ją wysłała, wiedziała, że jej transakcja została przetworzona. + +```rust +{ + let mut txn = readTransferTxn(message); +``` + +Potrzebujemy, aby `txn` było mutowalne, ponieważ nie odczytujemy adresu nadawcy z komunikatu, ale z podpisu. + +```rust + let (fromAddress, txnHash1, txnHash2) = signatureToAddressAndHash( + message, + pubKeyX, + pubKeyY, + signature); + + txn.from = fromAddress; + + let newAccounts = apply_transfer_txn(accounts, txn); + + ( + hash_accounts(accounts), + hash_accounts(newAccounts), + txnHash1, + txnHash2 + ) +} +``` + +### Etap 2 - Dodawanie serwera {#stage-2} + +W drugim etapie dodajemy serwer, który odbiera i implementuje transakcje przelewów z przeglądarki. + +Aby zobaczyć to w działaniu: + +1. Zatrzymaj Vite, jeśli jest uruchomiony. + +2. Pobierz gałąź, która zawiera serwer i upewnij się, że masz wszystkie niezbędne moduły. + + ```sh + git checkout 02-add-server + cd client + npm install + cd ../server + npm install + ``` + + Nie ma potrzeby kompilowania kodu Noir, jest on taki sam jak kod, którego użyłeś w etapie 1. + +3. Uruchom serwer. + + ```sh + npm run start + ``` + +4. W osobnym oknie wiersza poleceń uruchom Vite, aby obsługiwać kod przeglądarki. + + ```sh + cd client + npm run dev + ``` + +5. Przejdź do kodu klienta pod adresem [http://localhost:5173](http://localhost:5173) + +6. Zanim będziesz mógł wystawić transakcję, musisz znać nonce, a także kwotę, którą możesz wysłać. Aby uzyskać te informacje, kliknij **Aktualizuj dane konta** i podpisz komunikat. + + Mamy tu dylemat. Z jednej strony nie chcemy podpisywać komunikatu, który można ponownie wykorzystać ([atak typu replay](https://en.wikipedia.org/wiki/Replay_attack)), dlatego w ogóle chcemy nonce. Jednak nie mamy jeszcze nonce. Rozwiązaniem jest wybranie nonce, które można użyć tylko raz i które już mamy po obu stronach, na przykład bieżący czas. + + Problem z tym rozwiązaniem polega na tym, że czas może nie być idealnie zsynchronizowany. Zamiast tego podpisujemy wartość, która zmienia się co minutę. Oznacza to, że nasze okno podatności na ataki typu replay wynosi co najwyżej jedną minutę. Biorąc pod uwagę, że w środowisku produkcyjnym podpisane żądanie będzie chronione przez TLS, a druga strona tunelu — serwer — może już ujawnić saldo i nonce (musi je znać, aby działać), jest to akceptowalne ryzyko. + +7. Gdy przeglądarka otrzyma z powrotem saldo i nonce, wyświetli formularz przelewu. Wybierz adres docelowy i kwotę, a następnie kliknij **Przelej**. Podpisz to żądanie. + +8. Aby zobaczyć przelew, kliknij **Aktualizuj dane konta** lub spójrz w okno, w którym uruchamiasz serwer. Serwer rejestruje stan za każdym razem, gdy się zmienia. + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + Nasłuchiwanie na porcie 3000 + Transakcja send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 36000 finney (milliEth) 0 przetworzona + Nowy stan: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ma 64000 (1) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 ma 100000 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC ma 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 ma 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 ma 100000 (0) + Transakcja send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 7200 finney (milliEth) 1 przetworzona + Nowy stan: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ma 56800 (2) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 ma 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC ma 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 ma 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 ma 100000 (0) + Transakcja send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 3000 finney (milliEth) 2 przetworzona + Nowy stan: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ma 53800 (3) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 ma 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC ma 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 ma 139000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 ma 100000 (0) + ``` + +#### `server/index.mjs` {#server-index-mjs-1} + +[Ten plik](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/index.mjs) zawiera proces serwera i współdziała z kodem Noir w [`main.nr`](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/noir/src/main.nr). Oto wyjaśnienie ciekawszych części. + +```js +import { Noir } from '@noir-lang/noir_js' +``` + +Biblioteka [noir.js](https://www.npmjs.com/package/@noir-lang/noir_js) stanowi interfejs między kodem JavaScript a kodem Noir. + +```js +const circuit = JSON.parse(await fs.readFile("./noir/target/zkBank.json")) +const noir = new Noir(circuit) +``` + +Załaduj obwód arytmetyczny — skompilowany program Noir, który stworzyliśmy w poprzednim etapie — i przygotuj go do wykonania. + +```js +// Informacje o koncie udostępniamy tylko w odpowiedzi na podpisane żądanie +const accountInformation = async signature => { + const fromAddress = await recoverAddress({ + hash: hashMessage("Get account data " + Math.floor((new Date().getTime())/60000)), + signature + }) +``` + +Aby podać informacje o koncie, potrzebujemy tylko podpisu. Powodem jest to, że wiemy już, jaki będzie komunikat, a zatem znamy jego hasz. + +```js +const processMessage = async (message, signature) => { +``` + +Przetwórz komunikat i wykonaj zakodowaną w nim transakcję. + +```js + // Pobierz klucz publiczny + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +Teraz, gdy uruchamiamy JavaScript na serwerze, możemy pobrać klucz publiczny tam, a nie na kliencie. + +```js + let noirResult + try { + noirResult = await noir.execute({ + message, + signature: signature.slice(2,-2).match(/.{2}/g).map(x => `0x${x}`), + pubKeyX, + pubKeyY, + accounts: Accounts + }) +``` + +`noir.execute` uruchamia program Noir. Parametry są równoważne z tymi podanymi w [`Prover.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml). Zauważ, że długie wartości są podawane jako tablica ciągów szesnastkowych (`["0x60", "0xA7"]`), a nie jako pojedyncza wartość szesnastkowa (`0x60A7`), tak jak to robi Viem. + +```js + } catch (err) { + console.log(`Noir error: ${err}`) + throw Error("Nieprawidłowa transakcja, nie przetworzono") + } +``` + +Jeśli wystąpi błąd, przechwyć go, a następnie przekaż uproszczoną wersję do klienta. + +```js + Accounts[fromAccountNumber].nonce++ + Accounts[fromAccountNumber].balance -= amount + Accounts[toAccountNumber].balance += amount +``` + +Zastosuj transakcję. Zrobiliśmy to już w kodzie Noir, ale łatwiej jest to zrobić ponownie tutaj, niż wyodrębniać stamtąd wynik. + +```js +let Accounts = [ + { + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + balance: 5000, + nonce: 0, + }, +``` + +Początkowa struktura `Konta`. + +### Etap 3 - Inteligentne kontrakty Ethereum {#stage-3} + +1. Zatrzymaj procesy serwera i klienta. + +2. Pobierz gałąź z inteligentnymi kontraktami i upewnij się, że masz wszystkie niezbędne moduły. + + ```sh + git checkout 03-smart-contracts + cd client + npm install + cd ../server + npm install + ``` + +3. Uruchom `anvil` w osobnym oknie wiersza poleceń. + +4. Wygeneruj klucz weryfikacyjny i weryfikator solidity, a następnie skopiuj kod weryfikatora do projektu Solidity. + + ```sh + cd noir + bb write_vk -b ./target/zkBank.json -o ./target --oracle_hash keccak + bb write_solidity_verifier -k ./target/vk -o ./target/Verifier.sol + cp target/Verifier.sol ../../smart-contracts/src + ``` + +5. Przejdź do inteligentnych kontraktów i ustaw zmienne środowiskowe, aby używać blockchaina `anvil`. + + ```sh + cd ../../smart-contracts + export ETH_RPC_URL=http://localhost:8545 + ETH_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + ``` + +6. Wdróż `Verifier.sol` i przechowaj adres w zmiennej środowiskowej. + + ```sh + VERIFIER_ADDRESS=`forge create src/Verifier.sol:HonkVerifier --private-key $ETH_PRIVATE_KEY --optimize --broadcast | awk '/Deployed to:/ {print $3}'` + echo $VERIFIER_ADDRESS + ``` + +7. Wdróż kontrakt `ZkBank`. + + ```sh + ZKBANK_ADDRESS=`forge create ZkBank --private-key $ETH_PRIVATE_KEY --broadcast --constructor-args $VERIFIER_ADDRESS 0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b | awk '/Deployed to:/ {print $3}'` + echo $ZKBANK_ADDRESS + ``` + + Wartość `0x199..67b` to hasz Pedersena początkowego stanu `Kont`. Jeśli zmodyfikujesz ten stan początkowy w pliku `server/index.mjs`, możesz uruchomić transakcję, aby zobaczyć początkowy hasz zgłoszony przez dowód o zerowej wiedzy. + +8. Uruchom serwer. + + ```sh + cd ../server + npm run start + ``` + +9. Uruchom klienta w innym oknie wiersza poleceń. + + ```sh + cd client + npm run dev + ``` + +10. Uruchom kilka transakcji. + +11. Aby zweryfikować, czy stan zmienił się w łańcuchu, uruchom ponownie proces serwera. Zobaczysz, że `ZkBank` nie akceptuje już transakcji, ponieważ oryginalna wartość hasza w transakcjach różni się od wartości hasza przechowywanej w łańcuchu. + + Jest to oczekiwany typ błędu. + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + Nasłuchiwanie na porcie 3000 + Błąd weryfikacji: ContractFunctionExecutionError: Funkcja kontraktu "processTransaction" została cofnięta z następującego powodu: + Zły stary hasz stanu + + Wywołanie kontraktu: + adres: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + funkcja: processTransaction(bytes _proof, bytes32[] _publicInputs) + argumenty: (0x0000000000000000000000000000000000000000000000042ab5d6d1986846cf00000000000000000000000000000000000000000000000b75c020998797da7800000000000000000000000000000000000000000000000 + ``` + +#### `server/index.mjs` {#server-index-mjs-2} + +Zmiany w tym pliku dotyczą głównie tworzenia faktycznego dowodu i przesyłania go do łańcucha. + +```js +import { exec } from 'child_process' +import util from 'util' + +const execPromise = util.promisify(exec) +``` + +Musimy użyć [pakietu Barretenberg](https://github.com/AztecProtocol/aztec-packages/tree/next/barretenberg), aby utworzyć faktyczny dowód do wysłania w łańcuchu. Możemy użyć tego pakietu, uruchamiając interfejs wiersza poleceń (`bb`) lub używając [biblioteki JavaScript, `bb.js`](https://www.npmjs.com/package/@aztec/bb.js). Biblioteka JavaScript jest znacznie wolniejsza niż natywne uruchamianie kodu, więc używamy tutaj [`exec`](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback), aby użyć wiersza poleceń. + +Zauważ, że jeśli zdecydujesz się na użycie `bb.js`, musisz użyć wersji kompatybilnej z wersją Noir, której używasz. W chwili pisania tego tekstu obecna wersja Noir (1.0.0-beta.11) używa `bb.js` w wersji 0.87. + +```js +const zkBankAddress = process.env.ZKBANK_ADDRESS || "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" +``` + +Adres tutaj jest tym, który otrzymujesz, gdy zaczynasz z czystym `anvil` i postępujesz zgodnie z powyższymi wskazówkami. + +```js +const walletClient = createWalletClient({ + chain: anvil, + transport: http(), + account: privateKeyToAccount("0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6") +}) +``` + +Ten klucz prywatny jest jednym z domyślnych, wstępnie zasilonych kont w `anvil`. + +```js +const generateProof = async (witness, fileID) => { +``` + +Wygeneruj dowód za pomocą pliku wykonywalnego `bb`. + +```js + const fname = `witness-${fileID}.gz` + await fs.writeFile(fname, witness) +``` + +Zapisz świadka do pliku. + +```js + await execPromise(`bb prove -b ./noir/target/zkBank.json -w ${fname} -o ${fileID} --oracle_hash keccak --output_format fields`) +``` + +Faktycznie utwórz dowód. Ten krok tworzy również plik ze zmiennymi publicznymi, ale nie potrzebujemy go. Otrzymaliśmy już te zmienne z `noir.execute`. + +```js + const proof = "0x" + JSON.parse(await fs.readFile(`./${fileID}/proof_fields.json`)).reduce((a,b) => a+b, "").replace(/0x/g, "") +``` + +Dowód to tablica JSON wartości `Pole`, z których każda jest reprezentowana jako wartość szesnastkowa. Musimy jednak wysłać go w transakcji jako pojedynczą wartość `bajtów`, którą Viem reprezentuje za pomocą dużego ciągu szesnastkowego. Tutaj zmieniamy format, łącząc wszystkie wartości, usuwając wszystkie `0x`, a następnie dodając jedno na końcu. + +```js + await execPromise(`rm -r ${fname} ${fileID}`) + + return proof +} +``` + +Posprzątaj i zwróć dowód. + +```js +const processMessage = async (message, signature) => { + . + . + . + + const publicFields = noirResult.returnValue.map(x=>'0x' + x.slice(2).padStart(64, "0")) +``` + +Pola publiczne muszą być tablicą 32-bajtowych wartości. Jednakże, ponieważ musieliśmy podzielić hasz transakcji na dwie wartości `Pole`, pojawia się on jako wartość 16-bajtowa. Tutaj dodajemy zera, aby Viem zrozumiał, że jest to w rzeczywistości 32 bajty. + +```js + const proof = await generateProof(noirResult.witness, `${fromAddress}-${nonce}`) +``` + +Każdy adres używa każdego nonce tylko raz, więc możemy użyć kombinacji `fromAddress` i `nonce` jako unikalnego identyfikatora dla pliku świadka i katalogu wyjściowego. + +```js + try { + await zkBank.write.processTransaction([ + proof, publicFields]) + } catch (err) { + console.log(`Verification error: ${err}`) + throw Error("Nie można zweryfikować transakcji w łańcuchu") + } + . + . + . +} +``` + +Wyślij transakcję do łańcucha. + +#### `smart-contracts/src/ZkBank.sol` {#smart-contracts-src-zkbank-sol} + +To jest kod w łańcuchu, który odbiera transakcję. + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.21; + +import {HonkVerifier} from "./Verifier.sol"; + +contract ZkBank { + HonkVerifier immutable myVerifier; + bytes32 currentStateHash; + + constructor(address _verifierAddress, bytes32 _initialStateHash) { + currentStateHash = _initialStateHash; + myVerifier = HonkVerifier(_verifierAddress); + } +``` + +Kod w łańcuchu musi śledzić dwie zmienne: weryfikator (osobny kontrakt tworzony przez `nargo`) i bieżący hasz stanu. + +```solidity + event TransactionProcessed( + bytes32 indexed transactionHash, + bytes32 oldStateHash, + bytes32 newStateHash + ); +``` + +Za każdym razem, gdy stan się zmienia, emitujemy zdarzenie `TransactionProcessed`. + +```solidity + function processTransaction( + bytes calldata _proof, + bytes32[] calldata _publicFields + ) public { +``` + +Ta funkcja przetwarza transakcje. Otrzymuje dowód (jako `bajty`) i publiczne dane wejściowe (jako tablicę `bytes32`), w formacie wymaganym przez weryfikator (w celu zminimalizowania przetwarzania w łańcuchu, a tym samym kosztów gazu). + +```solidity + require(_publicInputs[0] == currentStateHash, + "Zły stary hasz stanu"); +``` + +Dowód o zerowej wiedzy musi polegać na tym, że transakcja zmienia nasz obecny hasz na nowy. + +```solidity + myVerifier.verify(_proof, _publicFields); +``` + +Wywołaj kontrakt weryfikatora, aby zweryfikować dowód o zerowej wiedzy. Ten krok cofa transakcję, jeśli dowód o zerowej wiedzy jest nieprawidłowy. + +```solidity + currentStateHash = _publicFields[1]; + + emit TransactionProcessed( + _publicFields[2]<<128 | _publicFields[3], + _publicFields[0], + _publicFields[1] + ); + } +} +``` + +Jeśli wszystko się zgadza, zaktualizuj hasz stanu na nową wartość i wyemituj zdarzenie `TransactionProcessed`. + +## Nadużycia przez scentralizowany komponent {#abuses} + +Bezpieczeństwo informacji składa się z trzech atrybutów: + +- _Poufność_, użytkownicy nie mogą czytać informacji, do których nie są upoważnieni. +- _Integralność_, informacje nie mogą być zmieniane, z wyjątkiem upoważnionych użytkowników w autoryzowany sposób. +- _Dostępność_, autoryzowani użytkownicy mogą korzystać z systemu. + +W tym systemie integralność jest zapewniana poprzez dowody o zerowej wiedzy. Dostępność jest znacznie trudniejsza do zagwarantowania, a poufność jest niemożliwa, ponieważ bank musi znać saldo każdego konta i wszystkie transakcje. Nie ma sposobu, aby uniemożliwić podmiotowi, który posiada informacje, udostępnianie tych informacji. + +Możliwe byłoby stworzenie prawdziwie poufnego banku przy użyciu [adresów stealth](https://vitalik.eth.limo/general/2023/01/20/stealth.html), ale to wykracza poza zakres tego artykułu. + +### Fałszywe informacje {#false-info} + +Jednym ze sposobów, w jaki serwer może naruszyć integralność, jest dostarczanie fałszywych informacji, gdy [żądane są dane](https://github.com/qbzzt/250911-zk-bank/blob/03-smart-contracts/server/index.mjs#L278-L291). + +Aby to rozwiązać, możemy napisać drugi program Noir, który otrzymuje konta jako prywatne dane wejściowe i adres, dla którego żądane są informacje, jako publiczne dane wejściowe. Danymi wyjściowymi są saldo i nonce tego adresu oraz hasz kont. + +Oczywiście tego dowodu nie można zweryfikować w łańcuchu, ponieważ nie chcemy publikować nonce i sald w łańcuchu. Można go jednak zweryfikować za pomocą kodu klienta działającego w przeglądarce. + +### Wymuszone transakcje {#forced-txns} + +Zwykłym mechanizmem zapewniającym dostępność i zapobiegającym cenzurze na L2 są [wymuszone transakcje](https://docs.optimism.io/stack/transactions/forced-transaction). Ale wymuszone transakcje nie łączą się z dowodami o zerowej wiedzy. Serwer jest jedynym podmiotem, który może weryfikować transakcje. + +Możemy zmodyfikować `smart-contracts/src/ZkBank.sol`, aby akceptować wymuszone transakcje i uniemożliwić serwerowi zmianę stanu do czasu ich przetworzenia. Jednak to naraża nas na prosty atak typu „odmowa usługi”. Co jeśli wymuszona transakcja jest nieprawidłowa i dlatego niemożliwa do przetworzenia? + +Rozwiązaniem jest posiadanie dowodu o zerowej wiedzy, że wymuszona transakcja jest nieprawidłowa. Daje to serwerowi trzy opcje: + +- Przetwórz wymuszoną transakcję, dostarczając dowód o zerowej wiedzy, że została przetworzona i nowy hasz stanu. +- Odrzuć wymuszoną transakcję i dostarcz do kontraktu dowód o zerowej wiedzy, że transakcja jest nieprawidłowa (nieznany adres, zły nonce lub niewystarczające saldo). +- Zignoruj wymuszoną transakcję. Nie ma sposobu, aby zmusić serwer do faktycznego przetworzenia transakcji, ale oznacza to, że cały system jest niedostępny. + +#### Obligacje dostępności {#avail-bonds} + +W rzeczywistej implementacji prawdopodobnie istniałby jakiś motyw zysku, aby serwer działał. Możemy wzmocnić tę zachętę, zmuszając serwer do opublikowania obligacji dostępności, którą każdy może spalić, jeśli wymuszona transakcja nie zostanie przetworzona w określonym czasie. + +### Zły kod Noir {#bad-noir-code} + +Zwykle, aby ludzie zaufali inteligentnemu kontraktowi, przesyłamy kod źródłowy do [eksploratora bloków](https://eth.blockscout.com/address/0x7D16d2c4e96BCFC8f815E15b771aC847EcbDB48b?tab=contract). Jednak w przypadku dowodów o zerowej wiedzy jest to niewystarczające. + +`Verifier.sol` zawiera klucz weryfikacyjny, który jest funkcją programu Noir. Jednak ten klucz nie mówi nam, jaki był program Noir. Aby faktycznie mieć zaufane rozwiązanie, należy przesłać program Noir (i wersję, która go utworzyła). W przeciwnym razie dowody o zerowej wiedzy mogą odzwierciedlać inny program, z tylnymi drzwiami. + +Dopóki eksploratory bloków nie zaczną pozwalać nam na przesyłanie i weryfikowanie programów Noir, powinieneś robić to samodzielnie (najlepiej do [IPFS](/developers/tutorials/ipfs-decentralized-ui/)). Wtedy zaawansowani użytkownicy będą mogli pobrać kod źródłowy, samodzielnie go skompilować, utworzyć `Verifier.sol` i zweryfikować, czy jest on identyczny z tym w łańcuchu. + +## Wnioski {#conclusion} + +Aplikacje typu plasma wymagają scentralizowanego komponentu do przechowywania informacji. To otwiera potencjalne luki w zabezpieczeniach, ale w zamian pozwala nam zachować prywatność w sposób niedostępny w samym blockchainie. Dzięki dowodom o zerowej wiedzy możemy zapewnić integralność i ewentualnie sprawić, że utrzymanie dostępności będzie ekonomicznie korzystne dla każdego, kto prowadzi scentralizowany komponent. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). + +## Podziękowania {#acknowledgements} + +- Josh Crites przeczytał szkic tego artykułu i pomógł mi w kłopotliwej kwestii związanej z Noir. + +Wszelkie pozostałe błędy są moją odpowiedzialnością. diff --git a/public/content/translations/pl/developers/tutorials/calling-a-smart-contract-from-javascript/index.md b/public/content/translations/pl/developers/tutorials/calling-a-smart-contract-from-javascript/index.md index 48a7726e19d..92c32702720 100644 --- a/public/content/translations/pl/developers/tutorials/calling-a-smart-contract-from-javascript/index.md +++ b/public/content/translations/pl/developers/tutorials/calling-a-smart-contract-from-javascript/index.md @@ -1,12 +1,8 @@ --- -title: Wywołanie inteligentnego kontraktu z JavaScript -description: Jak wywołać funkcję inteligentnego kontraktu z JavaScript za pomocą tokena Dai — przykład +title: "Wywołanie inteligentnego kontraktu z JavaScript" +description: "Jak wywołać funkcję inteligentnego kontraktu z JavaScript za pomocą tokena Dai — przykład" author: jdourlens -tags: - - "transakcje" - - "frontend" - - "JavaScript" - - "web3.js" +tags: [ "transakcje", "frontend", "JavaScript", "web3.js" ] skill: beginner lang: pl published: 2020-04-19 @@ -15,15 +11,15 @@ sourceUrl: https://ethereumdev.io/calling-a-smart-contract-from-javascript/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -W tym samouczku zobaczymy, jak wywołać funkcję [inteligentnego kontraktu](/developers/docs/smart-contracts/) za pomocą JavaScript. Najpierw odczytam stan inteligentnego kontraktu (np. saldo posiadacza ERC20), a następnie zmodyfikujemy stan blockchain poprzez transfer tokenów. Powinieneś być już zaznajomiony z [konfiguracją środowiska JS, aby wchodzić w interakcje z blockchainem](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/). +W tym samouczku zobaczymy, jak wywołać funkcję [inteligentnego kontraktu](/developers/docs/smart-contracts/) za pomocą JavaScript. Najpierw odczytamy stan inteligentnego kontraktu (np. saldo posiadacza ERC20), a następnie zmodyfikujemy stan blockchaina, dokonując transferu tokena. Powinieneś już znać [konfigurację środowiska JS do interakcji z blockchainem](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/). -W tych przykładach pobawimy się tokenem DAI, w celach testowych rozwidlimy blockchain za pomocą ganache-cli i odblokujemy adres, który ma już dużo DAI: +W tym przykładzie pobawimy się tokenem DAI, w celach testowych sforkujemy blockchain za pomocą ganache-cli i odblokujemy adres, który ma już dużo DAI: ```bash ganache-cli -f https://mainnet.infura.io/v3/[YOUR INFURA KEY] -d -i 66 1 --unlock 0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81 ``` -Aby wchodzić w interakcje z inteligentnym kontraktem, potrzebujemy jego adresu i ABI: +Aby wejść w interakcję z inteligentnym kontraktem, będziemy potrzebować jego adresu i ABI: ```js const ERC20TransferABI = [ @@ -74,9 +70,9 @@ const ERC20TransferABI = [ const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f" ``` -W przypadku tego projektu usunęliśmy kompletny ABI ERC2, aby zachować tylko funkcje `balanceOf` i `transfer`, ale znajdziesz [pełny ABI ERC20 tutaj](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/). +Na potrzeby tego projektu okroiliśmy kompletne ABI ERC20, aby zachować tylko funkcje `balanceOf` i `transfer`, ale pełne ABI ERC20 można znaleźć [tutaj](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/). -Następnie musimy utworzyć instancję inteligentnego kontraktu: +Następnie musimy utworzyć instancję naszego inteligentnego kontraktu: ```js const web3 = new Web3("http://localhost:8545") @@ -84,45 +80,52 @@ const web3 = new Web3("http://localhost:8545") const daiToken = new web3.eth.Contract(ERC20TransferABI, DAI_ADDRESS) ``` -Ustawimy też dwa adresy: +Skonfigurujemy również dwa adresy: -- ten, który otrzyma transfer i -- ten, który już odblokowaliśmy, który go wyśle: +- ten, który otrzyma transfer, oraz +- ten, który już odblokowaliśmy i który go wyśle: ```js -const senderAddress = "0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81"const receiverAddress = "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +const senderAddress = "0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81" +const receiverAddress = "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" ``` -W następnej części wywołamy funkcję `balanceOf`, aby pobrać aktualną ilość tokenów z obu posiadanych adresów. +W następnej części wywołamy funkcję `balanceOf`, aby pobrać aktualną liczbę tokenów posiadanych przez oba adresy. -## Call: Odczyt wartości z inteligentnego kontraktu {#call-reading-value-from-a-smart-contract} +## Wywołanie: odczytywanie wartości z inteligentnego kontraktu {#call-reading-value-from-a-smart-contract} -Pierwszy przykład wywoła metodę „stałą” i wykona metodę inteligentnego kontraktu w EVM bez wysyłania żadnej transakcji. W tym celu odczytamy saldo adresu ERC20. [Przeczytaj nasz artykuł o tokenach ERC20](/developers/tutorials/understand-the-erc-20-token-smart-contract/). +W pierwszym przykładzie zostanie wywołana „stała” metoda i jej metoda inteligentnego kontraktu zostanie wykonana w EVM bez wysyłania jakiejkolwiek transakcji. W tym celu odczytamy saldo ERC20 adresu. [Przeczytaj nasz artykuł o tokenach ERC20](/developers/tutorials/understand-the-erc-20-token-smart-contract/). -Możesz uzyskać dostęp do metod utworzonej instancji kontraktu inteligentnego, dla którego podano ABI, w następujący sposób: `yourContract.methods.methodname`. Używając funkcji `call`, otrzymasz wynik wykonania funkcji. +Możesz uzyskać dostęp do metod utworzonej instancji inteligentnego kontraktu, dla którego podano ABI, w następujący sposób: `yourContract.methods.methodname`. Używając funkcji `call`, otrzymasz wynik wykonania funkcji. ```js -daiToken.methods.balanceOf(senderAddress).call(function (err, res) { if (err) { console.log("An error occurred", err) return } console.log("The balance is: ", res)}) +daiToken.methods.balanceOf(senderAddress).call(function (err, res) { + if (err) { + console.log("Wystąpił błąd", err) + return + } + console.log("Saldo wynosi: ", res) +}) ``` -Pamiętaj, że DAI ERC20 ma 18 miejsc po przecinku, co oznacza, że ​​musisz usunąć 18 zer, aby uzyskać prawidłową kwotę. uint256 są zwracane jako ciągi, ponieważ JavaScript nie obsługuje dużych wartości numerycznych. Jeśli nie masz pewności, [jak radzić sobie z dużymi liczbami w JS, sprawdź nasz samouczek na temat bignumber.js](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/). +Pamiętaj, że DAI ERC20 ma 18 miejsc po przecinku, co oznacza, że musisz usunąć 18 zer, aby uzyskać prawidłową kwotę. Wartości uint256 są zwracane jako ciągi znaków, ponieważ JavaScript nie obsługuje dużych wartości numerycznych. Jeśli nie masz pewności, [jak radzić sobie z dużymi liczbami w JS, sprawdź nasz samouczek o bignumber.js](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/). -## Send: Wysyłanie transakcji do funkcji inteligentnych kontraktów {#send-sending-a-transaction-to-a-smart-contract-function} +## Wyślij: wysyłanie transakcji do funkcji inteligentnego kontraktu {#send-sending-a-transaction-to-a-smart-contract-function} -W drugim przykładzie wywołamy funkcję transferu inteligentnego kontraktu DAI, aby wysłać 10 DAI na nasz drugi adres. Funkcja trasferu przyjmuje dwa parametry: adres odbiorcy oraz ilość tokenu do transferu: +W drugim przykładzie wywołamy funkcję transferu inteligentnego kontraktu DAI, aby wysłać 10 DAI na nasz drugi adres. Funkcja transferu przyjmuje dwa parametry: adres odbiorcy i liczbę tokenów do transferu: ```js daiToken.methods .transfer(receiverAddress, "100000000000000000000") .send({ from: senderAddress }, function (err, res) { if (err) { - console.log("An error occurred", err) + console.log("Wystąpił błąd", err) return } - console.log("Hash of the transaction: " + res) + console.log("Hasz transakcji: " + res) }) ``` -Funkcja wywołania zwraca skrót transakcji, która zostanie wykopana w blockchain. W Ethereum skróty transakcji są przewidywalne — w ten sposób możemy uzyskać skrót transakcji przed jej wykonaniem ([dowiedz się, jak obliczane są skróty](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction)). +Funkcja wywołania zwraca hasz transakcji, która zostanie wydobyta w blockchainie. W Ethereum hasze transakcji są przewidywalne – w ten sposób możemy uzyskać hasz transakcji przed jej wykonaniem ([dowiedz się, jak obliczane są hasze, tutaj](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction)). -Ponieważ funkcja przesyła transakcję tylko do łańcucha bloków, nie możemy zobaczyć wyniku, dopóki nie wiemy, kiedy został wydobyty i włączony do łańcucha bloków. W następnym samouczku nauczymy się, [jak poczekać aż transakcja zostanie wykonana na blockchainie, wiedząc, że jest skrótem](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/). +Ponieważ funkcja jedynie przesyła transakcję do blockchaina, nie możemy zobaczyć wyniku, dopóki nie dowiemy się, kiedy zostanie ona wydobyta i dołączona do blockchaina. W następnym samouczku dowiemy się, [jak czekać na wykonanie transakcji w blockchainie, znając jej hasz](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/). diff --git a/public/content/translations/pl/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md b/public/content/translations/pl/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md new file mode 100644 index 00000000000..4acdbf742ad --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md @@ -0,0 +1,585 @@ +--- +title: "Tworzenie interfejsu użytkownika dla Twojego kontraktu" +description: "Korzystając z nowoczesnych komponentów, takich jak TypeScript, React, Vite i Wagmi, omówimy nowoczesny, ale minimalistyczny interfejs użytkownika i dowiemy się, jak połączyć portfel z interfejsem użytkownika, wywołać inteligentny kontrakt w celu odczytania informacji, wysłać transakcję do inteligentnego kontraktu i monitorować zdarzenia z inteligentnego kontraktu w celu identyfikacji zmian." +author: Ori Pomerantz +tags: [ "typescript", "react", "vite", "wagmi", "frontend" ] +skill: beginner +published: 2023-11-01 +lang: pl +sidebarDepth: 3 +--- + +Znalazłeś funkcję, której potrzebujemy w ekosystemie Ethereum. Napisałeś inteligentne kontrakty, aby go zaimplementować, a może nawet powiązany kod, który działa offchain. To świetnie! Niestety, bez interfejsu użytkownika nie będziesz mieć żadnych użytkowników, a ostatnim razem, gdy pisałeś stronę internetową, ludzie używali modemów dial-up, a JavaScript był nowością. + +Ten artykuł jest dla Ciebie. Zakładam, że znasz programowanie i może trochę JavaScript i HTML, ale Twoje umiejętności w zakresie interfejsu użytkownika są przestarzałe i nieaktualne. Razem przeanalizujemy prostą, nowoczesną aplikację, abyś zobaczył, jak się to robi w dzisiejszych czasach. + +## Dlaczego jest to ważne {#why-important} + +Teoretycznie możesz po prostu kazać ludziom używać [Etherscan](https://holesky.etherscan.io/address/0x432d810484add7454ddb3b5311f0ac2e95cecea8#writeContract) lub [Blockscout](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=write_contract), aby wchodzić w interakcję z Twoimi kontraktami. To będzie świetne dla doświadczonych Eterean. Ale my staramy się służyć [kolejnemu miliardowi ludzi](https://blog.ethereum.org/2021/05/07/ethereum-for-the-next-billion). Nie stanie się to bez wspaniałego doświadczenia użytkownika, a przyjazny interfejs użytkownika jest tego dużą częścią. + +## Aplikacja Greeter {#greeter-app} + +Istnieje wiele teorii na temat działania nowoczesnego interfejsu użytkownika i [wiele dobrych stron](https://react.dev/learn/thinking-in-react), [które to wyjaśniają](https://wagmi.sh/core/getting-started). Zamiast powtarzać świetną pracę wykonaną przez te strony, założę, że wolisz uczyć się przez działanie i zaczniesz od aplikacji, którą możesz się pobawić. Nadal potrzebujesz teorii, aby załatwić sprawy, i do tego dojdziemy - po prostu przejdziemy plik źródłowy po pliku źródłowym i omówimy sprawy, gdy do nich dojdziemy. + +### Instalacja {#installation} + +1. W razie potrzeby dodaj [blockchain Holesky](https://chainlist.org/?search=holesky&testnets=true) do swojego portfela i [pobierz testowe ETH](https://www.holeskyfaucet.io/). + +2. Sklonuj repozytorium na GitHubie. + + ```sh + git clone https://github.com/qbzzt/20230801-modern-ui.git + ``` + +3. Zainstaluj niezbędne pakiety. + + ```sh + cd 20230801-modern-ui + pnpm install + ``` + +4. Uruchom aplikację. + + ```sh + pnpm dev + ``` + +5. Przejdź do adresu URL wyświetlanego przez aplikację. W większości przypadków jest to [http://localhost:5173/](http://localhost:5173/). + +6. Możesz zobaczyć kod źródłowy kontraktu, nieco zmodyfikowaną wersję Greeter od Hardhat, [na eksploratorze blockchain](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contract). + +### Przegląd plików {#file-walk-through} + +#### `index.html` {#index-html} + +Ten plik jest standardowym szablonem HTML, z wyjątkiem tej linii, która importuje plik skryptu. + +```html + +``` + +#### `src/main.tsx` {#main-tsx} + +Rozszerzenie pliku mówi nam, że ten plik jest [komponentem React](https://www.w3schools.com/react/react_components.asp) napisanym w [TypeScript](https://www.typescriptlang.org/), rozszerzeniem JavaScriptu, które obsługuje [sprawdzanie typów](https://en.wikipedia.org/wiki/Type_system#Type_checking). TypeScript jest kompilowany do JavaScriptu, więc możemy go używać do wykonywania po stronie klienta. + +```tsx +import '@rainbow-me/rainbowkit/styles.css' +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import * as React from 'react' +import * as ReactDOM from 'react-dom/client' +import { WagmiConfig } from 'wagmi' +import { chains, config } from './wagmi' +``` + +Importuj kod biblioteki, którego potrzebujemy. + +```tsx +import { App } from './App' +``` + +Importuj komponent React, który implementuje aplikację (patrz poniżej). + +```tsx +ReactDOM.createRoot(document.getElementById('root')!).render( +``` + +Utwórz główny komponent React. Parametr `render` to [JSX](https://www.w3schools.com/react/react_jsx.asp), język rozszerzeń, który używa zarówno HTML, jak i JavaScript/TypeScript. Wykrzyknik tutaj mówi komponentowi TypeScript: "nie wiesz, że `document.getElementById('root')` będzie prawidłowym parametrem dla `ReactDOM.createRoot`, ale nie martw się - jestem deweloperem i mówię ci, że będzie". + +```tsx + +``` + +Aplikacja znajduje się wewnątrz [komponentu `React.StrictMode`](https://react.dev/reference/react/StrictMode). Ten komponent informuje bibliotekę React o wstawieniu dodatkowych kontroli debugowania, co jest przydatne podczas tworzenia. + +```tsx + +``` + +Aplikacja znajduje się również wewnątrz [komponentu `WagmiConfig`](https://wagmi.sh/react/api/WagmiProvider). [Biblioteka wagmi (we are going to make it)](https://wagmi.sh/) łączy definicje interfejsu użytkownika React z [biblioteką viem](https://viem.sh/) do pisania zdecentralizowanej aplikacji Ethereum. + +```tsx + +``` + +I wreszcie [komponent `RainbowKitProvider`](https://www.rainbowkit.com/). Ten komponent obsługuje logowanie i komunikację między portfelem a aplikacją. + +```tsx + +``` + +Teraz możemy mieć komponent dla aplikacji, który faktycznie implementuje interfejs użytkownika. Znak `/>` na końcu komponentu informuje React, że ten komponent nie ma w sobie żadnych definicji, zgodnie ze standardem XML. + +```tsx + + + , +) +``` + +Oczywiście musimy zamknąć pozostałe komponenty. + +#### `src/App.tsx` {#app-tsx} + +```tsx +import { ConnectButton } from '@rainbow-me/rainbowkit' +import { useAccount } from 'wagmi' +import { Greeter } from './components/Greeter' + +export function App() { +``` + +To jest standardowy sposób tworzenia komponentu React – zdefiniowanie funkcji, która jest wywoływana za każdym razem, gdy musi zostać wyrenderowana. Ta funkcja zazwyczaj ma na górze kod TypeScript lub JavaScript, po którym następuje instrukcja `return`, która zwraca kod JSX. + +```tsx + const { isConnected } = useAccount() +``` + +Tutaj używamy [`useAccount`](https://wagmi.sh/react/api/hooks/useAccount), aby sprawdzić, czy jesteśmy połączeni z blockchainem przez portfel, czy nie. + +Zgodnie z konwencją, w React funkcje o nazwie `use...` są [hookami](https://www.w3schools.com/react/react_hooks.asp), które zwracają pewien rodzaj danych. Kiedy używasz takich hooków, nie tylko Twój komponent otrzymuje dane, ale gdy te dane się zmieniają, komponent jest ponownie renderowany z zaktualizowanymi informacjami. + +```tsx + return ( + <> +``` + +JSX komponentu React _musi_ zwrócić jeden komponent. Gdy mamy wiele komponentów i nie mamy niczego, co "naturalnie" je opakowuje, używamy pustego komponentu (`<> ...` `), aby uczynić je pojedynczym komponentem. + +```tsx +

Greeter

+ +``` + +Komponent [`ConnectButton`](https://www.rainbowkit.com/docs/connect-button) otrzymujemy z RainbowKit. Gdy nie jesteśmy połączeni, daje nam przycisk `Connect Wallet`, który otwiera okno modalne, które wyjaśnia działanie portfeli i pozwala wybrać, którego używasz. Gdy jesteśmy połączeni, wyświetla używany przez nas blockchain, adres naszego konta i saldo ETH. Możemy użyć tych wyświetlaczy, aby przełączyć sieć lub się rozłączyć. + +```tsx + {isConnected && ( +``` + +Gdy musimy wstawić rzeczywisty JavaScript (lub TypeScript, który zostanie skompilowany do JavaScriptu) do JSX, używamy nawiasów (`{}`). + +Składnia `a && b` jest skrótem od [`a ?` b : a`](https://www.w3schools.com/react/react_es6_ternary.asp). Oznacza to, że jeśli `a`jest prawdziwe, wynikiem jest`b`, a w przeciwnym razie wynikiem jest `a`(które może być`false`, `0` itp.). Jest to łatwy sposób, aby powiedzieć React, że komponent powinien być wyświetlany tylko wtedy, gdy spełniony jest określony warunek. + +W tym przypadku chcemy pokazać użytkownikowi `Greeter` tylko wtedy, gdy użytkownik jest połączony z blockchainem. + +```tsx + + )} + + ) +} +``` + +#### `src/components/Greeter.tsx` {#greeter-tsx} + +Ten plik zawiera większość funkcjonalności interfejsu użytkownika. Zawiera definicje, które normalnie znajdowałyby się w wielu plikach, ale ponieważ jest to samouczek, program jest zoptymalizowany pod kątem łatwości zrozumienia za pierwszym razem, a nie wydajności czy łatwości konserwacji. + +```tsx +import { useState, ChangeEventHandler } from 'react' +import { useNetwork, + useReadContract, + usePrepareContractWrite, + useContractWrite, + useContractEvent + } from 'wagmi' +``` + +Używamy tych funkcji bibliotecznych. Ponownie, są one wyjaśnione poniżej, w miejscu ich użycia. + +```tsx +import { AddressType } from 'abitype' +``` + +[Biblioteka `abitype`](https://abitype.dev/) dostarcza nam definicje TypeScript dla różnych typów danych Ethereum, takich jak [`AddressType`](https://abitype.dev/config#addresstype). + +```tsx +let greeterABI = [ + . + . + . +] as const // greeterABI +``` + +ABI - binarny interfejs aplikacji dla kontraktu `Greeter`. +Jeśli tworzysz kontrakty i interfejs użytkownika w tym samym czasie, normalnie umieszczasz je w tym samym repozytorium i używasz ABI wygenerowanego przez kompilator Solidity jako pliku w swojej aplikacji. Jednak nie jest to tutaj konieczne, ponieważ kontrakt jest już opracowany i nie ulegnie zmianie. + +```tsx +type AddressPerBlockchainType = { + [key: number]: AddressType +} +``` + +TypeScript jest silnie typowany. Używamy tej definicji do określenia adresu, na którym kontrakt `Greeter` jest wdrożony na różnych łańcuchach. Kluczem jest liczba (chainId), a wartością jest `AddressType` (adres). + +```tsx +const contractAddrs: AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' +} +``` + +Adres kontraktu na dwóch obsługiwanych sieciach: [Holesky](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contact_code) i [Sepolia](https://eth-sepolia.blockscout.com/address/0x7143d5c190F048C8d19fe325b748b081903E3BF0?tab=contact_code). + +Uwaga: W rzeczywistości istnieje trzecia definicja, dla Redstone Holesky, zostanie ona wyjaśniona poniżej. + +```tsx +type ShowObjectAttrsType = { + name: string, + object: any +} +``` + +Ten typ jest używany jako parametr komponentu `ShowObject` (wyjaśnionego później). Zawiera nazwę obiektu i jego wartość, które są wyświetlane w celach debugowania. + +```tsx +type ShowGreetingAttrsType = { + greeting: string | undefined +} +``` + +W dowolnym momencie możemy wiedzieć, jakie jest powitanie (ponieważ odczytaliśmy je z blockchainu) lub nie wiedzieć (ponieważ jeszcze go nie otrzymaliśmy). Dlatego warto mieć typ, który może być albo ciągiem znaków, albo niczym. + +##### Komponent `Greeter` {#greeter-component} + +```tsx +const Greeter = () => { +``` + +Wreszcie możemy zdefiniować komponent. + +```tsx + const { chain } = useNetwork() +``` + +Informacje o łańcuchu, którego używamy, dzięki uprzejmości [wagmi](https://wagmi.sh/react/hooks/useNetwork). +Ponieważ jest to hak (`use...`), za każdym razem, gdy ta informacja się zmienia, komponent jest ponownie rysowany. + +```tsx + const greeterAddr = chain && contractAddrs[chain.id] +``` + +Adres kontraktu Greeter, który różni się w zależności od łańcucha (i który jest `undefined`, jeśli nie mamy informacji o łańcuchu lub jesteśmy na łańcuchu bez tego kontraktu). + +```tsx + const readResults = useReadContract({ + address: greeterAddr, + abi: greeterABI, + functionName: "greet" , // Brak argumentów + watch: true + }) +``` + +Hak [`useReadContract`](https://wagmi.sh/react/api/hooks/useReadContract) odczytuje informacje z kontraktu. Możesz zobaczyć dokładnie, jakie informacje zwraca, rozwijając `readResults` w interfejsie użytkownika. W tym przypadku chcemy, aby nadal szukał, abyśmy byli informowani o zmianie powitania. + +**Uwaga:** Moglibyśmy nasłuchiwać [zdarzeń `setGreeting`](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=logs), aby wiedzieć, kiedy zmienia się powitanie i aktualizować je w ten sposób. Jednak, chociaż może to być bardziej wydajne, nie będzie miało zastosowania we wszystkich przypadkach. Gdy użytkownik przełącza się na inny łańcuch, powitanie również się zmienia, ale tej zmianie nie towarzyszy zdarzenie. Moglibyśmy mieć jedną część kodu nasłuchującą zdarzeń, a drugą do identyfikowania zmian łańcucha, ale byłoby to bardziej skomplikowane niż tylko ustawienie [parametru `watch`](https://wagmi.sh/react/api/hooks/useReadContract#watch-optional). + +```tsx + const [ newGreeting, setNewGreeting ] = useState("") +``` + +Hook [`useState`](https://www.w3schools.com/react/react_usestate.asp) React pozwala nam zdefiniować zmienną stanu, której wartość utrzymuje się od jednego renderowania komponentu do drugiego. Wartością początkową jest parametr, w tym przypadku pusty ciąg znaków. + +Hook `useState` zwraca listę z dwiema wartościami: + +1. Bieżąca wartość zmiennej stanu. +2. Funkcja do modyfikowania zmiennej stanu w razie potrzeby. Ponieważ jest to hak, za każdym razem, gdy jest wywoływany, komponent jest ponownie renderowany. + +W tym przypadku używamy zmiennej stanu dla nowego powitania, które użytkownik chce ustawić. + +```tsx + const greetingChange : ChangeEventHandler = (evt) => + setNewGreeting(evt.target.value) +``` + +Jest to procedura obsługi zdarzeń dla zmiany pola wprowadzania nowego powitania. Typ [`ChangeEventHandler`](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events/) określa, że jest to procedura obsługi zmiany wartości elementu wejściowego HTML. Część `` jest używana, ponieważ jest to [typ generyczny](https://www.w3schools.com/typescript/typescript_basic_generics.php). + +```tsx + const preparedTx = usePrepareContractWrite({ + address: greeterAddr, + abi: greeterABI, + functionName: 'setGreeting', + args: [ newGreeting ] + }) + const workingTx = useContractWrite(preparedTx.config) +``` + +To jest proces przesyłania transakcji blockchain z perspektywy klienta: + +1. Wyślij transakcję do węzła w łańcuchu bloków za pomocą [`eth_estimateGas`](https://docs.alchemy.com/reference/eth-estimategas). +2. Poczekaj na odpowiedź z węzła. +3. Po otrzymaniu odpowiedzi, poproś użytkownika o podpisanie transakcji za pośrednictwem portfela. Ten krok _musi_ nastąpić po otrzymaniu odpowiedzi węzła, ponieważ użytkownikowi wyświetlany jest koszt gazu transakcji przed jej podpisaniem. +4. Poczekaj na zatwierdzenie przez użytkownika. +5. Wyślij transakcję ponownie, tym razem za pomocą [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction). + +Krok 2 prawdopodobnie zajmie zauważalną ilość czasu, podczas którego użytkownicy zastanawialiby się, czy ich polecenie zostało naprawdę odebrane przez interfejs użytkownika i dlaczego nie są jeszcze proszeni o podpisanie transakcji. To powoduje złe doświadczenie użytkownika (UX). + +Rozwiązaniem jest użycie [hooków przygotowawczych](https://wagmi.sh/react/prepare-hooks). Za każdym razem, gdy parametr się zmienia, natychmiast wysyłaj do węzła żądanie `eth_estimateGas`. Następnie, gdy użytkownik faktycznie chce wysłać transakcję (w tym przypadku przez naciśnięcie **Update greeting**), koszt gazu jest znany, a użytkownik może natychmiast zobaczyć stronę portfela. + +```tsx + return ( +``` + +Teraz możemy wreszcie utworzyć rzeczywisty kod HTML do zwrócenia. + +```tsx + <> +

Greeter

+ { + !readResults.isError && !readResults.isLoading && + + } +
+``` + +Utwórz komponent `ShowGreeting` (wyjaśniony poniżej), ale tylko wtedy, gdy powitanie zostało pomyślnie odczytane z blockchainu. + +```tsx + +``` + +Jest to pole tekstowe, w którym użytkownik może ustawić nowe powitanie. Za każdym razem, gdy użytkownik naciśnie klawisz, wywołujemy `greetingChange`, które wywołuje `setNewGreeting`. Ponieważ `setNewGreeting` pochodzi z hooka `useState`, powoduje to ponowne renderowanie komponentu `Greeter`. Oznacza to, że: + +- Musimy określić `value`, aby zachować wartość nowego powitania, ponieważ w przeciwnym razie powróciłoby ono do wartości domyślnej, czyli pustego ciągu znaków. +- `usePrepareContractWrite` jest wywoływane za każdym razem, gdy `newGreeting` się zmienia, co oznacza, że zawsze będzie miało najnowsze `newGreeting` w przygotowanej transakcji. + +```tsx + +``` + +Jeśli nie ma `workingTx.write`, oznacza to, że wciąż czekamy na informacje niezbędne do wysłania aktualizacji powitania, więc przycisk jest wyłączony. Jeśli istnieje wartość `workingTx.write`, to jest to funkcja do wywołania w celu wysłania transakcji. + +```tsx +
+ + + + + ) +} +``` + +Na koniec, aby pomóc Ci zobaczyć, co robimy, pokaż trzy obiekty, których używamy: + +- `readResults` +- `preparedTx` +- `workingTx` + +##### Komponent `ShowGreeting` {#showgreeting-component} + +Ten komponent pokazuje + +```tsx +const ShowGreeting = (attrs : ShowGreetingAttrsType) => { +``` + +Funkcja komponentu otrzymuje parametr ze wszystkimi atrybutami komponentu. + +```tsx + return {attrs.greeting} +} +``` + +##### Komponent `ShowObject` {#showobject-component} + +W celach informacyjnych używamy komponentu `ShowObject` do pokazania ważnych obiektów (`readResults` do odczytywania powitania oraz `preparedTx` i `workingTx` do transakcji, które tworzymy). + +```tsx +const ShowObject = (attrs: ShowObjectAttrsType ) => { + const keys = Object.keys(attrs.object) + const funs = keys.filter(k => typeof attrs.object[k] == "function") + return <> +
+``` + +Nie chcemy zaśmiecać interfejsu użytkownika wszystkimi informacjami, więc aby umożliwić ich przeglądanie lub zamykanie, używamy znacznika [`details`](https://www.w3schools.com/tags/tag_details.asp). + +```tsx + {attrs.name} +
+        {JSON.stringify(attrs.object, null, 2)}
+```
+
+Większość pól jest wyświetlana za pomocą [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp).
+
+```tsx
+      
+ { funs.length > 0 && + <> + Functions: +
    +``` + +Wyjątkiem są funkcje, które nie są częścią [standardu JSON](https://www.json.org/json-en.html), więc muszą być wyświetlane osobno. + +```tsx + {funs.map((f, i) => +``` + +Wewnątrz JSX kod w nawiasach klamrowych `{` `}` jest interpretowany jako JavaScript. Następnie kod w nawiasach zwykłych `(` `)` jest ponownie interpretowany jako JSX. + +```tsx + (
  • {f}
  • ) + )} +``` + +React wymaga, aby znaczniki w [drzewie DOM](https://www.w3schools.com/js/js_htmldom.asp) miały odrębne identyfikatory. Oznacza to, że dzieci tego samego znacznika (w tym przypadku [lista nieuporządkowana](https://www.w3schools.com/tags/tag_ul.asp)) potrzebują różnych atrybutów `key`. + +```tsx +
+ + } +
+ +} +``` + +Zakończ różne znaczniki HTML. + +##### Ostateczny `export` {#the-final-export} + +```tsx +export { Greeter } +``` + +Komponent `Greeter` jest tym, który musimy wyeksportować dla aplikacji. + +#### `src/wagmi.ts` {#wagmi-ts} + +Na koniec, różne definicje związane z WAGMI znajdują się w `src/wagmi.ts`. Nie będę tutaj wszystkiego wyjaśniać, ponieważ większość z tego to szablon, którego prawdopodobnie nie będziesz musiał zmieniać. + +Kod tutaj nie jest dokładnie taki sam jak [na GitHubie](https://github.com/qbzzt/20230801-modern-ui/blob/main/src/wagmi.ts), ponieważ w dalszej części artykułu dodajemy kolejny łańcuch ([Redstone Holesky](https://redstone.xyz/docs/network-info)). + +```ts +import { getDefaultWallets } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig } from 'wagmi' +import { holesky, sepolia } from 'wagmi/chains' +``` + +Importuj łańcuchy bloków, które obsługuje aplikacja. Listę obsługiwanych łańcuchów można zobaczyć [w viem github](https://github.com/wagmi-dev/viem/tree/main/src/chains/definitions). + +```ts +import { publicProvider } from 'wagmi/providers/public' + +const walletConnectProjectId = 'c96e690bb92b6311e8e9b2a6a22df575' +``` + +Aby móc korzystać z [WalletConnect](https://walletconnect.com/), potrzebujesz identyfikatora projektu dla swojej aplikacji. Możesz go uzyskać na stronie [cloud.walletconnect.com](https://cloud.walletconnect.com/sign-in). + +```ts +const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia ], + [ + publicProvider(), + ], +) + +const { connectors } = getDefaultWallets({ + appName: 'My wagmi + RainbowKit App', + chains, + projectId: walletConnectProjectId, +}) + +export const config = createConfig({ + autoConnect: true, + connectors, + publicClient, + webSocketPublicClient, +}) + +export { chains } +``` + +### Dodawanie kolejnego blockchaina {#add-blockchain} + +Obecnie istnieje wiele [rozwiązań skalujących L2](/layer-2/) i możesz chcieć obsługiwać niektóre, których viem jeszcze nie obsługuje. Aby to zrobić, zmodyfikuj `src/wagmi.ts`. Te instrukcje wyjaśniają, jak dodać [Redstone Holesky](https://redstone.xyz/docs/network-info). + +1. Zaimportuj typ `defineChain` z viem. + + ```ts + import { defineChain } from 'viem' + ``` + +2. Dodaj definicję sieci. + + ```ts + const redstoneHolesky = defineChain({ + id: 17_001, + name: 'Redstone Holesky', + network: 'redstone-holesky', + nativeCurrency: { + decimals: 18, + name: 'Ether', + symbol: 'ETH', + }, + rpcUrls: { + default: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + public: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + }, + blockExplorers: { + default: { name: 'Explorer', url: 'https://explorer.holesky.redstone.xyz' }, + }, + }) + ``` + +3. Dodaj nowy łańcuch do wywołania `configureChains`. + + ```ts + const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia, redstoneHolesky ], + [ publicProvider(), ], + ) + ``` + +4. Upewnij się, że aplikacja zna adres Twoich kontraktów w nowej sieci. W tym przypadku modyfikujemy `src/components/Greeter.tsx`: + + ```ts + const contractAddrs : AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Redstone Holesky + 17001: '0x4919517f82a1B89a32392E1BF72ec827ba9986D3', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' + } + ``` + +## Wnioski {#conclusion} + +Oczywiście, tak naprawdę nie zależy Ci na udostępnieniu interfejsu użytkownika dla `Greeter`. Chcesz stworzyć interfejs użytkownika dla własnych kontraktów. Aby utworzyć własną aplikację, wykonaj następujące kroki: + +1. Określ, aby utworzyć aplikację wagmi. + + ```sh copy + pnpm create wagmi + ``` + +2. Nazwij aplikację. + +3. Wybierz framework **React**. + +4. Wybierz wariant **Vite**. + +5. Możesz [dodać zestaw Rainbow](https://www.rainbowkit.com/docs/installation#manual-setup). + +Teraz idź i spraw, aby Twoje kontrakty były użyteczne dla całego świata. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). + diff --git a/public/content/translations/pl/developers/tutorials/deploying-your-first-smart-contract/index.md b/public/content/translations/pl/developers/tutorials/deploying-your-first-smart-contract/index.md index b87270a560b..f0494c1235c 100644 --- a/public/content/translations/pl/developers/tutorials/deploying-your-first-smart-contract/index.md +++ b/public/content/translations/pl/developers/tutorials/deploying-your-first-smart-contract/index.md @@ -1,13 +1,8 @@ --- -title: Wdrożenie pierwszego inteligentnego kontraktu -description: Wprowadzenie do wdrożenia pierwszego inteligentnego kontraktu w sieci testowej Ethereum +title: "Wdrożenie pierwszego inteligentnego kontraktu" +description: "Wprowadzenie do wdrożenia pierwszego inteligentnego kontraktu w sieci testowej Ethereum" author: "jdourlens" -tags: - - "inteligentne kontrakty" - - "remix" - - "solidity" - - "pierwsze kroki" - - "wdrożenie" +tags: [ "smart kontrakty", "remix", "solidity", "wdrażanie" ] skill: beginner lang: pl published: 2020-04-03 @@ -16,32 +11,33 @@ sourceUrl: https://ethereumdev.io/deploying-your-first-smart-contract/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -Chyba jesteś tak samo podekscytowany jak my [wdrażaniem](/developers/docs/smart-contracts/deploying/) i interakcją z pierwszym [inteligentnym kontraktem](/developers/docs/smart-contracts/) na blockchainie Ethereum. +Zgaduję, że jesteś tak samo podekscytowany jak my, aby [wdrożyć](/developers/docs/smart-contracts/deploying/) i wejść w interakcję ze swoim pierwszym [inteligentnym kontraktem](/developers/docs/smart-contracts/) na blockchainie Ethereum. -Nie martw się, ponieważ jest to nasz pierwszy inteligentny kontrakt, wdrożymy go w [lokalnej sieci testowej](/developers/docs/networks/), więc wdrożenie nic nie kosztuje i możesz bawić się nim tyle, ile chcesz. +Nie przejmuj się, ponieważ jest to nasz pierwszy inteligentny kontrakt, wdrożymy go w lokalnej [sieci testowej](/developers/docs/networks/), więc jego wdrożenie nic nie kosztuje i możesz się nim bawić, ile tylko chcesz. -## Pisanie kontraktu {#writing-our-contract} +## Pisanie naszego kontraktu {#writing-our-contract} Pierwszym krokiem jest [odwiedzenie Remix](https://remix.ethereum.org/) i utworzenie nowego pliku. W lewej górnej części interfejsu Remix dodaj nowy plik i wprowadź żądaną nazwę pliku. -![Dodawanie nowego pliku do interfejsu Remix](./remix.png) +![Dodawanie nowego pliku w interfejsie Remix](./remix.png) W nowym pliku wkleimy następujący kod. ```solidity -pragma solidity 0.5.17; +// SPDX-License-Identifier: MIT +pragma solidity >=0.5.17; contract Counter { - // Public variable of type unsigned int to keep the number of counts + // Publiczna zmienna typu unsigned int do przechowywania liczby zliczeń uint256 public count = 0; - // Function that increments our counter + // Funkcja, która zwiększa nasz licznik function increment() public { count += 1; } - // Not necessary getter to get the count value + // Niepotrzebny getter do pobrania wartości licznika function getCount() public view returns (uint256) { return count; } @@ -49,20 +45,20 @@ contract Counter { } ``` -Jeśli masz doświadczenie w programowaniu, możesz łatwo odgadnąć, co robi ten program. Oto wyjaśnienie kolejnych wierszy: +Jeśli masz doświadczenie w programowaniu, możesz łatwo odgadnąć, co robi ten program. Oto wyjaśnienie linijka po linijce: -- Wiersz 3: Określamy kontrakt nazwą `Counter`. -- Wiersz 6: Nasz kontrakt przechowuje jedną niepodpisaną liczbę całkowitą o nazwie `count` zaczynając od 0. -- Wiersz 9: Pierwsza funkcja zmieni stan kontraktu i zwiększy `increment()` zmienną `count`>. -- Wiersz 14: Druga funkcja to tylko getter, który może odczytywać wartość zmiennej `count` poza inteligentnym kontraktem. Zauważ, że ponieważ zdefiniowaliśmy zmienną `count` jako publiczną, to nie jest konieczne, ale jest to przykład. +- Wiersz 4: Definiujemy kontrakt o nazwie `Counter`. +- Wiersz 7: Nasz kontrakt przechowuje jedną liczbę całkowitą bez znaku o nazwie `count`, zaczynając od 0. +- Wiersz 10: Pierwsza funkcja modyfikuje stan kontraktu i zwiększa naszą zmienną `count`. +- Wiersz 15: Druga funkcja to tylko getter, który umożliwia odczytanie wartości zmiennej `count` poza inteligentnym kontraktem. Zauważ, że ponieważ zdefiniowaliśmy naszą zmienną `count` jako publiczną, nie jest to konieczne, ale zostało pokazane jako przykład. -To wszystko dotyczy naszego pierwszego prostego inteligentnego kontraktu. Jak możesz wiedzieć, wygląda to na klasę z języków programowania obiektowego takich jak Java lub C++. Nadszedł czas, aby pobawić się naszym kontraktem. +To wszystko, jeśli chodzi o nasz pierwszy prosty inteligentny kontrakt. Jak być może wiesz, wygląda to jak klasa z języków programowania zorientowanego obiektowo (OOP), takich jak Java lub C++. Nadszedł czas, aby pobawić się naszym kontraktem. -## Wdrażanie kontraktu {#deploying-our-contract} +## Wdrażanie naszego kontraktu {#deploying-our-contract} -Ponieważ napisaliśmy pierwszy inteligentny kontrakt, teraz wdrożymy go w blockchainie, aby móc się nim bawić. +Ponieważ napisaliśmy nasz pierwszy inteligentny kontrakt, teraz wdrożymy go w blockchainie, aby móc się nim bawić. -[Wdrażanie inteligentnego kontraktu w blockchainie](/developers/docs/smart-contracts/deploying/) to w rzeczywistości tylko wysłanie transakcji zawierającej kod skompilowanego inteligentnego kontraktu bez określania odbiorców. +[Wdrażanie inteligentnego kontraktu na blockchainie](/developers/docs/smart-contracts/deploying/) to w rzeczywistości tylko wysłanie transakcji zawierającej kod skompilowanego inteligentnego kontraktu bez określania żadnych odbiorców. Najpierw [skompilujemy kontrakt](/developers/docs/smart-contracts/compiling/), klikając ikonę kompilacji po lewej stronie: @@ -70,30 +66,30 @@ Najpierw [skompilujemy kontrakt](/developers/docs/smart-contracts/compiling/), k Następnie kliknij przycisk kompilacji: -![Przycisk kompilacji w Remix Solidity](./remix-compile.png) +![Przycisk kompilacji w kompilatorze Remix Solidity](./remix-compile.png) -Możesz wybrać opcję „Automatyczna kompilacja”, aby umowa była zawsze kompilowana po zapisaniu zawartości w edytorze tekstowym. +Możesz wybrać opcję "Automatyczna kompilacja", aby kontrakt był zawsze kompilowany po zapisaniu zawartości w edytorze tekstowym. -Następnie przejdź do ekranu wdrażania i uruchamiania transakcji: +Następnie przejdź do ekranu "wdrażanie i uruchamianie transakcji": ![Ikona wdrażania na pasku narzędzi Remix](./remix-deploy.png) -Po przejściu do ekranu „wdróż i uruchom” transakcje sprawdź dokładnie, czy pojawia się nazwa Twojego kontraktu i kliknij Wdróż. Jak widać na górze strony, obecne środowisko to „Maszyna wirtualna JavaScript”, co oznacza, że ​​wdrożymy inteligentny kontrakt i będziemy nad nim pracować w lokalnym testowym blockchainie, aby móc testować szybciej i bez żadnych opłat. +Gdy znajdziesz się na ekranie "wdrażanie i uruchamianie transakcji", upewnij się, że wyświetla się nazwa Twojego kontraktu, a następnie kliknij "Wdróż". Jak widać na górze strony, obecne środowisko to "JavaScript VM", co oznacza, że będziemy wdrażać i wchodzić w interakcję z naszym inteligentnym kontraktem na lokalnym testowym blockchainie, aby móc go testować szybciej i bez żadnych opłat. -![Przycisk wdrażania w kompilatorze Remix Solidity](./remix-deploy.png) +![Przycisk wdrażania w kompilatorze Remix Solidity](./remix-deploy-button.png) -Po kliknięciu przycisku „Wdróż” na dole pojawi się Twój kontrakt. Kliknij strzałkę po lewej stronie, aby ją rozwinąć i wyświetlić zawartość kontraktu. To jest utworzona zmienna `counter`, funkcja `increment()` i getter `getCounter()`. +Po kliknięciu przycisku "Wdróż", na dole pojawi się Twój kontrakt. Kliknij strzałkę po lewej stronie, aby go rozwinąć i wyświetlić zawartość naszego kontraktu. To jest nasza zmienna `counter`, nasza funkcja `increment()` i getter `getCounter()`. -Jeśli klikniesz przycisk `count` lub `getCount`, zostanie pobrana i wyświetlona zmienna `count`. Ponieważ funkcja `increment` nie została jeszcze wywołana, wyświetli 0. +Jeśli klikniesz przycisk `count` lub `getCount`, zostanie odczytana zawartość zmiennej `count` z kontraktu i wyświetlona. Ponieważ nie wywołaliśmy jeszcze funkcji `increment`, wyświetli się 0. ![Przycisk funkcji w kompilatorze Remix Solidity](./remix-function-button.png) -Wywołajmy funkcję `increment`, klikając przycisk. Zobaczysz dzienniki transakcji, wyświetlone na dole okna. Zobaczysz, że dzienniki są inne, gdy naciśniesz przycisk pobierania danych zamiast przycisku `increment`. To dlatego, że odczyt danych w blockchainie nie wymaga żadnych transakcji (pisanie) ani opłat. Ponieważ tylko modyfikacja stanu łańcucha bloków wymaga dokonania transakcji: +Wywołajmy teraz funkcję `increment`, klikając przycisk. Zobaczysz logi wykonanych transakcji, które pojawią się na dole okna. Zobaczysz, że logi są inne, gdy naciskasz przycisk pobierania danych zamiast przycisku `increment`. Dzieje się tak, ponieważ odczytywanie danych z blockchaina nie wymaga żadnych transakcji (zapisu) ani opłat. Ponieważ tylko modyfikowanie stanu blockchaina wymaga wykonania transakcji: -![Dziennik transakcji](./transaction-log.png) +![Log transakcji](./transaction-log.png) -Po naciśnięciu przycisku inkrement, który wygeneruje transakcję, aby wywołać naszą funkcję `increment()`, jeśli ponownie klikniemy przycisk count lub getCount, odczytamy nowo zaktualizowany stan naszego inteligentnego kontraktu ze zmienną count większą niż 0. +Po naciśnięciu przycisku `increment`, który wygeneruje transakcję wywołującą naszą funkcję `increment()`, jeśli ponownie klikniemy przyciski `count` lub `getCount`, odczytamy nowo zaktualizowany stan naszego inteligentnego kontraktu ze zmienną `count` większą od 0. ![Nowo zaktualizowany stan inteligentnego kontraktu](./updated-state.png) -W następnym samouczku omówimy [jak dodawać zdarzenia do inteligentnych kontraktów](/developers/tutorials/logging-events-smart-contracts/). Rejestrowanie zdarzeń jest wygodnym sposobem debugowania inteligentnego kontraktu i zrozumienia, co się dzieje podczas wywoływania funkcji. +W następnym samouczku omówimy, [jak możesz dodawać zdarzenia do swoich inteligentnych kontraktów](/developers/tutorials/logging-events-smart-contracts/). Rejestrowanie zdarzeń jest wygodnym sposobem debugowania inteligentnego kontraktu i zrozumienia, co się dzieje podczas wywoływania funkcji. diff --git a/public/content/translations/pl/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md b/public/content/translations/pl/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md new file mode 100644 index 00000000000..15dc728b16c --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md @@ -0,0 +1,372 @@ +--- +title: "Jak rozwijać i testować dApp na lokalnej, wieloklientowej sieci testowej" +description: "Ten poradnik najpierw przeprowadzi Cię przez proces tworzenia i konfigurowania wieloklientowej lokalnej sieci testowej Ethereum, a następnie pokaże, jak użyć tej sieci testowej do wdrożenia i przetestowania dApp." +author: "Tedi Mitiku" +tags: + [ + "klienci", + "węzły", + "smart kontrakty", + "kompozycyjność", + "warstwa konsensusu", + "warstwa wykonawcza", + "testowanie" + ] +skill: intermediate +lang: pl +published: 2023-04-11 +--- + +## Wprowadzenie {#introduction} + +Ten poradnik przeprowadzi Cię przez proces tworzenia konfigurowalnej lokalnej sieci testowej Ethereum, wdrażania na niej smart kontraktu i używania sieci testowej do przeprowadzania testów Twojej dApp. Ten poradnik jest przeznaczony dla deweloperów dApp, którzy chcą rozwijać i testować swoje dapki lokalnie w różnych konfiguracjach sieci przed wdrożeniem na działającą sieć testową lub sieć główną. + +W tym poradniku: + +- Utworzyć lokalną sieć testową Ethereum za pomocą pakietu [`eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) przy użyciu [Kurtosis](https://www.kurtosis.com/), +- Połączyć swoje środowisko programistyczne dApp Hardhat z lokalną siecią testową w celu kompilacji, wdrożenia i przetestowania dApp oraz +- Skonfigurować lokalną sieć testową, w tym parametry takie jak liczba węzłów i określone pary klientów EL/CL, aby umożliwić procesy programistyczne i testowe w różnych konfiguracjach sieci. + +### Czym jest Kurtosis? {#what-is-kurtosis} + +[Kurtosis](https://www.kurtosis.com/) to komponowalny system budowania przeznaczony do konfigurowania wielokontenerowych środowisk testowych. W szczególności umożliwia deweloperom tworzenie odtwarzalnych środowisk, które wymagają dynamicznej logiki konfiguracji, takich jak sieci testowe blockchain. + +W tym poradniku pakiet eth-network-package Kurtosis uruchamia lokalną sieć testową Ethereum z obsługą klienta warstwy wykonawczej (EL) [`geth`](https://geth.ethereum.org/), a także klientów warstwy konsensusu (CL) [`teku`](https://consensys.io/teku), [`lighthouse`](https://lighthouse.sigmaprime.io/) i [`lodestar`](https://lodestar.chainsafe.io/). Ten pakiet służy jako konfigurowalna i komponowalna alternatywa dla sieci w frameworkach takich jak Hardhat Network, Ganache i Anvil. Kurtosis oferuje deweloperom większą kontrolę i elastyczność nad sieciami testowymi, których używają, co jest głównym powodem, dla którego [Ethereum Foundation użyła Kurtosis do testowania Połączenia](https://www.kurtosis.com/blog/testing-the-ethereum-merge) i nadal używa go do testowania aktualizacji sieci. + +## Konfiguracja Kurtosis {#setting-up-kurtosis} + +Zanim przejdziesz dalej, upewnij się, że masz: + +- [Zainstalowany i uruchomiony silnik Docker](https://docs.kurtosis.com/install/#i-install--start-docker) na swoim komputerze lokalnym +- [Zainstalowany Kurtosis CLI](https://docs.kurtosis.com/install#ii-install-the-cli) (lub zaktualizowany do najnowszej wersji, jeśli masz już zainstalowany CLI) +- Zainstalowane [Node.js](https://nodejs.org/en), [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) i [npx](https://www.npmjs.com/package/npx) (dla Twojego środowiska dApp) + +## Tworzenie lokalnej sieci testowej Ethereum {#instantiate-testnet} + +Aby uruchomić lokalną sieć testową Ethereum, wykonaj: + +```python +kurtosis --enclave local-eth-testnet run github.com/kurtosis-tech/eth-network-package +``` + +Uwaga: to polecenie nazywa Twoją sieć: \"local-eth-testnet\" za pomocą flagi `--enclave`. + +Kurtosis wydrukuje kroki, które podejmuje w tle, podczas gdy interpretuje, waliduje, a następnie wykonuje instrukcje. Na końcu powinieneś zobaczyć dane wyjściowe podobne do poniższych: + +```python +INFO[2023-04-04T18:09:44-04:00] ====================================================== +INFO[2023-04-04T18:09:44-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-04T18:09:44-04:00] ====================================================== +Name: local-eth-testnet +UUID: 39372d756ae8 +Status: RUNNING +Creation Time: Tue, 04 Apr 2023 18:09:03 EDT + +========================================= Files Artifacts ========================================= +UUID Name +d4085a064230 cl-genesis-data +1c62cb792e4c el-genesis-data +bd60489b73a7 genesis-generation-config-cl +b2e593fe5228 genesis-generation-config-el +d552a54acf78 geth-prefunded-keys +5f7e661eb838 prysm-password +054e7338bb59 validator-keystore-0 + +========================================== User Services ========================================== +UUID Name Ports Status +e20f129ee0c5 cl-client-0-beacon http: 4000/tcp -> RUNNING + metrics: 5054/tcp -> + tcp-discovery: 9000/tcp -> 127.0.0.1:54263 + udp-discovery: 9000/udp -> 127.0.0.1:60470 +a8b6c926cdb4 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:54267 RUNNING + metrics: 5064/tcp -> +d7b802f623e8 el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:54253 RUNNING + rpc: 8545/tcp -> 127.0.0.1:54251 + tcp-discovery: 30303/tcp -> 127.0.0.1:54254 + udp-discovery: 30303/udp -> 127.0.0.1:53834 + ws: 8546/tcp -> 127.0.0.1:54252 +514a829c0a84 prelaunch-data-generator-1680646157905431468 STOPPED +62bd62d0aa7a prelaunch-data-generator-1680646157915424301 STOPPED +05e9619e0e90 prelaunch-data-generator-1680646157922872635 STOPPED + +``` + +Gratulacje! Użyłeś Kurtosis do utworzenia lokalnej sieci testowej Ethereum z klientem CL (`lighthouse`) i klientem EL (`geth`) za pośrednictwem Dockera. + +### Podsumowanie {#review-instantiate-testnet} + +W tej sekcji wykonałeś polecenie, które poleciło Kurtosis użycie pakietu [`eth-network-package` hostowanego zdalnie na GitHub](https://github.com/kurtosis-tech/eth-network-package) do uruchomienia lokalnej sieci testowej Ethereum w enklawie Kurtosis [Enclave](https://docs.kurtosis.com/advanced-concepts/enclaves/). Wewnątrz enklawy znajdziesz zarówno \"artefakty plików\", jak i \"usługi użytkownika\". + +[Artefakty plików](https://docs.kurtosis.com/advanced-concepts/files-artifacts/) w Twojej enklawie zawierają wszystkie dane wygenerowane i wykorzystane do uruchomienia klientów EL i CL. Dane zostały utworzone za pomocą usługi `prelaunch-data-generator` zbudowanej z tego [obrazu Docker](https://github.com/ethpandaops/ethereum-genesis-generator) + +Usługi użytkownika wyświetlają wszystkie skonteneryzowane usługi działające w Twojej enklawie. Zauważysz, że został utworzony pojedynczy węzeł, zawierający zarówno klienta EL, jak i klienta CL. + +## Połącz swoje środowisko programistyczne dApp z lokalną siecią testową Ethereum {#connect-your-dapp} + +### Konfiguracja środowiska programistycznego dApp {#set-up-dapp-env} + +Teraz, gdy masz działającą lokalną sieć testową, możesz połączyć swoje środowisko programistyczne dApp, aby korzystać z lokalnej sieci testowej. W tym poradniku zostanie użyty framework Hardhat do wdrożenia dApp do gry w blackjacka na Twojej lokalnej sieci testowej. + +Aby skonfigurować środowisko programistyczne dApp, sklonuj repozytorium zawierające naszą przykładową dApp i zainstaluj jego zależności, uruchamiając: + +```python +git clone https://github.com/kurtosis-tech/awesome-kurtosis.git && cd awesome-kurtosis/smart-contract-example && yarn +``` + +Użyty tutaj folder [smart-contract-example](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example) zawiera typową konfigurację dla dewelopera dApp korzystającego z frameworka [Hardhat](https://hardhat.org/): + +- [`contracts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/contracts) zawiera kilka prostych smart kontraktów dla dApp do gry w Blackjacka +- [`scripts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/scripts) zawiera skrypt do wdrożenia kontraktu tokena na Twojej lokalnej sieci Ethereum +- [`test/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/test) zawiera prosty test .js dla Twojego kontraktu tokena, aby potwierdzić, że dla każdego gracza w naszej dApp do gry w Blackjacka zostało wybitych 1000 żetonów +- [`hardhat.config.ts`](https://github.com/kurtosis-tech/awesome-kurtosis/blob/main/smart-contract-example/hardhat.config.ts) konfiguruje Twoją instalację Hardhat + +### Konfiguracja Hardhat do korzystania z lokalnej sieci testowej {#configure-hardhat} + +Po skonfigurowaniu środowiska programistycznego dApp, połączysz teraz Hardhat z lokalną siecią testową Ethereum wygenerowaną za pomocą Kurtosis. Aby to osiągnąć, zastąp `<$YOUR_PORT>` w strukturze `localnet` w pliku konfiguracyjnym `hardhat.config.ts` portem z danych wyjściowych rpc uri dowolnej usługi `el-client-`. W tym przykładowym przypadku portem byłoby `64248`. Twój port będzie inny. + +Przykład w `hardhat.config.ts`: + +```js +localnet: { +url: 'http://127.0.0.1:<$YOUR_PORT>',// TODO: ZASTĄP $YOUR_PORT PORTEM URI WĘZŁA WYGENEROWANYM PRZEZ PAKIET SIECI ETH KURTOSIS + +// To są klucze prywatne powiązane z prefinansowanymi kontami testowymi utworzonymi przez eth-network-package +// +accounts: [ + "ef5177cd0b6b21c87db5a0bf35d4084a8a57a9d6a064f86d51ac85f2b873a4e2", + "48fcc39ae27a0e8bf0274021ae6ebd8fe4a0e12623d61464c498900b28feb567", + "7988b3a148716ff800414935b305436493e1f25237a2a03e5eebc343735e2f31", + "b3c409b6b0b3aa5e65ab2dc1930534608239a478106acf6f3d9178e9f9b00b35", + "df9bb6de5d3dc59595bcaa676397d837ff49441d211878c024eabda2cd067c9f", + "7da08f856b5956d40a72968f93396f6acff17193f013e8053f6fbb6c08c194d6", + ], +}, +``` + +Po zapisaniu pliku Twoje środowisko programistyczne dApp Hardhat jest połączone z lokalną siecią testową Ethereum! Możesz sprawdzić, czy Twoja sieć testowa działa, uruchamiając: + +```python +npx hardhat balances --network localnet +``` + +Dane wyjściowe powinny wyglądać mniej więcej tak: + +```python +0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766 has balance 10000000000000000000000000 +0x4E9A3d9D1cd2A2b2371b8b3F489aE72259886f1A has balance 10000000000000000000000000 +0xdF8466f277964Bb7a0FFD819403302C34DCD530A has balance 10000000000000000000000000 +0x5c613e39Fc0Ad91AfDA24587e6f52192d75FBA50 has balance 10000000000000000000000000 +0x375ae6107f8cC4cF34842B71C6F746a362Ad8EAc has balance 10000000000000000000000000 +0x1F6298457C5d76270325B724Da5d1953923a6B88 has balance 10000000000000000000000000 +``` + +To potwierdza, że Hardhat korzysta z Twojej lokalnej sieci testowej i wykrywa wstępnie zasilone konta utworzone przez `eth-network-package`. + +### Wdróż i przetestuj swoją dApp lokalnie {#deploy-and-test-dapp} + +Gdy środowisko programistyczne dApp jest w pełni połączone z lokalną siecią testową Ethereum, możesz teraz uruchamiać procesy programistyczne i testowe dla swojej dApp, korzystając z lokalnej sieci testowej. + +Aby skompilować i wdrożyć smart kontrakt `ChipToken.sol` do lokalnego prototypowania i rozwoju, uruchom: + +```python +npx hardhat compile +npx hardhat run scripts/deploy.ts --network localnet +``` + +Dane wyjściowe powinny wyglądać mniej więcej tak: + +```python +ChipToken wdrożono do: 0xAb2A01BC351770D09611Ac80f1DE076D56E0487d +``` + +Teraz spróbuj uruchomić test `simple.js` na swojej lokalnej dApp, aby potwierdzić, że każdemu graczowi w naszej dApp Blackjack zostało wybite 1000 żetonów: + +Dane wyjściowe powinny wyglądać mniej więcej tak: + +```python +npx hardhat test --network localnet +``` + +Dane wyjściowe powinny wyglądać mniej więcej tak: + +```python +ChipToken + wybij + ✔ powinien wybić 1000 żetonów dla GRACZA PIERWSZEGO + + 1 przeszedł (654ms) +``` + +### Podsumowanie {#review-dapp-workflows} + +W tym momencie skonfigurowałeś środowisko programistyczne dApp, połączyłeś je z lokalną siecią Ethereum utworzoną przez Kurtosis oraz skompilowałeś, wdrożyłeś i uruchomiłeś prosty test dla swojej dApp. + +Teraz zbadajmy, jak można skonfigurować podstawową sieć do testowania naszych dapek w różnych konfiguracjach sieci. + +## Konfiguracja lokalnej sieci testowej Ethereum {#configure-testnet} + +### Zmiana konfiguracji klienta i liczby węzłów {#configure-client-config-and-num-nodes} + +Twoją lokalną sieć testową Ethereum można skonfigurować do używania różnych par klientów EL i CL, a także różnej liczby węzłów, w zależności od scenariusza i konkretnej konfiguracji sieci, którą chcesz rozwijać lub testować. Oznacza to, że po skonfigurowaniu możesz uruchomić dostosowaną lokalną sieć testową i używać jej do uruchamiania tych samych procesów (wdrażanie, testy itp.) w różnych konfiguracjach sieci, aby upewnić się, że wszystko działa zgodnie z oczekiwaniami. Aby dowiedzieć się więcej o innych parametrach, które możesz modyfikować, odwiedź ten link. + +Spróbuj! Możesz przekazać różne opcje konfiguracyjne do `eth-network-package` za pośrednictwem pliku JSON. Ten plik JSON z parametrami sieci dostarcza określonych konfiguracji, których Kurtosis użyje do skonfigurowania lokalnej sieci Ethereum. + +Weź domyślny plik konfiguracyjny i edytuj go, aby uruchomić dwa węzły z różnymi parami EL/CL: + +- Węzeł 1 z `geth`/`lighthouse` +- Węzeł 2 z `geth`/`lodestar` +- Węzeł 3 z `geth`/`teku` + +Ta konfiguracja tworzy heterogeniczną sieć implementacji węzłów Ethereum do testowania Twojej dApp. Twój plik konfiguracyjny powinien teraz wyglądać następująco: + +```yaml +{ + "participants": + [ + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lighthouse", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lodestar", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "teku", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + ], + "network_params": + { + "preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete", + "num_validator_keys_per_node": 64, + "network_id": "3151908", + "deposit_contract_address": "0x4242424242424242424242424242424242424242", + "seconds_per_slot": 12, + "genesis_delay": 120, + "capella_fork_epoch": 5, + }, +} +``` + +Każda struktura `participants` odpowiada węzłowi w sieci, więc 3 struktury `participants` poinformują Kurtosis, aby uruchomić 3 węzły w Twojej sieci. Każda struktura `participants` pozwoli Ci określić parę EL i CL używaną dla tego konkretnego węzła. + +Struktura `network_params` konfiguruje ustawienia sieci, które są używane do tworzenia plików genezy dla każdego węzła, a także inne ustawienia, takie jak sekundy na slot sieci. + +Zapisz edytowany plik parametrów w dowolnym katalogu (w poniższym przykładzie jest on zapisany na pulpicie), a następnie użyj go do uruchomienia pakietu Kurtosis, uruchamiając: + +```python +kurtosis clean -a && kurtosis run --enclave local-eth-testnet github.com/kurtosis-tech/eth-network-package \"$(cat ~/eth-network-params.json)\" +``` + +Uwaga: polecenie `kurtosis clean -a` jest tutaj używane, aby poinstruować Kurtosis, aby zniszczył starą sieć testową i jej zawartość przed uruchomieniem nowej. + +Ponownie, Kurtosis będzie działać przez chwilę i wydrukuje poszczególne kroki, które mają miejsce. Ostatecznie, dane wyjściowe powinny wyglądać mniej więcej tak: + +```python +Starlark code successfully run. No output was returned. +INFO[2023-04-07T11:43:16-04:00] ========================================================== +INFO[2023-04-07T11:43:16-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-07T11:43:16-04:00] ========================================================== +Name: local-eth-testnet +UUID: bef8c192008e +Status: RUNNING +Creation Time: Fri, 07 Apr 2023 11:41:58 EDT + +========================================= Files Artifacts ========================================= +UUID Name +cc495a8e364a cl-genesis-data +7033fcdb5471 el-genesis-data +a3aef43fc738 genesis-generation-config-cl +8e968005fc9d genesis-generation-config-el +3182cca9d3cd geth-prefunded-keys +8421166e234f prysm-password +d9e6e8d44d99 validator-keystore-0 +23f5ba517394 validator-keystore-1 +4d28dea40b5c validator-keystore-2 + +========================================== User Services ========================================== +UUID Name Ports Status +485e6fde55ae cl-client-0-beacon http: 4000/tcp -> http://127.0.0.1:65010 RUNNING + metrics: 5054/tcp -> http://127.0.0.1:65011 + tcp-discovery: 9000/tcp -> 127.0.0.1:65012 + udp-discovery: 9000/udp -> 127.0.0.1:54455 +73739bd158b2 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:65016 RUNNING + metrics: 5064/tcp -> http://127.0.0.1:65017 +1b0a233cd011 cl-client-1-beacon http: 4000/tcp -> 127.0.0.1:65021 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65023 + tcp-discovery: 9000/tcp -> 127.0.0.1:65024 + udp-discovery: 9000/udp -> 127.0.0.1:56031 + validator-metrics: 5064/tcp -> 127.0.0.1:65022 +949b8220cd53 cl-client-1-validator http: 4000/tcp -> 127.0.0.1:65028 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65030 + tcp-discovery: 9000/tcp -> 127.0.0.1:65031 + udp-discovery: 9000/udp -> 127.0.0.1:60784 + validator-metrics: 5064/tcp -> 127.0.0.1:65029 +c34417bea5fa cl-client-2 http: 4000/tcp -> 127.0.0.1:65037 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65035 + tcp-discovery: 9000/tcp -> 127.0.0.1:65036 + udp-discovery: 9000/udp -> 127.0.0.1:63581 +e19738e6329d el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:64986 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64988 + tcp-discovery: 30303/tcp -> 127.0.0.1:64987 + udp-discovery: 30303/udp -> 127.0.0.1:55706 + ws: 8546/tcp -> 127.0.0.1:64989 +e904687449d9 el-client-1 engine-rpc: 8551/tcp -> 127.0.0.1:64993 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64995 + tcp-discovery: 30303/tcp -> 127.0.0.1:64994 + udp-discovery: 30303/udp -> 127.0.0.1:58096 + ws: 8546/tcp -> 127.0.0.1:64996 +ad6f401126fa el-client-2 engine-rpc: 8551/tcp -> 127.0.0.1:65003 RUNNING + rpc: 8545/tcp -> 127.0.0.1:65001 + tcp-discovery: 30303/tcp -> 127.0.0.1:65000 + udp-discovery: 30303/udp -> 127.0.0.1:57269 + ws: 8546/tcp -> 127.0.0.1:65002 +12d04a9dbb69 prelaunch-data-generator-1680882122181135513 STOPPED +5b45f9c0504b prelaunch-data-generator-1680882122192182847 STOPPED +3d4aaa75e218 prelaunch-data-generator-1680882122201668972 STOPPED +``` + +Gratulacje! Pomyślnie skonfigurowałeś swoją lokalną sieć testową, aby miała 3 węzły zamiast 1. Aby uruchomić te same procesy, co wcześniej, w swojej dApp (wdrażanie i testowanie), wykonaj te same operacje, co poprzednio, zastępując `<$YOUR_PORT>` w strukturze `localnet` w pliku konfiguracyjnym `hardhat.config.ts` portem z danych wyjściowych rpc uri dowolnej usługi `el-client-` w nowej, 3-węzłowej lokalnej sieci testowej. + +## Wnioski {#conclusion} + +I to wszystko! Podsumowując ten krótki poradnik, Ty: + +- Utworzyłeś lokalną sieć testową Ethereum za pośrednictwem Dockera przy użyciu Kurtosis +- Połączyłeś swoje lokalne środowisko programistyczne dApp z lokalną siecią Ethereum +- Wdrożyłeś dApp i uruchomiłeś prosty test na lokalnej sieci Ethereum +- Skonfigurowałeś podstawową sieć Ethereum, aby miała 3 węzły + +Chcielibyśmy usłyszeć od Ciebie, co poszło Ci dobrze, co można by poprawić, lub odpowiedzieć na wszelkie Twoje pytania. Nie wahaj się skontaktować z nami za pośrednictwem [GitHub](https://github.com/kurtosis-tech/kurtosis/issues/new/choose) lub [napisz do nas e-mail](mailto:feedback@kurtosistech.com)! + +### Inne przykłady i poradniki {#other-examples-guides} + +Zachęcamy do zapoznania się z naszym [szybkim startem](https://docs.kurtosis.com/quickstart) (gdzie zbudujesz bazę danych Postgres i API) oraz innymi przykładami w naszym repozytorium [awesome-kurtosis](https://github.com/kurtosis-tech/awesome-kurtosis), gdzie znajdziesz świetne przykłady, w tym pakiety do: + +- Uruchamiania tej samej lokalnej sieci testowej Ethereum, ale z podłączonymi dodatkowymi usługami, takimi jak spamer transakcji (do symulowania transakcji), monitor forka oraz podłączona instancja Grafana i Prometheus +- Przeprowadzania [testu podsieci](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/ethereum-network-partition-test) na tej samej lokalnej sieci Ethereum diff --git a/public/content/translations/pl/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md b/public/content/translations/pl/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md new file mode 100644 index 00000000000..84a4beaaeb2 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md @@ -0,0 +1,144 @@ +--- +title: "Zmniejszanie kontraktów w walce z limitem rozmiaru kontraktu" +description: "Co możesz zrobić, aby Twoje inteligentne kontrakty nie stały się zbyt duże?" +author: Markus Waas +lang: pl +tags: [ "solidity", "smart kontrakty", "przechowywanie" ] +skill: intermediate +published: 2020-06-26 +source: soliditydeveloper.com +sourceUrl: https://soliditydeveloper.com/max-contract-size +--- + +## Dlaczego istnieje limit? {#why-is-there-a-limit} + +[22 listopada 2016 r.](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/) hard fork Spurious Dragon wprowadził [EIP-170](https://eips.ethereum.org/EIPS/eip-170), który dodał limit rozmiaru inteligentnego kontraktu wynoszący 24,576 kb. Dla Ciebie, jako dewelopera Solidity, oznacza to, że gdy dodajesz coraz więcej funkcjonalności do swojego kontraktu, w pewnym momencie osiągniesz limit i podczas wdrażania zobaczysz błąd: + +`Warning: Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.` + +Limit ten został wprowadzony, aby zapobiegać atakom typu „odmowa usługi” (Denial-of-Service, DOS). Każde wywołanie kontraktu jest stosunkowo tanie pod względem zużycia gazu. Jednak wpływ wywołania kontraktu na węzły Ethereum wzrasta nieproporcjonalnie w zależności od rozmiaru kodu wywoływanego kontraktu (odczytywanie kodu z dysku, wstępne przetwarzanie kodu, dodawanie danych do dowodu Merkle). Zawsze, gdy mamy do czynienia z sytuacją, w której atakujący potrzebuje niewielu zasobów, aby spowodować dużo pracy dla innych, pojawia się potencjalne zagrożenie atakami DOS. + +Początkowo był to mniejszy problem, ponieważ jednym z naturalnych ograniczeń rozmiaru kontraktu jest limit gazu w bloku. Oczywiście kontrakt musi zostać wdrożony w ramach transakcji, która zawiera cały kod bajtowy kontraktu. Jeśli w bloku umieścisz tylko tę jedną transakcję, możesz zużyć cały ten gaz, ale nie jest on nieskończony. Od czasu [aktualizacji London](/ethereum-forks/#london) limit gazu w bloku może wahać się między 15 a 30 milionami jednostek w zależności od zapotrzebowania w sieci. + +W dalszej części przyjrzymy się kilku metodom uporządkowanym według ich potencjalnego wpływu. Pomyśl o tym w kategoriach utraty wagi. Najlepszą strategią na osiągnięcie docelowej wagi (w naszym przypadku 24 kb) jest skupienie się w pierwszej kolejności na metodach o dużym wpływie. W większości przypadków wystarczy zmiana diety, aby osiągnąć cel, ale czasami potrzeba czegoś więcej. Wtedy możesz dodać trochę ćwiczeń (średni wpływ), a nawet suplementy (mały wpływ). + +## Duży wpływ {#big-impact} + +### Oddziel swoje kontrakty {#separate-your-contracts} + +To powinno być zawsze Twoje pierwsze podejście. Jak możesz podzielić kontrakt na kilka mniejszych? Zazwyczaj zmusza to do opracowania dobrej architektury dla swoich kontraktów. Mniejsze kontrakty są zawsze preferowane z perspektywy czytelności kodu. Aby podzielić kontrakty, zadaj sobie pytanie: + +- Które funkcje pasują do siebie? Każdy zestaw funkcji może najlepiej pasować do osobnego kontraktu. +- Które funkcje nie wymagają odczytywania stanu kontraktu lub tylko określonego podzbioru stanu? +- Czy możesz rozdzielić przechowywanie i funkcjonalność? + +### Biblioteki {#libraries} + +Jednym z prostych sposobów na przeniesienie kodu funkcjonalności z dala od miejsca przechowywania danych jest użycie [biblioteki](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#libraries). Nie deklaruj funkcji biblioteki jako wewnętrznych (internal), ponieważ zostaną one [dodane do kontraktu](https://ethereum.stackexchange.com/questions/12975/are-internal-functions-in-libraries-not-covered-by-linking) bezpośrednio podczas kompilacji. Ale jeśli używasz funkcji publicznych (public), to w rzeczywistości znajdą się one w osobnym kontrakcie bibliotecznym. Rozważ użycie [`using for`](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#using-for), aby uczynić korzystanie z bibliotek wygodniejszym. + +### Proxy {#proxies} + +Bardziej zaawansowaną strategią jest system proxy. Biblioteki używają w tle `DELEGATECALL`, który po prostu wykonuje funkcję innego kontraktu w kontekście stanu kontraktu wywołującego. Zapoznaj się z [tym wpisem na blogu](https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2), aby dowiedzieć się więcej o systemach proxy. Dają one więcej funkcjonalności, np. umożliwiają aktualizację, ale dodają też sporo złożoności. Nie dodawałbym ich tylko po to, aby zmniejszyć rozmiar kontraktu, chyba że z jakiegoś powodu jest to jedyna dostępna opcja. + +## Średni wpływ {#medium-impact} + +### Usuń funkcje {#remove-functions} + +To powinno być oczywiste. Funkcje znacznie zwiększają rozmiar kontraktu. + +- **Zewnętrzne (External)**: Często dla wygody dodajemy wiele funkcji typu view. Jest to w porządku, dopóki nie osiągniesz limitu rozmiaru. Wtedy warto poważnie zastanowić się nad usunięciem wszystkich funkcji oprócz tych absolutnie niezbędnych. +- **Wewnętrzne (Internal)**: Możesz także usunąć funkcje wewnętrzne/prywatne i po prostu wstawić kod w miejscu wywołania, o ile funkcja jest wywoływana tylko raz. + +### Unikaj dodatkowych zmiennych {#avoid-additional-variables} + +```solidity +function get(uint id) returns (address,address) { + MyStruct memory myStruct = myStructs[id]; + return (myStruct.addr1, myStruct.addr2); +} +``` + +```solidity +function get(uint id) returns (address,address) { + return (myStructs[id].addr1, myStructs[id].addr2); +} +``` + +Prosta zmiana, taka jak ta, robi różnicę **0,28 kb**. Istnieje szansa, że znajdziesz wiele podobnych sytuacji w swoich kontraktach, a te mogą zsumować się do znacznych oszczędności. + +### Skróć komunikaty o błędach {#shorten-error-message} + +Długie komunikaty `revert` i w szczególności wiele różnych komunikatów `revert` może niepotrzebnie zwiększać rozmiar kontraktu. Zamiast tego użyj krótkich kodów błędów i dekoduj je w swojej aplikacji. Długi komunikat może stać się znacznie krótszy: + +```solidity +require(msg.sender == owner, "Tylko właściciel tego kontraktu może wywołać tę funkcję"); +``` + +```solidity +require(msg.sender == owner, "OW1"); +``` + +### Używaj niestandardowych błędów zamiast komunikatów o błędach + +Niestandardowe błędy zostały wprowadzone w [Solidity 0.8.4](https://blog.soliditylang.org/2021/04/21/custom-errors/). Są świetnym sposobem na zmniejszenie rozmiaru Twoich kontraktów, ponieważ są kodowane w ABI jako selektory (tak jak funkcje). + +```solidity +error Unauthorized(); + +if (msg.sender != owner) { + revert Unauthorized(); +} +``` + +### Rozważ niską wartość „runs” w optymalizatorze {#consider-a-low-run-value-in-the-optimizer} + +Możesz również zmienić ustawienia optymalizatora. Domyślna wartość 200 oznacza, że próbuje on zoptymalizować kod bajtowy tak, jakby funkcja była wywoływana 200 razy. Jeśli zmienisz tę wartość na 1, w zasadzie mówisz optymalizatorowi, aby optymalizował pod kątem jednokrotnego uruchomienia każdej funkcji. Funkcja zoptymalizowana pod kątem jednokrotnego uruchomienia oznacza, że jest zoptymalizowana pod kątem samego wdrożenia. Pamiętaj, że **zwiększa to [koszty gazu](/developers/docs/gas/) za uruchamianie funkcji**, więc możesz nie chcieć tego robić. + +## Mały wpływ {#small-impact} + +### Unikaj przekazywania struktur do funkcji {#avoid-passing-structs-to-functions} + +Jeśli używasz [ABIEncoderV2](https://solidity.readthedocs.io/en/v0.6.10/layout-of-source-files.html#abiencoderv2), pomocne może być nieprzekazywanie struktur do funkcji. Zamiast przekazywać parametr jako strukturę, przekaż wymagane parametry bezpośrednio. W tym przykładzie zaoszczędziliśmy kolejne **0,1 kb**. + +```solidity +function get(uint id) returns (address,address) { + return _get(myStruct); +} + +function _get(MyStruct memory myStruct) private view returns(address,address) { + return (myStruct.addr1, myStruct.addr2); +} +``` + +```solidity +function get(uint id) returns(address,address) { + return _get(myStructs[id].addr1, myStructs[id].addr2); +} + +function _get(address addr1, address addr2) private view returns(address,address) { + return (addr1, addr2); +} +``` + +### Deklaruj poprawną widoczność dla funkcji i zmiennych {#declare-correct-visibility-for-functions-and-variables} + +- Funkcje lub zmienne, które są wywoływane tylko z zewnątrz? Deklaruj je jako `external` zamiast `public`. +- Funkcje lub zmienne wywoływane tylko z wnętrza kontraktu? Deklaruj je jako `private` lub `internal` zamiast `public`. + +### Usuń modyfikatory {#remove-modifiers} + +Modyfikatory, zwłaszcza gdy są intensywnie używane, mogą mieć znaczący wpływ na rozmiar kontraktu. Rozważ ich usunięcie i zamiast tego użyj funkcji. + +```solidity +modifier checkStuff() {} + +function doSomething() checkStuff {} +``` + +```solidity +function checkStuff() private {} + +function doSomething() { checkStuff(); } +``` + +Te wskazówki powinny pomóc znacznie zmniejszyć rozmiar kontraktu. Jeszcze raz podkreślam, zawsze skupiaj się na dzieleniu kontraktów, jeśli to możliwe, aby uzyskać największy efekt. diff --git a/public/content/translations/pl/developers/tutorials/eip-1271-smart-contract-signatures/index.md b/public/content/translations/pl/developers/tutorials/eip-1271-smart-contract-signatures/index.md new file mode 100644 index 00000000000..d2f6304813f --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/eip-1271-smart-contract-signatures/index.md @@ -0,0 +1,129 @@ +--- +title: "EIP-1271: Podpisywanie i weryfikowanie podpisów inteligentnych kontraktów" +description: "Omówienie generowania i weryfikacji podpisów inteligentnych kontraktów za pomocą EIP-1271. Omawiamy również implementację EIP-1271 stosowaną w Safe (dawniej Gnosis Safe), aby dać deweloperom inteligentnych kontraktów konkretny przykład, na którym mogą się wzorować." +author: Nathan H. Leung +lang: pl +tags: + [ + "eip-1271", + "smart kontrakty", + "weryfikacja", + "podpisywanie" + ] +skill: intermediate +published: 2023-01-12 +--- + +Standard [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) pozwala inteligentnym kontraktom weryfikować podpisy. + +W tym samouczku przedstawiamy przegląd podpisów cyfrowych, tło EIP-1271 oraz specyficzną implementację EIP-1271 używaną przez [Safe](https://safe.global/) (wcześniej Gnosis Safe). Wszystko to może posłużyć jako punkt wyjścia do implementacji EIP-1271 w Twoich własnych kontraktach. + +## Czym jest podpis? + +W tym kontekście podpis (a dokładniej „podpis cyfrowy”) to komunikat oraz pewnego rodzaju dowód, że komunikat pochodzi od określonej osoby/nadawcy/adresu. + +Na przykład podpis cyfrowy może wyglądać tak: + +1. Komunikat: „Chcę zalogować się do tej witryny za pomocą mojego portfela Ethereum”. +2. Podpisujący: Mój adres to `0x000…` +3. Dowód: Oto dowód na to, że ja, `0x000...`, faktycznie stworzyłem cały ten komunikat (zazwyczaj jest to coś kryptograficznego). + +Należy pamiętać, że podpis cyfrowy zawiera zarówno „komunikat”, jak i „podpis”. + +Dlaczego? Na przykład, gdybyś dał mi umowę do podpisania, a ja odciąłbym stronę z podpisem i oddał Ci tylko moje podpisy bez reszty umowy, umowa nie byłaby ważna. + +W ten sam sposób podpis cyfrowy nic nie znaczy bez powiązanego z nim komunikatu! + +## Dlaczego EIP-1271 istnieje? + +Aby utworzyć podpis cyfrowy do użytku w blockchainach opartych na Ethereum, zazwyczaj potrzebny jest tajny klucz prywatny, którego nikt inny nie zna. To właśnie sprawia, że Twój podpis jest Twój (nikt inny nie może stworzyć tego samego podpisu bez znajomości tajnego klucza). + +Twoje konto Ethereum (tj. konto zewnętrznego właściciela/EOA) ma przypisany do niego klucz prywatny i to właśnie ten klucz prywatny jest zazwyczaj używany, gdy strona internetowa lub dapka prosi o podpis (np. przy „Zaloguj się z Ethereum”). + +Aplikacja może [zweryfikować podpis](https://www.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum), który tworzysz za pomocą biblioteki zewnętrznej, takiej jak ethers.js, [bez znajomości Twojego klucza prywatnego](https://en.wikipedia.org/wiki/Public-key_cryptography) i mieć pewność, że to _Ty_ go stworzyłeś. + +> W rzeczywistości, ponieważ podpisy cyfrowe EOA wykorzystują kryptografię klucza publicznego, mogą być generowane i weryfikowane **offchain**! Tak działa bezgazowe głosowanie DAO — zamiast przesyłania głosów onchain, podpisy cyfrowe mogą być tworzone i weryfikowane offchain za pomocą bibliotek kryptograficznych. + +Podczas gdy konta EOA posiadają klucz prywatny, konta inteligentnych kontraktów nie posiadają żadnego rodzaju klucza prywatnego ani tajnego (więc "Zaloguj się za pomocą Ethereum", itp. nie może natywnie działać z kontami inteligentnych kontraktów). + +Problem, który EIP-1271 ma na celu rozwiązać: skąd możemy wiedzieć, że podpis inteligentnego kontraktu jest ważny, jeśli inteligentny kontrakt nie ma "tajemnicy", którą mógłby włączyć do podpisu? + +## Jak działa EIP-1271? + +Inteligentne kontrakty nie mają kluczy prywatnych, których można użyć do podpisywania komunikatów. Skąd więc możemy wiedzieć, czy podpis jest autentyczny? + +Cóż, jednym z pomysłów jest to, że możemy po prostu _zapytać_ inteligentny kontrakt, czy podpis jest autentyczny! + +EIP-1271 standaryzuje ideę „pytania” inteligentnego kontraktu, czy dany podpis jest ważny. + +Kontrakt, który implementuje EIP-1271, musi mieć funkcję o nazwie `isValidSignature`, która przyjmuje komunikat i podpis. Kontrakt może następnie uruchomić pewną logikę walidacji (specyfikacja nie narzuca tutaj niczego konkretnego), a następnie zwrócić wartość wskazującą, czy podpis jest ważny, czy nie. + +Jeśli `isValidSignature` zwróci prawidłowy wynik, to jest to prawie tak, jakby kontrakt mówił: "tak, zatwierdzam ten podpis + komunikat!". + +### Interfejs + +Oto dokładny interfejs w specyfikacji EIP-1271 (o parametrze `_hash` porozmawiamy poniżej, ale na razie pomyśl o nim jako o weryfikowanym komunikacie): + +```jsx +pragma solidity ^0.5.0; + +contract ERC1271 { + + // bytes4(keccak256("isValidSignature(bytes32,bytes)") + bytes4 constant internal MAGICVALUE = 0x1626ba7e; + + /** + * @dev Powinna zwrócić, czy podany podpis jest ważny dla podanego haszu + * @param _hash Hasz danych do podpisania + * @param _signature Tablica bajtów podpisu powiązana z _hasz + * + * MUSI zwrócić magiczną wartość bytes4 0x1626ba7e, gdy funkcja przejdzie pomyślnie. + * NIE MOŻE modyfikować stanu (używając STATICCALL dla solc < 0.5, modyfikator view dla solc > 0.5) + * MUSI zezwalać na wywołania zewnętrzne + */ + function isValidSignature( + bytes32 _hash, + bytes memory _signature) + public + view + returns (bytes4 magicValue); +} +``` + +## Przykładowa implementacja EIP-1271: Safe + +Kontrakty mogą implementować `isValidSignature` na wiele sposobów – specyfikacja nie mówi wiele o dokładnej implementacji. + +Jednym z godnych uwagi kontraktów, który implementuje EIP-1271, jest Safe (wcześniej Gnosis Safe). + +W kodzie Safe `isValidSignature` [jest zaimplementowane](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol) tak, że podpisy mogą być tworzone i weryfikowane na [dwa sposoby](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support): + +1. Komunikaty onchain + 1. Tworzenie: właściciel Safe tworzy nową transakcję Safe, aby „podpisać” komunikat, przekazując go jako dane do transakcji. Gdy wystarczająca liczba właścicieli podpisze transakcję, aby osiągnąć próg multisig, transakcja jest rozgłaszana i uruchamiana. W transakcji jest funkcja Safe o nazwie (`signMessage(bytes calldata _data)`), która dodaje komunikat do listy "zatwierdzonych" komunikatów. + 2. Weryfikacja: wywołaj `isValidSignature` w kontrakcie Safe i przekaż komunikat do weryfikacji jako parametr komunikatu oraz [pustą wartość dla parametru podpisu](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32) (tj. `0x`). Safe zobaczy, że parametr podpisu jest pusty i zamiast kryptograficznie weryfikować podpis, będzie wiedział, żeby po prostu sprawdzić, czy komunikat znajduje się na liście "zatwierdzonych" komunikatów. +2. Komunikaty offchain: + 1. Tworzenie: właściciel Safe tworzy komunikat offchain, a następnie prosi innych właścicieli Safe o indywidualne podpisanie komunikatu, dopóki nie będzie wystarczającej liczby podpisów, aby przekroczyć próg zatwierdzenia multisig. + 2. Weryfikacja: wywołaj `isValidSignature`. W parametrze komunikatu przekaż komunikat do zweryfikowania. W parametrze podpisu przekaż połączone ze sobą indywidualne podpisy każdego właściciela Safe, jeden po drugim. Safe sprawdzi, czy jest wystarczająco dużo podpisów, aby osiągnąć próg **oraz** czy każdy podpis jest ważny. Jeśli tak, zwróci wartość wskazującą pomyślną weryfikację podpisu. + +## Czym dokładnie jest parametr `_hash`? Dlaczego nie przekazać całego komunikatu? + +Być może zauważyłeś, że funkcja `isValidSignature` w [interfejsie EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) nie przyjmuje samego komunikatu, ale parametr `_hash`. Oznacza to, że zamiast przekazywać do `isValidSignature` pełny komunikat o dowolnej długości, przekazujemy 32-bajtowy hasz komunikatu (zazwyczaj keccak256). + +Każdy bajt calldata – tj. dane parametrów funkcji przekazywane do funkcji inteligentnego kontraktu – [kosztuje 16 jednostek gazu (4 jednostki gazu w przypadku bajtu zerowego)](https://eips.ethereum.org/EIPS/eip-2028), więc może to zaoszczędzić dużo gazu, jeśli komunikat jest długi. + +### Poprzednie specyfikacje EIP-1271 + +Istnieją specyfikacje EIP-1271, które mają funkcję `isValidSignature` z pierwszym parametrem typu `bytes` (o dowolnej długości, zamiast o stałej długości `bytes32`) i nazwą parametru `message`. Jest to [starsza wersja](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206) standardu EIP-1271. + +## Jak EIP-1271 powinien być zaimplementowany w moich własnych kontraktach? + +Specyfikacja jest w tym zakresie bardzo otwarta. Implementacja Safe zawiera kilka dobrych pomysłów: + +- Można uznać podpisy EOA od "właściciela" kontraktu za ważne. +- Można przechowywać listę zatwierdzonych komunikatów i tylko je uważać za ważne. + +Ostatecznie zależy to od Ciebie jako dewelopera kontraktu! + +## Podsumowanie + +[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) to wszechstronny standard, który pozwala inteligentnym kontraktom weryfikować podpisy. Otwiera to drzwi do tego, aby inteligentne kontrakty działały bardziej jak EOA – na przykład zapewniając sposób na działanie "Logowania za pomocą Ethereum" z inteligentnymi kontraktami – i może być wdrażany na wiele sposobów (Safe ma nietrywialną, interesującą implementację do rozważenia). diff --git a/public/content/translations/pl/developers/tutorials/erc-721-vyper-annotated-code/index.md b/public/content/translations/pl/developers/tutorials/erc-721-vyper-annotated-code/index.md new file mode 100644 index 00000000000..cd2a07345b7 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/erc-721-vyper-annotated-code/index.md @@ -0,0 +1,713 @@ +--- +title: "Omówienie kontraktu ERC-721 w języku Vyper" +description: "Kontrakt ERC-721 Ryuyi Nakamury i jego działanie" +author: Ori Pomerantz +lang: pl +tags: [ "vyper", "erc-721", "python" ] +skill: beginner +published: 2021-04-01 +--- + +## Wprowadzenie {#introduction} + +Standard [ERC-721](/developers/docs/standards/tokens/erc-721/) służy do przechowywania własności niewymienialnych tokenów (NFT). +Tokeny [ERC-20](/developers/docs/standards/tokens/erc-20/) zachowują się jak towar, ponieważ nie ma różnicy między poszczególnymi tokenami. +W przeciwieństwie do nich tokeny ERC-721 są przeznaczone dla aktywów, które są podobne, ale nie identyczne, takich jak różne [kreskówki z kotami](https://www.cryptokitties.co/) +lub tytuły własności do różnych nieruchomości. + +W tym artykule przeanalizujemy [kontrakt ERC-721 Ryuyi Nakamury](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy). +Ten kontrakt jest napisany w [Vyper](https://vyper.readthedocs.io/en/latest/index.html), języku programowania kontraktów podobnym do Pythona, zaprojektowanym tak, aby trudniej było w nim napisać niebezpieczny kod niż w Solidity. + +## Kontrakt {#contract} + +```python +# @dev Implementacja standardu niewymienialnych tokenów ERC-721. +# @author Ryuya Nakamura (@nrryuya) +# Zmodyfikowano na podstawie: https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy +``` + +Komentarze w Vyper, podobnie jak w Pythonie, zaczynają się od hasza (`#`) i trwają do końca linii. Komentarze zawierające +`@` są używane przez [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) do tworzenia czytelnej dla człowieka +dokumentacji. + +```python +from vyper.interfaces import ERC721 + +implements: ERC721 +``` + +Interfejs ERC-721 jest wbudowany w język Vyper. +[Definicję kodu można zobaczyć tutaj](https://github.com/vyperlang/vyper/blob/master/vyper/builtin_interfaces/ERC721.py). +Definicja interfejsu jest napisana w Pythonie, a nie w Vyper, ponieważ interfejsy są używane nie tylko w ramach +blockchainu, ale także podczas wysyłania transakcji do blockchainu z zewnętrznego klienta, który może być napisany w +Pythonie. + +Pierwsza linia importuje interfejs, a druga określa, że go tutaj implementujemy. + +### Interfejs ERC721Receiver {#receiver-interface} + +```python +# Interfejs dla kontraktu wywoływanego przez safeTransferFrom() +interface ERC721Receiver: + def onERC721Received( +``` + +ERC-721 obsługuje dwa rodzaje transferów: + +- `transferFrom`, który pozwala nadawcy określić dowolny adres docelowy i przenosi odpowiedzialność + za transfer na nadawcę. Oznacza to, że można dokonać transferu na nieprawidłowy adres, w takim przypadku + NFT zostanie utracony na zawsze. +- `safeTransferFrom`, który sprawdza, czy adres docelowy jest kontraktem. Jeśli tak, kontrakt ERC-721 + pyta kontrakt odbierający, czy chce otrzymać NFT. + +Aby odpowiedzieć na żądania `safeTransferFrom`, kontrakt odbierający musi zaimplementować `ERC721Receiver`. + +```python + _operator: address, + _from: address, +``` + +Adres `_from` to obecny właściciel tokena. Adres `_operator` to ten, który +zażądał transferu (te dwa adresy mogą nie być takie same ze względu na pozwolenia). + +```python + _tokenId: uint256, +``` + +Identyfikatory tokenów ERC-721 mają 256 bitów. Zazwyczaj są one tworzone poprzez haszowanie opisu tego, co +reprezentuje dany token. + +```python + _data: Bytes[1024] +``` + +Żądanie może zawierać do 1024 bajtów danych użytkownika. + +```python + ) -> bytes32: view +``` + +Aby zapobiec przypadkom, w których kontrakt przypadkowo akceptuje transfer, wartość zwracana nie jest wartością logiczną (boolean), +ale 256 bitami o określonej wartości. + +Ta funkcja jest typu `view`, co oznacza, że może odczytywać stan blockchaina, ale nie może go modyfikować. + +### Zdarzenia {#events} + +[Zdarzenia](https://media.consensys.net/technical-introduction-to-events-and-logs-in-ethereum-a074d65dd61e) +są emitowane w celu informowania użytkowników i serwerów spoza blockchaina o zdarzeniach. Należy pamiętać, że zawartość zdarzeń +nie jest dostępna dla kontraktów na blockchainie. + +```python +# @dev Emitowane, gdy własność dowolnego NFT zmienia się w wyniku dowolnego mechanizmu. To zdarzenie jest emitowane, gdy NFT są +# tworzone (`from` == 0) i niszczone (`to` == 0). Wyjątek: podczas tworzenia kontraktu dowolna +# liczba NFT może zostać utworzona i przypisana bez emitowania zdarzenia Transfer. W momencie dowolnego +# transferu zatwierdzony adres dla tego NFT (jeśli istnieje) jest resetowany do zera. +# @param _from Nadawca NFT (jeśli adres jest adresem zerowym, oznacza to utworzenie tokena). +# @param _to Odbiorca NFT (jeśli adres jest adresem zerowym, oznacza to zniszczenie tokena). +# @param _tokenId NFT, które zostało przetransferowane. +event Transfer: + sender: indexed(address) + receiver: indexed(address) + tokenId: indexed(uint256) +``` + +Jest to podobne do zdarzenia Transfer w ERC-20, z tym wyjątkiem, że zamiast kwoty podajemy `tokenId`. +Nikt nie jest właścicielem adresu zerowego, więc umownie używamy go do zgłaszania tworzenia i niszczenia tokenów. + +```python +# @dev Emitowane, gdy zatwierdzony adres dla NFT jest zmieniany lub ponownie zatwierdzany. Adres zerowy +# oznacza, że nie ma zatwierdzonego adresu. Kiedy emitowane jest zdarzenie Transfer, oznacza to również, +# że zatwierdzony adres dla tego NFT (jeśli istnieje) jest resetowany do zera. +# @param _owner Właściciel NFT. +# @param _approved Adres, który zatwierdzamy. +# @param _tokenId NFT, które zatwierdzamy. +event Approval: + owner: indexed(address) + approved: indexed(address) + tokenId: indexed(uint256) +``` + +Zatwierdzenie ERC-721 jest podobne do pozwolenia (allowance) w ERC-20. Określony adres ma pozwolenie na transfer określonego +tokena. Daje to mechanizm, dzięki któremu kontrakty mogą reagować na przyjęcie tokena. Kontrakty nie mogą +nasłuchiwać zdarzeń, więc jeśli po prostu prześlesz im token, nie będą o tym „wiedziały”. W ten sposób +właściciel najpierw przesyła zatwierdzenie, a następnie wysyła żądanie do kontraktu: „Zatwierdziłem transfer tokena +X, proszę go wykonać...”. + +Jest to wybór projektowy mający na celu upodobnienie standardu ERC-721 do standardu ERC-20. Ponieważ +tokeny ERC-721 nie są wymienialne, kontrakt może również zidentyfikować, że otrzymał określony token, sprawdzając +jego własność. + +```python +# @dev Emitowane, gdy operator jest włączany lub wyłączany dla właściciela. Operator może zarządzać +# wszystkimi NFT właściciela. +# @param _owner Właściciel NFT. +# @param _operator Adres, któremu ustawiamy uprawnienia operatora. +# @param _approved Status uprawnień operatora (true, jeśli uprawnienia operatora są nadane, a false, jeśli +# cofnięte). +event ApprovalForAll: + owner: indexed(address) + operator: indexed(address) + approved: bool +``` + +Czasami przydatne jest posiadanie _operatora_, który może zarządzać wszystkimi tokenami konta określonego typu (tymi, którymi zarządza określony kontrakt), podobnie jak pełnomocnictwo. Na przykład mogę chcieć nadać takie uprawnienie kontraktowi, który sprawdza, czy +nie kontaktowałem się z nim przez sześć miesięcy, a jeśli tak, to rozdziela moje aktywa między moich spadkobierców (jeśli jeden z nich o to poprosi; kontrakty +nie mogą nic zrobić bez wywołania przez transakcję). W ERC-20 możemy po prostu dać wysokie pozwolenie kontraktowi spadkowemu, +ale to nie działa w przypadku ERC-721, ponieważ tokeny nie są wymienialne. To jest odpowiednik. + +Wartość `approved` mówi nam, czy zdarzenie dotyczy zatwierdzenia, czy cofnięcia zatwierdzenia. + +### Zmienne stanu {#state-vars} + +Zmienne te zawierają aktualny stan tokenów: które z nich są dostępne i kto je posiada. Większość z nich +to obiekty `HashMap`, [jednokierunkowe mapowania, które istnieją między dwoma typami](https://vyper.readthedocs.io/en/latest/types.html#mappings). + +```python +# @dev Mapowanie z ID NFT na adres, który jest jego właścicielem. +idToOwner: HashMap[uint256, address] + +# @dev Mapowanie z ID NFT na zatwierdzony adres. +idToApprovals: HashMap[uint256, address] +``` + +Tożsamości użytkowników i kontraktów w Ethereum są reprezentowane przez 160-bitowe adresy. Te dwie zmienne mapują +identyfikatory tokenów do ich właścicieli i osób zatwierdzonych do ich transferu (maksymalnie jedna na każdy token). W Ethereum +niezainicjowane dane są zawsze zerowe, więc jeśli nie ma właściciela lub zatwierdzonego podmiotu transferującego, wartość dla danego tokena +jest zerowa. + +```python +# @dev Mapowanie adresu właściciela na liczbę jego tokenów. +ownerToNFTokenCount: HashMap[address, uint256] +``` + +Ta zmienna przechowuje liczbę tokenów dla każdego właściciela. Nie ma mapowania z właścicieli na tokeny, więc +jedynym sposobem na zidentyfikowanie tokenów, które posiada dany właściciel, jest prześledzenie historii zdarzeń w blockchainie +i odnalezienie odpowiednich zdarzeń `Transfer`. Możemy użyć tej zmiennej, aby wiedzieć, kiedy mamy wszystkie NFT i nie +musimy szukać dalej w czasie. + +Należy pamiętać, że ten algorytm działa tylko w przypadku interfejsów użytkownika i serwerów zewnętrznych. Kod działający na samym +blockchainie nie może odczytywać przeszłych zdarzeń. + +```python +# @dev Mapowanie adresu właściciela na mapowanie adresów operatorów. +ownerToOperators: HashMap[address, HashMap[address, bool]] +``` + +Konto może mieć więcej niż jednego operatora. Prosta `HashMap` jest niewystarczająca, aby +je śledzić, ponieważ każdy klucz prowadzi do pojedynczej wartości. Zamiast tego jako wartości można użyć +`HashMap[address, bool]`. Domyślnie wartość dla każdego adresu to `False`, co oznacza, że +nie jest on operatorem. W razie potrzeby można ustawić wartości na `True`. + +```python +# @dev Adres mintera (podmiotu wybijającego), który może wybić token +minter: address +``` + +Nowe tokeny muszą być w jakiś sposób tworzone. W tym kontrakcie jest jeden podmiot, który ma do tego prawo, czyli +`minter`. To prawdopodobnie wystarczy na przykład w przypadku gry. Do innych celów może być konieczne +stworzenie bardziej skomplikowanej logiki biznesowej. + +```python +# @dev Mapowanie ID interfejsu na wartość boolowską informującą, czy jest on obsługiwany +supportedInterfaces: HashMap[bytes32, bool] + +# @dev ID interfejsu ERC165 dla ERC165 +ERC165_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7 + +# @dev ID interfejsu ERC165 dla ERC721 +ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000080ac58cd +``` + +[ERC-165](https://eips.ethereum.org/EIPS/eip-165) określa mechanizm, dzięki któremu kontrakt może ujawnić, w jaki sposób aplikacje +mogą się z nim komunikować, a także z którymi standardami ERC jest zgodny. W tym przypadku kontrakt jest zgodny z ERC-165 i ERC-721. + +### Funkcje {#functions} + +To są funkcje, które faktycznie implementują ERC-721. + +#### Konstruktor {#constructor} + +```python +@external +def __init__(): +``` + +W Vyper, podobnie jak w Pythonie, funkcja konstruktora nazywa się `__init__`. + +```python + """ + @dev Konstruktor kontraktu. + """ +``` + +W Pythonie i w Vyper można również utworzyć komentarz, określając wieloliniowy ciąg znaków (który zaczyna się i kończy +na `"""`) i nie używając go w żaden sposób. Te komentarze mogą również zawierać +[NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html). + +```python + self.supportedInterfaces[ERC165_INTERFACE_ID] = True + self.supportedInterfaces[ERC721_INTERFACE_ID] = True + self.minter = msg.sender +``` + +Aby uzyskać dostęp do zmiennych stanu, użyj `self.` (ponownie, tak samo jak w Pythonie). + +#### Funkcje widoku {#views} + +Są to funkcje, które nie modyfikują stanu blockchaina, a zatem mogą być wykonywane za +darmo, jeśli są wywoływane z zewnątrz. Jeśli funkcje widoku są wywoływane przez kontrakt, nadal muszą być wykonane na +każdym węźle i dlatego kosztują gaz. + +```python +@view +@external +``` + +Te słowa kluczowe przed definicją funkcji, które zaczynają się od znaku „małpy” (`@`), nazywane są _dekoratorami_. Określają +one okoliczności, w których funkcja może być wywołana. + +- `@view` określa, że ta funkcja jest widokiem. +- `@external` określa, że ta konkretna funkcja może być wywoływana przez transakcje i przez inne kontrakty. + +```python +def supportsInterface(_interfaceID: bytes32) -> bool: +``` + +W przeciwieństwie do Pythona Vyper jest [językiem z typowaniem statycznym](https://wikipedia.org/wiki/Type_system#Static_type_checking). +Nie można zadeklarować zmiennej ani parametru funkcji bez zidentyfikowania [typu danych](https://vyper.readthedocs.io/en/latest/types.html). W tym przypadku parametrem wejściowym jest `bytes32`, wartość 256-bitowa +(256 bitów to natywny rozmiar słowa [Wirtualnej Maszyny Ethereum](/developers/docs/evm/)). Wyjściem jest wartość logiczna +(boolean). Zgodnie z konwencją nazwy parametrów funkcji zaczynają się od podkreślenia (`_`). + +```python + """ + @dev Identyfikacja interfejsu jest określona w ERC-165. + @param _interfaceID Id interfejsu + """ + return self.supportedInterfaces[_interfaceID] +``` + +Zwraca wartość z HashMap `self.supportedInterfaces`, która jest ustawiana w konstruktorze (`__init__`). + +```python +### FUNKCJE WIDOKU ### + +``` + +Są to funkcje widoku, które udostępniają informacje o tokenach użytkownikom i innym kontraktom. + +```python +@view +@external +def balanceOf(_owner: address) -> uint256: + """ + @dev Zwraca liczbę NFT posiadanych przez `_owner`. + Zgłasza błąd, jeśli `_owner` jest adresem zerowym. NFT przypisane do adresu zerowego są uważane za nieprawidłowe. + @param _owner Adres, dla którego należy sprawdzić saldo. + """ + assert _owner != ZERO_ADDRESS +``` + +Ta linia [stwierdza](https://vyper.readthedocs.io/en/latest/statements.html#assert), że `_owner` nie jest +zerowy. Jeśli tak jest, występuje błąd, a operacja jest cofana. + +```python + return self.ownerToNFTokenCount[_owner] + +@view +@external +def ownerOf(_tokenId: uint256) -> address: + """ + @dev Zwraca adres właściciela NFT. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + @param _tokenId Identyfikator NFT. + """ + owner: address = self.idToOwner[_tokenId] + # Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT + assert owner != ZERO_ADDRESS + return owner +``` + +W Wirtualnej Maszynie Ethereum (EVM) każda pamięć, w której nie jest przechowywana żadna wartość, jest zerowa. +Jeśli nie ma tokena pod `_tokenId`, to wartość `self.idToOwner[_tokenId]` wynosi zero. W takim +przypadku funkcja jest cofana. + +```python +@view +@external +def getApproved(_tokenId: uint256) -> address: + """ + @dev Pobiera zatwierdzony adres dla pojedynczego NFT. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + @param _tokenId ID NFT, którego zatwierdzenie ma być sprawdzone. + """ + # Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT + assert self.idToOwner[_tokenId] != ZERO_ADDRESS + return self.idToApprovals[_tokenId] +``` + +Należy pamiętać, że `getApproved` _może_ zwrócić zero. Jeśli token jest prawidłowy, zwraca `self.idToApprovals[_tokenId]`. +Jeśli nie ma podmiotu zatwierdzającego, ta wartość wynosi zero. + +```python +@view +@external +def isApprovedForAll(_owner: address, _operator: address) -> bool: + """ + @dev Sprawdza, czy `_operator` jest zatwierdzonym operatorem dla `_owner`. + @param _owner Adres, który jest właścicielem NFT. + @param _operator Adres, który działa w imieniu właściciela. + """ + return (self.ownerToOperators[_owner])[_operator] +``` + +Ta funkcja sprawdza, czy `_operator` ma prawo zarządzać wszystkimi tokenami `_owner` w tym kontrakcie. +Ponieważ może istnieć wielu operatorów, jest to dwupoziomowa mapa HashMap. + +#### Funkcje pomocnicze transferu {#transfer-helpers} + +Funkcje te implementują operacje, które są częścią transferu lub zarządzania tokenami. + +```python + +### FUNKCJE POMOCNICZE TRANSFERU ### + +@view +@internal +``` + +Ten dekorator, `@internal`, oznacza, że funkcja jest dostępna tylko z innych funkcji w tym +samym kontrakcie. Zgodnie z konwencją te nazwy funkcji również zaczynają się od podkreślenia (`_`). + +```python +def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool: + """ + @dev Zwraca informację, czy dany podmiot wydający może przetransferować dany identyfikator tokena + @param spender adres podmiotu wydającego do zapytania + @param tokenId identyfikator uint256 tokena do przetransferowania + @return bool, czy msg.sender jest zatwierdzony dla danego identyfikatora tokena, + jest operatorem właściciela lub jest właścicielem tokena + """ + owner: address = self.idToOwner[_tokenId] + spenderIsOwner: bool = owner == _spender + spenderIsApproved: bool = _spender == self.idToApprovals[_tokenId] + spenderIsApprovedForAll: bool = (self.ownerToOperators[owner])[_spender] + return (spenderIsOwner or spenderIsApproved) or spenderIsApprovedForAll +``` + +Istnieją trzy sposoby, w jakie adres może być uprawniony do transferu tokena: + +1. Adres jest właścicielem tokena +2. Adres jest zatwierdzony do wydania tego tokena +3. Adres jest operatorem dla właściciela tokena + +Powyższa funkcja może być widokiem, ponieważ nie zmienia stanu. Aby obniżyć koszty operacyjne, każda +funkcja, która _może_ być widokiem, _powinna_ być widokiem. + +```python +@internal +def _addTokenTo(_to: address, _tokenId: uint256): + """ + @dev Dodaje NFT do danego adresu + Zgłasza błąd, jeśli `_tokenId` jest własnością kogoś. + """ + # Zgłasza błąd, jeśli `_tokenId` jest własnością kogoś + assert self.idToOwner[_tokenId] == ZERO_ADDRESS + # Zmień właściciela + self.idToOwner[_tokenId] = _to + # Zmień śledzenie licznika + self.ownerToNFTokenCount[_to] += 1 + + +@internal +def _removeTokenFrom(_from: address, _tokenId: uint256): + """ + @dev Usuwa NFT z danego adresu + Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem. + """ + # Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem + assert self.idToOwner[_tokenId] == _from + # Zmień właściciela + self.idToOwner[_tokenId] = ZERO_ADDRESS + # Zmień śledzenie licznika + self.ownerToNFTokenCount[_from] -= 1 +``` + +Gdy wystąpi problem z transferem, cofamy wywołanie. + +```python +@internal +def _clearApproval(_owner: address, _tokenId: uint256): + """ + @dev Czyści zatwierdzenie danego adresu + Zgłasza błąd, jeśli `_owner` nie jest obecnym właścicielem. + """ + # Zgłasza błąd, jeśli `_owner` nie jest obecnym właścicielem + assert self.idToOwner[_tokenId] == _owner + if self.idToApprovals[_tokenId] != ZERO_ADDRESS: + # Resetuj zatwierdzenia + self.idToApprovals[_tokenId] = ZERO_ADDRESS +``` + +Zmieniaj wartość tylko w razie potrzeby. Zmienne stanu znajdują się w pamięci (storage). Zapis do pamięci jest +jedną z najdroższych operacji, jakie wykonuje EVM (Wirtualna Maszyna Ethereum) (pod względem +[gazu](/developers/docs/gas/)). Dlatego dobrym pomysłem jest jego minimalizowanie, nawet zapisywanie +istniejącej wartości ma wysoki koszt. + +```python +@internal +def _transferFrom(_from: address, _to: address, _tokenId: uint256, _sender: address): + """ + @dev Wykonuje transfer NFT. + Zgłasza błąd, chyba że `msg.sender` jest obecnym właścicielem, autoryzowanym operatorem lub zatwierdzonym + adresem dla tego NFT. (UWAGA: `msg.sender` nie jest dozwolony w funkcji prywatnej, więc przekaż `_sender`.) + Zgłasza błąd, jeśli `_to` jest adresem zerowym. + Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + """ +``` + +Mamy tę funkcję wewnętrzną, ponieważ istnieją dwa sposoby transferu tokenów (zwykły i bezpieczny), ale +chcemy, aby było tylko jedno miejsce w kodzie, w którym to robimy, aby ułatwić audyt. + +```python + # Sprawdź wymagania + assert self._isApprovedOrOwner(_sender, _tokenId) + # Zgłasza błąd, jeśli `_to` jest adresem zerowym + assert _to != ZERO_ADDRESS + # Wyczyść zatwierdzenie. Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem + self._clearApproval(_from, _tokenId) + # Usuń NFT. Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT + self._removeTokenFrom(_from, _tokenId) + # Dodaj NFT + self._addTokenTo(_to, _tokenId) + # Zarejestruj transfer + log Transfer(_from, _to, _tokenId) +``` + +Aby wyemitować zdarzenie w Vyper, użyj instrukcji `log` ([więcej szczegółów tutaj](https://vyper.readthedocs.io/en/latest/event-logging.html#event-logging)). + +#### Funkcje transferu {#transfer-funs} + +```python + +### FUNKCJE TRANSFERU ### + +@external +def transferFrom(_from: address, _to: address, _tokenId: uint256): + """ + @dev Zgłasza błąd, chyba że `msg.sender` jest obecnym właścicielem, autoryzowanym operatorem lub zatwierdzonym + adresem dla tego NFT. + Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem. + Zgłasza błąd, jeśli `_to` jest adresem zerowym. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + @notice Wywołujący jest odpowiedzialny za potwierdzenie, że `_to` jest w stanie odbierać NFT, w przeciwnym razie + mogą one zostać trwale utracone. + @param _from Obecny właściciel NFT. + @param _to Nowy właściciel. + @param _tokenId NFT do przetransferowania. + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +Ta funkcja pozwala na transfer na dowolny adres. O ile adres nie jest adresem użytkownika lub kontraktem, który +wie, jak transferować tokeny, każdy przetransferowany token utknie na tym adresie i będzie bezużyteczny. + +```python +@external +def safeTransferFrom( + _from: address, + _to: address, + _tokenId: uint256, + _data: Bytes[1024]=b"" + ): + """ + @dev Przenosi własność NFT z jednego adresu na inny. + Zgłasza błąd, chyba że `msg.sender` jest obecnym właścicielem, autoryzowanym operatorem lub + zatwierdzonym adresem dla tego NFT. + Zgłasza błąd, jeśli `_from` nie jest obecnym właścicielem. + Zgłasza błąd, jeśli `_to` jest adresem zerowym. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + Jeśli `_to` jest inteligentnym kontraktem, wywołuje `onERC721Received` na `_to` i zgłasza błąd, jeśli + zwracana wartość nie jest `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + UWAGA: bytes4 jest reprezentowane przez bytes32 z dopełnieniem + @param _from Obecny właściciel NFT. + @param _to Nowy właściciel. + @param _tokenId NFT do przetransferowania. + @param _data Dodatkowe dane bez określonego formatu, wysyłane w wywołaniu do `_to`. + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +Można najpierw wykonać transfer, ponieważ w razie problemu i tak cofniemy całą operację, więc wszystko, +co zostało zrobione w wywołaniu, zostanie anulowane. + +```python + if _to.is_contract: # sprawdź, czy `_to` jest adresem kontraktu +``` + +Najpierw sprawdź, czy adres jest kontraktem (czy ma kod). Jeśli nie, załóż, że jest to adres +użytkownika, a użytkownik będzie mógł użyć tokena lub go przetransferować. Ale niech to nie uśpi twojej +czujności. Możesz stracić tokeny, nawet używając `safeTransferFrom`, jeśli przetransferujesz +je na adres, do którego nikt nie zna klucza prywatnego. + +```python + returnValue: bytes32 = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) +``` + +Wywołaj kontrakt docelowy, aby sprawdzić, czy może on odbierać tokeny ERC-721. + +```python + # Zgłasza błąd, jeśli miejscem docelowym transferu jest kontrakt, który nie implementuje „onERC721Received” + assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes32) +``` + +Jeśli miejscem docelowym jest kontrakt, ale taki, który nie akceptuje tokenów ERC-721 (lub który zdecydował się nie akceptować tego +konkretnego transferu), operacja zostanie cofnięta. + +```python +@external +def approve(_approved: address, _tokenId: uint256): + """ + @dev Ustawia lub ponownie zatwierdza zatwierdzony adres dla NFT. Adres zerowy wskazuje, że nie ma zatwierdzonego adresu. + Zgłasza błąd, chyba że `msg.sender` jest obecnym właścicielem NFT lub autoryzowanym operatorem obecnego właściciela. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. (UWAGA: nie jest to zapisane w EIP) + Zgłasza błąd, jeśli `_approved` jest obecnym właścicielem. (UWAGA: nie jest to zapisane w EIP) + @param _approved Adres do zatwierdzenia dla danego ID NFT. + @param _tokenId ID tokena do zatwierdzenia. + """ + owner: address = self.idToOwner[_tokenId] + # Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT + assert owner != ZERO_ADDRESS + # Zgłasza błąd, jeśli `_approved` jest obecnym właścicielem + assert _approved != owner +``` + +Zgodnie z konwencją, jeśli nie chcesz mieć podmiotu zatwierdzającego, wyznaczasz adres zerowy, a nie siebie. + +```python + # Sprawdź wymagania + senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender + senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender] + assert (senderIsOwner or senderIsApprovedForAll) +``` + +Aby ustawić zatwierdzenie, możesz być właścicielem lub operatorem autoryzowanym przez właściciela. + +```python + # Ustaw zatwierdzenie + self.idToApprovals[_tokenId] = _approved + log Approval(owner, _approved, _tokenId) + + +@external +def setApprovalForAll(_operator: address, _approved: bool): + """ + @dev Włącza lub wyłącza zatwierdzenie dla strony trzeciej („operatora”) do zarządzania wszystkimi + aktywami `msg.sender`. Emituje również zdarzenie ApprovalForAll. + Zgłasza błąd, jeśli `_operator` to `msg.sender`. (UWAGA: nie jest to zapisane w EIP) + @notice Działa to nawet wtedy, gdy nadawca nie posiada w danym momencie żadnych tokenów. + @param _operator Adres do dodania do zestawu autoryzowanych operatorów. + @param _approved True, jeśli operator jest zatwierdzony, false, aby cofnąć zatwierdzenie. + """ + # Zgłasza błąd, jeśli `_operator` to `msg.sender` + assert _operator != msg.sender + self.ownerToOperators[msg.sender][_operator] = _approved + log ApprovalForAll(msg.sender, _operator, _approved) +``` + +#### Wybijanie nowych tokenów i niszczenie istniejących {#mint-burn} + +Konto, które utworzyło kontrakt, jest `minterem`, superużytkownikiem upoważnionym do wybijania +nowych NFT. Jednak nawet on nie może palić istniejących tokenów. Może to zrobić tylko właściciel lub podmiot +upoważniony przez właściciela. + +```python +### FUNKCJE WYBIJANIA I PALENIA ### + +@external +def mint(_to: address, _tokenId: uint256) -> bool: +``` + +Ta funkcja zawsze zwraca `True`, ponieważ jeśli operacja się nie powiedzie, jest cofana. + +```python + """ + @dev Funkcja do wybijania tokenów + Zgłasza błąd, jeśli `msg.sender` nie jest minterem. + Zgłasza błąd, jeśli `_to` jest adresem zerowym. + Zgłasza błąd, jeśli `_tokenId` jest własnością kogoś. + @param _to Adres, który otrzyma wybite tokeny. + @param _tokenId Identyfikator tokena do wybicia. + @return Wartość logiczna wskazująca, czy operacja zakończyła się powodzeniem. + """ + # Zgłasza błąd, jeśli `msg.sender` nie jest minterem + assert msg.sender == self.minter +``` + +Tylko minter (konto, które utworzyło kontrakt ERC-721) może wybijać nowe tokeny. Może to być +problemem w przyszłości, jeśli będziemy chcieli zmienić tożsamość mintera. W +kontrakcie produkcyjnym prawdopodobnie chciałbyś mieć funkcję, która pozwala minterowi na przekazanie +uprawnień mintera komuś innemu. + +```python + # Zgłasza błąd, jeśli `_to` jest adresem zerowym + assert _to != ZERO_ADDRESS + # Dodaj NFT. Zgłasza błąd, jeśli `_tokenId` jest własnością kogoś + self._addTokenTo(_to, _tokenId) + log Transfer(ZERO_ADDRESS, _to, _tokenId) + return True +``` + +Zgodnie z konwencją wybijanie nowych tokenów liczy się jako transfer z adresu zerowego. + +```python + +@external +def burn(_tokenId: uint256): + """ + @dev Pali określony token ERC721. + Zgłasza błąd, chyba że `msg.sender` jest obecnym właścicielem, autoryzowanym operatorem lub zatwierdzonym + adresem dla tego NFT. + Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT. + @param _tokenId uint256 id tokena ERC721 do spalenia. + """ + # Sprawdź wymagania + assert self._isApprovedOrOwner(msg.sender, _tokenId) + owner: address = self.idToOwner[_tokenId] + # Zgłasza błąd, jeśli `_tokenId` nie jest prawidłowym NFT + assert owner != ZERO_ADDRESS + self._clearApproval(owner, _tokenId) + self._removeTokenFrom(owner, _tokenId) + log Transfer(owner, ZERO_ADDRESS, _tokenId) +``` + +Każdy, kto ma prawo do transferu tokena, może go spalić. Chociaż spalenie wydaje się równoznaczne z +transferem na adres zerowy, adres zerowy w rzeczywistości nie otrzymuje tokena. Pozwala to na +zwolnienie całej pamięci, która była używana dla tokena, co może obniżyć koszt gazu transakcji. + +## Korzystanie z tego kontraktu {#using-contract} + +W przeciwieństwie do Solidity, Vyper nie ma dziedziczenia. Jest to celowy wybór projektowy, aby +kod był jaśniejszy, a tym samym łatwiejszy do zabezpieczenia. Tak więc, aby stworzyć własny kontrakt ERC-721 w Vyper, bierzesz ten +kontrakt i modyfikujesz go +w celu zaimplementowania pożądanej logiki biznesowej. + +## Wnioski {#conclusion} + +Dla przypomnienia, oto niektóre z najważniejszych pomysłów w tym kontrakcie: + +- Aby odbierać tokeny ERC-721 za pomocą bezpiecznego transferu, kontrakty muszą implementować interfejs `ERC721Receiver`. +- Nawet jeśli użyjesz bezpiecznego transferu, tokeny mogą utknąć, jeśli wyślesz je na adres, którego klucz prywatny + jest nieznany. +- Gdy wystąpi problem z operacją, dobrym pomysłem jest `cofnięcie` (revert) wywołania, a nie tylko zwrócenie + wartości błędu. +- Tokeny ERC-721 istnieją, gdy mają właściciela. +- Istnieją trzy sposoby autoryzacji do transferu NFT. Możesz być właścicielem, być zatwierdzonym dla konkretnego tokena + lub być operatorem dla wszystkich tokenów właściciela. +- Przeszłe zdarzenia są widoczne tylko poza blockchainem. Kod działający wewnątrz blockchaina nie może ich zobaczyć. + +Teraz idź i zaimplementuj bezpieczne kontrakty Vyper. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). + diff --git a/public/content/translations/pl/developers/tutorials/erc20-annotated-code/index.md b/public/content/translations/pl/developers/tutorials/erc20-annotated-code/index.md new file mode 100644 index 00000000000..c61ec7ae2a0 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/erc20-annotated-code/index.md @@ -0,0 +1,873 @@ +--- +title: "Przewodnik po kontrakcie ERC-20" +description: "Co znajduje się w kontrakcie ERC-20 OpenZeppelin i dlaczego tam jest?" +author: Ori Pomerantz +lang: pl +tags: [ "solidity", "erc-20" ] +skill: beginner +published: 2021-03-09 +--- + +## Wprowadzenie {#introduction} + +Jednym z najczęstszych zastosowań Ethereum jest tworzenie przez grupę wymienialnych tokenów, w pewnym sensie własnej waluty. Tokeny te zazwyczaj są zgodne ze standardem, +[ERC-20](/developers/docs/standards/tokens/erc-20/). Standard ten umożliwia pisanie narzędzi, takich jak pule płynności i portfele, które działają ze wszystkimi tokenami ERC-20 +. W tym artykule przeanalizujemy [implementację ERC20 w Solidity od OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol), a także [definicję interfejsu](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol). + +To jest kod źródłowy z adnotacjami. Jeśli chcesz zaimplementować ERC-20, +[przeczytaj ten samouczek](https://docs.openzeppelin.com/contracts/2.x/erc20-supply). + +## Interfejs {#the-interface} + +Celem standardu takiego jak ERC-20 jest umożliwienie wielu implementacji tokenów, które są interoperacyjne w różnych aplikacjach, takich jak portfele i zdecentralizowane giełdy. Aby to osiągnąć, tworzymy +[interfejs](https://www.geeksforgeeks.org/solidity/solidity-basics-of-interface/). Każdy kod, który musi używać kontraktu tokenu, +może używać tych samych definicji w interfejsie i być kompatybilnym ze wszystkimi kontraktami tokenów, które go używają, niezależnie od tego, czy jest to portfel, taki jak +MetaMask, dapka, taka jak etherscan.io, czy inny kontrakt, taki jak pula płynności. + +![Ilustracja interfejsu ERC-20](erc20_interface.png) + +Jeśli jesteś doświadczonym programistą, prawdopodobnie pamiętasz podobne konstrukcje w [Javie](https://www.w3schools.com/java/java_interface.asp) +lub nawet w [plikach nagłówkowych C](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html). + +Jest to definicja [interfejsu ERC-20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) +pochodząca z OpenZeppelin. Jest to tłumaczenie [standardu czytelnego dla człowieka](https://eips.ethereum.org/EIPS/eip-20) na kod Solidity. Oczywiście, sam +interfejs nie definiuje _jak_ cokolwiek zrobić. Jest to wyjaśnione w poniższym kodzie źródłowym kontraktu. + +  + +```solidity +// SPDX-License-Identifier: MIT +``` + +Pliki Solidity powinny zawierać identyfikator licencji. [Listę licencji można zobaczyć tutaj](https://spdx.org/licenses/). Jeśli potrzebujesz innej +licencji, po prostu wyjaśnij to w komentarzach. + +  + +```solidity +pragma solidity >=0.6.0 <0.8.0; +``` + +Język Solidity wciąż szybko się rozwija, a nowe wersje mogą nie być kompatybilne ze starym kodem +([zobacz tutaj](https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html)). Dlatego dobrym pomysłem jest określenie nie tylko minimalnej +wersji języka, ale także maksymalnej wersji, najnowszej, z którą testowano kod. + +  + +```solidity +/** + * @dev Interfejs standardu ERC20 zdefiniowany w EIP. + */ +``` + +Zapis `@dev` w komentarzu jest częścią [formatu NatSpec](https://docs.soliditylang.org/en/develop/natspec-format.html), używanego do tworzenia +dokumentacji z kodu źródłowego. + +  + +```solidity +interface IERC20 { +``` + +Zgodnie z konwencją, nazwy interfejsów zaczynają się od `I`. + +  + +```solidity + /** + * @dev Zwraca liczbę istniejących tokenów. + */ + function totalSupply() external view returns (uint256); +``` + +Ta funkcja jest `zewnętrzna`, co oznacza, że [może być wywoływana tylko spoza kontraktu](https://docs.soliditylang.org/en/v0.7.0/cheatsheet.html#index-2). +Zwraca całkowitą podaż tokenów w kontrakcie. Wartość ta jest zwracana przy użyciu najpopularniejszego typu w Ethereum, 256-bitowej liczby całkowitej bez znaku (256 bitów to +natywny rozmiar słowa EVM). Ta funkcja jest również typu `view`, co oznacza, że nie zmienia ona stanu, więc może być wykonana na pojedynczym węźle zamiast być uruchamiana przez +każdy węzeł w blockchainie. Ten rodzaj funkcji nie generuje transakcji i nie kosztuje [gazu](/developers/docs/gas/). + +**Uwaga:** Teoretycznie mogłoby się wydawać, że twórca kontraktu mógłby oszukiwać, zwracając mniejszą całkowitą podaż niż rzeczywista wartość, sprawiając, że każdy token wydaje się +bardziej wartościowy, niż jest w rzeczywistości. Jednakże obawa ta ignoruje prawdziwą naturę blockchaina. Wszystko, co dzieje się w blockchainie, może zostać zweryfikowane przez +każdy węzeł. Aby to osiągnąć, kod maszynowy i pamięć masowa każdego kontraktu są dostępne na każdym węźle. Chociaż nie jest wymagane publikowanie kodu Solidity +kontraktu, nikt nie potraktuje Cię poważnie, chyba że opublikujesz kod źródłowy i wersję Solidity, za pomocą której został on skompilowany, aby można go było +zweryfikować z dostarczonym kodem maszynowym. +Na przykład zobacz [ten kontrakt](https://eth.blockscout.com/address/0xa530F85085C6FE2f866E7FdB716849714a89f4CD?tab=contract). + +  + +```solidity + /** + * @dev Zwraca liczbę tokenów posiadanych przez `konto`. + */ + function balanceOf(address account) external view returns (uint256); +``` + +Jak sama nazwa wskazuje, `balanceOf` zwraca saldo konta. Konta Ethereum są identyfikowane w Solidity za pomocą typu `adres`, który przechowuje 160 bitów. +Jest również `zewnętrzna` i typu `view`. + +  + +```solidity + /** + * @dev Przenosi tokeny w `ilości` z konta wywołującego do `odbiorcy`. + * + * Zwraca wartość logiczną wskazującą, czy operacja się powiodła. + * + * Emituje zdarzenie {Transfer}. + */ + function transfer(address recipient, uint256 amount) external returns (bool); +``` + +Funkcja `transfer` przenosi tokeny od wywołującego na inny adres. Wiąże się to ze zmianą stanu, więc nie jest to `widok`. +Gdy użytkownik wywołuje tę funkcję, tworzy transakcję i ponosi koszty gazu. Emituje również zdarzenie `Transfer`, aby poinformować wszystkich w +blockchainie o tym zdarzeniu. + +Funkcja ma dwa rodzaje danych wyjściowych dla dwóch różnych typów wywołujących: + +- Użytkownicy wywołujący funkcję bezpośrednio z interfejsu użytkownika. Zazwyczaj użytkownik przesyła transakcję + i nie czeka na odpowiedź, co może zająć nieokreśloną ilość czasu. Użytkownik może zobaczyć, co się stało + , szukając potwierdzenia transakcji (które jest identyfikowane przez hasz transakcji) lub szukając + zdarzenia `Transfer`. +- Inne kontrakty, które wywołują funkcję w ramach ogólnej transakcji. Kontrakty te otrzymują wynik natychmiast, + ponieważ działają w tej samej transakcji, więc mogą użyć wartości zwrotnej funkcji. + +Ten sam typ danych wyjściowych jest tworzony przez inne funkcje, które zmieniają stan kontraktu. + +  + +Zezwolenia pozwalają kontu na wydanie pewnej liczby tokenów należących do innego właściciela. +Jest to przydatne na przykład w przypadku kontraktów, które działają jako sprzedawcy. Kontrakty nie mogą +monitorować zdarzeń, więc jeśli kupujący miałby przenieść tokeny do kontraktu sprzedawcy +bezpośrednio, kontrakt ten nie wiedziałby, że został opłacony. Zamiast tego, kupujący zezwala +kontraktowi sprzedawcy na wydanie określonej kwoty, a sprzedawca transferuje tę kwotę. +Odbywa się to za pomocą funkcji wywoływanej przez kontrakt sprzedawcy, więc kontrakt sprzedawcy +może wiedzieć, czy się to udało. + +```solidity + /** + * @dev Zwraca pozostałą liczbę tokenów, które `spender` będzie mógł + * wydać w imieniu `owner` poprzez {transferFrom}. Domyślnie + * jest to zero. + * + * Wartość ta zmienia się po wywołaniu {approve} lub {transferFrom}. + */ + function allowance(address owner, address spender) external view returns (uint256); +``` + +Funkcja `allowance` pozwala każdemu sprawdzić, jakie jest zezwolenie, które jeden +adres (`właściciel`) daje innemu adresowi (`wydającemu`) do wydania. + +  + +```solidity + /** + * @dev Ustawia `amount` jako zezwolenie `spendera` na tokeny wywołującego. + * + * Zwraca wartość logiczną wskazującą, czy operacja się powiodła. + * + * WAŻNE: Należy pamiętać, że zmiana zezwolenia za pomocą tej metody niesie ze sobą ryzyko, + * że ktoś może użyć zarówno starego, jak i nowego zezwolenia przez niefortunne + * uporządkowanie transakcji. Jednym z możliwych rozwiązań w celu złagodzenia tego stanu wyścigu + * jest najpierw zmniejszenie zezwolenia wydającego do 0 i ustawienie + * pożądanej wartości później: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emituje zdarzenie {Approval}. + */ + function approve(address spender, uint256 amount) external returns (bool); +``` + +Funkcja `approve` tworzy zezwolenie. Pamiętaj, aby przeczytać wiadomość o tym, +jak można ją nadużywać. W Ethereum kontrolujesz kolejność własnych transakcji, +ale nie możesz kontrolować kolejności, w jakiej transakcje innych osób będą +wykonywane, chyba że nie prześlesz własnej transakcji, dopóki nie zobaczysz, że +transakcja drugiej strony miała miejsce. + +  + +```solidity + /** + * @dev Przenosi tokeny o `wartości` `amount` z `nadawcy` do `odbiorcy` przy użyciu + * mechanizmu zezwoleń. `Kwota` jest następnie odejmowana od zezwolenia wywołującego + * . + * + * Zwraca wartość logiczną wskazującą, czy operacja się powiodła. + * + * Emituje zdarzenie {Transfer}. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +``` + +Na koniec `transferFrom` jest używane przez wydającego do faktycznego wydania zezwolenia. + +  + +```solidity + + /** + * @dev Emitowane, gdy tokeny `value` są przenoszone z jednego konta (`from`) na drugie (`to`). + * + * Zauważ, że `value` może być zerowe. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitowane, gdy pozwolenie `spendera` dla `owner` jest ustawiane przez wywołanie {approve}. `value` to nowe pozwolenie. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} +``` + +Te zdarzenia są emitowane, gdy zmienia się stan kontraktu ERC-20. + +## Właściwy kontrakt {#the-actual-contract} + +To jest właściwy kontrakt, który implementuje standard ERC-20, [pobrany stąd](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol). +Nie jest on przeznaczony do użycia w obecnej formie, ale można go [odziedziczyć](https://www.tutorialspoint.com/solidity/solidity_inheritance.htm), aby rozszerzyć go do czegoś użytecznego. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.8.0; +``` + +  + +### Instrukcje importu {#import-statements} + +Oprócz powyższych definicji interfejsu, definicja kontraktu importuje dwa inne pliki: + +```solidity + +import "../../GSN/Context.sol"; +import "./IERC20.sol"; +import "../../math/SafeMath.sol"; +``` + +- `GSN/Context.sol` to definicje wymagane do użycia [OpenGSN](https://www.opengsn.org/), systemu, który pozwala użytkownikom bez etheru korzystać z blockchainu. Zauważ, że jest to stara wersja. Jeśli chcesz zintegrować z OpenGSN, [użyj tego samouczka](https://docs.opengsn.org/javascript-client/tutorial.html). +- [Biblioteka SafeMath](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/), która zapobiega przepełnieniom/niedopełnieniom arytmetycznym dla wersji Solidity **<0.8.0**. W Solidity ≥0.8.0, operacje arytmetyczne automatycznie cofają się w przypadku przepełnienia/niedopełnienia, co sprawia, że biblioteka SafeMath jest niepotrzebna. Ten kontrakt używa SafeMath dla wstecznej kompatybilności ze starszymi wersjami kompilatora. + +  + +Ten komentarz wyjaśnia cel kontraktu. + +```solidity +/** + * @dev Implementacja interfejsu {IERC20}. + * + * Ta implementacja jest niezależna od sposobu tworzenia tokenów. Oznacza to, że mechanizm zasilania musi zostać dodany w kontrakcie pochodnym za pomocą {_mint}. + * Ogólny mechanizm można znaleźć w {ERC20PresetMinterPauser}. + * + * WSKAZÓWKA: Szczegółowy opis można znaleźć w naszym przewodniku + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[Jak + * wdrażać mechanizmy dostaw]. + * + * Postępowaliśmy zgodnie z ogólnymi wytycznymi OpenZeppelin: funkcje w przypadku niepowodzenia cofają się, zamiast zwracać „fałsz”. + * To zachowanie jest jednak konwencjonalne i nie jest sprzeczne z oczekiwaniami aplikacji ERC20. + * + * Dodatkowo zdarzenie {Approval} jest emitowane przy wywołaniach {transferFrom}. + * Umożliwia to aplikacjom odtworzenie uprawnień dla wszystkich kont poprzez nasłuchiwanie tych zdarzeń. + * Inne implementacje EIP mogą nie emitować tych zdarzeń, ponieważ nie jest to wymagane przez specyfikację. + * + * Wreszcie, niestandardowe funkcje {decreaseAllowance} i {increaseAllowance} zostały dodane w celu złagodzenia dobrze znanych problemów związanych z ustawianiem przydziałów. + * Zobacz {IERC20-approve}. + */ + +``` + +### Definicja kontraktu {#contract-definition} + +```solidity +contract ERC20 is Context, IERC20 { +``` + +Ta linia określa dziedziczenie, w tym przypadku z `IERC20` z góry i `Context`, dla OpenGSN. + +  + +```solidity + + using SafeMath for uint256; + +``` + +Ta linia dołącza bibliotekę `SafeMath` do typu `uint256`. Tę bibliotekę można znaleźć [tutaj](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol). + +### Definicje zmiennych {#variable-definitions} + +Te definicje określają zmienne stanu kontraktu. Te zmienne są zadeklarowane jako `private`, ale oznacza to tylko, że inne kontrakty na blockchainie nie mogą ich odczytać. _Na blockchainie nie ma sekretów_, oprogramowanie na każdym węźle ma stan każdego kontraktu w każdym bloku. Zgodnie z konwencją zmienne stanu nazywane są `_`. + +Pierwsze dwie zmienne to [mapowania](https://www.tutorialspoint.com/solidity/solidity_mappings.htm), co oznacza, że zachowują się mniej więcej tak samo jak [tablice asocjacyjne](https://wikipedia.org/wiki/Associative_array), z tym wyjątkiem, że klucze są wartościami numerycznymi. Pamięć jest przydzielana tylko dla wpisów, które mają wartości różne od domyślnej (zero). + +```solidity + mapping (address => uint256) private _balances; +``` + +Pierwsze mapowanie, `_balances`, to adresy i ich odpowiednie salda tego tokena. Aby uzyskać dostęp do salda, użyj tej składni: `_balances[]`. + +  + +```solidity + mapping (address => mapping (address => uint256)) private _allowances; +``` + +Ta zmienna, `_allowances`, przechowuje wyjaśnione wcześniej uprawnienia. Pierwszy indeks to właściciel tokenów, a drugi to kontrakt z przydziałem. Aby uzyskać dostęp do kwoty, jaką adres A może wydać z konta adresu B, użyj `_allowances[B][A]`. + +  + +```solidity + uint256 private _totalSupply; +``` + +Jak sama nazwa wskazuje, ta zmienna śledzi całkowitą podaż tokenów. + +  + +```solidity + string private _name; + string private _symbol; + uint8 private _decimals; +``` + +Te trzy zmienne są używane w celu poprawy czytelności. Dwie pierwsze są oczywiste, ale `_decimals` nie jest. + +Z jednej strony Ethereum nie ma zmiennych zmiennoprzecinkowych ani ułamkowych. Z drugiej strony ludzie lubią mieć możliwość dzielenia tokenów. Jednym z powodów, dla których ludzie zdecydowali się na złoto jako walutę, było to, że trudno było wydać resztę, gdy ktoś chciał kupić kaczkę za część krowy. + +Rozwiązaniem jest śledzenie liczb całkowitych, ale zamiast prawdziwego tokena liczenie tokena ułamkowego, który jest prawie bezwartościowy. W przypadku etheru token ułamkowy nazywa się wei, a 10^18 wei jest równe jednemu ETH. W momencie pisania tego tekstu 10 000 000 000 000 wei to w przybliżeniu jeden cent amerykański lub eurocent. + +Aplikacje muszą wiedzieć, jak wyświetlić saldo tokena. Jeśli użytkownik ma 3 141 000 000 000 000 000 wei, czy to 3,14 ETH? 31,41 ETH? 3141 ETH? W przypadku etheru zdefiniowano 10^18 wei na ETH, ale dla Twojego tokena możesz wybrać inną wartość. Jeśli dzielenie tokena nie ma sensu, możesz użyć wartości `_decimals` równej zero. Jeśli chcesz używać tego samego standardu co ETH, użyj wartości **18**. + +### Konstruktor {#the-constructor} + +```solidity + /** + * @dev Ustawia wartości dla {name} i {symbol}, inicjalizuje {decimals} z domyślną wartością 18. + * + * Aby wybrać inną wartość dla {decimals}, użyj {_setupDecimals}. + * + * Wszystkie trzy z tych wartości są niezmienne: można je ustawić tylko raz podczas tworzenia. + */ + constructor (string memory name_, string memory symbol_) public { + // W Solidity ≥0.7.0, „public” jest domyślne i można je pominąć. + + _name = name_; + _symbol = symbol_; + _decimals = 18; + } +``` + +Konstruktor jest wywoływany przy pierwszym utworzeniu kontraktu. Zgodnie z konwencją parametry funkcji są nazywane `_`. + +### Funkcje interfejsu użytkownika {#user-interface-functions} + +```solidity + /** + * @dev Zwraca nazwę tokena. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Zwraca symbol tokena, zazwyczaj krótszą wersję nazwy. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Zwraca liczbę miejsc po przecinku używaną do uzyskania jego reprezentacji przez użytkownika. + * Na przykład, jeśli `decimals` wynosi `2`, saldo `505` tokenów powinno być wyświetlone użytkownikowi jako `5,05` (`505 / 10 ** 2`). + * + * Tokeny zazwyczaj wybierają wartość 18, naśladując związek między etherem a wei. + * Jest to wartość, której używa {ERC20}, chyba że zostanie wywołana funkcja {_setupDecimals}. + * + * UWAGA: Informacje te są wykorzystywane wyłącznie do celów _wyświetlania_: w żaden sposób nie wpływają na arytmetykę kontraktu, + * w tym {IERC20-balanceOf} i {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } +``` + +Te funkcje, `name`, `symbol` i `decimals`, pomagają interfejsom użytkownika dowiedzieć się o Twoim kontrakcie, aby mogły go poprawnie wyświetlać. + +Typem zwracanym jest `string memory`, co oznacza zwrócenie ciągu znaków przechowywanego w pamięci. Zmienne, takie jak ciągi znaków, mogą być przechowywane w trzech lokalizacjach: + +| | Czas życia | Dostęp do kontraktu | Koszt gazu | +| -------------- | ----------------- | ------------------- | --------------------------------------------------------------------------- | +| Pamięć | Wywołanie funkcji | Odczyt/Zapis | Dziesiątki lub setki (więcej dla wyższych lokalizacji) | +| Calldata | Wywołanie funkcji | Tylko do odczytu | Nie może być używany jako typ zwracany, tylko jako typ parametru funkcji | +| Przechowywanie | Do zmiany | Odczyt/Zapis | Wysoki (800 za odczyt, 20 tys. za zapis) | + +W tym przypadku najlepszym wyborem jest `memory`. + +### Odczyt informacji o tokenie {#read-token-information} + +Są to funkcje, które dostarczają informacji o tokenie, albo o całkowitej podaży, albo o saldzie konta. + +```solidity + /** + * @dev Zobacz {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } +``` + +Funkcja `totalSupply` zwraca całkowitą podaż tokenów. + +  + +```solidity + /** + * @dev Zobacz {IERC20-balanceOf}. + */ + function balanceOf(address account) public view override returns (uint256) { + return _balances[account]; + } +``` + +Odczytaj saldo konta. Zauważ, że każdy może sprawdzić saldo konta każdego innego. Nie ma sensu próbować ukrywać tych informacji, ponieważ i tak są one dostępne w każdym węźle. _Na blockchainie nie ma żadnych tajemnic._ + +### Przelewanie tokenów {#transfer-tokens} + +```solidity + /** + * @dev Zobacz {IERC20-transfer}. + * + * Wymagania: + * + * - `recipient` nie może być adresem zerowym. + * - wywołujący musi mieć saldo co najmniej `amount`. + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { +``` + +Funkcja `transfer` jest wywoływana w celu przesłania tokenów z konta nadawcy na inne. Zauważ, że chociaż zwraca ona wartość logiczną, to zawsze jest to **prawda**. Jeśli przelew się nie powiedzie, kontrakt cofa wywołanie. + +  + +```solidity + _transfer(_msgSender(), recipient, amount); + return true; + } +``` + +Funkcja `_transfer` wykonuje właściwą pracę. Jest to funkcja prywatna, która może być wywoływana tylko przez inne funkcje kontraktu. Zgodnie z konwencją funkcje prywatne są nazywane `_`, tak samo jak zmienne stanu. + +Zazwyczaj w Solidity używamy `msg.sender` dla nadawcy wiadomości. Jednakże psuje to [OpenGSN](http://opengsn.org/). Jeśli chcemy zezwolić na transakcje bez etheru za pomocą naszego tokena, musimy użyć `_msgSender()`. Zwraca `msg.sender` dla normalnych transakcji, ale dla transakcji bez etheru zwraca oryginalnego sygnatariusza, a nie kontrakt, który przekazał wiadomość. + +### Funkcje przydziału {#allowance-functions} + +Są to funkcje, które implementują funkcjonalność przydziału: `allowance`, `approve`, `transferFrom` i `_approve`. Dodatkowo implementacja OpenZeppelin wykracza poza podstawowy standard, zawierając pewne funkcje poprawiające bezpieczeństwo: `increaseAllowance` i `decreaseAllowance`. + +#### Funkcja przydziału {#allowance} + +```solidity + /** + * @dev Zobacz {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } +``` + +Funkcja `allowance` pozwala każdemu sprawdzić dowolny przydział. + +#### Funkcja approve {#approve} + +```solidity + /** + * @dev Zobacz {IERC20-approve}. + * + * Wymagania: + * + * - `spender` nie może być adresem zerowym. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { +``` + +Ta funkcja jest wywoływana w celu utworzenia przydziału. Jest podobna do powyższej funkcji `transfer`: + +- Funkcja po prostu wywołuje funkcję wewnętrzną (w tym przypadku `_approve`), która wykonuje prawdziwą pracę. +- Funkcja albo zwraca `true` (jeśli się powiedzie), albo cofa (jeśli nie). + +  + +```solidity + _approve(_msgSender(), spender, amount); + return true; + } +``` + +Używamy funkcji wewnętrznych, aby zminimalizować liczbę miejsc, w których zachodzą zmiany stanu. _Każda_ funkcja, która zmienia stan, jest potencjalnym zagrożeniem bezpieczeństwa, które musi być poddane audytowi bezpieczeństwa. W ten sposób mamy mniejsze szanse na popełnienie błędu. + +#### Funkcja transferFrom {#transferFrom} + +Jest to funkcja, którą wydający wywołuje, aby wydać przydział. Wymaga to dwóch operacji: przelania wydawanej kwoty i zmniejszenia o nią przydziału. + +```solidity + /** + * @dev Zobacz {IERC20-transferFrom}. + * + * Emituje zdarzenie {Approval} wskazujące zaktualizowany przydział. Nie jest to wymagane przez EIP. + * Zobacz notatkę na początku {ERC20}. + * + * Wymagania: + * + * - `sender` i `recipient` nie mogą być adresem zerowym. + * - `sender` musi mieć saldo co najmniej `amount`. + * - wywołujący musi mieć przydział na tokeny ``sender`` w wysokości co najmniej + * `amount`. + */ + function transferFrom(address sender, address recipient, uint256 amount) public virtual + override returns (bool) { + _transfer(sender, recipient, amount); +``` + +  + +Wywołanie funkcji `a.sub(b, "message")` robi dwie rzeczy. Po pierwsze, oblicza `a-b`, co jest nowym przydziałem. +Po drugie, sprawdza, czy ten wynik nie jest ujemny. Jeśli jest ujemny, wywołanie cofa się z podaną wiadomością. Zauważ, że gdy wywołanie jest cofane, wszelkie przetwarzanie wykonane wcześniej podczas tego wywołania jest ignorowane, więc nie musimy cofać `_transfer`. + +```solidity + _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, + "ERC20: kwota transferu przekracza przydział")); + return true; + } +``` + +#### Dodatki bezpieczeństwa OpenZeppelin {#openzeppelin-safety-additions} + +Niebezpieczne jest ustawianie niezerowego przydziału na inną niezerową wartość, ponieważ kontrolujesz tylko kolejność własnych transakcji, a nie cudzych. Wyobraź sobie, że masz dwóch użytkowników, naiwną Alicję i nieuczciwego Billa. Alicja chce skorzystać z usługi Billa, która jej zdaniem kosztuje pięć tokenów – więc daje Billowi przydział w wysokości pięciu tokenów. + +Następnie coś się zmienia i cena Billa wzrasta do dziesięciu tokenów. Alicja, która nadal chce skorzystać z usługi, wysyła transakcję, która ustala przydział dla Billa na dziesięć. W momencie, gdy Bill zobaczy tę nową transakcję w puli transakcji, wysyła transakcję, która wydaje pięć tokenów Alicji i ma znacznie wyższą cenę gazu, dzięki czemu zostanie szybciej wykopana. W ten sposób Bill może najpierw wydać pięć tokenów, a następnie, +gdy nowe zezwolenie Alicji zostanie wydobyte, wydać kolejne dziesięć, co daje łączną cenę piętnastu tokenów, czyli więcej niż +chciała autoryzować Alicja. Ta technika nazywa się +[front-runningiem](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/#front-running) + +| Transakcja Alicji | Nonce Alicji | Transakcja Billa | Nonce Billa | Zezwolenie Billa | Całkowity dochód Billa od Alicji | +| ------------------------------------ | ------------ | ------------------------------------------------ | ----------- | ---------------- | -------------------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| approve(Bill, 10) | 11 | | | 10 | 5 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 | + +Aby uniknąć tego problemu, te dwie funkcje (`increaseAllowance` i `decreaseAllowance`) pozwalają +na modyfikację zezwolenia o określoną kwotę. Więc jeśli Bill wydał już pięć tokenów, będzie mógł +wydać tylko pięć więcej. W zależności od czasu, istnieją dwa sposoby, na które może to zadziałać, oba +z których kończą się tym, że Bill dostaje tylko dziesięć tokenów: + +A: + +| Transakcja Alicji | Nonce Alicji | Transakcja Billa | Nonce Billa | Zezwolenie Billa | Całkowity dochód Billa od Alicji | +| --------------------------------------------- | -----------: | ----------------------------------------------- | ----------: | ---------------: | -------------------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| increaseAllowance(Bill, 5) | 11 | | | 0+5 = 5 | 5 | +| | | transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 | + +B: + +| Transakcja Alicji | Nonce Alicji | Transakcja Billa | Nonce Billa | Zezwolenie Billa | Całkowity dochód Billa od Alicji | +| --------------------------------------------- | -----------: | ------------------------------------------------ | ----------: | ---------------: | -------------------------------: | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| increaseAllowance(Bill, 5) | 11 | | | 5+5 = 10 | 0 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 | + +```solidity + /** + * @dev Atomowo zwiększa zezwolenie udzielone `spenderowi` przez wywołującego. + * + * Jest to alternatywa dla {approve}, która może być używana jako środek zaradczy na + * problemy opisane w {IERC20-approve}. + * + * Emituje zdarzenie {Approval} wskazujące zaktualizowane zezwolenie. + * + * Wymagania: + * + * - `spender` nie może być adresem zerowym. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); + return true; + } +``` + +Funkcja `a.add(b)` to bezpieczne dodawanie. W mało prawdopodobnym przypadku, gdy `a`+`b`>=`2^256`, nie zawija się ono +w sposób, w jaki robi to normalne dodawanie. + +```solidity + + /** + * @dev Atomowo zmniejsza zezwolenie udzielone `spenderowi` przez wywołującego. + * + * Jest to alternatywa dla {approve}, która może być używana jako środek zaradczy na + * problemy opisane w {IERC20-approve}. + * + * Emituje zdarzenie {Approval} wskazujące zaktualizowane zezwolenie. + * + * Wymagania: + * + * - `spender` nie może być adresem zerowym. + * - `spender` musi mieć zezwolenie dla wywołującego w wysokości co najmniej + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, + "ERC20: decreased allowance below zero")); + return true; + } +``` + +### Funkcje modyfikujące informacje o tokenie {#functions-that-modify-token-information} + +Są to cztery funkcje, które wykonują rzeczywistą pracę: `_transfer`, `_mint`, `_burn` i `_approve`. + +#### Funkcja _transfer {#_transfer} + +```solidity + /** + * @dev Przenosi tokeny o wartości `amount` z `nadawcy` do `odbiorcy`. + * + * Ta wewnętrzna funkcja jest odpowiednikiem {transfer} i może być używana do + * np. implementacji automatycznych opłat za tokeny, mechanizmów cięcia itp. + * + * Emituje zdarzenie {Transfer}. + * + * Wymagania: + * + * - `nadawca` nie może być adresem zerowym. + * - `odbiorca` nie może być adresem zerowym. + * - `nadawca` musi mieć saldo co najmniej `amount`. + */ + function _transfer(address sender, address recipient, uint256 amount) internal virtual { +``` + +Ta funkcja, `_transfer`, transferuje tokeny z jednego konta na drugie. Jest ona wywoływana zarówno przez +`transfer` (dla transferów z własnego konta nadawcy), jak i `transferFrom` (dla używania zezwoleń +do transferu z konta kogoś innego). + +  + +```solidity + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); +``` + +Nikt w rzeczywistości nie posiada adresu zerowego w Ethereum (tzn. nikt nie zna klucza prywatnego, którego pasujący klucz publiczny +jest przekształcany na adres zerowy). Gdy ludzie używają tego adresu, jest to zwykle błąd oprogramowania - więc +kończymy niepowodzeniem, jeśli adres zerowy jest używany jako nadawca lub odbiorca. + +  + +```solidity + _beforeTokenTransfer(sender, recipient, amount); + +``` + +Istnieją dwa sposoby wykorzystania tego kontraktu: + +1. Użyj go jako szablonu dla własnego kodu +2. [Dziedzicz po nim](https://www.bitdegree.org/learn/solidity-inheritance) i nadpisuj tylko te funkcje, które musisz zmodyfikować + +Druga metoda jest znacznie lepsza, ponieważ kod OpenZeppelin ERC-20 został już poddany audytowi i wykazano, że jest bezpieczny. Gdy używasz dziedziczenia, +jasne jest, jakie funkcje modyfikujesz, a aby zaufać twojemu kontraktowi, ludzie muszą tylko poddać audytowi te konkretne funkcje. + +Często przydatne jest wykonanie funkcji za każdym razem, gdy tokeny zmieniają właściciela. Jednak `_transfer` jest bardzo ważną funkcją i możliwe jest +napisanie jej w sposób niebezpieczny (patrz poniżej), więc najlepiej jej nie nadpisywać. Rozwiązaniem jest `_beforeTokenTransfer`, +[funkcja typu hook](https://wikipedia.org/wiki/Hooking). Możesz nadpisać tę funkcję, a będzie ona wywoływana przy każdym transferze. + +  + +```solidity + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[recipient] = _balances[recipient].add(amount); +``` + +To są linie, które faktycznie wykonują transfer. Zauważ, że **nic** nie ma między nimi, i że odejmujemy +przekazaną kwotę od nadawcy przed dodaniem jej do odbiorcy. Jest to ważne, ponieważ gdyby w środku było +wywołanie innego kontraktu, mogłoby to zostać wykorzystane do oszukania tego kontraktu. W ten sposób transfer +jest atomowy, nic nie może się zdarzyć w jego środku. + +  + +```solidity + emit Transfer(sender, recipient, amount); + } +``` + +Na koniec wyemituj zdarzenie `Transfer`. Zdarzenia nie są dostępne dla inteligentnych kontraktów, ale kod działający poza blockchainem +może nasłuchiwać zdarzeń i na nie reagować. Na przykład portfel może śledzić, kiedy właściciel dostaje więcej tokenów. + +#### Funkcje _mint i _burn {#_mint-and-_burn} + +Te dwie funkcje (`_mint` i `_burn`) modyfikują całkowitą podaż tokenów. +Są one wewnętrzne i w tym kontrakcie nie ma funkcji, która by je wywoływała, +więc są przydatne tylko wtedy, gdy dziedziczysz po kontrakcie i dodajesz własną +logikę, aby zdecydować, w jakich warunkach emitować nowe tokeny lub spalać istniejące +. + +**UWAGA:** Każdy token ERC-20 ma własną logikę biznesową, która dyktuje zarządzanie tokenami. +Na przykład, kontrakt o stałej podaży może wywoływać `_mint` tylko +w konstruktorze i nigdy nie wywoływać `_burn`. Kontrakt, który sprzedaje tokeny, +wywoła `_mint`, gdy zostanie opłacony, i prawdopodobnie wywoła `_burn` w pewnym momencie, +aby uniknąć niekontrolowanej inflacji. + +```solidity + /** @dev Tworzy `amount` tokenów i przypisuje je do `account`, zwiększając + * całkowitą podaż. + * + * Emituje zdarzenie {Transfer} z `from` ustawionym na adres zerowy. + * + * Wymagania: + * + * - `to` nie może być adresem zerowym. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + _beforeTokenTransfer(address(0), account, amount); + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } +``` + +Pamiętaj o aktualizacji `_totalSupply`, gdy zmieni się całkowita liczba tokenów. + +  + +```solidity + /** + * @dev Niszczy tokeny o `wartości` `amount` z `konta`, zmniejszając + * całkowitą podaż. + * + * Emituje zdarzenie {Transfer} z `to` ustawionym na adres zerowy. + * + * Wymagania: + * + * - `konto` nie może być adresem zerowym. + * - `konto` musi mieć co najmniej `amount` tokenów. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } +``` + +Funkcja `_burn` jest prawie identyczna z `_mint`, z tym że działa w przeciwnym kierunku. + +#### Funkcja _approve {#_approve} + +To jest funkcja, która faktycznie określa zezwolenia. Zauważ, że pozwala ona właścicielowi określić +zezwolenie, które jest wyższe niż bieżące saldo właściciela. Jest to w porządku, ponieważ saldo jest +sprawdzane w momencie transferu, kiedy może być inne niż saldo w momencie tworzenia zezwolenia +. + +```solidity + /** + * @dev Ustawia `amount` jako zezwolenie `spendera` na tokeny `właściciela`. + * + * Ta wewnętrzna funkcja jest odpowiednikiem `approve` i może być używana do + * np. ustawiania automatycznych zezwoleń dla niektórych podsystemów itp. + * + * Emituje zdarzenie {Approval}. + * + * Wymagania: + * + * - `właściciel` nie może być adresem zerowym. + * - `spender` nie może być adresem zerowym. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; +``` + +  + +Emituj zdarzenie `Approval`. W zależności od tego, jak napisana jest aplikacja, kontrakt wydającego może być poinformowany o +zatwierdzeniu przez właściciela lub przez serwer, który nasłuchuje tych zdarzeń. + +```solidity + emit Approval(owner, spender, amount); + } + +``` + +### Modyfikacja zmiennej Decimals {#modify-the-decimals-variable} + +```solidity + + + /** + * @dev Ustawia {decimals} na wartość inną niż domyślna 18. + * + * OSTRZEŻENIE: Ta funkcja powinna być wywoływana tylko z konstruktora. Większość + * aplikacji, które wchodzą w interakcję z kontraktami tokenów, nie spodziewa się, + * że {decimals} kiedykolwiek się zmieni i może działać niepoprawnie, jeśli tak się stanie. + */ + function _setupDecimals(uint8 decimals_) internal { + _decimals = decimals_; + } +``` + +Ta funkcja modyfikuje zmienną `_decimals`, która służy do informowania interfejsów użytkownika, jak interpretować kwotę. +Powinieneś ją wywołać z konstruktora. Byłoby nieuczciwe wywoływać ją w dowolnym późniejszym momencie, a aplikacje +nie są zaprojektowane do obsługi tego. + +### Hooki {#hooks} + +```solidity + + /** + * @dev Hook, który jest wywoływany przed każdym transferem tokenów. Obejmuje to + * minting i burning. + * + * Warunki wywołania: + * + * - gdy `from` i `to` są oba niezerowe, `amount` tokenów ``from`` + * zostanie przetransferowane do `to`. + * - gdy `from` jest zerem, `amount` tokenów zostanie wyemitowane dla `to`. + * - gdy `to` jest zerem, `amount` tokenów ``from`` zostanie spalonych. + * - `from` i `to` nigdy nie są oba zerami. + * + * Aby dowiedzieć się więcej o hookach, przejdź do xref:ROOT:extending-contracts.adoc#using-hooks[Używanie hooków]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } +} +``` + +To jest funkcja hook, która ma być wywoływana podczas transferów. Jest tutaj pusta, ale jeśli potrzebujesz, +aby coś robiła, po prostu ją nadpisujesz. + +## Wnioski {#conclusion} + +Dla przypomnienia, oto niektóre z najważniejszych pomysłów w tym kontrakcie (moim zdaniem, twoje prawdopodobnie będą się różnić): + +- _W blockchainie nie ma tajemnic_. Wszelkie informacje, do których inteligentny kontrakt ma dostęp, + są dostępne dla całego świata. +- Możesz kontrolować kolejność własnych transakcji, ale nie to, kiedy odbywają się transakcje innych osób + . To jest powód, dla którego zmiana zezwolenia może być niebezpieczna, ponieważ pozwala + wydającemu wydać sumę obu zezwoleń. +- Wartości typu `uint256` zawijają się. Innymi słowy, _0-1=2^256-1_. Jeśli nie jest to pożądane + zachowanie, musisz to sprawdzić (lub użyć biblioteki SafeMath, która robi to za Ciebie). Zauważ, że to się zmieniło w + [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html). +- Wykonuj wszystkie zmiany stanu określonego typu w określonym miejscu, ponieważ ułatwia to audyt. + To jest powód, dla którego mamy, na przykład, `_approve`, które jest wywoływane przez `approve`, `transferFrom`, + `increaseAllowance` i `decreaseAllowance` +- Zmiany stanu powinny być atomowe, bez żadnych innych działań w ich środku (jak widać + w `_transfer`). Dzieje się tak, ponieważ podczas zmiany stanu masz niespójny stan. Na przykład, + między czasem, w którym odejmujesz od salda nadawcy, a czasem, w którym dodajesz do salda + odbiorcy, istnieje mniej tokenów, niż powinno być. Może to być potencjalnie nadużywane, jeśli + pomiędzy nimi są operacje, zwłaszcza wywołania innego kontraktu. + +Teraz, gdy zobaczyłeś, jak napisany jest kontrakt OpenZeppelin ERC-20, a zwłaszcza jak jest +on uczyniony bardziej bezpiecznym, idź i napisz własne bezpieczne kontrakty i aplikacje. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). diff --git a/public/content/translations/pl/developers/tutorials/erc20-with-safety-rails/index.md b/public/content/translations/pl/developers/tutorials/erc20-with-safety-rails/index.md new file mode 100644 index 00000000000..547dce7f155 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/erc20-with-safety-rails/index.md @@ -0,0 +1,217 @@ +--- +title: ERC-20 z zabezpieczeniami +description: "Jak pomóc ludziom unikać prostych błędów" +author: Ori Pomerantz +lang: pl +tags: [ "erc-20" ] +skill: beginner +published: 2022-08-15 +--- + +## Wprowadzenie {#introduction} + +Jedną z wielkich zalet Ethereum jest to, że nie ma centralnego organu, który mógłby modyfikować lub cofać Twoje transakcje. Jednym z wielkich problemów z Ethereum jest to, że nie ma centralnego organu z uprawnieniami do cofania błędów użytkowników lub nielegalnych transakcji. W tym artykule dowiesz się o niektórych typowych błędach popełnianych przez użytkowników z tokenami [ERC-20](/developers/docs/standards/tokens/erc-20/), a także o tym, jak tworzyć kontrakty ERC-20, które pomagają użytkownikom unikać tych błędów lub które dają centralnemu organowi pewne uprawnienia (na przykład do zamrażania kont). + +Pamiętaj, że chociaż będziemy używać [kontraktu tokena ERC-20 OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20), ten artykuł nie wyjaśnia go szczegółowo. Możesz znaleźć te informacje [tutaj](/developers/tutorials/erc20-annotated-code). + +Jeśli chcesz zobaczyć pełny kod źródłowy: + +1. Otwórz [Remix IDE](https://remix.ethereum.org/). +2. Kliknij ikonę klonowania z GitHuba (![ikona klonowania z GitHuba](icon-clone.png)). +3. Sklonuj repozytorium z GitHuba `https://github.com/qbzzt/20220815-erc20-safety-rails`. +4. Otwórz **contracts > erc20-safety-rails.sol**. + +## Tworzenie kontraktu ERC-20 {#creating-an-erc-20-contract} + +Zanim dodamy funkcjonalność zabezpieczeń, potrzebujemy kontraktu ERC-20. W tym artykule użyjemy [kreatora kontraktów OpenZeppelin](https://docs.openzeppelin.com/contracts/5.x/wizard). Otwórz go w innej przeglądarce i postępuj zgodnie z poniższymi instrukcjami: + +1. Wybierz **ERC20**. + +2. Wprowadź te ustawienia: + + | Parametr | Wartość | + | ---------------------- | ---------------- | + | Nazwa | SafetyRailsToken | + | Symbol | SAFE | + | Premint | 1000 | + | Funkcje | Brak | + | Kontrola dostępu | Ownable | + | Możliwość aktualizacji | Brak | + +3. Przewiń w górę i kliknij **Otwórz w Remix** (dla Remix) lub **Pobierz**, aby użyć innego środowiska. Zakładam, że używasz Remix, jeśli używasz czegoś innego, po prostu wprowadź odpowiednie zmiany. + +4. Mamy teraz w pełni funkcjonalny kontrakt ERC-20. Możesz rozwinąć `.deps` > `npm`, aby zobaczyć zaimportowany kod. + +5. Skompiluj, wdróż i pobaw się kontraktem, aby zobaczyć, że działa on jak kontrakt ERC-20. Jeśli chcesz dowiedzieć się, jak używać Remix, [skorzystaj z tego samouczka](https://remix.ethereum.org/?#activate=udapp,solidity,LearnEth). + +## Częste błędy {#common-mistakes} + +### Błędy {#the-mistakes} + +Użytkownicy czasami wysyłają tokeny na zły adres. Chociaż nie możemy czytać w ich myślach, aby wiedzieć, co zamierzali zrobić, istnieją dwa rodzaje błędów, które zdarzają się często i są łatwe do wykrycia: + +1. Wysyłanie tokenów na własny adres kontraktu. Na przykład, [token OP Optimism](https://optimism.mirror.xyz/qvd0WfuLKnePm1Gxb9dpGchPf5uDz5NSMEFdgirDS4c) zdołał zgromadzić [ponad 120 000](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000042) tokenów OP w mniej niż dwa miesiące. Reprezentuje to znaczną ilość bogactwa, które ludzie przypuszczalnie po prostu stracili. + +2. Wysyłanie tokenów na pusty adres, taki, który nie odpowiada [kontu zewnętrznemu (EOA)](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs) lub [inteligentnemu kontraktowi](/developers/docs/smart-contracts). Chociaż nie mam statystyk dotyczących tego, jak często to się zdarza, [jeden incydent mógł kosztować 20 000 000 tokenów](https://gov.optimism.io/t/message-to-optimism-community-from-wintermute/2595). + +### Zapobieganie transferom {#preventing-transfers} + +Kontrakt ERC-20 OpenZeppelin zawiera [hak (hook), `_beforeTokenTransfer`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L364-L368), który jest wywoływany przed transferem tokena. Domyślnie ten hak nic nie robi, ale możemy podpiąć do niego naszą własną funkcjonalność, taką jak kontrole, które cofają transakcję w razie problemu. + +Aby użyć tego haka, dodaj tę funkcję po konstruktorze: + +```solidity + function _beforeTokenTransfer(address from, address to, uint256 amount) + internal virtual + override(ERC20) + { + super._beforeTokenTransfer(from, to, amount); + } +``` + +Niektóre części tej funkcji mogą być nowe, jeśli nie znasz dobrze języka Solidity: + +```solidity + internal virtual +``` + +Słowo kluczowe `virtual` oznacza, że tak jak odziedziczyliśmy funkcjonalność z `ERC20` i nadpisaliśmy tę funkcję, inne kontrakty mogą dziedziczyć po nas i nadpisywać tę funkcję. + +```solidity + override(ERC20) +``` + +Musimy jawnie określić, że [nadpisujemy](https://docs.soliditylang.org/en/v0.8.15/contracts.html#function-overriding) definicję `_beforeTokenTransfer` z tokena ERC20. Ogólnie rzecz biorąc, jawne definicje są znacznie lepsze z punktu widzenia bezpieczeństwa niż te niejawne – nie możesz zapomnieć, że coś zrobiłeś, jeśli masz to tuż przed oczami. To jest również powód, dla którego musimy określić, którą `_beforeTokenTransfer` z klasy nadrzędnej nadpisujemy. + +```solidity + super._beforeTokenTransfer(from, to, amount); +``` + +Ta linia wywołuje funkcję `_beforeTokenTransfer` kontraktu lub kontraktów, z których dziedziczyliśmy i które ją posiadają. W tym przypadku jest to tylko `ERC20`, `Ownable` nie ma tego haka. Mimo że obecnie `ERC20._beforeTokenTransfer` nic nie robi, wywołujemy ją na wypadek, gdyby w przyszłości została dodana jakaś funkcjonalność (i zdecydujemy się wtedy na ponowne wdrożenie kontraktu, ponieważ kontrakty nie zmieniają się po wdrożeniu). + +### Kodowanie wymagań {#coding-the-requirements} + +Chcemy dodać do funkcji następujące wymagania: + +- Adres `to` nie może być równy `address(this)`, czyli adresowi samego kontraktu ERC-20. +- Adres `to` nie może być pusty, musi być to: + - Konto zewnętrzne (EOA). Nie możemy bezpośrednio sprawdzić, czy adres jest EOA, ale możemy sprawdzić saldo ETH adresu. Konta EOA prawie zawsze mają jakieś saldo, nawet jeśli nie są już używane – trudno jest je wyczyścić do ostatniego wei. + - Inteligentny kontrakt. Sprawdzanie, czy adres jest inteligentnym kontraktem, jest nieco trudniejsze. Istnieje kod operacyjny, który sprawdza długość kodu zewnętrznego, o nazwie [`EXTCODESIZE`](https://www.evm.codes/#3b), ale nie jest on dostępny bezpośrednio w Solidity. Musimy do tego użyć [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html), który jest asemblerem EVM. Istnieją inne wartości, których moglibyśmy użyć z Solidity ([`
.code` i `
.codehash`](https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#members-of-address-types)), ale kosztują więcej. + +Przeanalizujmy nowy kod linia po linii: + +```solidity + require(to != address(this), "Nie można wysyłać tokenów na adres kontraktu"); +``` + +To jest pierwsze wymaganie, sprawdzić, czy `to` i `this(address)` nie są tym samym. + +```solidity + bool isToContract; + assembly { + isToContract := gt(extcodesize(to), 0) + } +``` + +W ten sposób sprawdzamy, czy adres jest kontraktem. Nie możemy otrzymać wyniku bezpośrednio z Yul, więc zamiast tego definiujemy zmienną do przechowywania wyniku (w tym przypadku `isToContract`). Yul działa w ten sposób, że każdy kod operacyjny jest traktowany jako funkcja. Najpierw więc wywołujemy [`EXTCODESIZE`](https://www.evm.codes/#3b), aby uzyskać rozmiar kontraktu, a następnie używamy [`GT`](https://www.evm.codes/#11), aby sprawdzić, czy nie jest on zerowy (mamy do czynienia z liczbami całkowitymi bez znaku, więc oczywiście nie może być ujemny). Następnie zapisujemy wynik do `isToContract`. + +```solidity + require(to.balance != 0 || isToContract, "Nie można wysyłać tokenów na pusty adres"); +``` + +I na koniec mamy faktyczne sprawdzanie pustych adresów. + +## Dostęp administracyjny {#admin-access} + +Czasami przydatne jest posiadanie administratora, który może cofać błędy. Aby zmniejszyć potencjał nadużyć, ten administrator może być [multisigiem](https://blog.logrocket.com/security-choices-multi-signature-wallets/), dzięki czemu wiele osób musi zgodzić się na daną akcję. W tym artykule omówimy dwie funkcje administracyjne: + +1. Zamrażanie i odmrażanie kont. Może to być przydatne, na przykład, gdy konto może być zagrożone. +2. Czyszczenie aktywów. + + Czasami oszuści wysyłają fałszywe tokeny do kontraktu prawdziwego tokena, aby zyskać na wiarygodności. Na przykład, [zobacz tutaj](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe?tab=holders). Prawdziwy kontrakt ERC-20 to [0x4200....0042](https://optimism.blockscout.com/token/0x4200000000000000000000000000000000000042). Oszustwo, które go udaje, to [0x234....bbe](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe). + + Możliwe jest również, że ludzie przez pomyłkę wyślą prawdziwe tokeny ERC-20 do naszego kontraktu, co jest kolejnym powodem, dla którego warto mieć sposób na ich wyciągnięcie. + +OpenZeppelin dostarcza dwa mechanizmy umożliwiające dostęp administracyjny: + +- Kontrakty [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) mają jednego właściciela. Funkcje, które mają [modyfikator](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm) `onlyOwner`, mogą być wywoływane tylko przez tego właściciela. Właściciele mogą przenieść własność na kogoś innego lub całkowicie się jej zrzec. Prawa wszystkich pozostałych kont są zazwyczaj identyczne. +- Kontrakty [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) mają [kontrolę dostępu opartą na rolach (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control). + +Dla uproszczenia, w tym artykule używamy `Ownable`. + +### Zamrażanie i rozmrażanie kontraktów {#freezing-and-thawing-contracts} + +Zamrażanie i rozmrażanie kontraktów wymaga kilku zmian: + +- [Mapowanie](https://www.tutorialspoint.com/solidity/solidity_mappings.htm) adresów na [wartości logiczne](https://en.wikipedia.org/wiki/Boolean_data_type), aby śledzić, które adresy są zamrożone. Wszystkie wartości są początkowo zerowe, co dla wartości logicznych jest interpretowane jako fałsz (false). Jest to pożądane, ponieważ domyślnie konta nie są zamrożone. + + ```solidity + mapping(address => bool) public frozenAccounts; + ``` + +- [Zdarzenia](https://www.tutorialspoint.com/solidity/solidity_events.htm), aby informować wszystkich zainteresowanych, gdy konto zostanie zamrożone lub rozmrożone. Technicznie rzecz biorąc, zdarzenia nie są wymagane do tych działań, ale pomaga to kodowi offchain nasłuchiwać tych zdarzeń i wiedzieć, co się dzieje. Uważa się za dobry zwyczaj, aby inteligentny kontrakt je emitował, gdy dzieje się coś, co może być istotne dla kogoś innego. + + Zdarzenia są indeksowane, więc będzie można wyszukać wszystkie przypadki zamrożenia lub rozmrożenia konta. + + ```solidity + // Gdy konta są zamrażane lub odmrażane + event AccountFrozen(address indexed _addr); + event AccountThawed(address indexed _addr); + ``` + +- Funkcje do zamrażania i rozmrażania kont. Te dwie funkcje są prawie identyczne, więc omówimy tylko funkcję zamrażania. + + ```solidity + function freezeAccount(address addr) + public + onlyOwner + ``` + + Funkcje oznaczone jako [`public`](https://www.tutorialspoint.com/solidity/solidity_contracts.htm) mogą być wywoływane z innych inteligentnych kontraktów lub bezpośrednio przez transakcję. + + ```solidity + { + require(!frozenAccounts[addr], "Konto jest już zamrożone"); + frozenAccounts[addr] = true; + emit AccountFrozen(addr); + } // freezeAccount + ``` + + Jeśli konto jest już zamrożone, cofnij transakcję. W przeciwnym razie zamroź je i `emituj` zdarzenie. + +- Zmień `_beforeTokenTransfer`, aby uniemożliwić przenoszenie pieniędzy z zamrożonego konta. Pamiętaj, że pieniądze nadal mogą być przelewane na zamrożone konto. + + ```solidity + require(!frozenAccounts[from], "Konto jest zamrożone"); + ``` + +### Czyszczenie aktywów {#asset-cleanup} + +Aby uwolnić tokeny ERC-20 przechowywane przez ten kontrakt, musimy wywołać funkcję na kontrakcie tokena, do którego należą, albo [`transfer`](https://eips.ethereum.org/EIPS/eip-20#transfer), albo [`approve`](https://eips.ethereum.org/EIPS/eip-20#approve). W tym przypadku nie ma sensu marnować gazu na przydziały (allowances), możemy równie dobrze przenieść je bezpośrednio. + +```solidity + function cleanupERC20( + address erc20, + address dest + ) + public + onlyOwner + { + IERC20 token = IERC20(erc20); +``` + +To jest składnia do tworzenia obiektu dla kontraktu, gdy otrzymamy jego adres. Możemy to zrobić, ponieważ mamy definicję tokenów ERC20 jako część kodu źródłowego (patrz linia 4), a ten plik zawiera [definicję dla IERC20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol), interfejs dla kontraktu ERC-20 OpenZeppelin. + +```solidity + uint balance = token.balanceOf(address(this)); + token.transfer(dest, balance); + } +``` + +To jest funkcja czyszcząca, więc przypuszczalnie nie chcemy zostawiać żadnych tokenów. Zamiast ręcznego pobierania salda od użytkownika, możemy równie dobrze zautomatyzować ten proces. + +## Wnioski {#conclusion} + +To nie jest idealne rozwiązanie – nie ma idealnego rozwiązania problemu „użytkownik popełnił błąd”. Jednak używanie tego rodzaju kontroli może przynajmniej zapobiec niektórym błędom. Możliwość zamrażania kont, chociaż niebezpieczna, może być użyta do ograniczenia szkód niektórych hacków poprzez uniemożliwienie hakerowi dostępu do skradzionych środków. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). diff --git a/public/content/translations/pl/developers/tutorials/ethereum-for-web2-auth/index.md b/public/content/translations/pl/developers/tutorials/ethereum-for-web2-auth/index.md new file mode 100644 index 00000000000..c8983d34669 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/ethereum-for-web2-auth/index.md @@ -0,0 +1,886 @@ +--- +title: "Używanie Ethereum do uwierzytelniania web2" +description: "Po przeczytaniu tego samouczka deweloper będzie w stanie zintegrować logowanie Ethereum (web3) z logowaniem SAML, standardem używanym w web2 do zapewniania jednokrotnego logowania i innych powiązanych usług. Pozwala to na uwierzytelnianie dostępu do zasobów web2 poprzez podpisy Ethereum, z atrybutami użytkownika pochodzącymi z poświadczeń." +author: Ori Pomerantz +tags: [ "web2", "uwierzytelnianie", "eas" ] +skill: beginner +lang: pl +published: 2025-04-30 +--- + +## Wprowadzenie + +[SAML](https://www.onelogin.com/learn/saml) to standard używany w web2, który pozwala [dostawcy tożsamości (IdP)](https://en.wikipedia.org/wiki/Identity_provider#SAML_identity_provider) na dostarczanie informacji o użytkowniku [dostawcom usług (SP)](https://en.wikipedia.org/wiki/Service_provider_\(SAML\)). + +W tym samouczku dowiesz się, jak zintegrować podpisy Ethereum z SAML, aby umożliwić użytkownikom używanie ich portfeli Ethereum do uwierzytelniania się w usługach web2, które jeszcze nie obsługują natywnie Ethereum. + +Pamiętaj, że ten samouczek został napisany dla dwóch różnych grup odbiorców: + +- Ludzie z kręgu Ethereum, którzy rozumieją Ethereum i potrzebują nauczyć się SAML +- Osoby z Web2, które rozumieją SAML i uwierzytelnianie web2 i muszą nauczyć się Ethereum + +W rezultacie będzie on zawierał wiele materiałów wprowadzających, które już znasz. Możesz je pominąć. + +### SAML dla osób z kręgu Ethereum + +SAML to scentralizowany protokół. Dostawca usług (SP) akceptuje asercje (takie jak "to jest mój użytkownik Jan, powinien mieć uprawnienia do wykonywania A, B i C") od dostawcy tożsamości (IdP) tylko wtedy, gdy ma z nim wcześniej ustaloną relację zaufania lub z [urzędem certyfikacji](https://www.ssl.com/article/what-is-a-certificate-authority-ca/), który podpisał certyfikat tegoż IdP. + +Na przykład SP może być biurem podróży świadczącym usługi turystyczne dla firm, a IdP może być wewnętrzną stroną internetową firmy. Gdy pracownicy muszą zarezerwować podróż służbową, biuro podróży wysyła ich do uwierzytelnienia przez firmę, zanim pozwoli im faktycznie zarezerwować podróż. + +![Proces SAML krok po kroku](./fig-01-saml.png) + +W ten sposób trzy podmioty, przeglądarka, SP i IdP, negocjują dostęp. SP nie musi z góry wiedzieć nic o użytkowniku korzystającym z przeglądarki, wystarczy, że ufa IdP. + +### Ethereum dla osób z kręgu SAML + +Ethereum to system zdecentralizowany. + +![Logowanie Ethereum](./fig-02-eth-logon.png) + +Użytkownicy posiadają klucz prywatny (zazwyczaj przechowywany w rozszerzeniu przeglądarki). Z klucza prywatnego można wyprowadzić klucz publiczny, a z niego 20-bajtowy adres. Gdy użytkownicy muszą zalogować się do systemu, są proszeni o podpisanie wiadomości z nonce (wartością jednorazowego użytku). Serwer może zweryfikować, czy podpis został utworzony przez ten adres. + +![Pobieranie dodatkowych danych z poświadczeń](./fig-03-eas-data.png) + +Podpis weryfikuje tylko adres Ethereum. Aby uzyskać inne atrybuty użytkownika, zazwyczaj używa się [poświadczeń](https://attest.org/). Poświadczenie zazwyczaj zawiera następujące pola: + +- **Poświadczający**, adres, który dokonał poświadczenia +- **Odbiorca**, adres, którego dotyczy poświadczenie +- **Dane**, czyli dane, które są poświadczane, takie jak imię, uprawnienia itp. +- **Schemat**, identyfikator schematu używanego do interpretacji danych. + +Ze względu na zdecentralizowany charakter Ethereum każdy użytkownik może tworzyć poświadczenia. Tożsamość poświadczającego jest ważna, aby zidentyfikować, które poświadczenia uważamy za wiarygodne. + +## Konfiguracja + +Pierwszym krokiem jest zapewnienie komunikacji pomiędzy SAML SP i SAML IdP. + +1. Pobierz oprogramowanie. Przykładowe oprogramowanie do tego artykułu znajduje się [na githubie](https://github.com/qbzzt/250420-saml-ethereum). Różne etapy są przechowywane w różnych gałęziach, na tym etapie potrzebujesz gałęzi `saml-only` + + ```sh + git clone https://github.com/qbzzt/250420-saml-ethereum -b saml-only + cd 250420-saml-ethereum + pnpm install + ``` + +2. Utwórz klucze z certyfikatami z podpisem własnym. Oznacza to, że klucz jest swoim własnym urzędem certyfikacji i musi zostać ręcznie zaimportowany do dostawcy usług. Więcej informacji można znaleźć w [dokumentacji OpenSSL](https://docs.openssl.org/master/man1/openssl-req/). + + ```sh + mkdir keys + cd keys + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-sp.crt -keyout saml-sp.pem -subj /CN=sp/ + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-idp.crt -keyout saml-idp.pem -subj /CN=idp/ + cd .. + ``` + +3. Uruchom serwery (zarówno SP, jak i IdP) + + ```sh + pnpm start + ``` + +4. Przejdź do SP pod adresem URL [http://localhost:3000/](http://localhost:3000/) i kliknij przycisk, aby zostać przekierowanym do IdP (port 3001). + +5. Podaj IdP swój adres e-mail i kliknij **Zaloguj się do dostawcy usług**. Zobaczysz, że zostaniesz przekierowany z powrotem do dostawcy usług (port 3000) i że zna Cię on po Twoim adresie e-mail. + +### Szczegółowe wyjaśnienie + +Oto co się dzieje, krok po kroku: + +![Normalne logowanie SAML bez Ethereum](./fig-04-saml-no-eth.png) + +#### src/config.mts + +Ten plik zawiera konfigurację zarówno dla dostawcy tożsamości, jak i dostawcy usług. Zwykle byłyby to dwa różne podmioty, ale tutaj dla uproszczenia możemy współdzielić kod. + +```typescript +const fs = await import("fs") + +const protocol="http" +``` + +Na razie tylko testujemy, więc możemy używać HTTP. + +```typescript +export const spCert = fs.readFileSync("keys/saml-sp.crt").toString() +export const idpCert = fs.readFileSync("keys/saml-idp.crt").toString() +``` + +Odczytaj klucze publiczne, które są normalnie dostępne dla obu komponentów (i są albo bezpośrednio zaufane, albo podpisane przez zaufany urząd certyfikacji). + +```typescript +export const spPort = 3000 +export const spHostname = "localhost" +export const spDir = "sp" + +export const idpPort = 3001 +export const idpHostname = "localhost" +export const idpDir = "idp" + +export const spUrl = `${protocol}://${spHostname}:${spPort}/${spDir}` +export const idpUrl = `${protocol}://${idpHostname}:${idpPort}/${idpDir}` +``` + +Adresy URL dla obu komponentów. + +```typescript +export const spPublicData = { +``` + +Dane publiczne dla dostawcy usług. + +```typescript + entityID: `${spUrl}/metadata`, +``` + +Zgodnie z konwencją, w SAML `entityID` to adres URL, pod którym dostępne są metadane podmiotu. Te metadane odpowiadają danym publicznym tutaj, z tą różnicą, że są w formie XML. + +```typescript + wantAssertionsSigned: true, + authnRequestsSigned: false, + signingCert: spCert, + allowCreate: true, + assertionConsumerService: [{ + Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + Location: `${spUrl}/assertion`, + }] + } +``` + +Najważniejszą definicją dla naszych celów jest `assertionConsumerServer`. Oznacza to, że aby potwierdzić coś (na przykład, "użytkownik, który wysyła Ci te informacje, to somebody@example.com") dostawcy usług, musimy użyć metody [HTTP POST](https://www.w3schools.com/tags/ref_httpmethods.asp) na adres URL `http://localhost:3000/sp/assertion`. + +```typescript +export const idpPublicData = { + entityID: `${idpUrl}/metadata`, + signingCert: idpCert, + wantAuthnRequestsSigned: false, + singleSignOnService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/login` + }], + singleLogoutService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/logout` + }], + } +``` + +Dane publiczne dostawcy tożsamości są podobne. Określa on, że aby zalogować użytkownika, należy wysłać żądanie POST na adres `http://localhost:3001/idp/login`, a aby go wylogować, na adres `http://localhost:3001/idp/logout`. + +#### src/sp.mts + +To jest kod, który implementuje dostawcę usług. + +```typescript +import * as config from "./config.mts" +const fs = await import("fs") +const saml = await import("samlify") +``` + +Do implementacji SAML używamy biblioteki [`samlify`](https://www.npmjs.com/package/samlify). + +```typescript +import * as validator from "@authenio/samlify-node-xmllint" +saml.setSchemaValidator(validator) +``` + +Biblioteka `samlify` oczekuje, że pakiet zweryfikuje, czy kod XML jest poprawny, podpisany oczekiwanym kluczem publicznym itp. Do tego celu używamy [`@authenio/samlify-node-xmllint`](https://www.npmjs.com/package/@authenio/samlify-node-xmllint). + +```typescript +const express = (await import("express")).default +const spRouter = express.Router() +const app = express() +``` + +[`Router`](https://expressjs.com/en/5x/api.html#router) z [`express`](https://expressjs.com/) to "mini strona internetowa", którą można zamontować wewnątrz strony internetowej. W tym przypadku używamy go do zgrupowania wszystkich definicji dostawcy usług. + +```typescript +const spPrivateKey = fs.readFileSync("keys/saml-sp.pem").toString() + +const sp = saml.ServiceProvider({ + privateKey: spPrivateKey, + ...config.spPublicData +}) +``` + +Własna reprezentacja dostawcy usług to wszystkie dane publiczne oraz klucz prywatny, którego używa do podpisywania informacji. + +```typescript +const idp = saml.IdentityProvider(config.idpPublicData); +``` + +Dane publiczne zawierają wszystko, co dostawca usług musi wiedzieć o dostawcy tożsamości. + +```typescript +spRouter.get(`/metadata`, + (req, res) => res.header("Content-Type", "text/xml").send(sp.getMetadata()) +) +``` + +Aby umożliwić interoperacyjność z innymi komponentami SAML, dostawcy usług i tożsamości powinni udostępniać swoje dane publiczne (zwane metadanymi) w formacie XML pod adresem `/metadata`. + +```typescript +spRouter.post(`/assertion`, +``` + +Jest to strona, do której przeglądarka uzyskuje dostęp w celu identyfikacji. Asercja zawiera identyfikator użytkownika (tutaj używamy adresu e-mail) i może zawierać dodatkowe atrybuty. To jest procedura obsługi kroku 7 na powyższym diagramie sekwencji. + +```typescript + async (req, res) => { + // console.log(`Odpowiedź SAML:\n${Buffer.from(req.body.SAMLResponse, 'base64').toString('utf-8')}`) +``` + +Możesz użyć polecenia w komentarzu, aby zobaczyć dane XML podane w asercji. Są one [zakodowane w base64](https://en.wikipedia.org/wiki/Base64). + +```typescript + try { + const loginResponse = await sp.parseLoginResponse(idp, 'post', req); +``` + +Analizuj żądanie logowania z serwera tożsamości. + +```typescript + res.send(` + + +

Witaj ${loginResponse.extract.nameID}

+ + + `) + res.send(); +``` + +Wyślij odpowiedź HTML, aby pokazać użytkownikowi, że otrzymaliśmy dane logowania. + +```typescript + } catch (err) { + console.error('Błąd przetwarzania odpowiedzi SAML:', err); + res.status(400).send('Uwierzytelnianie SAML nie powiodło się'); + } + } +) +``` + +Poinformuj użytkownika w przypadku niepowodzenia. + +```typescript +spRouter.get('/login', +``` + +Utwórz żądanie logowania, gdy przeglądarka spróbuje uzyskać dostęp do tej strony. To jest procedura obsługi kroku 1 na powyższym diagramie sekwencji. + +```typescript + async (req, res) => { + const loginRequest = await sp.createLoginRequest(idp, "post") +``` + +Pobierz informacje, aby wysłać żądanie logowania. + +```typescript + res.send(` + + + +``` + +Ta strona automatycznie przesyła formularz (patrz poniżej). W ten sposób użytkownik nie musi nic robić, aby zostać przekierowanym. To jest krok 2 na powyższym diagramie sekwencji. + +```typescript +
+``` + +Wyślij żądanie POST do `loginRequest.entityEndpoint` (adres URL punktu końcowego dostawcy tożsamości). + +```typescript + +``` + +Nazwa danych wejściowych to `loginRequest.type` (`SAMLRequest`). Zawartością tego pola jest `loginRequest.context`, który jest ponownie kodem XML zakodowanym w base64. + +```typescript +
+ + + `) + } +) + +app.use(express.urlencoded({extended: true})) +``` + +[Ten middleware](https://expressjs.com/en/5x/api.html#express.urlencoded) odczytuje treść [żądania HTTP](https://www.tutorialspoint.com/http/http_requests.htm). Domyślnie express je ignoruje, ponieważ większość żądań go nie wymaga. Potrzebujemy go, ponieważ POST używa treści. + +```typescript +app.use(`/${config.spDir}`, spRouter) +``` + +Zamontuj router w katalogu dostawcy usług (`/sp`). + +```typescript +app.get("/", (req, res) => { + res.send(` + + + + + + `) +}) +``` + +Jeśli przeglądarka spróbuje uzyskać dostęp do katalogu głównego, udostępnij jej link do strony logowania. + +```typescript +app.listen(config.spPort, () => { + console.log(`dostawca usług działa na http://${config.spHostname}:${config.spPort}`) +}) +``` + +Nasłuchuj na `spPort` za pomocą tej aplikacji express. + +#### src/idp.mts + +To jest dostawca tożsamości. Jest on bardzo podobny do dostawcy usług, poniższe wyjaśnienia dotyczą części, które się różnią. + +```typescript +const xmlParser = new (await import("fast-xml-parser")).XMLParser( + { + ignoreAttributes: false, // Zachowaj atrybuty + attributeNamePrefix: "@_", // Prefiks dla atrybutów + } +) +``` + +Musimy odczytać i zrozumieć żądanie XML, które otrzymujemy od dostawcy usług. + +```typescript +const getLoginPage = requestId => ` +``` + +Ta funkcja tworzy stronę z automatycznie przesyłanym formularzem, która jest zwracana w kroku 4 powyższego diagramu sekwencji. + +```typescript + + + Strona logowania + + +

Strona logowania

+
+ + Adres e-mail: +
+ +``` + +Są dwa pola, które wysyłamy do dostawcy usług: + +1. `requestId`, na który odpowiadamy. +2. Identyfikator użytkownika (na razie używamy adresu e-mail podanego przez użytkownika). + +```typescript +
+ + + +const idpRouter = express.Router() + +idpRouter.post("/loginSubmitted", async (req, res) => { + const loginResponse = await idp.createLoginResponse( +``` + +To jest procedura obsługi kroku 5 na powyższym diagramie sekwencji. [`idp.createLoginResponse`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L73-L125) tworzy odpowiedź na żądanie logowania. + +```typescript + sp, + { + authnContextClassRef: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport', + audience: sp.entityID, +``` + +Odbiorcą jest dostawca usług. + +```typescript + extract: { + request: { + id: req.body.requestId + } + }, +``` + +Informacje wyodrębnione z żądania. Jedynym parametrem w żądaniu, który nas interesuje, jest requestId, który pozwala dostawcy usług dopasować żądania i ich odpowiedzi. + +```typescript + signingKey: { privateKey: idpPrivateKey, publicKey: config.idpCert } // Zapewnij podpisywanie +``` + +Potrzebujemy `signingKey`, aby mieć dane do podpisania odpowiedzi. Dostawca usług nie ufa niepodpisanym żądaniom. + +```typescript + }, + "post", + { + email: req.body.email +``` + +To jest pole z informacjami o użytkowniku, które odsyłamy do dostawcy usług. + +```typescript + } + ); + + res.send(` + + + + +
+ +
+ + + `) +}) +``` + +Ponownie, użyj automatycznie przesyłanego formularza. To jest krok 6 na powyższym diagramie sekwencji. + +```typescript + +// Punkt końcowy IdP dla żądań logowania +idpRouter.post(`/login`, +``` + +To jest punkt końcowy, który odbiera żądanie logowania od dostawcy usług. To jest procedura obsługi kroku 3 na powyższym diagramie sekwencji. + +```typescript + async (req, res) => { + try { + // Obejście, ponieważ nie mogłem sprawić, by parseLoginRequest zadziałało. + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getLoginPage(samlRequest["samlp:AuthnRequest"]["@_ID"])) +``` + +Powinniśmy być w stanie użyć [`idp.parseLoginRequest`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L127-L144), aby odczytać ID żądania uwierzytelnienia. Jednak nie udało mi się go uruchomić i nie było warto poświęcać na to dużo czasu, więc użyłem [uniwersalnego parsera XML](https://www.npmjs.com/package/fast-xml-parser). Informacją, której potrzebujemy, jest atrybut `ID` wewnątrz tagu ``, który znajduje się na najwyższym poziomie XML. + +## Używanie podpisów Ethereum + +Teraz, gdy możemy wysłać tożsamość użytkownika do dostawcy usług, następnym krokiem jest uzyskanie tożsamości użytkownika w zaufany sposób. Viem pozwala nam po prostu poprosić portfel o adres użytkownika, ale oznacza to proszenie przeglądarki o informacje. Nie kontrolujemy przeglądarki, więc nie możemy automatycznie ufać odpowiedzi, którą od niej otrzymujemy. + +Zamiast tego IdP wyśle przeglądarce ciąg do podpisania. Jeśli portfel w przeglądarce podpisze ten ciąg, oznacza to, że to naprawdę ten adres (tzn. zna on klucz prywatny, który odpowiada temu adresowi). + +Aby zobaczyć to w działaniu, zatrzymaj istniejące IdP i SP i uruchom te polecenia: + +```sh +git checkout eth-signatures +pnpm install +pnpm start +``` + +Następnie przejdź [do SP](http://localhost:3000) i postępuj zgodnie z instrukcjami. + +Zauważ, że w tym momencie nie wiemy, jak uzyskać adres e-mail z adresu Ethereum, więc zamiast tego zgłaszamy `@bad.email.address` do SP. + +### Szczegółowe wyjaśnienie + +Zmiany dotyczą kroków 4–5 na poprzednim diagramie. + +![SAML z podpisem Ethereum](./fig-05-saml-w-signature.png) + +Jedynym plikiem, który zmieniliśmy, jest `idp.mts`. Oto zmienione części. + +```typescript +import { v4 as uuidv4 } from 'uuid' +import { verifyMessage } from 'viem' +``` + +Potrzebujemy tych dwóch dodatkowych bibliotek. Używamy [`uuid`](https://www.npmjs.com/package/uuid) do tworzenia wartości [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce). Sama wartość nie ma znaczenia, tylko fakt, że jest używana tylko raz. + +Biblioteka [`viem`](https://viem.sh/) pozwala nam używać definicji Ethereum. Tutaj potrzebujemy jej do zweryfikowania, czy podpis jest rzeczywiście ważny. + +```typescript +const loginPrompt = "Aby uzyskać dostęp do dostawcy usług, podpisz ten nonce: " +``` + +Portfel prosi użytkownika o pozwolenie na podpisanie wiadomości. Wiadomość, która jest tylko nonce, może dezorientować użytkowników, dlatego dołączamy ten monit. + +```typescript +// Trzymaj tutaj requestID +let nonces = {} +``` + +Potrzebujemy informacji o żądaniu, aby móc na nie odpowiedzieć. Moglibyśmy wysłać je z żądaniem (krok 4) i otrzymać je z powrotem (krok 5). Jednak nie możemy ufać informacjom, które otrzymujemy z przeglądarki, która jest pod kontrolą potencjalnie wrogiego użytkownika. Więc lepiej przechowywać je tutaj, z nonce jako kluczem. + +Zauważ, że dla uproszczenia robimy to tutaj jako zmienną. Ma to jednak kilka wad: + +- Jesteśmy podatni na atak typu „odmowa usługi”. Złośliwy użytkownik mógłby próbować logować się wielokrotnie, zapełniając naszą pamięć. +- Jeśli proces IdP musi zostać ponownie uruchomiony, tracimy istniejące wartości. +- Nie możemy równoważyć obciążenia między wieloma procesami, ponieważ każdy z nich miałby swoją własną zmienną. + +W systemie produkcyjnym użylibyśmy bazy danych i zaimplementowali jakiś mechanizm wygasania. + +```typescript +const getSignaturePage = requestId => { + const nonce = uuidv4() + nonces[nonce] = requestId +``` + +Utwórz nonce i przechowaj `requestId` do przyszłego użytku. + +```typescript + return ` + + + + + +

Proszę podpisać

+ +
+ + + +` +} +``` + +Reszta to standardowy HTML. + +```typescript +idpRouter.get("/signature/:nonce/:account/:signature", async (req, res) => { +``` + +To jest procedura obsługi kroku 5 na diagramie sekwencji. + +```typescript + const requestId = nonces[req.params.nonce] + if (requestId === undefined) { + res.send("Zły nonce") + return ; + } + + nonces[req.params.nonce] = undefined +``` + +Pobierz identyfikator żądania i usuń nonce z `nonces`, aby upewnić się, że nie można go ponownie użyć. + +```typescript + try { +``` + +Ponieważ istnieje tak wiele sposobów, w jakie podpis może być nieważny, opakowujemy to w `try...` blok `catch`, aby przechwycić wszelkie zgłoszone błędy. + +```typescript + const validSignature = await verifyMessage({ + address: req.params.account, + message: `${loginPrompt}${req.params.nonce}`, + signature: req.params.signature + }) +``` + +Użyj [`verifyMessage`](https://viem.sh/docs/actions/public/verifyMessage#verifymessage) do zaimplementowania kroku 5.5 na diagramie sekwencji. + +```typescript + if (!validSignature) + throw("Zły podpis") + } catch (err) { + res.send("Błąd:" + err) + return ; + } +``` + +Reszta procedury obsługi jest równoważna z tym, co zrobiliśmy wcześniej w procedurze obsługi `/loginSubmitted`, z wyjątkiem jednej małej zmiany. + +```typescript + const loginResponse = await idp.createLoginResponse( + . + . + . + { + email: req.params.account + "@bad.email.address" + } + ); +``` + +Nie mamy rzeczywistego adresu e-mail (uzyskamy go w następnej sekcji), więc na razie zwracamy adres Ethereum i wyraźnie oznaczamy go jako niebędący adresem e-mail. + +```typescript +// Punkt końcowy IdP dla żądań logowania +idpRouter.post(`/login`, + async (req, res) => { + try { + // Obejście, ponieważ nie mogłem sprawić, by parseLoginRequest zadziałało. + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getSignaturePage(samlRequest["samlp:AuthnRequest"]["@_ID"])) + } catch (err) { + console.error('Błąd przetwarzania odpowiedzi SAML:', err); + res.status(400).send('Uwierzytelnianie SAML nie powiodło się'); + } + } +) +``` + +Zamiast `getLoginPage`, użyj teraz `getSignaturePage` w procedurze obsługi kroku 3. + +## Uzyskiwanie adresu e-mail + +Następnym krokiem jest uzyskanie adresu e-mail, identyfikatora wymaganego przez dostawcę usług. Aby to zrobić, używamy [Ethereum Attestation Service (EAS)](https://attest.org/). + +Najłatwiejszym sposobem na uzyskanie poświadczeń jest użycie [API GraphQL](https://docs.attest.org/docs/developer-tools/api). Używamy tego zapytania: + +``` +query GetAttestationsByRecipient { + attestations( + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } + take: 1 + ) { + data + id + attester + } +} +``` + +Ten [`schemaId`](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977) zawiera tylko adres e-mail. To zapytanie prosi o poświadczenia tego schematu. Temat poświadczenia nazywa się `recipient`. Jest to zawsze adres Ethereum. + +Ostrzeżenie: Sposób, w jaki uzyskujemy tutaj poświadczenia, ma dwa problemy z bezpieczeństwem. + +- Korzystamy z punktu końcowego API `https://optimism.easscan.org/graphql`, który jest scentralizowanym komponentem. Możemy pobrać atrybut `id`, a następnie sprawdzić on-chain, aby zweryfikować, czy poświadczenie jest prawdziwe, ale punkt końcowy API nadal może cenzurować poświadczenia, nie informując nas o nich. + + Ten problem nie jest niemożliwy do rozwiązania, moglibyśmy uruchomić własny punkt końcowy GraphQL i pobierać poświadczenia z logów łańcucha, ale jest to nadmierne dla naszych celów. + +- Nie sprawdzamy tożsamości poświadczającego. Każdy może podać nam fałszywe informacje. W rzeczywistej implementacji mielibyśmy zestaw zaufanych poświadczających i sprawdzalibyśmy tylko ich poświadczenia. + +Aby zobaczyć to w działaniu, zatrzymaj istniejące IdP i SP i uruchom te polecenia: + +```sh +git checkout email-address +pnpm install +pnpm start +``` + +Następnie podaj swój adres e-mail. Masz na to dwa sposoby: + +- Zaimportuj portfel za pomocą klucza prywatnego i użyj testowego klucza prywatnego `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`. + +- Dodaj poświadczenie dla własnego adresu e-mail: + + 1. Przejdź do [schematu w eksploratorze poświadczeń](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977). + + 2. Kliknij **Poświadcz za pomocą schematu**. + + 3. Wprowadź swój adres Ethereum jako odbiorcę, swój adres e-mail jako adres e-mail i wybierz **Onchain**. Następnie kliknij **Utwórz poświadczenie**. + + 4. Zatwierdź transakcję w swoim portfelu. Będziesz potrzebować trochę ETH w [łańcuchu bloków Optimism](https://app.optimism.io/bridge/deposit), aby zapłacić za gaz. + +Tak czy inaczej, po wykonaniu tej czynności przejdź do [http://localhost:3000](http://localhost:3000) i postępuj zgodnie z instrukcjami. Jeśli zaimportowałeś testowy klucz prywatny, otrzymany adres e-mail to `test_addr_0@example.com`. Jeśli użyłeś własnego adresu, powinien to być adres, który poświadczyłeś. + +### Szczegółowe wyjaśnienie + +![Przejście od adresu Ethereum do adresu e-mail](./fig-06-saml-sig-n-email.png) + +Nowe kroki to komunikacja GraphQL, kroki 5.6 i 5.7. + +Ponownie, oto zmienione części `idp.mts`. + +```typescript +import { GraphQLClient } from 'graphql-request' +import { SchemaEncoder } from '@ethereum-attestation-service/eas-sdk' +``` + +Zaimportuj biblioteki, których potrzebujemy. + +```typescript +const graphqlEndpointUrl = "https://optimism.easscan.org/graphql" +``` + +Dla każdego łańcucha bloków istnieje [oddzielny punkt końcowy](https://docs.attest.org/docs/developer-tools/api). + +```typescript +const graphqlClient = new GraphQLClient(graphqlEndpointUrl, { fetch }) +``` + +Utwórz nowego klienta `GraphQLClient`, którego możemy użyć do odpytywania punktu końcowego. + +```typescript +const graphqlSchema = 'string emailAddress' +const graphqlEncoder = new SchemaEncoder(graphqlSchema) +``` + +GraphQL daje nam tylko nieprzezroczysty obiekt danych z bajtami. Aby go zrozumieć, potrzebujemy schematu. + +```typescript +const ethereumAddressToEmail = async ethAddr => { +``` + +Funkcja do konwersji adresu Ethereum na adres e-mail. + +```typescript + const query = ` + query GetAttestationsByRecipient { +``` + +To jest zapytanie GraphQL. + +```typescript + poświadczenia( +``` + +Szukamy poświadczeń. + +```typescript + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } +``` + +Poświadczenia, których chcemy, to te w naszym schemacie, gdzie odbiorcą jest `getAddress(ethAddr)`. Funkcja [`getAddress`](https://viem.sh/docs/utilities/getAddress#getaddress) upewnia się, że nasz adres ma poprawną [sumę kontrolną](https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md). Jest to konieczne, ponieważ w GraphQL wielkość liter ma znaczenie. "0xBAD060A7", "0xBad060A7" i "0xbad060a7" to różne wartości. + +```typescript + take: 1 +``` + +Niezależnie od tego, ile poświadczeń znajdziemy, chcemy tylko pierwsze. + +```typescript + ) { + data + id + attester + } + }` +``` + +Pola, które chcemy otrzymać. + +- `attester`: Adres, który przesłał poświadczenie. Zwykle służy to do decydowania, czy ufać poświadczeniu, czy nie. +- `id`: ID poświadczenia. Możesz użyć tej wartości, aby [odczytać poświadczenie on-chain](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000021?tab=read_proxy&source_address=0x4E0275Ea5a89e7a3c1B58411379D1a0eDdc5b088#0xa3112a64), aby zweryfikować, czy informacje z zapytania GraphQL są poprawne. +- `data`: Dane schematu (w tym przypadku adres e-mail). + +```typescript + const queryResult = await graphqlClient.request(query) + + if (queryResult.attestations.length == 0) + return "no_address@available.is" +``` + +Jeśli nie ma poświadczenia, zwróć wartość, która jest oczywiście nieprawidłowa, ale która wydawałaby się ważna dla dostawcy usług. + +```typescript + const attestationDataFields = graphqlEncoder.decodeData(queryResult.attestations[0].data) + return attestationDataFields[0].value.value +} +``` + +Jeśli istnieje wartość, użyj `decodeData` do zdekodowania danych. Nie potrzebujemy metadanych, które dostarcza, tylko samej wartości. + +```typescript + const loginResponse = await idp.createLoginResponse( + sp, + { + . + . + . + }, + "post", + { + email: await ethereumAddressToEmail(req.params.account) + } + ); +``` + +Użyj nowej funkcji, aby uzyskać adres e-mail. + +## A co z decentralizacją? + +W tej konfiguracji użytkownicy nie mogą udawać kogoś, kim nie są, o ile polegamy na godnych zaufania poświadczających w mapowaniu adresów Ethereum na adresy e-mail. Jednak nasz dostawca tożsamości jest nadal scentralizowanym komponentem. Każdy, kto ma klucz prywatny dostawcy tożsamości, może wysyłać fałszywe informacje do dostawcy usług. + +Może istnieć rozwiązanie wykorzystujące [obliczenia wielostronne (MPC)](https://en.wikipedia.org/wiki/Secure_multi-party_computation). Mam nadzieję napisać o tym w przyszłym samouczku. + +## Podsumowanie + +Przyjęcie standardu logowania, takiego jak podpisy Ethereum, stoi przed problemem jajka i kury. Dostawcy usług chcą dotrzeć do jak najszerszego rynku. Użytkownicy chcą mieć dostęp do usług bez martwienia się o obsługę ich standardu logowania. +Tworzenie adapterów, takich jak IdP Ethereum, może pomóc nam pokonać tę przeszkodę. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). diff --git a/public/content/translations/pl/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md b/public/content/translations/pl/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md index cf2a15cfcc5..d155d9ef78e 100644 --- a/public/content/translations/pl/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md +++ b/public/content/translations/pl/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md @@ -1,100 +1,101 @@ --- -title: Pierwsze kroki programowania w Ethereum za pomocą Alchemy -description: "To jest przewodnik dla początkujących, jak rozpocząć programowanie w Ethereum za pomocą Alchemy. Przeprowadzimy Cię od rejestracji w Alchemy, przez wysłanie żądania w wierszu poleceń, do napisania pierwszego skryptu web3! Nie jest wymagane doświadczenie w programowaniu blockchain!" +title: Pierwsze kroki w programowaniu w Ethereum +description: "To jest przewodnik dla początkujących, jak zacząć programować w Ethereum. Przeprowadzimy Cię od uruchomienia punktu końcowego API, przez wysłanie żądania z wiersza poleceń, aż po napisanie Twojego pierwszego skryptu web3! Doświadczenie w programowaniu blockchain nie jest wymagane!" author: "Elan Halpern" tags: - - "pierwsze kroki" - - "javascript" - - "ethers.js" - - "węzły" - - "zapytania" - - "alchemy" + [ + "JavaScript", + "ethers.js", + "węzły", + "zapytania", + "alchemy" + ] skill: beginner lang: pl published: 2020-10-30 -source: Średni +source: Medium sourceUrl: https://medium.com/alchemy-api/getting-started-with-ethereum-development-using-alchemy-c3d6a45c567f --- -![Logo Ethereum i Alchemy](./ethereum-alchemy.png) +![Loga Ethereum i Alchemy](./ethereum-alchemy.png) -To jest przewodnik dla początkujących po rozpoczęciu programowania w Ethereum przy użyciu [Alchemy](https://alchemyapi.io/), wiodącej platformy dla twórców blockchainów wykorzystywanej przez miliony użytkowników z 70% najlepszych aplikacji blockchain, w tym Maker, 0x, MyEtherWallet, Dharma i Kyber. +To jest przewodnik dla początkujących, jak zacząć programować w Ethereum. W tym samouczku będziemy używać [Alchemy](https://alchemyapi.io/), wiodącej platformy dla deweloperów blockchain, która obsługuje miliony użytkowników z 70% najlepszych aplikacji blockchain, w tym Maker, 0x, MyEtherWallet, Dharma i Kyber. Alchemy da nam dostęp do punktu końcowego API w łańcuchu Ethereum, dzięki czemu będziemy mogli odczytywać i zapisywać transakcje. -Zarejestruj się w Alchemy, aby napisać swój pierwszy skrypt web3! Nie jest wymagane doświadczenie w programowaniu blockchain! +Przeprowadzimy Cię od rejestracji w Alchemy do napisania pierwszego skryptu web3! Doświadczenie w programowaniu blockchain nie jest wymagane! -## 1\. Zarejestruj się na darmowym koncie Alchemy {#sign-up-for-a-free-alchemy-account} +## 1. Zarejestruj darmowe konto Alchemy {#sign-up-for-a-free-alchemy-account} -Tworzenie konta z Alchemy jest łatwe, [zarejestruj się za darmo tutaj](https://auth.alchemyapi.io/signup). +Utworzenie konta w Alchemy jest proste, [zarejestruj się za darmo tutaj](https://auth.alchemy.com/). -## 2\. Utwórz aplikację Alchemy {#create-an-alchemy-app} +## 2. Utwórz aplikację Alchemy {#create-an-alchemy-app} -Aby korzystać z produktów Alchemy, potrzebujesz klucza API do uwierzytelnienia swoich żądań. +Aby komunikować się z łańcuchem Ethereum i korzystać z produktów Alchemy, potrzebujesz klucza API do uwierzytelniania swoich żądań. -Możesz [tworzyć klucze API z panelu](http://dashboard.alchemyapi.io/). Aby utworzyć nowy klucz, przejdź do „Utwórz aplikację”, jak pokazano poniżej: +Możesz [utworzyć klucze API z pulpitu nawigacyjnego](https://dashboard.alchemy.com/). Aby utworzyć nowy klucz, przejdź do „Utwórz aplikację”, jak pokazano poniżej: -Specjalne podziękowania dla [_ShapeShift_](https://shapeshift.com/) _za umożliwienie nam pokazania ich panelu!_ +Specjalne podziękowania dla [_ShapeShift_](https://shapeshift.com/) _za umożliwienie nam pokazania ich pulpitu nawigacyjnego!_ -![Pulpit Alchemy](./alchemy-dashboard.png) +![Pulpit nawigacyjny Alchemy](./alchemy-dashboard.png) -Wypełnij szczegóły w sekcji „Utwórz aplikację”, aby uzyskać swój nowy klucz. Możesz również zobaczyć aplikacje, które wcześniej stworzyłeś i aplikacje wykonane przez swój zespół tutaj. Pociągnij istniejące klucze, klikając „Wyświetl klucz” dla dowolnej aplikacji. +Wypełnij dane w sekcji „Utwórz aplikację”, aby otrzymać nowy klucz. Możesz tu również zobaczyć aplikacje utworzone wcześniej przez Ciebie i przez Twój zespół. Pobierz istniejące klucze, klikając „Wyświetl klucz” dla dowolnej aplikacji. -![Utwórz aplikację za pomocą zrzutu ekranu Alchemy](./create-app.png) +![Zrzut ekranu tworzenia aplikacji za pomocą Alchemy](./create-app.png) -Możesz również ściągnąć istniejące klucze API, umieszczając kursor myszy nad „Aplikacje” i wybierając jeden. Możesz tutaj „Wyświetlić klucz”, a także „Edytować aplikację”, aby dodać określone domeny do białej listy, zobaczyć kilka narzędzi dla programistów i wyświetlić dane analityczne. +Możesz także pobrać istniejące klucze API, najeżdżając kursorem na „Aplikacje” i wybierając jedną z nich. Możesz tu „Wyświetlić klucz”, a także „Edytować aplikację”, aby dodać określone domeny do białej listy, zobaczyć kilka narzędzi dla deweloperów i wyświetlić analitykę. -![Gif pokazuje użytkownikowi jak ściągnąć klucze API](./pull-api-keys.gif) +![Gif pokazujący, jak użytkownik może pobrać klucze API](./pull-api-keys.gif) -## 3\. Zgłoś żądanie z wiersza poleceń {#make-a-request-from-the-command-line} +## 3. Wyślij żądanie z wiersza poleceń {#make-a-request-from-the-command-line} -Współpracuj z blockchainem Ethereum przez Alchemy, używając JSON-RPC i curl. +Wchodź w interakcje z blockchainem Ethereum za pośrednictwem Alchemy za pomocą JSON-RPC i curl. -Dla żądań ręcznych, zalecamy zastosowanie `JSON-RPC` poprzez `POST`. Wystarczy przekazać nagłówek `Content-Type: application/json` i zapytanie jako treść `POST` z następującymi polami: +W przypadku żądań ręcznych zalecamy interakcję z `JSON-RPC` za pośrednictwem żądań `POST`. Po prostu przekaż nagłówek `Content-Type: application/json` i swoje zapytanie jako treść `POST` z następującymi polami: -- `jsonrpc`: wersja JSON-RPC - obecnie obsługiwana jest tylko `2.0`. -- `method`: metoda ETH API. [Zobacz materiały dot. API.](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) -- `params`: lista parametrów do przekazania do metody. -- `id`: identyfikator Twojego żądania. Zostanie zwrócony wraz z odpowiedzią, dzięki czemu można śledzić, do którego żądania należy odpowiedź. +- `jsonrpc`: Wersja JSON-RPC — obecnie obsługiwana jest tylko wersja `2.0`. +- `method`: Metoda API ETH. [Zobacz dokumentację API.](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) +- `params`: Lista parametrów do przekazania do metody. +- `id`: ID Twojego żądania. Zostanie zwrócone w odpowiedzi, dzięki czemu możesz śledzić, do którego żądania należy dana odpowiedź. -Poniżej znajduje się przykład, który można uruchomić z wiersza poleceń, aby uzyskać aktualną cenę gazu: +Oto przykład, który możesz uruchomić z wiersza poleceń, aby pobrać aktualną cenę gazu: ```bash -curl [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/v2/demo) \ +curl https://eth-mainnet.alchemyapi.io/v2/demo \ -X POST \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}' ``` -**_UWAGA:_** _Zamień_ [_https://eth-mainnet.alchemyapi. o/v2/demo_](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) _z własnym kluczem API_ [_https://eth-mainnet.alchemyapi.io/v2/your-api-key_](https://eth-mainnet.alchemyapi.io/jsonrpc/your-api-key)_._ +_**UWAGA:** Zastąp [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) własnym kluczem API `https://eth-mainnet.alchemyapi.io/v2/**your-api-key`._ -**Wynik:** +**Wyniki:** ```json -{ "id": 73,"jsonrpc": "2.0","result": "0x09184e72a000" // 100000000000000000 } +{ "id": 73,"jsonrpc": "2.0","result": "0x09184e72a000" // 10000000000000 } ``` -## 4\. Skonfiguruj swojego klienta Web3 {#set-up-your-web3-client} +## 4. Skonfiguruj swojego klienta Web3 {#set-up-your-web3-client} -**Jeśli masz istniejącego klienta,** zmień adres URL aktualnego dostawcy węzła na adres URL Alchemy z kluczem API: `"https://eth-mainnet.alchemyapi.io/v2/your-api-key"` +**Jeśli masz już istniejącego klienta,** zmień adres URL swojego obecnego dostawcy węzła na adres URL Alchemy z Twoim kluczem API: `“https://eth-mainnet.alchemyapi.io/v2/your-api-key\"` -**_UWAGA:_** Skrypty poniżej muszą być uruchomione w **kontekście węzłów** lub **zapisane w pliku**, nie uruchamiaj z wiersza poleceń. Jeśli nie masz jeszcze zainstalowanego węzła lub npm, sprawdź ten [przewodnik konfiguracji macs](https://app.gitbook.com/@alchemyapi/s/alchemy/guides/alchemy-for-macs). +**_UWAGA:_** Poniższe skrypty muszą być uruchamiane w **kontekście node** lub **zapisane w pliku**, a nie z wiersza poleceń. Jeśli nie masz jeszcze zainstalowanego Node lub npm, zapoznaj się z tym krótkim [przewodnikiem konfiguracji dla komputerów Mac](https://app.gitbook.com/@alchemyapi/s/alchemy/guides/alchemy-for-macs). -Istnieją tony [bibliotek Web3](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries) które możesz zintegrować z alchemy. zalecamy użycie [Alchemy Web3](https://docs.alchemy.com/reference/api-overview), upuszczonego zamiennika dla web3., zbudowany i skonfigurowany do bezproblemowej pracy z Alchemy. Zapewnia to wiele zalet, takich jak automatyczne próby i solidne wsparcie WebSocket. +Istnieje mnóstwo [bibliotek Web3](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries), które można zintegrować z Alchemy, jednak zalecamy użycie [Alchemy Web3](https://docs.alchemy.com/reference/api-overview), zamiennika dla web3.js, stworzonego i skonfigurowanego do bezproblemowej pracy z Alchemy. Zapewnia to wiele korzyści, takich jak automatyczne ponawianie prób i solidne wsparcie dla WebSocket. -Aby zainstalować AlchemyWeb3.js, **przejdź do katalogu projektu** i uruchom: +Aby zainstalować AlchemyWeb3.js, **przejdź do katalogu swojego projektu** i uruchom: -**Z Yarn:** +**Za pomocą Yarn:** ``` -yarn dodaj @alch/alchemy-web3 +yarn add @alch/alchemy-web3 ``` -**Z NPM:** +**Za pomocą NPM:** ``` npm install @alch/alchemy-web3 ``` -Aby wejść w interakcję z infrastrukturą węzła Alchemy, uruchom w NodeJS lub dodaj to do pliku JavaScript: +Aby wejść w interakcję z infrastrukturą węzłów Alchemy, uruchom w NodeJS lub dodaj to do pliku JavaScript: ```js const { createAlchemyWeb3 } = require("@alch/alchemy-web3") @@ -103,52 +104,53 @@ const web3 = createAlchemyWeb3( ) ``` -## 5\. Napisz swój pierwszy skrypt Web3! {#write-your-first-web3-script} +## 5. Napisz swój pierwszy skrypt Web3! {#write-your-first-web3-script} -Teraz, aby ubrudzić sobie ręce odrobiną programowania web3, napiszemy prosty skrypt, który wypisuje najnowszy numer bloku z sieci głównej Ethereum. +Teraz, aby trochę pobrudzić sobie ręce programowaniem w web3, napiszemy prosty skrypt, który wyświetla numer ostatniego bloku z sieci głównej Ethereum. -1. **Jeśli jeszcze tego nie zrobiłeś, w swoim terminalu utwórz nowy katalog projektów i przejdź do niego:** +**1. Jeśli jeszcze tego nie zrobiłeś, utwórz w terminalu nowy katalog projektu i przejdź do niego:** ``` -mkdir web3-examplecd web3-example +mkdir web3-example +cd web3-example ``` -**2\. Zainstaluj zależność Alchemy web3 (lub dowolny web3) w swoim projekcie, jeśli jeszcze tego nie zrobiłeś:** +**2. Zainstaluj w swoim projekcie zależność Alchemy web3 (lub dowolną web3), jeśli jeszcze tego nie zrobiłeś:** ``` npm install @alch/alchemy-web3 ``` -**3. Utwórz plik o nazwie** `index.js` **i dodaj następujące treści:** +**3. Utwórz plik o nazwie `index.js` i dodaj następującą zawartość:** -> Ostatecznie powinieneś zastąpić `demo` kluczem API Alchemy. +> Docelowo należy zastąpić `demo` swoim kluczem API HTTP Alchemy. ```js async function main() { const { createAlchemyWeb3 } = require("@alch/alchemy-web3") - const web3 = createAlchemyWeb3("https://eth- mainnet.alchemyapi.io/v2/demo") + const web3 = createAlchemyWeb3("https://eth-mainnet.alchemyapi.io/v2/demo") const blockNumber = await web3.eth.getBlockNumber() - console.log("The latest block number is " + blockNumber) + console.log("Najnowszy numer bloku to " + blockNumber) } main() ``` -Nie znasz rozwiązań asynchronicznych? Sprawdź to [Medium post](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c). +Nie znasz rozwiązań asynchronicznych? Sprawdź ten [wpis na Medium](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c). -**4\. Uruchom go w swoim terminalu, używając węzła** +**4. Uruchom to w terminalu za pomocą node** ``` node index.js ``` -**5. Powinieneś teraz zobaczyć najnowszy numer bloku w konsoli!** +**5. Powinieneś teraz zobaczyć w konsoli wynik z najnowszym numerem bloku!** ``` -The latest block number is 11043912 +Najnowszy numer bloku to 11043912 ``` -**Woo! Gratulacje! Właśnie napisałeś swój pierwszy skrypt web3 używając Alchemy 🎉** +**Woo! Gratulacje! Właśnie napisałeś swój pierwszy skrypt web3 przy użyciu Alchemy 🎉** -Nie jesteś pewien, co zrobić dalej? Spróbuj wdrożyć pierwszy kontrakt inteligentny i popracuj, programując w Solidity [_Hello World Smart_](https://docs.alchemyapi.io/tutorials/hello-world-smart-contract) _Contract Guide, lub sprawdź, co wiesz o pulpicie nawigacyjnym za pomocą_ [_Dashboard Demo App_](https://docs.alchemyapi.io/tutorials/demo-app)_!_ +Nie wiesz, co robić dalej? Spróbuj wdrożyć swój pierwszy smart kontrakt i pobrudź sobie ręce programowaniem w Solidity w naszym [przewodniku po smart kontraktach „Hello World”](https://www.alchemy.com/docs/hello-world-smart-contract) lub sprawdź swoją wiedzę o pulpicie nawigacyjnym za pomocą [aplikacji demonstracyjnej pulpitu nawigacyjnego](https://docs.alchemyapi.io/tutorials/demo-app)! -_[Zarejestruj się przy użyciu Alchemy za darmo](https://auth.alchemyapi.io/signup), sprawdź naszą [dokumentację](https://docs.alchemyapi.io/), oraz najnowsze wiadomości, obserwuj nas na [Twitterze](https://twitter.com/AlchemyPlatform)_. +_[Zarejestruj się w Alchemy za darmo](https://auth.alchemy.com/), sprawdź naszą [dokumentację](https://www.alchemy.com/docs/), a aby być na bieżąco z najnowszymi wiadomościami, obserwuj nas na [Twitterze](https://twitter.com/AlchemyPlatform)_. diff --git a/public/content/translations/pl/developers/tutorials/guide-to-smart-contract-security-tools/index.md b/public/content/translations/pl/developers/tutorials/guide-to-smart-contract-security-tools/index.md new file mode 100644 index 00000000000..128cd64046e --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/guide-to-smart-contract-security-tools/index.md @@ -0,0 +1,102 @@ +--- +title: "Przewodnik po narzędziach bezpieczeństwa inteligentnych kontraktów" +description: "Przegląd trzech różnych technik testowania i analizy programu" +author: "Trailofbits" +lang: pl +tags: [ "solidity", "smart kontrakty", "bezpieczeństwo" ] +skill: intermediate +published: 2020-09-07 +source: Building secure contracts +sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis +--- + +Użyjemy trzech odrębnych technik testowania i analizy programu: + +- **Analiza statyczna z użyciem [Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/).** Wszystkie ścieżki programu są aproksymowane i analizowane w tym samym czasie, poprzez różne reprezentacje programu (np. graf przepływu sterowania) +- **Fuzzing z użyciem [Echidna](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/).** Kod jest wykonywany z pseudolosowym generowaniem transakcji. Fuzzer będzie próbował znaleźć sekwencję transakcji naruszającą daną właściwość. +- **Wykonanie symboliczne z użyciem [Manticore](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/).** Formalna technika weryfikacji, która tłumaczy każdą ścieżkę wykonania na formułę matematyczną, na której można sprawdzać ograniczenia. + +Każda technika ma zalety i wady i będzie przydatna w [określonych przypadkach](#determining-security-properties): + +| Technika | Narzędzie | Zastosowanie | Szybkość | Pominięte błędy | Fałszywe alarmy | +| --------------------- | --------- | ------------------------------ | -------- | --------------- | --------------- | +| Analiza statyczna | Slither | CLI i skrypty | sekundy | umiarkowany | niski | +| Fuzzing | Echidna | Właściwości Solidity | minuty | niski | brak | +| Wykonanie symboliczne | Manticore | Właściwości Solidity i skrypty | godziny | brak\* | brak | + +\* jeśli wszystkie ścieżki zostaną zbadane bez przekroczenia limitu czasu + +**Slither** analizuje kontrakty w ciągu kilku sekund, jednak analiza statyczna może prowadzić do fałszywych alarmów i będzie mniej odpowiednia do złożonych sprawdzeń (np. sprawdzeń arytmetycznych). Uruchom Slither przez API, aby uzyskać łatwy dostęp do wbudowanych detektorów lub przez API, aby uzyskać dostęp do sprawdzeń zdefiniowanych przez użytkownika. + +**Echidna** musi działać przez kilka minut i będzie generować tylko prawdziwie pozytywne wyniki. Echidna sprawdza właściwości bezpieczeństwa dostarczone przez użytkownika, napisane w Solidity. Może pominąć błędy, ponieważ opiera się na losowej eksploracji. + +**Manticore** wykonuje analizę \ Podobnie jak Echidna, Manticore weryfikuje właściwości dostarczone przez użytkownika. Potrzebuje więcej czasu na uruchomienie, ale może udowodnić poprawność właściwości i nie zgłasza fałszywych alarmów. + +## Sugerowany przepływ pracy {#suggested-workflow} + +Zacznij od wbudowanych detektorów Slither, aby upewnić się, że żadne proste błędy nie są obecnie obecne ani nie zostaną wprowadzone później. Użyj Slither do sprawdzania właściwości związanych z dziedziczeniem, zależnościami zmiennych i problemami strukturalnymi. W miarę rozrastania się bazy kodu użyj Echidny do testowania bardziej złożonych właściwości maszyny stanu. Wróć do Slither, aby opracować niestandardowe sprawdzenia zabezpieczeń niedostępnych w Solidity, takie jak ochrona przed nadpisaniem funkcji. Na koniec użyj Manticore do przeprowadzenia ukierunkowanej weryfikacji krytycznych właściwości bezpieczeństwa, np. operacji arytmetycznych. + +- Użyj CLI Slither do wykrywania typowych problemów +- Użyj Echidny do testowania właściwości bezpieczeństwa wysokiego poziomu Twojego kontraktu +- Użyj Slither do pisania niestandardowych sprawdzeń statycznych +- Użyj Manticore, aby uzyskać dogłębną pewność co do krytycznych właściwości bezpieczeństwa + +**Uwaga na temat testów jednostkowych**. Testy jednostkowe są niezbędne do tworzenia oprogramowania wysokiej jakości. Jednakże techniki te nie są najlepiej przystosowane do znajdowania luk w zabezpieczeniach. Zazwyczaj są one używane do testowania pozytywnych zachowań kodu (tj. kod działa zgodnie z oczekiwaniami w normalnym kontekście), podczas gdy luki w zabezpieczeniach mają tendencję do występowania w przypadkach brzegowych, których deweloperzy nie wzięli pod uwagę. W naszym badaniu dziesiątek przeglądów bezpieczeństwa inteligentnych kontraktów, [pokrycie testami jednostkowymi nie miało wpływu na liczbę ani wagę luk w zabezpieczeniach](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/), które znaleźliśmy w kodzie naszych klientów. + +## Określanie właściwości bezpieczeństwa {#determining-security-properties} + +Aby skutecznie testować i weryfikować swój kod, musisz zidentyfikować obszary, które wymagają uwagi. Ponieważ Twoje zasoby przeznaczone na bezpieczeństwo są ograniczone, ważne jest określenie słabych lub wartościowych części Twojej bazy kodu, aby zoptymalizować Twój wysiłek. Modelowanie zagrożeń może pomóc. Rozważ przejrzenie: + +- [Szybkie oceny ryzyka (Rapid Risk Assessments)](https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment.html) (nasze preferowane podejście, gdy brakuje czasu) +- [Przewodnik po modelowaniu zagrożeń systemu zorientowanego na dane](https://csrc.nist.gov/pubs/sp/800/154/ipd) (znany również jako NIST 800-154) +- [Modelowanie zagrożeń wg Shostacka](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) +- [STRIDE](https://wikipedia.org/wiki/STRIDE_\(security\)) / [DREAD](https://wikipedia.org/wiki/DREAD_\(risk_assessment_model\)) +- [PASTA](https://wikipedia.org/wiki/Threat_model#P.A.S.T.A.) +- [Użycie asercji](https://blog.regehr.org/archives/1091) + +### Komponenty {#components} + +Wiedza o tym, co chcesz sprawdzić, pomoże Ci również w wyborze odpowiedniego narzędzia. + +Szerokie obszary, które są często istotne dla inteligentnych kontraktów, obejmują: + +- **Maszyna stanu.** Większość kontraktów można przedstawić jako maszynę stanu. Rozważ sprawdzenie, czy (1) nie można osiągnąć żadnego nieprawidłowego stanu, (2) jeśli stan jest prawidłowy, to można go osiągnąć, oraz (3) żaden stan nie blokuje kontraktu. + + - Echidna i Manticore to narzędzia, które należy preferować do testowania specyfikacji maszyn stanów. + +- **Kontrola dostępu.** Jeśli Twój system ma uprzywilejowanych użytkowników (np. właściciela, kontrolerów, ...) musisz upewnić się, że (1) każdy użytkownik może wykonywać tylko autoryzowane działania oraz (2) żaden użytkownik nie może blokować działań bardziej uprzywilejowanego użytkownika. + + - Slither, Echidna i Manticore mogą sprawdzać poprawność kontroli dostępu. Na przykład Slither może sprawdzić, czy tylko funkcje z białej listy nie mają modyfikatora onlyOwner. Echidna i Manticore są przydatne do bardziej złożonej kontroli dostępu, takiej jak uprawnienie przyznawane tylko wtedy, gdy kontrakt osiągnie określony stan. + +- **Operacje arytmetyczne.** Sprawdzanie poprawności operacji arytmetycznych ma kluczowe znaczenie. Używanie `SafeMath` wszędzie jest dobrym krokiem w celu zapobiegania przepełnieniom/niedopełnieniom, jednak nadal musisz brać pod uwagę inne wady arytmetyczne, w tym problemy z zaokrąglaniem i błędy, które blokują kontrakt. + + - Manticore jest tutaj najlepszym wyborem. Echidna może być używana, jeśli arytmetyka jest poza zakresem solwera SMT. + +- **Poprawność dziedziczenia.** Kontrakty Solidity w dużym stopniu opierają się na wielokrotnym dziedziczeniu. Łatwo można wprowadzić błędy, takie jak przesłaniająca funkcja bez wywołania `super` i błędnie zinterpretowany porządek linearyzacji c3. + + - Slither jest narzędziem zapewniającym wykrycie tych problemów. + +- **Interakcje zewnętrzne.** Kontrakty wchodzą w interakcje ze sobą, a niektórym kontraktom zewnętrznym nie należy ufać. Na przykład, jeśli Twój kontrakt opiera się na zewnętrznych oracle'ach, czy pozostanie bezpieczny, jeśli połowa dostępnych oracle'i zostanie naruszona? + + - Manticore i Echidna to najlepszy wybór do testowania zewnętrznych interakcji z Twoimi kontraktami. Manticore ma wbudowany mechanizm do zaślepiania zewnętrznych kontraktów. + +- **Zgodność ze standardami.** Standardy Ethereum (np. ERC20) mają w swojej historii błędy projektowe. Bądź świadomy ograniczeń standardu, na którym budujesz. + - Slither, Echidna i Manticore pomogą Ci wykryć odchylenia od danego standardu. + +### Ściągawka doboru narzędzi {#tool-selection-cheatsheet} + +| Komponent | Narzędzia | Przykłady | +| ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Maszyna stanu | Echidna, Manticore | | +| Kontrola dostępu | Slither, Echidna, Manticore | [Ćwiczenie 2 Slither](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise2.md), [Ćwiczenie 2 Echidna](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-2.md) | +| Operacje arytmetyczne | Manticore, Echidna | [Ćwiczenie 1 Echidna](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-1.md), [Ćwiczenia 1-3 Manticore](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore/exercises) | +| Poprawność dziedziczenia | Slither | [Ćwiczenie 1 Slither](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise1.md) | +| Interakcje zewnętrzne | Manticore, Echidna | | +| Zgodność ze standardem | Slither, Echidna, Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | + +Inne obszary będą wymagały sprawdzenia w zależności od Twoich celów, ale te ogólne obszary zainteresowania są dobrym punktem wyjścia dla każdego systemu inteligentnych kontraktów. + +Nasze publiczne audyty zawierają przykłady zweryfikowanych lub przetestowanych właściwości. Rozważ przeczytanie sekcji `Automated Testing and Verification` w poniższych raportach, aby przejrzeć rzeczywiste właściwości bezpieczeństwa: + +- [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) +- [Balancer](https://github.com/trailofbits/publications/blob/master/reviews/BalancerCore.pdf) diff --git a/public/content/translations/pl/developers/tutorials/hello-world-smart-contract-fullstack/index.md b/public/content/translations/pl/developers/tutorials/hello-world-smart-contract-fullstack/index.md new file mode 100644 index 00000000000..99b5e8c5c77 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/hello-world-smart-contract-fullstack/index.md @@ -0,0 +1,1543 @@ +--- +title: "Inteligentny kontrakt „Witaj świecie” dla początkujących – Fullstack" +description: "Samouczek wprowadzający na temat pisania i wdrażania prostego inteligentnego kontraktu na Ethereum." +author: "nstrike2" +tags: + [ + "solidity", + "hardhat", + "alchemy", + "smart kontrakty", + "wdrażanie", + "eksplorator bloków", + "frontend", + "transakcje" + ] +skill: beginner +lang: pl +published: 2021-10-25 +--- + +Ten przewodnik jest dla Ciebie, jeśli jesteś nowy w tworzeniu blockchaina i nie wiesz, od czego zacząć lub jak wdrażać i wchodzić w interakcję z inteligentnymi kontraktami. Przeprowadzimy Cię przez proces tworzenia i wdrażania prostego inteligentnego kontraktu w sieci testowej Goerli przy użyciu [MetaMask](https://metamask.io), [Solidity](https://docs.soliditylang.org/en/v0.8.0/), [Hardhat](https://hardhat.org) i [Alchemy](https://alchemy.com/eth). + +Do ukończenia tego samouczka potrzebne będzie konto Alchemy. [Zarejestruj się, aby założyć darmowe konto](https://www.alchemy.com/). + +Jeśli masz jakieś pytania, skontaktuj się z nami na [Discordzie Alchemy](https://discord.gg/gWuC7zB)! + +## Część 1 – Utwórz i wdróż swój inteligentny kontrakt za pomocą Hardhat {#part-1} + +### Połącz się z siecią Ethereum {#connect-to-the-ethereum-network} + +Istnieje wiele sposobów na wysyłanie żądań do łańcucha Ethereum. Dla uproszczenia, użyjemy darmowego konta na Alchemy, platformie deweloperskiej i interfejsie API blockchaina, które pozwalają nam komunikować się z łańcuchem Ethereum bez konieczności samodzielnego uruchamiania węzła. Alchemy posiada również narzędzia deweloperskie do monitorowania i analityki. Skorzystamy z nich w tym samouczku, aby zrozumieć, co dzieje się pod maską podczas wdrażania naszego inteligentnego kontraktu. + +### Utwórz swoją aplikację i klucz API {#create-your-app-and-api-key} + +Po utworzeniu konta Alchemy, można wygenerować klucz API, tworząc aplikację. Umożliwi to wysyłanie żądań do sieci testowej Goerli. Jeśli nie znasz sieci testowych, możesz [przeczytać przewodnik Alchemy dotyczący wyboru sieci](https://www.alchemy.com/docs/choosing-a-web3-network). + +Na pulpicie nawigacyjnym Alchemy znajdź menu rozwijane **Aplikacje** w pasku nawigacyjnym i kliknij **Utwórz aplikację**. + +![Utwórz aplikację Hello world](./hello-world-create-app.png) + +Nadaj swojej aplikacji nazwę „_Hello World_” i wpisz krótki opis. Wybierz **Staging** jako środowisko i **Goerli** jako sieć. + +![widok tworzenia aplikacji hello world](./create-app-view-hello-world.png) + +_Uwaga: upewnij się, że wybrałeś **Goerli**, w przeciwnym razie ten samouczek nie zadziała._ + +Kliknij **Utwórz aplikację**. Twoja aplikacja pojawi się w poniższej tabeli. + +### Utwórz konto Ethereum {#create-an-ethereum-account} + +Aby wysyłać i odbierać transakcje, potrzebujesz konta Ethereum. Użyjemy MetaMask, wirtualnego portfela w przeglądarce, który pozwala użytkownikom zarządzać adresem konta Ethereum. + +Możesz pobrać i utworzyć konto MetaMask za darmo [tutaj](https://metamask.io/download). Podczas tworzenia konta, lub jeśli już je posiadasz, upewnij się, że przełączyłeś się na „Sieć testową Goerli” w prawym górnym rogu (aby nie mieć do czynienia z prawdziwymi pieniędzmi). + +### Krok 4: Dodaj ether z Faucet {#step-4-add-ether-from-a-faucet} + +Aby wdrożyć swój inteligentny kontrakt w sieci testowej, będziesz potrzebować trochę fałszywych ETH. Aby uzyskać ETH w sieci Goerli, przejdź do Faucet Goerli i wprowadź adres swojego konta Goerli. Należy pamiętać, że krany Goerli mogą być ostatnio nieco zawodne - sprawdź [stronę sieci testowych](/developers/docs/networks/#goerli), aby uzyskać listę opcji do wypróbowania: + +_Uwaga: ze względu na przeciążenie sieci może to trochę potrwać._ + +### Krok 5: Sprawdź swoje saldo {#step-5-check-your-balance} + +Aby dwukrotnie sprawdzić, czy ETH znajduje się w Twoim portfelu, wykonaj żądanie [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) za pomocą [narzędzia kompozytora Alchemy](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). Zwróci to ilość ETH w naszym portfelu. Aby dowiedzieć się więcej, sprawdź [krótki samouczek Alchemy na temat korzystania z narzędzia kompozytora](https://youtu.be/r6sjRxBZJuU). + +Wprowadź swój adres konta MetaMask i kliknij **Wyślij żądanie**. Zobaczysz odpowiedź, która wygląda jak poniższy fragment kodu. + +```json +{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" } +``` + +> _Uwaga: Ten wynik jest w wei, nie w ETH. Wei jest używane jako najmniejsza jednostka etheru._ + +Uff! Wszystkie nasze fałszywe pieniądze są na miejscu. + +### Krok 6: Zainicjuj nasz projekt {#step-6-initialize-our-project} + +Najpierw musimy utworzyć folder dla naszego projektu. Przejdź do wiersza poleceń i wprowadź następujące informacje. + +``` +mkdir hello-world +cd hello-world +``` + +Teraz, gdy jesteśmy w folderze naszego projektu, użyjemy `npm init`, aby zainicjować projekt. + +> Jeśli nie masz jeszcze zainstalowanego npm, postępuj zgodnie z [tymi instrukcjami, aby zainstalować Node.js i npm](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm). + +Dla celów tego samouczka nie ma znaczenia, jak odpowiesz na pytania inicjujące. Oto, jak zrobiliśmy to dla odniesienia: + +``` +package name: (hello-world) +version: (1.0.0) +description: hello world smart contract +entry point: (index.js) +test command: +git repository: +keywords: +author: +license: (ISC) + +About to write to /Users/.../.../.../hello-world/package.json: + +{ + "name": "hello-world", + "version": "1.0.0", + "description": "hello world smart contract", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +``` + +Zatwierdź plik package.json i gotowe! + +### Krok 7: Pobierz Hardhat {#step-7-download-hardhat} + +Hardhat to środowisko programistyczne do kompilacji, wdrażania, testowania i debugowania oprogramowania Ethereum. Pomaga deweloperom w tworzeniu inteligentnych kontraktów i dapek lokalnie przed wdrożeniem ich na żywym łańcuchu. + +W naszym projekcie `hello-world` uruchom: + +``` +npm install --save-dev hardhat +``` + +Sprawdź tę stronę, aby uzyskać więcej szczegółów na temat [instrukcji instalacji](https://hardhat.org/getting-started/#overview). + +### Krok 8: Utwórz projekt Hardhat {#step-8-create-hardhat-project} + +W naszym folderze projektu `hello-world` uruchom: + +``` +npx hardhat +``` + +Powinieneś wtedy zobaczyć wiadomość powitalną i opcję wyboru tego, co chcesz zrobić. Wybierz „utwórz pusty hardhat.config.js”: + +``` +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 Witamy w Hardhat v2.0.11 👷‍ + +Co chcesz zrobić? … +Utwórz przykładowy projekt +❯ Utwórz pusty plik hardhat.config.js +Zamknij +``` + +Spowoduje to wygenerowanie pliku `hardhat.config.js` w projekcie. Użyjemy tego później w samouczku, aby określić konfigurację naszego projektu. + +### Krok 9: Dodaj foldery projektu {#step-9-add-project-folders} + +Aby utrzymać porządek w projekcie, utwórzmy dwa nowe foldery. W wierszu poleceń przejdź do katalogu głównego projektu `hello-world` i wpisz: + +``` +mkdir contracts +mkdir scripts +``` + +- w `contracts/` będziemy przechowywać plik z kodem naszego inteligentnego kontraktu hello world +- w `scripts/` będziemy przechowywać skrypty do wdrażania naszego kontraktu i interakcji z nim + +### Krok 10: Napisz nasz kontrakt {#step-10-write-our-contract} + +Możesz zadać sobie pytanie, kiedy napiszemy kod? Nadszedł czas! + +Otwórz projekt hello-world w swoim ulubionym edytorze. Inteligentne kontrakty najczęściej pisane są w Solidity, którego użyjemy do napisania naszego inteligentnego kontraktu. + +1. Przejdź do folderu `contracts` i utwórz nowy plik o nazwie `HelloWorld.sol` +2. Poniżej znajduje się przykładowy inteligentny kontrakt Witaj Świecie, którego będziemy używać w tym samouczku. Skopiuj poniższą zawartość do pliku `HelloWorld.sol`. + +_Uwaga: Pamiętaj, aby przeczytać komentarze, aby zrozumieć, co robi ten kontrakt._ + +``` +// Określa wersję Solidity, używając semantycznego wersjonowania. +// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity >=0.7.3; + +// Definiuje kontrakt o nazwie `HelloWorld`. +// Kontrakt jest zbiorem funkcji i danych (jego stanu). Po wdrożeniu kontrakt znajduje się pod określonym adresem w blockchainie Ethereum. Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld { + + // Emitowane, gdy wywoływana jest funkcja aktualizacji + // Zdarzenia inteligentnych kontraktów to sposób, w jaki kontrakt komunikuje, że coś wydarzyło się na blockchainie do front-endu aplikacji, który może „nasłuchiwać” określonych zdarzeń i podejmować działania, gdy one wystąpią. + event UpdatedMessages(string oldStr, string newStr); + + // Deklaruje zmienną stanu `message` typu `string`. + // Zmienne stanu to zmienne, których wartości są trwale przechowywane w pamięci kontraktu. Słowo kluczowe `public` udostępnia zmienne spoza kontraktu i tworzy funkcję, którą inne kontrakty lub klienci mogą wywołać w celu uzyskania dostępu do wartości. + string public message; + + // Podobnie jak w wielu językach obiektowych opartych na klasach, konstruktor jest specjalną funkcją, która jest wykonywana tylko podczas tworzenia kontraktu. + // Konstruktory służą do inicjalizacji danych kontraktu. Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + constructor(string memory initMessage) { + + // Akceptuje argument ciągu znaków `initMessage` i ustawia wartość w zmiennej pamięci kontraktu `message`). + message = initMessage; + } + + // Funkcja publiczna, która akceptuje argument w postaci ciągu znaków i aktualizuje zmienną pamięci masowej `message`. + function update(string memory newMessage) public { + string memory oldMsg = message; + message = newMessage; + emit UpdatedMessages(oldMsg, newMessage); + } +} +``` + +Jest to podstawowy inteligentny kontrakt, który przechowuje wiadomość po utworzeniu. Można go zaktualizować, wywołując funkcję `update`. + +### Krok 11: Podłącz MetaMask i Alchemy do swojego projektu {#step-11-connect-metamask-alchemy-to-your-project} + +Stworzyliśmy portfel MetaMask, konto Alchemy i napisaliśmy nasz inteligentny kontrakt, teraz nadszedł czas, aby połączyć te trzy elementy. + +Każda transakcja wysłana z Twojego portfela wymaga podpisu za pomocą Twojego unikalnego klucza prywatnego. Aby zapewnić naszemu programowi to uprawnienie, możemy bezpiecznie przechowywać nasz klucz prywatny w pliku środowiskowym. Będziemy tutaj również przechowywać klucz API dla Alchemy. + +> Aby dowiedzieć się więcej o wysyłaniu transakcji, sprawdź [ten samouczek](https://www.alchemy.com/docs/hello-world-smart-contract#step-11-connect-metamask--alchemy-to-your-project) na temat wysyłania transakcji za pomocą web3. + +Najpierw zainstaluj pakiet dotenv w katalogu swojego projektu: + +``` +npm install dotenv --save +``` + +Następnie utwórz plik `.env` w głównym katalogu projektu. Dodaj do niego swój klucz prywatny MetaMask i adres URL HTTP Alchemy API. + +Twój plik środowiskowy musi mieć nazwę `.env`, w przeciwnym razie nie zostanie rozpoznany jako plik środowiskowy. + +Nie nazywaj go `process.env` lub `.env-custom` ani w żaden inny sposób. + +- Postępuj zgodnie z [tymi instrukcjami](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key), aby wyeksportować swój klucz prywatny +- Poniżej dowiesz się, jak uzyskać adres URL interfejsu API HTTP Alchemy + +![](./get-alchemy-api-key.gif) + +Twój plik `.env` powinien wyglądać następująco: + +``` +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PRIVATE_KEY = "your-metamask-private-key" +``` + +Aby faktycznie połączyć je z naszym kodem, odwołamy się do tych zmiennych w naszym pliku `hardhat.config.js` w kroku 13. + +### Krok 12: Zainstaluj Ethers.js {#step-12-install-ethersjs} + +Ethers.js to biblioteka, która ułatwia interakcję i wysyłanie żądań do Ethereum poprzez opakowanie [standardowych metod JSON-RPC](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc) w bardziej przyjazne dla użytkownika metody. + +Hardhat pozwala nam na integrację [wtyczek](https://hardhat.org/plugins/) w celu uzyskania dodatkowych narzędzi i rozszerzonej funkcjonalności. Skorzystamy z [wtyczki Ethers](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers) do wdrażania kontraktów. + +W katalogu projektu wpisz: + +```bash +npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" +``` + +### Krok 13: Zaktualizuj hardhat.config.js {#step-13-update-hardhat-configjs} + +Do tej pory dodaliśmy kilka zależności i wtyczek, teraz musimy zaktualizować `hardhat.config.js`, aby nasz projekt wiedział o wszystkich. + +Zaktualizuj swój `hardhat.config.js`, aby wyglądał następująco: + +```javascript +/** + * @type import('hardhat/config').HardhatUserConfig + */ + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") + +const { API_URL, PRIVATE_KEY } = process.env + +module.exports = { + solidity: "0.7.3", + defaultNetwork: "goerli", + networks: { + hardhat: {}, + goerli: { + url: API_URL, + accounts: [`0x${PRIVATE_KEY}`], + }, + }, +} +``` + +### Krok 14: Skompiluj nasz kontrakt {#step-14-compile-our-contract} + +Aby upewnić się, że wszystko do tej pory działa, skompilujmy nasz kontrakt. Zadanie `compile` jest jednym z wbudowanych zadań hardhat. + +Z wiersza poleceń uruchom: + +```bash +npx hardhat compile +``` + +Możesz otrzymać ostrzeżenie o `SPDX license identifier not provided in source file`, ale nie musisz się tym martwić - miejmy nadzieję, że wszystko inne wygląda dobrze! Jeśli nie, zawsze możesz napisać wiadomość na [discordzie Alchemy](https://discord.gg/u72VCg3). + +### Krok 15: Napisz nasz skrypt wdrożeniowy {#step-15-write-our-deploy-script} + +Teraz, gdy nasz kontrakt jest napisany, a nasz plik konfiguracyjny jest gotowy, nadszedł czas, aby napisać nasz skrypt wdrażający kontrakt. + +Przejdź do folderu `scripts/` i utwórz nowy plik o nazwie `deploy.js`, dodając do niego następującą zawartość: + +```javascript +async function main() { + const HelloWorld = await ethers.getContractFactory("HelloWorld") + + // Rozpocznij wdrażanie, zwracając obietnicę, która rozwiązuje się do obiektu kontraktu + const hello_world = await HelloWorld.deploy("Hello World!") + console.log("Contract deployed to address:", hello_world.address) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) +``` + +Hardhat wykonuje niesamowitą robotę, wyjaśniając, co robi każda z tych linii kodu w swoim [samouczku dotyczącym kontraktów](https://hardhat.org/tutorial/testing-contracts.html#writing-tests), a my przyjęliśmy ich wyjaśnienia tutaj. + +```javascript +const HelloWorld = await ethers.getContractFactory("HelloWorld") +``` + +`ContractFactory` w ethers.js jest abstrakcją używaną do wdrażania nowych inteligentnych kontraktów, więc `HelloWorld` jest tutaj [fabryką](https://en.wikipedia.org/wiki/Factory_\(object-oriented_programming\)) dla instancji naszego kontraktu witaj świecie. Podczas korzystania z wtyczki `hardhat-ethers`, instancje `ContractFactory` i `Contract` są domyślnie połączone z pierwszym sygnatariuszem (właścicielem). + +```javascript +const hello_world = await HelloWorld.deploy() +``` + +Wywołanie `deploy()` w `ContractFactory` rozpocznie wdrażanie i zwróci `Promise`, które rozwiąże się do obiektu `Contract`. Jest to obiekt, który ma metodę dla każdej z naszych funkcji inteligentnego kontraktu. + +### Krok 16: Wdróż nasz kontrakt {#step-16-deploy-our-contract} + +Jesteśmy wreszcie gotowi do wdrożenia naszego inteligentnego kontraktu! Przejdź do wiersza poleceń i uruchom: + +```bash +npx hardhat run scripts/deploy.js --network goerli +``` + +Powinieneś wtedy zobaczyć coś takiego: + +```bash +Kontrakt wdrożony pod adresem: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +``` + +**Proszę zapisać ten adres**. Będziemy go używać w dalszej części samouczka. + +Jeśli przejdziemy do [Goerli etherscan](https://goerli.etherscan.io) i wyszukamy adres naszego kontraktu, powinniśmy zobaczyć, że został on pomyślnie wdrożony. Transakcja będzie wyglądać mniej więcej tak: + +![](./etherscan-contract.png) + +Adres `From` powinien pasować do adresu konta MetaMask, a adres `To` będzie zawierał informację **Contract Creation**. Jeśli klikniemy w transakcję, zobaczymy adres naszego kontraktu w polu `Do`. + +![](./etherscan-transaction.png) + +Gratulacje! Właśnie wdrożyłeś inteligentny kontrakt w sieci testowej Ethereum. + +Aby zrozumieć, co dzieje się pod maską, przejdź do zakładki Eksplorator w naszym [pulpicie nawigacyjnym Alchemy](https://dashboard.alchemy.com/explorer). Jeśli masz wiele aplikacji Alchemy, upewnij się, że filtrujesz według aplikacji i wybierz **Hello World**. + +![](./hello-world-explorer.png) + +Tutaj zobaczysz kilka metod JSON-RPC, które Hardhat/Ethers stworzył dla nas pod maską, gdy wywołaliśmy funkcję `.deploy()`. Dwie ważne metody to [`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction), czyli żądanie zapisu naszego kontraktu w łańcuchu Goerli, oraz [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash), czyli żądanie odczytania informacji o naszej transakcji na podstawie jej hasza. Aby dowiedzieć się więcej o wysyłaniu transakcji, sprawdź [nasz samouczek na temat wysyłania transakcji za pomocą Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/). + +## Część 2: Interakcja z Twoim inteligentnym kontraktem {#part-2-interact-with-your-smart-contract} + +Teraz, gdy pomyślnie wdrożyliśmy inteligentny kontrakt w sieci Goerli, nauczmy się, jak wchodzić z nim w interakcję. + +### Utwórz plik interact.js {#create-a-interactjs-file} + +To jest plik, w którym napiszemy nasz skrypt interakcji. Będziemy używać biblioteki Ethers.js, którą zainstalowałeś wcześniej w części 1. + +W folderze `scripts/` utwórz nowy plik o nazwie `interact.js` i dodaj następujący kod: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS +``` + +### Zaktualizuj swój plik .env {#update-your-env-file} + +Będziemy używać nowych zmiennych środowiskowych, więc musimy je zdefiniować w pliku `.env`, który [utworzyliśmy wcześniej](#step-11-connect-metamask-&-alchemy-to-your-project). + +Będziemy musieli dodać definicję dla naszego `API_KEY` Alchemy i `CONTRACT_ADDRESS`, gdzie został wdrożony nasz inteligentny kontrakt. + +Plik `.env` powinien wyglądać następująco: + +```bash +# .env + +API_URL = "https://eth-goerli.alchemyapi.io/v2/" +API_KEY = "" +PRIVATE_KEY = "" +CONTRACT_ADDRESS = "0x" +``` + +### Pobierz swoje ABI kontraktu {#grab-your-contract-ABI} + +Nasze [ABI (Application Binary Interface)](/glossary/#abi) kontraktu to interfejs do interakcji z naszym inteligentnym kontraktem. Hardhat automatycznie generuje ABI i zapisuje go w `HelloWorld.json`. Aby użyć ABI, będziemy musieli przeanalizować zawartość, dodając następujące wiersze kodu do naszego pliku `interact.js`: + +```javascript +// interact.js +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") +``` + +Jeśli chcesz zobaczyć ABI, możesz je wydrukować w swojej konsoli: + +```javascript +console.log(JSON.stringify(contract.abi)) +``` + +Aby zobaczyć swoje ABI wydrukowane na konsoli, przejdź do terminala i uruchom: + +```bash +npx hardhat run scripts/interact.js +``` + +### Utwórz instancję swojego kontraktu {#create-an-instance-of-your-contract} + +Aby wejść w interakcję z naszym kontraktem, musimy stworzyć jego instancję w naszym kodzie. Aby to zrobić za pomocą Ethers.js, będziemy musieli pracować z trzema koncepcjami: + +1. Dostawca - dostawca węzła, który daje Ci dostęp do odczytu i zapisu do blockchaina +2. Sygnatariusz - reprezentuje konto Ethereum, które może podpisywać transakcje +3. Kontrakt - obiekt Ethers.js reprezentujący określony kontrakt wdrożony w łańcuchu + +Użyjemy ABI kontraktu z poprzedniego kroku, aby stworzyć instancję naszego kontraktu: + +```javascript +// interact.js + +// Dostawca +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// Sygnatariusz +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// Kontrakt +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) +``` + +Dowiedz się więcej o Dostawcach, Sygnatariuszach i Kontraktach w [dokumentacji ethers.js](https://docs.ethers.io/v5/). + +### Przeczytaj wiadomość init {#read-the-init-message} + +Pamiętasz, jak wdrożyliśmy nasz kontrakt z `initMessage = "Hello world!"`? Teraz odczytamy tę wiadomość zapisaną w naszym inteligentnym kontrakcie i wydrukujemy ją na konsoli. + +W języku JavaScript funkcje asynchroniczne są używane podczas interakcji z sieciami. Aby dowiedzieć się więcej o funkcjach asynchronicznych, [przeczytaj ten artykuł](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff). + +Użyj poniższego kodu, aby wywołać funkcję `message` w naszym inteligentnym kontrakcie i odczytać wiadomość init: + +```javascript +// interact.js + +// ... + +asynchroniczna funkcja main() { + const message = await helloWorldContract.message() + console.log("Wiadomość to: " + message) +} +main() +``` + +Po uruchomieniu pliku za pomocą `npx hardhat run scripts/interact.js` w terminalu powinniśmy zobaczyć taką odpowiedź: + +``` +Wiadomość to: Witaj świecie! +``` + +Gratulacje! Właśnie pomyślnie odczytałeś dane inteligentnego kontraktu z blockchaina Ethereum, brawo! + +### Zaktualizuj wiadomość {#update-the-message} + +Zamiast tylko odczytywać wiadomość, możemy również zaktualizować wiadomość zapisaną w naszym inteligentnym kontrakcie za pomocą funkcji `update`! Całkiem fajne, prawda? + +Aby zaktualizować wiadomość, możemy bezpośrednio wywołać funkcję `update` na naszym obiekcie Contract: + +```javascript +// interact.js + +// ... + +asynchroniczna funkcja main() { + const message = await helloWorldContract.message() + console.log("Wiadomość to: " + message) + + console.log("Aktualizowanie wiadomości...") + const tx = await helloWorldContract.update("To jest nowa wiadomość.") + await tx.wait() +} +main() +``` + +Zauważ, że w linii 11, wywołujemy `.wait()` na zwróconym obiekcie transakcji. To zapewnia, że nasz skrypt czeka na wydobycie transakcji na blockchainie przed zakończeniem funkcji. Jeśli wywołanie `.wait()` nie zostanie uwzględnione, skrypt może nie zobaczyć zaktualizowanej wartości `message` w kontrakcie. + +### Przeczytaj nową wiadomość {#read-the-new-message} + +Powinieneś być w stanie powtórzyć [poprzedni krok](#read-the-init-message), aby odczytać zaktualizowaną wartość `message`. Poświęć chwilę i sprawdź, czy możesz dokonać niezbędnych zmian, aby wydrukować tę nową wartość! + +Jeśli potrzebujesz podpowiedzi, oto jak powinien wyglądać twój plik `interact.js` w tym momencie: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS + +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") + +// dostawca - Alchemy +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// podpisujący - ty +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// instancja kontraktu +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) + +asynchroniczna funkcja main() { + const message = await helloWorldContract.message() + console.log("Wiadomość to: " + message) + + console.log("Aktualizowanie wiadomości...") + const tx = await helloWorldContract.update("this is the new message") + await tx.wait() + + const newMessage = await helloWorldContract.message() + console.log("Nowa wiadomość to: " + newMessage) +} + +main() +``` + +Teraz po prostu uruchom skrypt, a powinieneś zobaczyć starą wiadomość, status aktualizacji i nową wiadomość wydrukowaną w terminalu! + +`npx hardhat run scripts/interact.js --network goerli` + +``` +Wiadomość to: Witaj świecie! +Aktualizowanie wiadomości... +Nowa wiadomość to: To jest nowa wiadomość. +``` + +Podczas uruchamiania tego skryptu możesz zauważyć, że krok `Aktualizowanie wiadomości...` zajmuje chwilę, zanim załaduje się nowa wiadomość. Jest to spowodowane procesem wydobycia. Jeśli jesteś ciekaw śledzenia transakcji podczas ich wydobywania, odwiedź [mempool Alchemy](https://dashboard.alchemyapi.io/mempool), aby zobaczyć status transakcji. Jeśli transakcja zostanie odrzucona, warto również sprawdzić [Goerli Etherscan](https://goerli.etherscan.io) i wyszukać swój hasz transakcji. + +## Część 3: Opublikuj swój inteligentny kontrakt w Etherscan {#part-3-publish-your-smart-contract-to-etherscan} + +Wykonałeś całą ciężką pracę, aby ożywić swój inteligentny kontrakt, teraz nadszedł czas, aby podzielić się nim ze światem! + +Weryfikując swój inteligentny kontrakt w Etherscan, każdy może zobaczyć jego kod źródłowy i wejść z nim w interakcję. Zaczynajmy! + +### Krok 1: Wygeneruj klucz API na swoim koncie Etherscan {#step-1-generate-an-api-key-on-your-etherscan-account} + +Klucz API Etherscan jest niezbędny do zweryfikowania, czy jesteś właścicielem inteligentnego kontraktu, który próbujesz opublikować. + +Jeśli nie masz jeszcze konta Etherscan, [załóż konto](https://etherscan.io/register). + +Po zalogowaniu znajdź swoją nazwę użytkownika w pasku nawigacyjnym, najedź na nią i wybierz przycisk **Mój profil**. + +Na stronie profilu powinieneś zobaczyć boczny pasek nawigacyjny. Z bocznego paska nawigacyjnego wybierz **Klucze API**. Następnie naciśnij przycisk „Dodaj”, aby utworzyć nowy klucz API, nazwij swoją aplikację **hello-world** i naciśnij przycisk **Utwórz nowy klucz API**. + +Nowy klucz API powinien pojawić się w tabeli kluczy API. Skopiuj klucz API do schowka. + +Następnie musimy dodać klucz API Etherscan do naszego pliku `.env`. + +Po dodaniu, twój plik `.env` powinien wyglądać tak: + +```javascript +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PUBLIC_KEY = "your-public-account-address" +PRIVATE_KEY = "your-private-account-address" +CONTRACT_ADDRESS = "your-contract-address" +ETHERSCAN_API_KEY = "your-etherscan-key" +``` + +### Inteligentne kontrakty wdrożone za pomocą Hardhat {#hardhat-deployed-smart-contracts} + +#### Zainstaluj hardhat-etherscan {#install-hardhat-etherscan} + +Publikowanie kontraktu w Etherscan za pomocą Hardhat jest proste. Na początek musisz zainstalować wtyczkę `hardhat-etherscan`. `hardhat-etherscan` automatycznie zweryfikuje kod źródłowy inteligentnego kontraktu i ABI w Etherscan. Aby to dodać, w katalogu `hello-world` uruchom: + +```text +npm install --save-dev @nomiclabs/hardhat-etherscan +``` + +Po zainstalowaniu, dołącz następującą instrukcję na początku pliku `hardhat.config.js` i dodaj opcje konfiguracyjne Etherscan: + +```javascript +// hardhat.config.js + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") +require("@nomiclabs/hardhat-etherscan") + +const { API_URL, PRIVATE_KEY, ETHERSCAN_API_KEY } = process.env + +module.exports = { + solidity: "0.7.3", + defaultNetwork: "goerli", + networks: { + hardhat: {}, + goerli: { + url: API_URL, + accounts: [`0x${PRIVATE_KEY}`], + }, + }, + etherscan: { + // Twój klucz API dla Etherscan + // Uzyskaj go na https://etherscan.io/ + apiKey: ETHERSCAN_API_KEY, + }, +} +``` + +#### Zweryfikuj swój inteligentny kontrakt na Etherscan {#verify-your-smart-contract-on-etherscan} + +Upewnij się, że wszystkie pliki są zapisane, a wszystkie zmienne `.env` są poprawnie skonfigurowane. + +Uruchom zadanie `verify`, podając adres kontraktu i sieć, w której jest wdrożony: + +```text +npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!' +``` + +Upewnij się, że `DEPLOYED_CONTRACT_ADDRESS` to adres Twojego wdrożonego inteligentnego kontraktu w sieci testowej Goerli. Ponadto ostatni argument (`'Hello World!'`) musi być tą samą wartością ciągu znaków, która została użyta [podczas kroku wdrażania w części 1](#write-our-deploy-script). + +Jeśli wszystko pójdzie dobrze, zobaczysz następujący komunikat w terminalu: + +```text +Pomyślnie przesłano kod źródłowy dla kontraktu +contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address +do weryfikacji na Etherscan. Oczekiwanie na wynik weryfikacji... + + +Pomyślnie zweryfikowano kontrakt HelloWorld na Etherscan. +https://goerli.etherscan.io/address/#contracts +``` + +Gratulacje! Twój kod inteligentnego kontraktu jest w Etherscan! + +### Sprawdź swój inteligentny kontrakt w Etherscan! {#check-out-your-smart-contract-on-etherscan} + +Po przejściu do linku podanego w terminalu, powinieneś być w stanie zobaczyć kod inteligentnego kontraktu i ABI opublikowane na Etherscan! + +**Hura - udało Ci się, mistrzu! Teraz każdy może wywołać lub zapisać do Twojego inteligentnego kontraktu! Nie możemy się doczekać, co zbudujesz dalej!** + +## Część 4 – Integracja inteligentnego kontraktu z frontendem {#part-4-integrating-your-smart-contract-with-the-frontend} + +Po ukończeniu tego samouczka dowiesz się, jak: + +- Połącz portfel MetaMask z Twoją dappką +- Odczytaj dane ze swojego inteligentnego kontraktu za pomocą interfejsu API [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) +- Podpisz transakcje Ethereum za pomocą MetaMask + +Dla tej dapki użyjemy [React](https://react.dev/) jako naszego frameworka frontendowego. Należy jednak zauważyć, że nie będziemy spędzać dużo czasu na omawianiu jego podstaw, ponieważ skupimy się głównie na wprowadzaniu funkcjonalności Web3 do naszego projektu. + +Jako warunek wstępny, powinieneś mieć podstawową wiedzę na temat React. Jeśli nie, polecamy ukończenie oficjalnego [samouczka Wprowadzenie do React](https://react.dev/learn). + +### Klonowanie plików startowych {#clone-the-starter-files} + +Najpierw przejdź do [repozytorium GitHub hello-world-part-four](https://github.com/alchemyplatform/hello-world-part-four-tutorial), aby pobrać pliki startowe dla tego projektu i sklonować to repozytorium na swój komputer lokalny. + +Otwórz sklonowane repozytorium lokalnie. Zauważ, że zawiera on dwa foldery: `starter-files` i `completed`. + +- `starter-files`- **będziemy pracować w tym katalogu**, połączymy interfejs użytkownika z Twoim portfelem Ethereum i inteligentnym kontraktem, który opublikowaliśmy w Etherscan w [części 3](#part-3). +- `completed` zawiera cały ukończony samouczek i powinien być używany tylko jako odniesienie, jeśli utkniesz. + +Następnie otwórz swoją kopię `starter-files` w ulubionym edytorze kodu, a następnie przejdź do folderu `src`. + +Cały kod, który napiszemy, będzie znajdować się w folderze `src`. Będziemy edytować komponent `HelloWorld.js` i pliki JavaScript `util/interact.js`, aby nadać naszemu projektowi funkcjonalność Web3. + +### Sprawdź pliki startowe {#check-out-the-starter-files} + +Zanim zaczniemy kodować, przeanalizujmy, co jest dla nas dostępne w plikach startowych. + +#### Uruchomienie projektu React {#get-your-react-project-running} + +Zacznijmy od uruchomienia projektu React w naszej przeglądarce. Piękno React polega na tym, że gdy nasz projekt jest już uruchomiony w przeglądarce, wszelkie zapisane przez nas zmiany będą na bieżąco aktualizowane w przeglądarce. + +Aby uruchomić projekt, przejdź do katalogu głównego folderu `starter-files` i uruchom `npm install` w terminalu, aby zainstalować zależności projektu: + +```bash +cd starter-files +npm install +``` + +Po zakończeniu instalacji uruchom `npm start` w terminalu: + +```bash +npm start +``` + +Spowoduje to otwarcie [http://localhost:3000/](http://localhost:3000/) w przeglądarce, gdzie zobaczysz frontend naszego projektu. Powinien on składać się z jednego pola (miejsce do aktualizacji wiadomości przechowywanej w inteligentnym kontrakcie), przycisku „Połącz portfel” i przycisku „Aktualizuj”. + +Jeśli spróbujesz kliknąć którykolwiek z przycisków, zauważysz, że nie działają – to dlatego, że wciąż musimy zaprogramować ich funkcjonalność. + +#### Komponent `HelloWorld.js` {#the-helloworld-js-component} + +Wróćmy do folderu `src` w naszym edytorze i otwórzmy plik `HelloWorld.js`. Jest bardzo ważne, abyśmy zrozumieli wszystko w tym pliku, ponieważ jest to główny komponent React, nad którym będziemy pracować. + +Na górze tego pliku zauważysz, że mamy kilka instrukcji importu, które są niezbędne do uruchomienia naszego projektu, w tym bibliotekę React, hooki useEffect i useState, niektóre elementy z `./util/interact.js` (opiszemy je bardziej szczegółowo wkrótce!) i logo Alchemy. + +```javascript +// HelloWorld.js + +import React from "react" +import { useEffect, useState } from "react" +import { + helloWorldContract, + connectWallet, + updateMessage, + loadCurrentMessage, + getCurrentWalletConnected, +} from "./util/interact.js" + +import alchemylogo from "./alchemylogo.svg" +``` + +Następnie mamy nasze zmienne stanu, które będziemy aktualizować po określonych zdarzeniach. + +```javascript +// HelloWorld.js + +// Zmienne stanu +const [walletAddress, setWallet] = useState("") +const [status, setStatus] = useState("") +const [message, setMessage] = useState("Brak połączenia z siecią.") +const [newMessage, setNewMessage] = useState("") +``` + +Oto, co reprezentuje każda ze zmiennych: + +- `walletAddress` - ciąg znaków, który przechowuje adres portfela użytkownika +- `status` - ciąg znaków, który przechowuje pomocną wiadomość, która prowadzi użytkownika, jak wchodzić w interakcję z dapp +- `message` - ciąg znaków, który przechowuje bieżącą wiadomość w inteligentnym kontrakcie +- `newMessage` - ciąg znaków, który przechowuje nową wiadomość, która zostanie zapisana w inteligentnym kontrakcie + +Po zmiennych stanu zobaczysz pięć niezaimplementowanych funkcji: `useEffect`, `addSmartContractListener`, `addWalletListener`, `connectWalletPressed` i `onUpdatePressed`. Poniżej wyjaśnimy, co robią: + +```javascript +// HelloWorld.js + +// wywoływane tylko raz +useEffect(async () => { + // TODO: zaimplementuj +}, []) + +function addSmartContractListener() { + // TODO: zaimplementuj +} + +function addWalletListener() { + // TODO: zaimplementuj +} + +const connectWalletPressed = async () => { + // TODO: zaimplementuj +} + +const onUpdatePressed = async () => { + // TODO: zaimplementuj +} +``` + +- [`useEffect`](https://legacy.reactjs.org/docs/hooks-effect.html) - to hook React, który jest wywoływany po wyrenderowaniu komponentu. Ponieważ ma przekazaną pustą tablicę `[]` jako właściwość (patrz linia 4), będzie wywoływany tylko podczas _pierwszego_ renderowania komponentu. Tutaj załadujemy bieżącą wiadomość zapisaną w naszym inteligentnym kontrakcie, wywołamy nasze inteligentne kontrakty i nasłuchiwacze portfela, a także zaktualizujemy nasz interfejs użytkownika, aby odzwierciedlić, czy portfel jest już podłączony. +- `addSmartContractListener` - ta funkcja konfiguruje nasłuchiwacza, który będzie obserwował zdarzenie `UpdatedMessages` naszego kontraktu HelloWorld i aktualizował nasz interfejs użytkownika, gdy wiadomość w naszym inteligentnym kontrakcie ulegnie zmianie. +- `addWalletListener` - ta funkcja konfiguruje nasłuchiwacza, który wykrywa zmiany w stanie portfela MetaMask użytkownika, np. gdy użytkownik odłącza portfel lub zmienia adresy. +- `connectWalletPressed` - ta funkcja zostanie wywołana w celu połączenia portfela MetaMask użytkownika z naszą dapp. +- `onUpdatePressed` - ta funkcja zostanie wywołana, gdy użytkownik będzie chciał zaktualizować wiadomość zapisaną w inteligentnym kontrakcie. + +Pod koniec tego pliku mamy interfejs użytkownika naszego komponentu. + +```javascript +// HelloWorld.js + +// interfejs użytkownika naszego komponentu +return ( +
+ + + +

Bieżąca wiadomość:

+

{message}

+ +

Nowa wiadomość:

+ +
+ setNewMessage(e.target.value)} + value={newMessage} + /> +

{status}

+ + +
+ +
+) +``` + +Jeśli dokładnie przeanalizujesz ten kod, zauważysz, gdzie używamy naszych różnych zmiennych stanu w naszym interfejsie użytkownika: + +- W liniach 6-12, jeśli portfel użytkownika jest podłączony (tj. `walletAddress.length > 0`), wyświetlamy skróconą wersję `walletAddress` użytkownika w przycisku o identyfikatorze „walletButton”; w przeciwnym razie jest tam po prostu napis „Połącz portfel”. +- W linii 17 wyświetlamy bieżącą wiadomość zapisaną w inteligentnym kontrakcie, która jest przechwytywana w ciągu znaków `message`. +- W liniach 23-26 używamy [komponentu kontrolowanego](https://legacy.reactjs.org/docs/forms.html#controlled-components), aby zaktualizować naszą zmienną stanu `newMessage`, gdy zmienia się wpis w polu tekstowym. + +Oprócz naszych zmiennych stanu, zobaczysz również, że funkcje `connectWalletPressed` i `onUpdatePressed` są wywoływane, gdy odpowiednio klikane są przyciski o identyfikatorach `publishButton` i `walletButton`. + +Na koniec zajmijmy się tym, gdzie ten komponent `HelloWorld.js` jest dodawany. + +Jeśli przejdziesz do pliku `App.js`, który jest głównym komponentem w React, który działa jako kontener dla wszystkich innych komponentów, zobaczysz, że nasz komponent `HelloWorld.js` jest wstrzykiwany w linii 7. + +Na koniec sprawdźmy jeszcze jeden plik, który został dla Ciebie przygotowany, plik `interact.js`. + +#### Plik `interact.js` {#the-interact-js-file} + +Ponieważ chcemy trzymać się paradygmatu [M-V-C](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller), będziemy chcieli mieć osobny plik, który zawiera wszystkie nasze funkcje do zarządzania logiką, danymi i regułami naszej dapki, a następnie będziemy mogli wyeksportować te funkcje do naszego frontendu (naszego komponentu `HelloWorld.js`). + +👆🏽 To jest dokładny cel naszego pliku `interact.js`! + +Przejdź do folderu `util` w swoim katalogu `src`, a zauważysz, że dołączyliśmy plik o nazwie `interact.js`, który będzie zawierał wszystkie nasze funkcje i zmienne interakcji z inteligentnym kontraktem i portfelem. + +```javascript +// interact.js + +//export const helloWorldContract; + +export const loadCurrentMessage = async () => {} + +export const connectWallet = async () => {} + +const getCurrentWalletConnected = async () => {} + +export const updateMessage = async (message) => {} +``` + +Na początku pliku zauważysz, że skomentowaliśmy obiekt `helloWorldContract`. Później w tym samouczku odkomentujemy ten obiekt i utworzymy instancję naszego inteligentnego kontraktu w tej zmiennej, którą następnie wyeksportujemy do naszego komponentu `HelloWorld.js`. + +Cztery niezaimplementowane funkcje po naszym obiekcie `helloWorldContract` robią następujące rzeczy: + +- `loadCurrentMessage` - ta funkcja obsługuje logikę ładowania bieżącej wiadomości zapisanej w inteligentnym kontrakcie. Wywoła ona żądanie _odczytu_ do inteligentnego kontraktu Witaj Świecie za pomocą [interfejsu API Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3). +- `connectWallet` - ta funkcja połączy MetaMask użytkownika z naszą dappką. +- `getCurrentWalletConnected` - ta funkcja sprawdzi, czy konto Ethereum jest już połączone z naszą dappką podczas ładowania strony i odpowiednio zaktualizuje nasz interfejs użytkownika. +- `updateMessage` - ta funkcja zaktualizuje wiadomość zapisaną w inteligentnym kontrakcie. Wykona ona żądanie _zapisu_ do inteligentnego kontraktu Witaj Świecie, więc portfel MetaMask użytkownika będzie musiał podpisać transakcję Ethereum, aby zaktualizować wiadomość. + +Teraz, gdy rozumiemy, z czym pracujemy, dowiedzmy się, jak czytać z naszego inteligentnego kontraktu! + +### Krok 3: Odczyt z Twojego inteligentnego kontraktu {#step-3-read-from-your-smart-contract} + +Aby odczytać dane z inteligentnego kontraktu, musisz pomyślnie skonfigurować: + +- Połączenie API z łańcuchem Ethereum +- Załadowana instancja Twojego inteligentnego kontraktu +- Funkcja do wywołania funkcji inteligentnego kontraktu +- Nasłuchiwacz do obserwowania aktualizacji, gdy zmieniają się dane, które odczytujesz z inteligentnego kontraktu + +To może brzmieć jak wiele kroków, ale nie martw się! Przeprowadzimy Cię przez każdy z nich krok po kroku! :\) + +#### Ustanów połączenie API z łańcuchem Ethereum {#establish-an-api-connection-to-the-ethereum-chain} + +Pamiętasz, jak w części 2 tego samouczka użyliśmy naszego klucza Alchemy Web3 do odczytu z naszego inteligentnego kontraktu ([https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library))? Będziesz również potrzebować klucza Alchemy Web3 w swojej dapce, aby czytać z łańcucha. + +Jeśli go jeszcze nie masz, najpierw zainstaluj [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3), przechodząc do katalogu głównego `starter-files` i uruchamiając następujące polecenie w terminalu: + +```text +npm install @alch/alchemy-web3 +``` + +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) to nakładka na [Web3.js](https://docs.web3js.org/), zapewniająca ulepszone metody API i inne kluczowe korzyści, które ułatwiają życie dewelopera web3. Został zaprojektowany tak, aby wymagał minimalnej konfiguracji, dzięki czemu możesz od razu zacząć go używać w swojej aplikacji! + +Następnie zainstaluj pakiet [dotenv](https://www.npmjs.com/package/dotenv) w katalogu projektu, abyśmy mieli bezpieczne miejsce do przechowywania naszego klucza API po jego pobraniu. + +```text +npm install dotenv --save +``` + +Dla naszej dapki **będziemy używać naszego klucza API Websockets** zamiast klucza API HTTP, ponieważ pozwoli nam to skonfigurować nasłuchiwacza, który wykrywa, kiedy zmienia się wiadomość zapisana w inteligentnym kontrakcie. + +Po uzyskaniu klucza API, utwórz plik `.env` w swoim katalogu głównym i dodaj do niego adres URL Alchemy Websockets. Następnie plik `.env` powinien wyglądać następująco: + +```javascript +REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/ +``` + +Teraz jesteśmy gotowi do skonfigurowania naszego punktu końcowego Alchemy Web3 w naszej dapce! Wróćmy do naszego pliku `interact.js`, który jest zagnieżdżony w naszym folderze `util` i dodajmy następujący kod na początku pliku: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const { createAlchemyWeb3 } = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +//export const helloWorldContract; +``` + +Powyżej najpierw zaimportowaliśmy klucz Alchemy z naszego pliku `.env`, a następnie przekazaliśmy nasz `alchemyKey` do `createAlchemyWeb3`, aby ustanowić nasz punkt końcowy Alchemy Web3. + +Gdy ten punkt końcowy jest gotowy, nadszedł czas, aby załadować nasz inteligentny kontrakt! + +#### Ładowanie Twojego inteligentnego kontraktu Witaj Świecie {#loading-your-hello-world-smart-contract} + +Aby załadować swój inteligentny kontrakt Witaj Świecie, będziesz potrzebować jego adresu kontraktu i ABI, które można znaleźć w Etherscan, jeśli ukończyłeś [część 3 tego samouczka](/developers/tutorials/hello-world-smart-contract-fullstack/#part-3-publish-your-smart-contract-to-etherscan-part-3-publish-your-smart-contract-to-etherscan). + +#### Jak uzyskać ABI kontraktu z Etherscan {#how-to-get-your-contract-abi-from-etherscan} + +Jeśli pominąłeś część 3 tego samouczka, możesz użyć kontraktu HelloWorld z adresem [0x6f3f635A9762B47954229Ea479b4541eAF402A6A](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code). Jego ABI można znaleźć [tutaj](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code). + +ABI kontraktu jest niezbędne do określenia, którą funkcję kontrakt wywoła, a także do zapewnienia, że funkcja zwróci dane w oczekiwanym formacie. Po skopiowaniu naszego ABI kontraktu, zapiszmy go jako plik JSON o nazwie `contract-abi.json` w swoim katalogu `src`. + +Twój plik contract-abi.json powinien być przechowywany w folderze src. + +Mając do dyspozycji adres kontraktu, ABI i punkt końcowy Alchemy Web3, możemy użyć [metody kontraktu](https://docs.web3js.org/api/web3-eth-contract/class/Contract), aby załadować instancję naszego inteligentnego kontraktu. Zaimportuj ABI kontraktu do pliku `interact.js` i dodaj adres kontraktu. + +```javascript +// interact.js + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" +``` + +Możemy teraz wreszcie odkomentować naszą zmienną `helloWorldContract` i załadować inteligentny kontrakt za pomocą naszego punktu końcowego AlchemyWeb3: + +```javascript +// interact.js +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +Podsumowując, pierwsze 12 linii pliku `interact.js` powinno teraz wyglądać tak: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const { createAlchemyWeb3 } = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" + +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +Teraz, gdy nasz kontrakt jest załadowany, możemy zaimplementować naszą funkcję `loadCurrentMessage`! + +#### Implementacja `loadCurrentMessage` w pliku `interact.js` {#implementing-loadCurrentMessage-in-your-interact-js-file} + +Ta funkcja jest super prosta. Zrobimy proste asynchroniczne wywołanie web3, aby odczytać z naszego kontraktu. Nasza funkcja zwróci wiadomość zapisaną w inteligentnym kontrakcie: + +Zaktualizuj `loadCurrentMessage` w swoim pliku `interact.js` do następującej postaci: + +```javascript +// interact.js + +export const loadCurrentMessage = async () => { + const message = await helloWorldContract.methods.message().call() + return message +} +``` + +Ponieważ chcemy wyświetlić ten inteligentny kontrakt w naszym interfejsie użytkownika, zaktualizujmy funkcję `useEffect` w naszym komponencie `HelloWorld.js` do następującej postaci: + +```javascript +// HelloWorld.js + +// wywoływane tylko raz +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) +}, []) +``` + +Zauważ, że chcemy, aby nasza funkcja `loadCurrentMessage` była wywoływana tylko raz podczas pierwszego renderowania komponentu. Wkrótce zaimplementujemy `addSmartContractListener`, aby automatycznie aktualizować interfejs użytkownika po zmianie wiadomości w inteligentnym kontrakcie. + +Zanim przejdziemy do naszego nasłuchiwacza, sprawdźmy, co mamy do tej pory! Zapisz pliki `HelloWorld.js` i `interact.js`, a następnie przejdź do [http://localhost:3000/](http://localhost:3000/) + +Zauważysz, że bieżąca wiadomość nie brzmi już „Brak połączenia z siecią”. Zamiast tego odzwierciedla ona wiadomość zapisaną w inteligentnym kontrakcie. Super! + +#### Twój interfejs użytkownika powinien teraz odzwierciedlać wiadomość zapisaną w inteligentnym kontrakcie {#your-UI-should-now-reflect-the-message-stored-in-the-smart-contract} + +A propos tego nasłuchiwacza... + +#### Zaimplementuj `addSmartContractListener` {#implement-addsmartcontractlistener} + +Jeśli przypomnisz sobie plik `HelloWorld.sol`, który napisaliśmy w [części 1 tej serii samouczków](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract#step-10-write-our-contract), przypomnisz sobie, że istnieje zdarzenie inteligentnego kontraktu o nazwie `UpdatedMessages`, które jest emitowane po wywołaniu funkcji `update` naszego inteligentnego kontraktu (patrz linie 9 i 27): + +```javascript +// HelloWorld.sol + +// Określa wersję Solidity, używając semantycznego wersjonowania. +// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity ^0.7.3; + +// Definiuje kontrakt o nazwie `HelloWorld`. +// Kontrakt jest zbiorem funkcji i danych (jego stanu). Po wdrożeniu kontrakt znajduje się pod określonym adresem w blockchainie Ethereum. Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld { + + // Emitowane, gdy wywoływana jest funkcja aktualizacji + // Zdarzenia inteligentnych kontraktów to sposób, w jaki kontrakt komunikuje, że coś wydarzyło się na blockchainie do front-endu aplikacji, który może „nasłuchiwać” określonych zdarzeń i podejmować działania, gdy one wystąpią. + event UpdatedMessages(string oldStr, string newStr); + + // Deklaruje zmienną stanu `message` typu `string`. + // Zmienne stanu to zmienne, których wartości są trwale przechowywane w pamięci kontraktu. Słowo kluczowe `public` udostępnia zmienne spoza kontraktu i tworzy funkcję, którą inne kontrakty lub klienci mogą wywołać w celu uzyskania dostępu do wartości. + string public message; + + // Podobnie jak w wielu językach obiektowych opartych na klasach, konstruktor jest specjalną funkcją, która jest wykonywana tylko podczas tworzenia kontraktu. + // Konstruktory służą do inicjalizacji danych kontraktu. Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + constructor(string memory initMessage) { + + // Akceptuje argument ciągu znaków `initMessage` i ustawia wartość w zmiennej pamięci kontraktu `message`). + message = initMessage; + } + + // Funkcja publiczna, która akceptuje argument w postaci ciągu znaków i aktualizuje zmienną pamięci masowej `message`. + function update(string memory newMessage) public { + string memory oldMsg = message; + message = newMessage; + emit UpdatedMessages(oldMsg, newMessage); + } +} +``` + +Zdarzenia inteligentnych kontraktów to sposób, w jaki kontrakt komunikuje, że coś się stało (tj. miało miejsce _zdarzenie_) na blockchainie do Twojej aplikacji front-endowej, która może „nasłuchiwać” określonych zdarzeń i podejmować działania, gdy one wystąpią. + +Funkcja `addSmartContractListener` będzie konkretnie nasłuchiwać zdarzenia `UpdatedMessages` naszego inteligentnego kontraktu Witaj Świecie i aktualizować nasz interfejs użytkownika, aby wyświetlić nową wiadomość. + +Zmodyfikuj `addSmartContractListener` do następującej postaci: + +```javascript +// HelloWorld.js + +function addSmartContractListener() { + helloWorldContract.events.UpdatedMessages({}, (error, data) => { + if (error) { + setStatus("😥 " + error.message) + } else { + setMessage(data.returnValues[1]) + setNewMessage("") + setStatus("🎉 Twoja wiadomość została zaktualizowana!") + } + }) +} +``` + +Przeanalizujmy, co się dzieje, gdy nasłuchiwacz wykryje zdarzenie: + +- Jeśli wystąpi błąd podczas emitowania zdarzenia, zostanie on odzwierciedlony w interfejsie użytkownika za pośrednictwem naszej zmiennej stanu `status`. +- W przeciwnym razie użyjemy zwróconego obiektu `data`. `data.returnValues` to tablica indeksowana od zera, w której pierwszy element tablicy przechowuje poprzednią wiadomość, a drugi element przechowuje zaktualizowaną. W sumie, w przypadku pomyślnego zdarzenia, ustawimy nasz ciąg znaków `message` na zaktualizowaną wiadomość, wyczyścimy ciąg znaków `newMessage` i zaktualizujemy naszą zmienną stanu `status`, aby odzwierciedlić, że nowa wiadomość została opublikowana w naszym inteligentnym kontrakcie. + +Na koniec wywołajmy naszego nasłuchiwacza w naszej funkcji `useEffect`, aby został zainicjowany podczas pierwszego renderowania komponentu `HelloWorld.js`. W sumie Twoja funkcja `useEffect` powinna wyglądać tak: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() +}, []) +``` + +Teraz, gdy jesteśmy w stanie czytać z naszego inteligentnego kontraktu, byłoby wspaniale dowiedzieć się, jak do niego pisać! Jednak, aby pisać do naszej dapki, musimy najpierw mieć do niej podłączony portfel Ethereum. + +Więc następnie zajmiemy się konfiguracją naszego portfela Ethereum (MetaMask), a następnie podłączeniem go do naszej dapki! + +### Krok 4: Skonfiguruj swój portfel Ethereum {#step-4-set-up-your-ethereum-wallet} + +Aby cokolwiek zapisać w łańcuchu Ethereum, użytkownicy muszą podpisywać transakcje za pomocą kluczy prywatnych swojego wirtualnego portfela. W tym samouczku użyjemy [MetaMask](https://metamask.io/), wirtualnego portfela w przeglądarce używanego do zarządzania adresem konta Ethereum, ponieważ znacznie ułatwia to podpisywanie transakcji dla użytkownika końcowego. + +Jeśli chcesz dowiedzieć się więcej o tym, jak działają transakcje w Ethereum, sprawdź [tę stronę](/developers/docs/transactions/) od Ethereum Foundation. + +#### Pobierz MetaMask {#download-metamask} + +Możesz pobrać i utworzyć konto MetaMask za darmo [tutaj](https://metamask.io/download). Podczas tworzenia konta, lub jeśli już je posiadasz, upewnij się, że przełączyłeś się na „Sieć testową Goerli” w prawym górnym rogu (aby nie mieć do czynienia z prawdziwymi pieniędzmi). + +#### Dodaj ether z Faucet {#add-ether-from-a-faucet} + +Aby podpisać transakcję na blockchainie Ethereum, będziemy potrzebować trochę fałszywego Eth. Aby uzyskać Eth, możesz przejść do [FaucETH](https://fauceth.komputing.org) i wprowadzić swój adres konta Goerli, kliknąć „Poproś o fundusze”, następnie wybrać „Ethereum Testnet Goerli” w menu rozwijanym i na koniec ponownie kliknąć przycisk „Poproś o fundusze”. Wkrótce powinieneś zobaczyć Eth na swoim koncie MetaMask! + +#### Sprawdź swoje saldo {#check-your-balance} + +Aby sprawdzić, czy nasze saldo jest na miejscu, wykonajmy żądanie [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) za pomocą [narzędzia kompozytora Alchemy](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). Zwróci to ilość Eth w naszym portfelu. Po wprowadzeniu adresu konta MetaMask i kliknięciu „Wyślij żądanie” powinieneś zobaczyć następującą odpowiedź: + +```text +{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"} +``` + +**UWAGA:** ten wynik jest w wei, a nie w eth. Wei jest używany jako najmniejsza jednostka etheru. Konwersja z wei na eth to: 1 eth = 10¹⁸ wei. Więc jeśli przekonwertujemy 0xde0b6b3a7640000 na system dziesiętny, otrzymamy 1\*10¹⁸, co równa się 1 eth. + +Uff! Nasze fałszywe pieniądze są na miejscu! 🤑 + +### Krok 5: Podłącz MetaMask do swojego interfejsu użytkownika {#step-5-connect-metamask-to-your-UI} + +Teraz, gdy nasz portfel MetaMask jest skonfigurowany, połączmy z nim naszą dapką! + +#### Funkcja `connectWallet` {#the-connectWallet-function} + +W naszym pliku `interact.js` zaimplementujmy funkcję `connectWallet`, którą następnie możemy wywołać w naszym komponencie `HelloWorld.js`. + +Zmodyfikujmy `connectWallet` do następującej postaci: + +```javascript +// interact.js + +export const connectWallet = async () => { + if (window.ethereum) { + try { + const addressArray = await window.ethereum.request({ + method: "eth_requestAccounts", + }) + const obj = { + status: "👆🏽 Wpisz wiadomość w polu tekstowym powyżej.", + address: addressArray[0], + } + return obj + } catch (err) { + return { + address: "", + status: "😥 " + err.message, + } + } + } else { + return { + address: "", + status: ( + +

+ {" "} + 🦊 + Musisz zainstalować MetaMask, wirtualny portfel Ethereum, w swojej + przeglądarce. + +

+
+ ), + } + } +} +``` + +Więc co dokładnie robi ten gigantyczny blok kodu? + +Po pierwsze, sprawdza, czy `window.ethereum` jest włączone w przeglądarce. + +`window.ethereum` to globalny interfejs API wstrzykiwany przez MetaMask i innych dostawców portfeli, który pozwala stronom internetowym na żądanie dostępu do kont Ethereum użytkowników. Jeśli zostanie zatwierdzony, może odczytywać dane z blockchainów, z którymi użytkownik jest połączony, i sugerować, aby użytkownik podpisywał wiadomości i transakcje. Sprawdź [dokumentację MetaMask](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents), aby uzyskać więcej informacji! + +Jeśli `window.ethereum` _nie jest_ obecne, oznacza to, że MetaMask nie jest zainstalowany. Powoduje to zwrócenie obiektu JSON, w którym zwrócony `adres` jest pustym ciągiem, a obiekt `status` JSX informuje, że użytkownik musi zainstalować MetaMask. + +Teraz, jeśli `window.ethereum` _jest_ obecne, to wtedy robi się ciekawie. + +Używając pętli try/catch, spróbujemy połączyć się z MetaMask, wywołując [`window.ethereum.request({ method: "eth_requestAccounts" });`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts). Wywołanie tej funkcji otworzy MetaMask w przeglądarce, gdzie użytkownik zostanie poproszony o podłączenie swojego portfela do Twojej dapki. + +- Jeśli użytkownik zdecyduje się połączyć, `method: "eth_requestAccounts"` zwróci tablicę zawierającą wszystkie adresy kont użytkownika, które połączyły się z dappką. W sumie nasza funkcja `connectWallet` zwróci obiekt JSON, który zawiera _pierwszy_ `adres` w tej tablicy (patrz linia 9) oraz wiadomość `status`, która prosi użytkownika o napisanie wiadomości do inteligentnego kontraktu. +- Jeśli użytkownik odrzuci połączenie, obiekt JSON będzie zawierał pusty ciąg dla zwróconego `adresu` oraz komunikat `status`, który odzwierciedla, że użytkownik odrzucił połączenie. + +Teraz, gdy napisaliśmy tę funkcję `connectWallet`, następnym krokiem jest wywołanie jej w naszym komponencie `HelloWorld.js`. + +#### Dodaj funkcję `connectWallet` do swojego komponentu interfejsu użytkownika HelloWorld.js {#add-the-connectWallet-function-to-your-HelloWorld-js-ui-component} + +Przejdź do funkcji `connectWalletPressed` w `HelloWorld.js` i zaktualizuj ją do następującej postaci: + +```javascript +// HelloWorld.js + +const connectWalletPressed = async () => { + const walletResponse = await connectWallet() + setStatus(walletResponse.status) + setWallet(walletResponse.address) +} +``` + +Zauważ, jak większość naszej funkcjonalności jest abstrahowana od naszego komponentu `HelloWorld.js` z pliku `interact.js`? Robimy tak, aby zachować zgodność z paradygmatem M-V-C! + +W `connectWalletPressed` po prostu wykonujemy wywołanie await do naszej zaimportowanej funkcji `connectWallet`, a za pomocą jej odpowiedzi aktualizujemy nasze zmienne `status` i `walletAddress` za pomocą ich hooków stanu. + +Teraz zapiszmy oba pliki (`HelloWorld.js` i `interact.js`) i przetestujmy nasz dotychczasowy interfejs użytkownika. + +Otwórz przeglądarkę na stronie [http://localhost:3000/](http://localhost:3000/) i naciśnij przycisk „Połącz portfel” w prawym górnym rogu strony. + +Jeśli masz zainstalowany MetaMask, powinieneś zostać poproszony o podłączenie swojego portfela do Twojej dapki. Zaakceptuj zaproszenie do połączenia. + +Powinieneś zobaczyć, że przycisk portfela odzwierciedla teraz, że Twój adres jest połączony! Jeeee 🔥 + +Następnie spróbuj odświeżyć stronę... to jest dziwne. Nasz przycisk portfela prosi nas o podłączenie MetaMask, mimo że jest już podłączony... + +Jednak nie ma się czego bać! Możemy łatwo to rozwiązać (zaadresować?) implementując `getCurrentWalletConnected`, który sprawdzi, czy adres jest już połączony z naszą dappką i odpowiednio zaktualizuje nasz interfejs użytkownika! + +#### Funkcja `getCurrentWalletConnected` {#the-getcurrentwalletconnected-function} + +Zaktualizuj swoją funkcję `getCurrentWalletConnected` w pliku `interact.js` do następującej postaci: + +```javascript +// interact.js + +export const getCurrentWalletConnected = async () => { + if (window.ethereum) { + try { + const addressArray = await window.ethereum.request({ + method: "eth_accounts", + }) + if (addressArray.length > 0) { + return { + address: addressArray[0], + status: "👆🏽 Wpisz wiadomość w polu tekstowym powyżej.", + } + } else { + return { + address: "", + status: "🦊 Połącz się z MetaMask za pomocą przycisku w prawym górnym rogu.", + } + } + } catch (err) { + return { + address: "", + status: "😥 " + err.message, + } + } + } else { + return { + address: "", + status: ( + +

+ {" "} + 🦊 + Musisz zainstalować MetaMask, wirtualny portfel Ethereum, w swojej + przeglądarce. + +

+
+ ), + } + } +} +``` + +Ten kod jest _bardzo_ podobny do funkcji `connectWallet`, którą właśnie napisaliśmy w poprzednim kroku. + +Główna różnica polega na tym, że zamiast wywoływać metodę `eth_requestAccounts`, która otwiera MetaMask, aby użytkownik mógł połączyć swój portfel, tutaj wywołujemy metodę `eth_accounts`, która po prostu zwraca tablicę zawierającą adresy MetaMask aktualnie połączone z naszą dapką. + +Aby zobaczyć tę funkcję w działaniu, wywołajmy ją w naszej funkcji `useEffect` naszego komponentu `HelloWorld.js`: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() + + const { address, status } = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) +}, []) +``` + +Zauważ, że używamy odpowiedzi z naszego wywołania `getCurrentWalletConnected`, aby zaktualizować nasze zmienne stanu `walletAddress` i `status`. + +Teraz, gdy dodałeś ten kod, spróbujmy odświeżyć okno przeglądarki. + +Fajnieee! Przycisk powinien informować, że jesteś połączony i pokazywać podgląd adresu podłączonego portfela - nawet po odświeżeniu! + +#### Zaimplementuj `addWalletListener` {#implement-addwalletlistener} + +Ostatnim krokiem w konfiguracji portfela naszej dapki jest zaimplementowanie nasłuchiwacza portfela, aby nasz interfejs użytkownika aktualizował się, gdy zmieni się stan naszego portfela, na przykład gdy użytkownik się rozłączy lub zmieni konto. + +W pliku `HelloWorld.js` zmodyfikuj swoją funkcję `addWalletListener` w następujący sposób: + +```javascript +// HelloWorld.js + +function addWalletListener() { + if (window.ethereum) { + window.ethereum.on("accountsChanged", (accounts) => { + if (accounts.length > 0) { + setWallet(accounts[0]) + setStatus("👆🏽 Wpisz wiadomość w polu tekstowym powyżej.") + } else { + setWallet("") + setStatus("🦊 Połącz się z MetaMask za pomocą przycisku w prawym górnym rogu.") + } + }) + } else { + setStatus( +

+ {" "} + 🦊 + Musisz zainstalować MetaMask, wirtualny portfel Ethereum, w swojej przeglądarce. + +

+ ) + } +} +``` + +Założę się, że w tym momencie nie potrzebujesz nawet naszej pomocy, aby zrozumieć, co się tutaj dzieje, ale dla porządku szybko to omówmy: + +- Najpierw nasza funkcja sprawdza, czy `window.ethereum` jest włączone (tj. MetaMask jest zainstalowany). + - Jeśli nie jest, po prostu ustawiamy naszą zmienną stanu `status` na ciąg JSX, który prosi użytkownika o zainstalowanie MetaMask. + - Jeśli jest włączone, ustawiamy nasłuchiwacz `window.ethereum.on("accountsChanged")` w linii 3, który nasłuchuje zmian stanu w portfelu MetaMask, co obejmuje sytuacje, gdy użytkownik podłącza dodatkowe konto do dapki, zmienia konta lub odłącza konto. Jeśli co najmniej jedno konto jest połączone, zmienna stanu `walletAddress` jest aktualizowana jako pierwsze konto w tablicy `konta` zwróconej przez nasłuchiwacz. W przeciwnym razie `walletAddress` jest ustawiany jako pusty ciąg. + +Na koniec musimy wywołać ją w naszej funkcji `useEffect`: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() + + const { address, status } = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) + + addWalletListener() +}, []) +``` + +I to wszystko! Pomyślnie ukończyliśmy programowanie całej naszej funkcjonalności portfela! Teraz przejdźmy do naszego ostatniego zadania: aktualizacji wiadomości zapisanej w naszym inteligentnym kontrakcie! + +### Krok 6: Zaimplementuj funkcję `updateMessage` {#step-6-implement-the-updateMessage-function} + +Dobra, ekipa, dotarliśmy do ostatniej prostej! W `updateMessage` w swoim pliku `interact.js`, zrobimy następujące rzeczy: + +1. Upewnij się, że wiadomość, którą chcemy opublikować w naszym inteligentnym kontakcie, jest ważna +2. Podpisz naszą transakcję za pomocą MetaMask +3. Wywołaj tę funkcję z naszego komponentu frontendowego `HelloWorld.js` + +To nie potrwa długo; dokończmy tę dappkę! + +#### Obsługa błędów wejściowych {#input-error-handling} + +Naturalnie, sensowne jest posiadanie jakiejś formy obsługi błędów wejściowych na początku funkcji. + +Będziemy chcieli, aby nasza funkcja zakończyła się wcześniej, jeśli nie ma zainstalowanego rozszerzenia MetaMask, nie jest podłączony portfel (tj. przekazany `address` jest pustym ciągiem znaków) lub `message` jest pustym ciągiem znaków. Dodajmy następującą obsługę błędów do `updateMessage`: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => { + if (!window.ethereum || address === null) { + return { + status: + "💡 Połącz swój portfel MetaMask, aby zaktualizować wiadomość na blockchainie.", + } + } + + if (message.trim() === "") { + return { + status: "❌ Twoja wiadomość nie może być pustym ciągiem znaków.", + } + } +} +``` + +Teraz, gdy mamy właściwą obsługę błędów wejściowych, nadszedł czas, aby podpisać transakcję za pomocą MetaMask! + +#### Podpisywanie naszej transakcji {#signing-our-transaction} + +Jeśli jesteś już zaznajomiony z tradycyjnymi transakcjami Ethereum web3, kod, który napiszemy dalej, będzie bardzo znajomy. Poniżej kodu obsługi błędów wejściowych dodaj następujący kod do `updateMessage`: + +```javascript +// interact.js + +// ustaw parametry transakcji +const transactionParameters = { + to: contractAddress, // Wymagane z wyjątkiem publikacji kontraktów. + from: address, // musi pasować do aktywnego adresu użytkownika. + data: helloWorldContract.methods.update(message).encodeABI(), +} + +// podpisz transakcję +try { + const txHash = await window.ethereum.request({ + method: "eth_sendTransaction", + params: [transactionParameters], + }) + return { + status: ( + + ✅{" "} + + Zobacz status swojej transakcji na Etherscan! + +
+ ℹ️ Gdy transakcja zostanie zweryfikowana przez sieć, wiadomość zostanie + zaktualizowana automatycznie. +
+ ), + } +} catch (error) { + return { + status: "😥 " + error.message, + } +} +``` + +Przeanalizujmy, co się dzieje. Najpierw ustawiamy parametry naszej transakcji, gdzie: + +- `to` określa adres odbiorcy (nasz inteligentny kontrakt) +- `from` określa sygnatariusza transakcji, zmienną `address`, którą przekazaliśmy do naszej funkcji +- `data` zawiera wywołanie metody `update` naszego inteligentnego kontraktu Witaj Świecie, otrzymując jako dane wejściowe naszą zmienną ciągu znaków `message` + +Następnie wykonujemy wywołanie await, `window.ethereum.request`, w którym prosimy MetaMask o podpisanie transakcji. Zauważ, że w liniach 11 i 12 określamy naszą metodę eth, `eth_sendTransaction` i przekazujemy nasze `transactionParameters`. + +W tym momencie w przeglądarce otworzy się MetaMask i poprosi użytkownika o podpisanie lub odrzucenie transakcji. + +- Jeśli transakcja się powiedzie, funkcja zwróci obiekt JSON, w którym ciąg JSX `status` prosi użytkownika o sprawdzenie Etherscan w celu uzyskania dalszych informacji o transakcji. +- Jeśli transakcja się nie powiedzie, funkcja zwróci obiekt JSON, w którym ciąg znaków `status` przekaże komunikat o błędzie. + +W sumie nasza funkcja `updateMessage` powinna wyglądać tak: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => { + // obsługa błędów wejściowych + if (!window.ethereum || address === null) { + return { + status: + "💡 Połącz swój portfel MetaMask, aby zaktualizować wiadomość na blockchainie.", + } + } + + if (message.trim() === "") { + return { + status: "❌ Twoja wiadomość nie może być pustym ciągiem znaków.", + } + } + + // ustaw parametry transakcji + const transactionParameters = { + to: contractAddress, // Wymagane z wyjątkiem publikacji kontraktów. + from: address, // musi pasować do aktywnego adresu użytkownika. + data: helloWorldContract.methods.update(message).encodeABI(), + } + + // podpisz transakcję + try { + const txHash = await window.ethereum.request({ + method: "eth_sendTransaction", + params: [transactionParameters], + }) + return { + status: ( + + ✅{" "} + + Zobacz status swojej transakcji na Etherscan! + +
+ ℹ️ Gdy transakcja zostanie zweryfikowana przez sieć, wiadomość zostanie + zaktualizowana automatycznie. +
+ ), + } + } catch (error) { + return { + status: "😥 " + error.message, + } + } +} +``` + +Na koniec musimy połączyć naszą funkcję `updateMessage` z naszym komponentem `HelloWorld.js`. + +#### Połącz `updateMessage` z frontendem `HelloWorld.js` {#connect-updatemessage-to-the-helloworld-js-frontend} + +Nasza funkcja `onUpdatePressed` powinna wykonać wywołanie await do zaimportowanej funkcji `updateMessage` i zmodyfikować zmienną stanu `status`, aby odzwierciedlić, czy nasza transakcja się powiodła, czy nie: + +```javascript +// HelloWorld.js + +const onUpdatePressed = async () => { + const { status } = await updateMessage(walletAddress, newMessage) + setStatus(status) +} +``` + +To super czyste i proste. I zgadnij co... TWOJA DAPPKA JEST UKOŃCZONA!!! + +Śmiało przetestuj przycisk **Aktualizuj**! + +### Stwórz swoją własną dappkę {#make-your-own-custom-dapp} + +Hura, dotarłeś do końca samouczka! Podsumowując, nauczyłeś się, jak: + +- Podłącz portfel MetaMask do swojego projektu dapp +- Odczytaj dane ze swojego inteligentnego kontraktu za pomocą interfejsu API [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) +- Podpisz transakcje Ethereum za pomocą MetaMask + +Teraz jesteś w pełni wyposażony, aby zastosować umiejętności z tego samouczka do zbudowania własnego, niestandardowego projektu dapp! Jak zawsze, jeśli masz jakieś pytania, nie wahaj się skontaktować z nami w celu uzyskania pomocy na [Discordzie Alchemy](https://discord.gg/gWuC7zB). 🧙‍♂️ + +Po ukończeniu tego samouczka daj nam znać, jak Ci poszło lub czy masz jakieś uwagi, oznaczając nas na Twitterze [@alchemyplatform](https://twitter.com/AlchemyPlatform)! diff --git a/public/content/translations/pl/developers/tutorials/hello-world-smart-contract/index.md b/public/content/translations/pl/developers/tutorials/hello-world-smart-contract/index.md new file mode 100644 index 00000000000..51f58532f80 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/hello-world-smart-contract/index.md @@ -0,0 +1,367 @@ +--- +title: "Inteligentny kontrakt Hello World dla początkujących" +description: "Samouczek wprowadzający na temat pisania i wdrażania prostego inteligentnego kontraktu na Ethereum." +author: "elanh" +tags: + [ + "solidity", + "hardhat", + "alchemy", + "smart kontrakty", + "wdrażanie" + ] +skill: beginner +lang: pl +published: 2021-03-31 +--- + +Jeśli dopiero zaczynasz przygodę z tworzeniem oprogramowania blockchain i nie wiesz, od czego zacząć, lub jeśli po prostu chcesz zrozumieć, jak wdrażać inteligentne kontrakty i wchodzić z nimi w interakcję, ten przewodnik jest dla Ciebie. Przeprowadzimy Cię przez proces tworzenia i wdrażania prostego inteligentnego kontraktu w sieci testowej Sepolia przy użyciu wirtualnego portfela [MetaMask](https://metamask.io/), [Solidity](https://docs.soliditylang.org/en/v0.8.0/), [Hardhat](https://hardhat.org/) i [Alchemy](https://www.alchemy.com/) (nie martw się, jeśli jeszcze nie rozumiesz, co to wszystko znaczy, wyjaśnimy to). + +W [części 2](https://docs.alchemy.com/docs/interacting-with-a-smart-contract) tego samouczka omówimy, jak wejść w interakcję z naszym inteligentnym kontraktem po jego wdrożeniu, a w [części 3](https://www.alchemy.com/docs/submitting-your-smart-contract-to-etherscan) omówimy, jak opublikować go na Etherscan. + +Jeśli w dowolnym momencie będziesz mieć pytania, śmiało odezwij się na [Discordzie Alchemy](https://discord.gg/gWuC7zB)! + +## Krok 1: Połącz się z siecią Ethereum {#step-1} + +Istnieje wiele sposobów na wysyłanie żądań do łańcucha Ethereum. Dla uproszczenia użyjemy darmowego konta na Alchemy, platformy deweloperskiej i interfejsu API blockchain, która pozwala nam komunikować się z łańcuchem Ethereum bez konieczności uruchamiania własnych węzłów. Platforma posiada również narzędzia deweloperskie do monitorowania i analityki, które wykorzystamy w tym samouczku, aby zrozumieć, co dzieje się „pod maską” podczas wdrażania naszego inteligentnego kontraktu. Jeśli nie masz jeszcze konta Alchemy, [możesz zarejestrować się za darmo tutaj](https://dashboard.alchemy.com/signup). + +## Krok 2: Stwórz swoją aplikację (i klucz API) {#step-2} + +Po utworzeniu konta Alchemy możesz wygenerować klucz API, tworząc aplikację. Pozwoli nam to na wysyłanie żądań do sieci testowej Sepolia. Jeśli nie znasz sieci testowych, sprawdź [tę stronę](/developers/docs/networks/). + +1. Przejdź na stronę "Utwórz nową aplikację" w pulpicie nawigacyjnym Alchemy, wybierając "Wybierz aplikację" na pasku nawigacyjnym i klikając "Utwórz nową aplikację" + +![Utwórz aplikację Hello world](./hello-world-create-app.png) + +2. Nazwij swoją aplikację "Hello World", podaj krótki opis i wybierz przypadek użycia, np. "Infrastruktura i narzędzia". Następnie wyszukaj "Ethereum" i wybierz sieć. + +![widok tworzenia aplikacji hello world](./create-app-view-hello-world.png) + +3. Kliknij "Dalej", aby kontynuować, następnie "Utwórz aplikację" i to wszystko! Twoja aplikacja powinna pojawić się w rozwijanym menu paska nawigacyjnego, z kluczem API dostępnym do skopiowania. + +## Krok 3: Utwórz konto Ethereum (adres) {#step-3} + +Potrzebujemy konta Ethereum do wysyłania i odbierania transakcji. W tym samouczku użyjemy MetaMask, wirtualnego portfela w przeglądarce, który służy do zarządzania adresem konta Ethereum. Więcej o [transakcjach](/developers/docs/transactions/). + +Możesz pobrać MetaMask i utworzyć darmowe konto Ethereum [tutaj](https://metamask.io/download). Podczas tworzenia konta lub jeśli już je posiadasz, pamiętaj, aby przełączyć się na sieć testową "Sepolia" za pomocą rozwijanego menu sieci (abyśmy nie mieli do czynienia z prawdziwymi pieniędzmi). + +Jeśli nie widzisz na liście sieci Sepolia, przejdź do menu, następnie do opcji Zaawansowane i przewiń w dół, aby włączyć opcję "Pokaż sieci testowe". W menu wyboru sieci wybierz kartę "Niestandardowe", aby znaleźć listę sieci testowych, i wybierz "Sepolia". + +![przykład metamask sepolia](./metamask-sepolia-example.png) + +## Krok 4: Dodaj ether z kranu (faucet) {#step-4} + +Aby wdrożyć nasz inteligentny kontrakt w sieci testowej, będziemy potrzebować trochę fałszywego ETH. Aby otrzymać Sepolia ETH, możesz przejść do [szczegółów sieci Sepolia](/developers/docs/networks/#sepolia), aby zobaczyć listę różnych kranów (faucetów). Jeśli jeden nie działa, spróbuj innego, ponieważ czasami mogą się wyczerpać. Otrzymanie fałszywego ETH może zająć trochę czasu ze względu na ruch w sieci. Wkrótce powinieneś zobaczyć ETH na swoim koncie Metamask! + +## Krok 5: Sprawdź saldo {#step-5} + +Aby upewnić się, że nasze saldo tam jest, wykonajmy żądanie [eth_getBalance](/developers/docs/apis/json-rpc/#eth_getbalance) za pomocą [narzędzia kompozytora Alchemy](https://sandbox.alchemy.com/?network=ETH_SEPOLIA&method=eth_getBalance&body.id=1&body.jsonrpc=2.0&body.method=eth_getBalance&body.params%5B0%5D=&body.params%5B1%5D=latest). Zwróci to ilość ETH w naszym portfelu. Po wprowadzeniu adresu konta MetaMask i kliknięciu „Wyślij żądanie” powinieneś zobaczyć następującą odpowiedź: + +```json +{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" } +``` + +> **UWAGA:** Ten wynik jest w wei, a nie w ETH. Wei jest używany jako najmniejsza jednostka etheru. Przeliczenie z wei na ETH wynosi: 1 eth = 1018 wei. Więc jeśli przekonwertujemy 0x2B5E3AF16B1880000 na liczbę dziesiętną, otrzymamy 5\*10¹⁸, co równa się 5 ETH. +> +> Uff! Nasze fałszywe pieniądze są na miejscu . + +## Krok 6: Zainicjuj nasz projekt {#step-6} + +Najpierw musimy utworzyć folder dla naszego projektu. Przejdź do wiersza poleceń i wpisz: + +``` +mkdir hello-world +cd hello-world +``` + +Teraz, gdy jesteśmy w folderze naszego projektu, użyjemy `npm init`, aby zainicjować projekt. Jeśli nie masz jeszcze zainstalowanego npm, postępuj zgodnie z [tymi instrukcjami](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm) (będziemy również potrzebować Node.js, więc pobierz go również!). + +``` +npm init +``` + +Nie ma większego znaczenia, jak odpowiesz na pytania instalacyjne, dla porównania przedstawiamy, jak my to zrobiliśmy: + +``` +nazwa pakietu: (hello-world) +wersja: (1.0.0) +opis: inteligentny kontrakt hello world +punkt wejścia: (index.js) +polecenie testowe: +repozytorium git: +słowa kluczowe: +autor: +licencja: (ISC) +Zapisywanie do /Users/.../.../.../hello-world/package.json: + +{ + "name": "hello-world", + "version": "1.0.0", + "description": "inteligentny kontrakt hello world", + "main": "index.js", + "scripts": { + "test": "echo \"Błąd: nie określono testu\" && exit 1" + }, + "author": "", + "license": "ISC" +} +``` + +Zatwierdź plik package.json i gotowe! + +## Krok 7: Pobierz [Hardhat](https://hardhat.org/getting-started/#overview) {#step-7} + +Hardhat to środowisko programistyczne do kompilacji, wdrażania, testowania i debugowania oprogramowania Ethereum. Pomaga deweloperom w tworzeniu inteligentnych kontraktów i dapek lokalnie przed wdrożeniem ich na żywym łańcuchu. + +W naszym projekcie `hello-world` uruchom: + +``` +npm install --save-dev hardhat +``` + +Sprawdź tę stronę, aby uzyskać więcej szczegółów na temat [instrukcji instalacji](https://hardhat.org/getting-started/#overview). + +## Krok 8: Stwórz projekt Hardhat {#step-8} + +W folderze naszego projektu uruchom: + +``` +npx hardhat +``` + +Powinieneś wtedy zobaczyć wiadomość powitalną i opcję wyboru tego, co chcesz zrobić. Wybierz „utwórz pusty hardhat.config.js”: + +``` +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 Witamy w Hardhat v2.0.11 👷‍? + +Co chcesz zrobić? … +Stwórz przykładowy projekt +❯ Stwórz pusty plik hardhat.config.js +Wyjdź +``` + +Spowoduje to wygenerowanie dla nas pliku `hardhat.config.js`, w którym określimy całą konfigurację naszego projektu (w kroku 13). + +## Krok 9: Dodaj foldery projektu {#step-9} + +Aby utrzymać porządek w naszym projekcie, utworzymy dwa nowe foldery. Przejdź do katalogu głównego projektu w wierszu poleceń i wpisz: + +``` +mkdir contracts +mkdir scripts +``` + +- w `contracts/` będziemy przechowywać plik z kodem naszego inteligentnego kontraktu hello world +- w `scripts/` będziemy przechowywać skrypty do wdrażania naszego kontraktu i interakcji z nim + +## Krok 10: Napisz nasz kontrakt {#step-10} + +Możesz zadawać sobie pytanie: kiedy, do licha, zaczniemy pisać kod?? Cóż, jesteśmy tutaj, w kroku 10. + +Otwórz projekt hello-world w swoim ulubionym edytorze (my lubimy [VSCode](https://code.visualstudio.com/)). Inteligentne kontrakty pisane są w języku o nazwie Solidity, którego użyjemy do napisania naszego inteligentnego kontraktu HelloWorld.sol.‌ + +1. Przejdź do folderu "contracts" i utwórz nowy plik o nazwie HelloWorld.sol +2. Poniżej znajduje się przykładowy inteligentny kontrakt Hello World z Ethereum Foundation, którego będziemy używać w tym samouczku. Skopiuj i wklej poniższą zawartość do pliku HelloWorld.sol i koniecznie przeczytaj komentarze, aby zrozumieć, co robi ten kontrakt: + +```solidity +// Określa wersję Solidity, używając wersjonowania semantycznego. +// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity ^0.7.0; + +// Definiuje kontrakt o nazwie `HelloWorld`. +// Kontrakt to zbiór funkcji i danych (jego stanu). Po wdrożeniu kontrakt znajduje się pod określonym adresem na blockchainie Ethereum. Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld { + + // Deklaruje zmienną stanu `message` typu `string`. + // Zmienne stanu to zmienne, których wartości są trwale przechowywane w pamięci kontraktu. Słowo kluczowe `public` udostępnia zmienne z zewnątrz kontraktu i tworzy funkcję, którą inne kontrakty lub klienci mogą wywołać w celu uzyskania dostępu do wartości. + string public message; + + // Podobnie jak w wielu obiektowych językach programowania opartych na klasach, konstruktor jest specjalną funkcją, która jest wykonywana tylko podczas tworzenia kontraktu. + // Konstruktory służą do inicjalizacji danych kontraktu. Dowiedz się więcej:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + constructor(string memory initMessage) { + + // Akceptuje argument typu string `initMessage` i ustawia jego wartość w zmiennej `message` w pamięci kontraktu). + message = initMessage; + } + + // Funkcja publiczna, która akceptuje argument typu string i aktualizuje zmienną `message` w pamięci. + function update(string memory newMessage) public { + message = newMessage; + } +} +``` + +To jest bardzo prosty inteligentny kontrakt, który przechowuje wiadomość po utworzeniu i może być aktualizowany przez wywołanie funkcji `update`. + +## Krok 11: Połącz MetaMask i Alchemy ze swoim projektem {#step-11} + +Stworzyliśmy portfel MetaMask, konto Alchemy i napisaliśmy nasz inteligentny kontrakt, teraz nadszedł czas, aby połączyć te trzy elementy. + +Każda transakcja wysłana z Twojego wirtualnego portfela wymaga podpisu przy użyciu Twojego unikalnego klucza prywatnego. Aby udzielić naszemu programowi tego uprawnienia, możemy bezpiecznie przechowywać nasz klucz prywatny (i klucz API Alchemy) w pliku środowiskowym. + +> Aby dowiedzieć się więcej o wysyłaniu transakcji, sprawdź [ten samouczek](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) o wysyłaniu transakcji przy użyciu web3. + +Najpierw zainstaluj pakiet dotenv w katalogu swojego projektu: + +``` +npm install dotenv --save +``` + +Następnie utwórz plik `.env` w katalogu głównym naszego projektu i dodaj do niego swój klucz prywatny MetaMask oraz adres URL HTTP API Alchemy. + +- Postępuj zgodnie z [tymi instrukcjami](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/), aby wyeksportować swój klucz prywatny +- Poniżej dowiesz się, jak uzyskać adres URL interfejsu API HTTP Alchemy + +![uzyskaj klucz api alchemy](./get-alchemy-api-key.png) + +Skopiuj adres URL interfejsu API Alchemy + +Twój plik `.env` powinien wyglądać następująco: + +``` +API_URL = "https://eth-sepolia.g.alchemy.com/v2/twój-klucz-api" +PRIVATE_KEY = "twój-klucz-prywatny-metamask" +``` + +Aby faktycznie połączyć je z naszym kodem, odwołamy się do tych zmiennych w naszym pliku `hardhat.config.js` w kroku 13. + + + + +Nie commituj pliku .env! Upewnij się, że nigdy nie udostępniasz ani nie ujawniasz nikomu swojego pliku .env, ponieważ w ten sposób narażasz swoje poufne dane. Jeśli używasz kontroli wersji, dodaj swój plik .env do pliku gitignore. + + + + +## Krok 12: Zainstaluj Ethers.js {#step-12-install-ethersjs} + +Ethers.js to biblioteka, która ułatwia interakcję i wysyłanie żądań do Ethereum, opakowując [standardowe metody JSON-RPC](/developers/docs/apis/json-rpc/) w bardziej przyjazne dla użytkownika metody. + +Hardhat bardzo ułatwia integrację [wtyczek](https://hardhat.org/plugins/) w celu uzyskania dodatkowych narzędzi i rozszerzonej funkcjonalności. Skorzystamy z [wtyczki Ethers](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers) do wdrażania kontraktów ([Ethers.js](https://github.com/ethers-io/ethers.js/) ma kilka bardzo przejrzystych metod wdrażania kontraktów). + +W katalogu projektu wpisz: + +``` +npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" +``` + +Będziemy również wymagać ethers w naszym pliku `hardhat.config.js` w następnym kroku. + +## Krok 13: Zaktualizuj hardhat.config.js {#step-13-update-hardhatconfigjs} + +Do tej pory dodaliśmy kilka zależności i wtyczek, teraz musimy zaktualizować `hardhat.config.js`, aby nasz projekt wiedział o wszystkich. + +Zaktualizuj swój `hardhat.config.js`, aby wyglądał następująco: + +``` +require('dotenv').config(); + +require("@nomiclabs/hardhat-ethers"); +const { API_URL, PRIVATE_KEY } = process.env; + +/** +* @type import('hardhat/config').HardhatUserConfig +*/ +module.exports = { + solidity: "0.7.3", + defaultNetwork: "sepolia", + networks: { + hardhat: {}, + sepolia: { + url: API_URL, + accounts: [`0x${PRIVATE_KEY}`] + } + }, +} +``` + +## Krok 14: Skompiluj nasz kontrakt {#step-14-compile-our-contracts} + +Aby upewnić się, że wszystko do tej pory działa, skompilujmy nasz kontrakt. Zadanie `compile` jest jednym z wbudowanych zadań hardhat. + +Z wiersza poleceń uruchom: + +``` +npx hardhat compile +``` + +Możesz otrzymać ostrzeżenie o `SPDX license identifier not provided in source file` (brak identyfikatora licencji SPDX w pliku źródłowym), ale nie musisz się tym martwić — miejmy nadzieję, że wszystko inne wygląda dobrze! Jeśli nie, zawsze możesz napisać wiadomość na [discordzie Alchemy](https://discord.gg/u72VCg3). + +## Krok 15: Napisz nasz skrypt wdrożeniowy {#step-15-write-our-deploy-scripts} + +Teraz, gdy nasz kontrakt jest napisany, a nasz plik konfiguracyjny jest gotowy, nadszedł czas, aby napisać nasz skrypt wdrażający kontrakt. + +Przejdź do folderu `scripts/` i utwórz nowy plik o nazwie `deploy.js`, dodając do niego następującą zawartość: + +``` +async function main() { + const HelloWorld = await ethers.getContractFactory("HelloWorld"); + + // Rozpocznij wdrażanie, zwracając obietnicę, która prowadzi do obiektu kontraktu + const hello_world = await HelloWorld.deploy("Hello World!"); + console.log("Kontrakt wdrożony pod adresem:", hello_world.address);} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error); + process.exit(1); + }); +``` + +Hardhat wykonuje niesamowitą robotę, wyjaśniając, co robi każda z tych linii kodu w swoim [samouczku dotyczącym kontraktów](https://hardhat.org/tutorial/testing-contracts.html#writing-tests), a my przyjęliśmy ich wyjaśnienia tutaj. + +``` +const HelloWorld = await ethers.getContractFactory("HelloWorld"); +``` + +`ContractFactory` w ethers.js to abstrakcja używana do wdrażania nowych inteligentnych kontraktów, więc `HelloWorld` jest tutaj fabryką dla instancji naszego kontraktu hello world. Podczas korzystania z wtyczki `hardhat-ethers` instancje `ContractFactory` i `Contract` są domyślnie połączone z pierwszym sygnatariuszem. + +``` +const hello_world = await HelloWorld.deploy(); +``` + +Wywołanie `deploy()` na `ContractFactory` rozpocznie wdrażanie i zwróci `Promise`, które prowadzi do `Contract`. Jest to obiekt, który ma metodę dla każdej z naszych funkcji inteligentnego kontraktu. + +## Krok 16: Wdróż nasz kontrakt {#step-16-deploy-our-contract} + +Jesteśmy wreszcie gotowi do wdrożenia naszego inteligentnego kontraktu! Przejdź do wiersza poleceń i uruchom: + +``` +npx hardhat run scripts/deploy.js --network sepolia +``` + +Powinieneś wtedy zobaczyć coś takiego: + +``` +Kontrakt wdrożony pod adresem: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +``` + +Jeśli przejdziemy do [Etherscan Sepolia](https://sepolia.etherscan.io/) i wyszukamy adres naszego kontraktu, powinniśmy zobaczyć, że został on pomyślnie wdrożony. Transakcja będzie wyglądać mniej więcej tak: + +![kontrakt etherscan](./etherscan-contract.png) + +Adres `Od` powinien pasować do adresu Twojego konta MetaMask, a adres `Do` będzie miał napis „Tworzenie Kontraktu”, ale jeśli klikniemy w transakcję, zobaczymy adres naszego kontraktu w polu `Do`: + +![transakcja etherscan](./etherscan-transaction.png) + +Gratulacje! Właśnie wdrożyłeś inteligentny kontrakt w łańcuchu Ethereum 🎉 + +Aby zrozumieć, co dzieje się pod maską, przejdźmy do karty Explorer w naszym [panelu Alchemy](https://dashboard.alchemyapi.io/explorer). Jeśli masz wiele aplikacji Alchemy, pamiętaj, aby filtrować według aplikacji i wybrać „Hello World”. +![eksplorator hello world](./hello-world-explorer.png) + +Tutaj zobaczysz kilka wywołań JSON-RPC, które Hardhat/Ethers wykonały za nas „pod maską”, gdy wywołaliśmy funkcję `.deploy()`. Dwa ważne, które należy tu wymienić, to [`eth_sendRawTransaction`](https://www.alchemy.com/docs/node/abstract/abstract-api-endpoints/eth-send-raw-transaction), czyli żądanie faktycznego zapisania naszego kontraktu w łańcuchu Sepolia, oraz [`eth_getTransactionByHash`](https://www.alchemy.com/docs/node/abstract/abstract-api-endpoints/eth-get-transaction-by-hash), czyli żądanie odczytania informacji o naszej transakcji na podstawie haszu (typowy wzorzec podczas +transakcji). Aby dowiedzieć się więcej o wysyłaniu transakcji, zapoznaj się z tym samouczkiem na temat [wysyłania transakcji za pomocą Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) + +To wszystko w części 1 tego samouczka, w części 2 faktycznie [wejdziemy w interakcję z naszym inteligentnym kontraktem](https://www.alchemy.com/docs/interacting-with-a-smart-contract) poprzez aktualizację naszej początkowej wiadomości, a w części 3 [opublikujemy nasz inteligentny kontrakt na Etherscan](https://www.alchemy.com/docs/submitting-your-smart-contract-to-etherscan), aby każdy wiedział, jak z nim wchodzić w interakcję. + +**Chcesz dowiedzieć się więcej o Alchemy?** Sprawdź naszą [stronę internetową](https://www.alchemy.com/eth). Nie chcesz przegapić żadnej aktualizacji? Zapisz się do naszego newslettera [tutaj](https://www.alchemy.com/newsletter)! Pamiętaj, aby dołączyć również do naszego [Discorda](https://discord.gg/u72VCg3).\*\*. diff --git a/public/content/translations/pl/developers/tutorials/how-to-implement-an-erc721-market/index.md b/public/content/translations/pl/developers/tutorials/how-to-implement-an-erc721-market/index.md index 4b8ddf84a6e..2effc79c82d 100644 --- a/public/content/translations/pl/developers/tutorials/how-to-implement-an-erc721-market/index.md +++ b/public/content/translations/pl/developers/tutorials/how-to-implement-an-erc721-market/index.md @@ -1,12 +1,8 @@ --- -title: Jak wdrożyć rynek ERC-721 -description: Jak umieścić tokenizowane przedmioty w celu sprzedaży w zdecentralizowanym serwisie ogłoszeniowym -author: "Alberto Cuesta Cañada" -tags: - - "inteligentne kontrakty" - - "erc-721" - - "solidity" - - "tokeny" +title: "Jak wdrożyć rynek ERC-721" +description: "Jak umieścić tokenizowane przedmioty w celu sprzedaży w zdecentralizowanym serwisie ogłoszeniowym" +author: "Alberto Cuesta Cañada" +tags: [ "smart kontrakty", "erc-721", "solidity", "tokeny" ] skill: intermediate lang: pl published: 2020-03-19 @@ -26,13 +22,13 @@ Blockchain ponownie zmieni te rynki — pozwolę sobie pokazać, w jaki sposób. Model biznesowy serwisu ogłoszeniowego w publicznym blockchainie będzie musiał różnić się od modelu Ebay i spółki. -Po pierwsze, jest [kąt decentralizacji](/developers/docs/web2-vs-web3/). Istniejące platformy muszą utrzymywać własne serwery. Zdecentralizowana platforma jest utrzymywana przez użytkowników, a zatem koszt obsługi głównej platformy spadnie do zera dla właściciela platformy. +Po pierwsze, jest [aspekt decentralizacji](/developers/docs/web2-vs-web3/). Istniejące platformy muszą utrzymywać własne serwery. Zdecentralizowana platforma jest utrzymywana przez użytkowników, a zatem koszt obsługi głównej platformy spadnie do zera dla właściciela platformy. -Następnie frontend — strona internetowa lub interfejs dający dostęp do platformy. Tutaj jest wiele możliwości. Właściciele platformy mogą ograniczyć dostęp i zmusić wszystkich do korzystania ze swojego interfejsu, pobierając opłaty. Właściciele platform mogą również zdecydować o otwarciu dostępu (Power to the People!) i pozwolić każdemu budować interfejsy na platformie. Lub właściciele mogliby wybrać jakiekolwiek pośrednie podejście. +Następnie frontend — strona internetowa lub interfejs dający dostęp do platformy. Tutaj jest wiele możliwości. Właściciele platformy mogą ograniczyć dostęp i zmusić wszystkich do korzystania ze swojego interfejsu, pobierając opłaty. Właściciele platformy mogą również zdecydować się na otwarcie dostępu (Władza w ręce ludu!) i pozwolić każdemu na budowanie interfejsów do platformy. Lub właściciele mogliby wybrać jakiekolwiek pośrednie podejście. _Liderzy biznesu, którzy mają więcej wizji niż ja, będą wiedzieć, jak na tym zarabiać. Widzę jedynie, że różni się to od status quo i prawdopodobnie jest opłacalne._ -Ponadto istnieje kąt automatyzacji i płatności. Niektóre rzeczy mogą być bardzo [skutecznie tokenizowane](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com) i sprzedawane w serwisach. Tokenizowane aktywa są łatwo przenoszone w blockchainie. Bardzo skomplikowane metody płatności mogą być łatwo wdrożone w blockchainie. +Ponadto istnieje kąt automatyzacji i płatności. Niektóre rzeczy można bardzo [skutecznie stokenizować](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com) i handlować nimi na tablicy ogłoszeń. Tokenizowane aktywa są łatwo przenoszone w blockchainie. Bardzo skomplikowane metody płatności mogą być łatwo wdrożone w blockchainie. Po prostu wyczuwam tutaj okazję biznesową. W łatwy sposób można wdrożyć serwis ogłoszeniowy bez kosztów bieżących, ze złożonymi ścieżkami płatności uwzględnionymi w każdej transakcji. Jestem pewien, że ktoś wymyśli, do czego to wykorzystać. @@ -40,9 +36,9 @@ Po prostu cieszę się, że to buduję. Rzućmy okiem na kod. ## Implementacja {#implementation} -Jakiś czas temu uruchomiliśmy [repozytorium open source](https://github.com/HQ20/contracts?ref=hackernoon.com) z implementacjami zastosowań biznesowych i innymi ciekawymi rzeczami. Rzuć okiem. +Jakiś czas temu uruchomiliśmy [repozytorium open source](https://github.com/HQ20/contracts?ref=hackernoon.com) z przykładowymi implementacjami biznesowymi i innymi dodatkami. Zachęcamy do zapoznania się. -Kod tego [serwisu ogłoszeniowego Ethereum](https://github.com/HQ20/contracts/tree/master/contracts/classifieds?ref=hackernoon.com) jest dostępny, możesz go używać do woli. Pamiętaj tylko, że kod nie został poddany audytowi i musisz zrobić własną analizę due dililgence, zanim włożysz w niego pieniądze. +Kod tej [tablicy ogłoszeń Ethereum](https://github.com/HQ20/contracts/tree/master/contracts/classifieds?ref=hackernoon.com) jest tam dostępny, prosimy, korzystajcie z niego i testujcie go do woli. Pamiętaj tylko, że kod nie został poddany audytowi i musisz zrobić własną analizę due dililgence, zanim włożysz w niego pieniądze. Podstawy tablicy nie są skomplikowane. Wszystkie reklamy na tablicy będą tylko strukturą z kilkoma polami: @@ -67,7 +63,7 @@ Korzystanie z mapowania oznacza, że przed opublikowaniem tej wiadomości musimy Następnie pojawia się pytanie, z czym mamy do czynienia i jaka waluta jest wykorzystywana do zapłaty za transakcję. -Jeśli chodzi o przedmioty, zamierzamy tylko poprosić o implementację interfejsu [ERC-721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol?ref=hackernoon.com), który naprawdę jest sposobem na reprezentowanie realnych pozycji świata w blockchain, chociaż [najlepiej współpracuje z cyfrowymi aktywami](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com). Zamierzamy określić nasz własny kontrakt ERC721 w konstruktorze, co oznacza, że wszelkie aktywa w naszym serwisie muszą być uprzednio tokenizowane. +W przypadku przedmiotów będziemy wymagać jedynie implementacji interfejsu [ERC-721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol?ref=hackernoon.com), który jest po prostu sposobem reprezentacji rzeczywistych przedmiotów w blockchainie, chociaż [najlepiej działa w przypadku aktywów cyfrowych](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com). Zamierzamy określić nasz własny kontrakt ERC721 w konstruktorze, co oznacza, że wszelkie aktywa w naszym serwisie muszą być uprzednio tokenizowane. W przypadku płatności zamierzamy zrobić coś podobnego. Większość projektów blockchain definiuje własną kryptowalutę [ERC-20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol?ref=hackernoon.com). Inni wolą korzystać z głównego nurtu takiego jak DAI. W tym serwisie ogłoszeniowym musisz tylko zdecydować podczas budowy, jaka będzie Twoja waluta. Łatwo. @@ -127,18 +123,18 @@ function cancelTrade(uint256 _trade) Trade memory trade = trades[_trade]; require( msg.sender == trade.poster, - "Trade can be cancelled only by poster." + "Ogłoszenie może być anulowane tylko przez wystawiającego." ); - require(trade.status == "Open", "Trade is not Open."); + require(trade.status == "Open", "Ogłoszenie nie jest otwarte."); itemToken.transferFrom(address(this), trade.poster, trade.item); trades[_trade].status = "Cancelled"; emit TradeStatusChange(_trade, "Cancelled"); } ``` -To już wszystko. Dotrwałeś do końca implementacji. To zaskakujące, jak kompaktowe są niektóre pojęcia biznesowe wyrażane w kodzie i jest to jeden z tych przypadków. Sprawdź pełną umowę [w naszym repozytorium](https://github.com/HQ20/contracts/blob/master/contracts/classifieds/Classifieds.sol). +To już wszystko. Dotrwałeś do końca implementacji. To zaskakujące, jak kompaktowe są niektóre pojęcia biznesowe wyrażane w kodzie i jest to jeden z tych przypadków. Sprawdź pełny kontrakt [w naszym repozytorium](https://github.com/HQ20/contracts/blob/master/contracts/classifieds/Classifieds.sol). -## Podsumowanie {#conclusion} +## Wnioski {#conclusion} Serwisy ogłoszeniowe to powszechna konfiguracja rynku, która intensywnie rosła wraz z Internetem, stając się niezwykle popularnym modelem biznesowym z kilkoma monopolistycznymi zwycięzcami. @@ -146,4 +142,4 @@ Serwisy ogłoszeniowe stały się również łatwym narzędziem do replikacji w W tym artykule podjąłem próbę połączenia realiów biznesowych serwisów ogłoszeniowych z implementacją technologii. Ta wiedza powinna pomóc w stworzeniu wizji i planu implementacji, jeśli masz odpowiednie umiejętności. -Jak zawsze, jeśli chcesz zbudować coś fajnego i chciałbyś otrzymać jakąś radę, proszę [napisz do mnie](https://albertocuesta.es/)! Zawsze chętnie służę pomocą. +Jak zawsze, jeśli chcecie zbudować coś fajnego i przydałaby Wam się jakaś rada, [skontaktujcie się ze mną](https://albertocuesta.es/)! Zawsze chętnie służę pomocą. From b3cff2c811c2994f1dfa8cc16df7ebdf1403c576 Mon Sep 17 00:00:00 2001 From: Joshua <62268199+minimalsm@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:08:10 +0000 Subject: [PATCH 3/9] i18n(pl): translation import part 09 of 13 (23 files) --- .../index.md | 208 ++ .../tutorials/server-components/index.md | 295 +++ .../index.md | 92 + .../developers/tutorials/short-abi/index.md | 585 +++++ .../index.md | 77 +- .../tutorials/stealth-addr/index.md | 443 ++++ .../index.md | 142 +- .../token-integration-checklist/index.md | 92 +- .../index.md | 174 +- .../index.md | 79 +- .../uniswap-v2-annotated-code/index.md | 1970 +++++++++++++++++ .../tutorials/using-websockets/index.md | 80 +- .../index.md | 141 +- .../index.md | 204 ++ .../index.md | 199 ++ .../tutorials/yellow-paper-evm/index.md | 278 +++ public/content/translations/pl/eips/index.md | 37 +- .../pl/energy-consumption/index.md | 59 +- .../translations/pl/eth/supply/index.md | 80 + .../translations/pl/ethereum-forks/index.md | 514 ++++- .../translations/pl/foundation/index.md | 37 +- .../content/translations/pl/gaming/index.md | 70 + .../content/translations/pl/glossary/index.md | 755 ++----- 23 files changed, 5473 insertions(+), 1138 deletions(-) create mode 100644 public/content/translations/pl/developers/tutorials/sending-transactions-using-web3-and-alchemy/index.md create mode 100644 public/content/translations/pl/developers/tutorials/server-components/index.md create mode 100644 public/content/translations/pl/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/index.md create mode 100644 public/content/translations/pl/developers/tutorials/short-abi/index.md create mode 100644 public/content/translations/pl/developers/tutorials/stealth-addr/index.md create mode 100644 public/content/translations/pl/developers/tutorials/uniswap-v2-annotated-code/index.md create mode 100644 public/content/translations/pl/developers/tutorials/waffle-say-hello-world-with-hardhat-and-ethers/index.md create mode 100644 public/content/translations/pl/developers/tutorials/waffle-test-simple-smart-contract/index.md create mode 100644 public/content/translations/pl/developers/tutorials/yellow-paper-evm/index.md create mode 100644 public/content/translations/pl/eth/supply/index.md create mode 100644 public/content/translations/pl/gaming/index.md diff --git a/public/content/translations/pl/developers/tutorials/sending-transactions-using-web3-and-alchemy/index.md b/public/content/translations/pl/developers/tutorials/sending-transactions-using-web3-and-alchemy/index.md new file mode 100644 index 00000000000..937eca077e6 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/sending-transactions-using-web3-and-alchemy/index.md @@ -0,0 +1,208 @@ +--- +title: "Wysyłanie transakcji za pomocą Web3" +description: "To jest przyjazny dla początkujących przewodnik po wysyłaniu transakcji Ethereum za pomocą Web3. Istnieją trzy główne kroki, aby wysłać transakcję do blockchaina Ethereum: tworzenie, podpisywanie i rozgłaszanie. Omówimy wszystkie trzy." +author: "Elan Halpern" +tags: [ "transakcje", "web3.js", "alchemy" ] +skill: beginner +lang: pl +published: 2020-11-04 +source: Alchemy docs +sourceUrl: https://www.alchemy.com/docs/how-to-send-transactions-on-ethereum +--- + +To jest przyjazny dla początkujących przewodnik po wysyłaniu transakcji Ethereum za pomocą Web3. Istnieją trzy główne kroki, aby wysłać transakcję do blockchaina Ethereum: tworzenie, podpisywanie i rozgłaszanie. Omówimy wszystkie trzy, mając nadzieję, że odpowiemy na wszelkie pytania, jakie możesz mieć! W tym samouczku będziemy używać [Alchemy](https://www.alchemy.com/), aby wysyłać nasze transakcje do łańcucha Ethereum. Możesz [utworzyć darmowe konto Alchemy tutaj](https://auth.alchemyapi.io/signup). + +**UWAGA:** Ten przewodnik dotyczy podpisywania transakcji w _backendzie_ aplikacji. Jeśli chcesz zintegrować podpisywanie transakcji we frontendzie, sprawdź integrację [Web3 z dostawcą przeglądarki](https://docs.alchemy.com/reference/api-overview#with-a-browser-provider). + +## Podstawy {#the-basics} + +Podobnie jak większość deweloperów blockchain na początku swojej drogi, być może szukałeś informacji o tym, jak wysłać transakcję (coś, co powinno być całkiem proste) i natknąłeś się na mnóstwo przewodników, z których każdy mówił co innego, co sprawiło, że czułeś się nieco przytłoczony i zdezorientowany. Jeśli jesteś w takiej sytuacji, nie martw się; wszyscy kiedyś byliśmy! Zanim więc zaczniemy, wyjaśnijmy sobie kilka kwestii: + +### 1. Alchemy nie przechowuje Twoich kluczy prywatnych {#alchemy-does-not-store-your-private-keys} + +- Oznacza to, że Alchemy nie może podpisywać i wysyłać transakcji w Twoim imieniu. Dzieje się tak ze względów bezpieczeństwa. Alchemy nigdy nie poprosi Cię o udostępnienie Twojego klucza prywatnego i nigdy nie powinieneś go udostępniać hostowanemu węzłowi (ani nikomu innemu). +- Możesz odczytywać dane z blockchaina za pomocą podstawowego API Alchemy, ale aby do niego zapisywać, musisz użyć czegoś innego do podpisania swoich transakcji przed wysłaniem ich przez Alchemy (to samo dotyczy każdej innej [usługi węzłów](/developers/docs/nodes-and-clients/nodes-as-a-service/)). + +### 2. Czym jest „signer”? {#what-is-a-signer} + +- Signerzy podpisują dla Ciebie transakcje, używając Twojego klucza prywatnego. W tym samouczku do podpisania naszej transakcji użyjemy [Alchemy web3](https://docs.alchemyapi.io/alchemy/documentation/alchemy-web3), ale można również użyć dowolnej innej biblioteki web3. +- We frontendzie dobrym przykładem signera jest [MetaMask](https://metamask.io/), który podpisuje i wysyła transakcje w Twoim imieniu. + +### 3. Dlaczego muszę podpisywać swoje transakcje? {#why-do-i-need-to-sign-my-transactions} + +- Każdy użytkownik, który chce wysłać transakcję w sieci Ethereum, musi ją podpisać (używając swojego klucza prywatnego), aby zweryfikować, że pochodzenie transakcji jest zgodne z deklarowanym. +- Niezwykle ważne jest, aby chronić ten klucz prywatny, ponieważ posiadanie do niego dostępu daje pełną kontrolę nad kontem Ethereum, pozwalając Tobie (lub każdemu, kto ma dostęp) na wykonywanie transakcji w Twoim imieniu. + +### 4. Jak chronić mój klucz prywatny? {#how-do-i-protect-my-private-key} + +- Istnieje wiele sposobów na ochronę klucza prywatnego i używanie go do wysyłania transakcji. W tym samouczku będziemy używać pliku `.env`. Można jednak również skorzystać z osobnego dostawcy, który przechowuje klucze prywatne, użyć pliku keystore lub innych opcji. + +### 5. Jaka jest różnica między `eth_sendTransaction` a `eth_sendRawTransaction`? {#difference-between-send-and-send-raw} + +`eth_sendTransaction` i `eth_sendRawTransaction` to funkcje API Ethereum, które rozgłaszają transakcję w sieci Ethereum, aby została ona dodana do przyszłego bloku. Różnią się one sposobem obsługi podpisywania transakcji. + +- [`eth_sendTransaction`](https://docs.web3js.org/api/web3-eth/function/sendTransaction) służy do wysyłania _niepodpisanych_ transakcji, co oznacza, że węzeł, do którego je wysyłasz, musi zarządzać Twoim kluczem prywatnym, aby mógł podpisać transakcję przed jej rozgłoszeniem w łańcuchu. Ponieważ Alchemy nie przechowuje kluczy prywatnych użytkowników, nie obsługuje tej metody. +- [`eth_sendRawTransaction`](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction) służy do rozgłaszania transakcji, które zostały już podpisane. Oznacza to, że najpierw musisz użyć [`signTransaction(tx, private_key)`](https://docs.web3js.org/api/web3-eth-accounts/function/signTransaction), a następnie przekazać wynik do `eth_sendRawTransaction`. + +Podczas korzystania z web3 dostęp do `eth_sendRawTransaction` uzyskuje się poprzez wywołanie funkcji [web3.eth.sendSignedTransaction](https://docs.web3js.org/api/web3-eth/function/sendSignedTransaction). + +Tego właśnie będziemy używać w tym samouczku. + +### 6. Czym jest biblioteka web3? {#what-is-the-web3-library} + +- Web3.js jest biblioteką opakowującą standardowe wywołania JSON-RPC, która jest dość często używana w deweloperce Ethereum. +- Istnieje wiele bibliotek web3 dla różnych języków. W tym samouczku będziemy używać [Alchemy Web3](https://docs.alchemy.com/reference/api-overview), który jest napisany w języku JavaScript. Możesz sprawdzić inne opcje [tutaj](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries), takie jak [ethers.js](https://docs.ethers.org/v5/). + +OK, teraz, gdy odpowiedzieliśmy na kilka pytań, przejdźmy do samouczka. W każdej chwili możesz zadawać pytania na [discordzie](https://discord.gg/gWuC7zB) Alchemy! + +### 7. Jak wysyłać bezpieczne, zoptymalizowane pod kątem opłat za gaz i prywatne transakcje? {#how-to-send-secure-gas-optimized-and-private-transactions} + +- [Alchemy ma zestaw interfejsów API Transact](https://docs.alchemy.com/reference/transact-api-quickstart). Możesz ich używać do wysyłania wzmocnionych transakcji, symulowania transakcji przed ich wykonaniem, wysyłania transakcji prywatnych oraz wysyłania transakcji zoptymalizowanych pod względem opłat za gaz. +- Możesz również użyć [API Notify](https://docs.alchemy.com/docs/alchemy-notify), aby otrzymywać powiadomienia, gdy Twoja transakcja zostanie pobrana z mempoola i dodana do łańcucha. + +**UWAGA:** Ten przewodnik wymaga posiadania konta Alchemy, adresu Ethereum lub portfela MetaMask oraz zainstalowanych NodeJs i npm. Jeśli nie, wykonaj następujące kroki: + +1. [Utwórz darmowe konto Alchemy](https://auth.alchemyapi.io/signup) +2. [Utwórz konto MetaMask](https://metamask.io/) (lub uzyskaj adres Ethereum) +3. [Wykonaj te kroki, aby zainstalować NodeJs i NPM](https://docs.alchemy.com/alchemy/guides/alchemy-for-macs) + +## Kroki wysyłania transakcji {#steps-to-sending-your-transaction} + +### 1. Utwórz aplikację Alchemy w sieci testowej Sepolia {#create-an-alchemy-app-on-the-sepolia-testnet} + +Przejdź do swojego [Panelu Alchemy](https://dashboard.alchemyapi.io/) i utwórz nową aplikację, wybierając Sepolia (lub dowolną inną sieć testową) jako swoją sieć. + +### 2. Poproś o ETH z kranu Sepolia {#request-eth-from-sepolia-faucet} + +Postępuj zgodnie z instrukcjami na stronie [kranu Sepolia od Alchemy](https://www.sepoliafaucet.com/), aby otrzymać ETH. Upewnij się, że podajesz swój adres Ethereum **Sepolia** (z MetaMask), a nie z innej sieci. Po wykonaniu instrukcji sprawdź, czy otrzymałeś ETH w swoim portfelu. + +### 3. Utwórz nowy katalog projektu i przejdź do niego za pomocą `cd` {#create-a-new-project-direction} + +Utwórz nowy katalog projektu z wiersza poleceń (terminal na komputerach Mac) i przejdź do niego: + +``` +mkdir sendtx-example +cd sendtx-example +``` + +### 4. Zainstaluj Alchemy Web3 (lub dowolną bibliotekę web3) {#install-alchemy-web3} + +Uruchom następujące polecenie w katalogu projektu, aby zainstalować [Alchemy Web3](https://docs.alchemy.com/reference/api-overview): + +Uwaga, jeśli chcesz użyć biblioteki ethers.js, [postępuj zgodnie z instrukcjami podanymi tutaj](https://docs.alchemy.com/docs/how-to-send-transactions-on-ethereum). + +``` +npm install @alch/alchemy-web3 +``` + +### 5. Zainstaluj dotenv {#install-dotenv} + +Użyjemy pliku `.env` do bezpiecznego przechowywania naszego klucza API i klucza prywatnego. + +``` +npm install dotenv --save +``` + +### 6. Utwórz plik `.env` {#create-the-dotenv-file} + +Utwórz plik `.env` w katalogu projektu i dodaj następującą treść (zastępując „`your-api-url`” i „`your-private-key`”): + +- Aby znaleźć adres URL interfejsu API Alchemy, przejdź do strony szczegółów aplikacji, którą właśnie utworzyłeś w panelu, kliknij „View Key” w prawym górnym rogu i pobierz adres URL HTTP. +- Aby znaleźć swój klucz prywatny za pomocą MetaMask, zapoznaj się z tym [przewodnikiem](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key). + +``` +API_URL = "your-api-url" +PRIVATE_KEY = "your-private-key" +``` + + + + +Nie commituj pliku .env! Upewnij się, że nigdy nie udostępniasz ani nie ujawniasz nikomu swojego pliku .env, ponieważ w ten sposób narażasz swoje poufne dane. Jeśli używasz kontroli wersji, dodaj swój plik .env do pliku gitignore. + + + + +### 7. Utwórz plik `sendTx.js` {#create-sendtx-js} + +Świetnie, teraz, gdy nasze poufne dane są chronione w pliku `.env`, zacznijmy kodować. W naszym przykładzie wysyłania transakcji będziemy odsyłać ETH z powrotem do kranu Sepolia. + +Utwórz plik `sendTx.js`, w którym skonfigurujemy i wyślemy naszą przykładową transakcję, i dodaj do niego następujące linie kodu: + +``` +async function main() { + require('dotenv').config(); + const { API_URL, PRIVATE_KEY } = process.env; + const { createAlchemyWeb3 } = require("@alch/alchemy-web3"); + const web3 = createAlchemyWeb3(API_URL); + const myAddress = '0x610Ae88399fc1687FA7530Aac28eC2539c7d6d63' //TODO: zastąp ten adres swoim własnym adresem publicznym + + const nonce = await web3.eth.getTransactionCount(myAddress, 'latest'); // nonce zaczyna liczyć od 0 + + const transaction = { + 'to': '0x31B98D14007bDEe637298086988A0bBd31184523', // adres kranu, na który ma być zwrócony eth + 'value': 1000000000000000000, // 1 ETH + 'gas': 30000, + 'nonce': nonce, + // opcjonalne pole danych do wysłania wiadomości lub wykonania smart kontraktu + }; + + const signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); + + web3.eth.sendSignedTransaction(signedTx.rawTransaction, function(error, hash) { + if (!error) { + console.log("🎉 Hasz Twojej transakcji to: ", hash, "\n Sprawdź Mempool Alchemy, aby zobaczyć status swojej transakcji!"); + } else { + console.log("❗Coś poszło nie tak podczas przesyłania transakcji:", error) + } + }); +} + +main(); +``` + +Pamiętaj, aby zastąpić adres w **wierszu 6** swoim własnym adresem publicznym. + +Zanim przejdziemy do uruchomienia tego kodu, omówmy kilka jego komponentów. + +- `nonce`: Specyfikacja nonce służy do śledzenia liczby transakcji wysłanych z Twojego adresu. Potrzebujemy tego ze względów bezpieczeństwa i aby zapobiegać [atakom typu replay](https://docs.alchemyapi.io/resources/blockchain-glossary#account-nonce). Aby uzyskać liczbę transakcji wysłanych z Twojego adresu, używamy [getTransactionCount](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_gettransactioncount). +- `transaction`: Obiekt transakcji ma kilka aspektów, które musimy określić. + - `to`: Jest to adres, na który chcemy wysłać ETH. W tym przypadku odsyłamy ETH z powrotem do [kranu Sepolia](https://sepoliafaucet.com/), z którego pierwotnie je pozyskaliśmy. + - `value`: Jest to kwota, którą chcemy wysłać, określona w Wei, gdzie 10^18 Wei = 1 ETH. + - `gas`: Istnieje wiele sposobów na określenie odpowiedniej ilości gazu do uwzględnienia w transakcji. Alchemy ma nawet [webhook ceny gazu](https://docs.alchemyapi.io/guides/alchemy-notify#address-activity-1), który powiadamia, gdy cena gazu spadnie poniżej określonego progu. W przypadku transakcji w sieci głównej Mainnet dobrą praktyką jest sprawdzanie estymatora gazu, takiego jak [ETH Gas Station](https://ethgasstation.info/), w celu określenia właściwej ilości gazu do uwzględnienia. 21000 to minimalna ilość gazu, jaką zużyje operacja na Ethereum, więc aby zapewnić, że nasza transakcja zostanie wykonana, wpisujemy tutaj 30000. + - `nonce`: patrz definicja nonce powyżej. Nonce zaczyna liczyć od zera. + - [OPCJONALNE] dane: Służy do wysyłania dodatkowych informacji wraz z transferem lub wywoływania smart kontraktu. Nie jest wymagane w przypadku transferów salda. Sprawdź uwagę poniżej. +- `signedTx`: Aby podpisać nasz obiekt transakcji, użyjemy metody `signTransaction` z naszym `PRIVATE_KEY`. +- `sendSignedTransaction`: Gdy mamy już podpisaną transakcję, możemy ją wysłać, aby została uwzględniona w kolejnym bloku, używając `sendSignedTransaction`. + +**Uwaga na temat danych** +Istnieją dwa główne typy transakcji, które można wysyłać w Ethereum. + +- Transfer salda: Wyślij ETH z jednego adresu na drugi. Pole danych nie jest wymagane, jednak jeśli chcesz wysłać dodatkowe informacje wraz z transakcją, możesz je umieścić w tym polu w formacie HEX. + - Załóżmy na przykład, że chcemy zapisać hasz dokumentu IPFS w łańcuchu Ethereum, aby nadać mu niezmienny znacznik czasu. Nasze pole danych powinno wtedy wyglądać następująco: `web3.utils.toHex(‘hasz IPFS‘)`. I teraz każdy może odpytać łańcuch i zobaczyć, kiedy ten dokument został dodany. +- Transakcja smart kontraktu: wykonanie kodu smart kontraktu w łańcuchu. W tym przypadku pole danych powinno zawierać inteligentną funkcję, którą chcesz wykonać, wraz z wszelkimi parametrami. + - Praktyczny przykład znajdziesz w kroku 8 tego [samouczka „Witaj, świecie”](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#step-8-create-the-transaction). + +### 8. Uruchom kod za pomocą `node sendTx.js` {#run-the-code-using-node-sendtx-js} + +Wróć do terminala lub wiersza poleceń i uruchom: + +``` +node sendTx.js +``` + +### 9. Zobacz swoją transakcję w Mempoolu {#see-your-transaction-in-the-mempool} + +Otwórz [stronę Mempool](https://dashboard.alchemyapi.io/mempool) w panelu Alchemy i filtruj według utworzonej aplikacji, aby znaleźć swoją transakcję. Tutaj możemy obserwować przejście naszej transakcji ze stanu oczekującego do stanu wydobycia (jeśli się powiedzie) lub do stanu porzucenia, jeśli się nie powiedzie. Upewnij się, że opcja jest ustawiona na „Wszystkie”, aby przechwycić transakcje „wydobyte”, „oczekujące” i „porzucone”. Możesz również wyszukać swoją transakcję, szukając transakcji wysłanych na adres `0x31b98d14007bdee637298086988a0bbd31184523`. + +Aby wyświetlić szczegóły transakcji po jej znalezieniu, wybierz jej hasz, co powinno przenieść Cię do widoku, który wygląda następująco: + +![Zrzut ekranu obserwatora Mempool](./mempool.png) + +Stamtąd możesz wyświetlić swoją transakcję w Etherscan, klikając ikonę zaznaczoną na czerwono! + +**Huraaa! Właśnie wysłałeś swoją pierwszą transakcję Ethereum za pomocą Alchemy 🎉** + +_Aby uzyskać opinie i sugestie dotyczące tego przewodnika, wyślij wiadomość do Elan na [Discordzie](https://discord.gg/A39JVCM) Alchemy!_ + +_Oryginalnie opublikowano na stronie [https://docs.alchemyapi.io/tutorials/sending-transactions-using-web3-and-alchemy](https://docs.alchemyapi.io/tutorials/sending-transactions-using-web3-and-alchemy)_ diff --git a/public/content/translations/pl/developers/tutorials/server-components/index.md b/public/content/translations/pl/developers/tutorials/server-components/index.md new file mode 100644 index 00000000000..04495a4d439 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/server-components/index.md @@ -0,0 +1,295 @@ +--- +title: "Komponenty serwera i agenty dla aplikacji web3" +description: "Po przeczytaniu tego samouczka będziesz w stanie pisać serwery TypeScript, które nasłuchują zdarzeń w łańcuchu bloków i odpowiednio na nie reagują własnymi transakcjami. Umożliwi to pisanie scentralizowanych aplikacji (ponieważ serwer jest pojedynczym punktem awarii), które mogą wchodzić w interakcje z jednostkami web3. Te same techniki mogą być również użyte do napisania agenta, który reaguje na zdarzenia onchain bez udziału człowieka." + +author: Ori Pomerantz +lang: pl +tags: [ "agent", "serwer", "offchain" ] +skill: beginner +published: 2024-07-15 +--- + +## Wprowadzenie {#introduction} + +W większości przypadków zdecentralizowana aplikacja wykorzystuje serwer do dystrybucji oprogramowania, ale cała faktyczna interakcja zachodzi między klientem (zazwyczaj przeglądarką internetową) a łańcuchem bloków. + +![Normalna interakcja między serwerem internetowym, klientem a łańcuchem bloków](./fig-1.svg) + +Istnieją jednak przypadki, w których aplikacja odniosłaby korzyść z posiadania niezależnie działającego komponentu serwera. Taki serwer byłby w stanie reagować na zdarzenia i żądania pochodzące z innych źródeł, takich jak API, emitując transakcje. + +![Interakcja z dodanym serwerem](./fig-2.svg) + +Istnieje kilka możliwych zadań, które taki serwer mógłby spełniać. + +- Posiadacz tajnego stanu. W grach często przydatne jest, aby nie wszystkie informacje znane grze były dostępne dla graczy. Jednakże _w łańcuchu bloków nie ma żadnych tajemnic_, każdą informację, która się w nim znajduje, każdy może łatwo poznać. Dlatego też, jeśli część stanu gry ma pozostać tajna, musi być przechowywana gdzie indziej (a ewentualne skutki tego stanu zweryfikowane za pomocą [dowodów o wiedzy zerowej](/zero-knowledge-proofs)). + +- Scentralizowana wyrocznia. Jeśli stawki są wystarczająco niskie, zewnętrzny serwer, który odczytuje pewne informacje online, a następnie publikuje je w łańcuchu, może być wystarczająco dobry, aby użyć go jako [wyroczni](/developers/docs/oracles/). + +- Agent. W łańcuchu bloków nic się nie dzieje bez transakcji, która to aktywuje. Serwer może działać w imieniu użytkownika, wykonując działania takie jak [arbitraż](/developers/docs/mev/#mev-examples-dex-arbitrage), gdy nadarzy się okazja. + +## Przykładowy program {#sample-program} + +Przykładowy serwer można zobaczyć [na GitHubie](https://github.com/qbzzt/20240715-server-component). Ten serwer nasłuchuje zdarzeń pochodzących z [tego kontraktu](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=contract_code), zmodyfikowanej wersji Greeter od Hardhat. Gdy powitanie zostanie zmienione, zmienia je z powrotem. + +Aby go uruchomić: + +1. Sklonuj repozytorium. + + ```sh copy + git clone https://github.com/qbzzt/20240715-server-component.git + cd 20240715-server-component + ``` + +2. Zainstaluj niezbędne pakiety. Jeśli jeszcze go nie masz, [najpierw zainstaluj Node](https://nodejs.org/en/download/package-manager). + + ```sh copy + npm install + ``` + +3. Edytuj plik `.env`, aby określić klucz prywatny konta, które posiada ETH w sieci testowej Holesky. Jeśli nie masz ETH na Holesky, możesz [użyć tego kraniku](https://holesky-faucet.pk910.de/). + + ```sh filename=".env" copy + PRIVATE_KEY=0x + ``` + +4. Uruchom serwer. + + ```sh copy + npm start + ``` + +5. Przejdź do [eksploratora bloków](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=write_contract) i używając innego adresu niż ten, który posiada klucz prywatny, zmodyfikuj powitanie. Zobacz, że powitanie jest automatycznie przywracane. + +### Jak to działa? {#how-it-works} + +Najłatwiejszym sposobem na zrozumienie, jak napisać komponent serwera, jest przeanalizowanie przykładu linijka po linijce. + +#### `src/app.ts` {#src-app-ts} + +Zdecydowana większość programu znajduje się w [`src/app.ts`](https://github.com/qbzzt/20240715-server-component/blob/main/src/app.ts). + +##### Tworzenie wymaganych obiektów + +```typescript +import { + createPublicClient, + createWalletClient, + getContract, + http, + Address, +} from "viem" +``` + +Są to potrzebne nam encje [Viem](https://viem.sh/), funkcje i [typ `Address`](https://viem.sh/docs/glossary/types#address). Ten serwer jest napisany w języku [TypeScript](https://www.typescriptlang.org/), który jest rozszerzeniem języka JavaScript, czyniącym go [silnie typowanym](https://en.wikipedia.org/wiki/Strong_and_weak_typing). + +```typescript +import { privateKeyToAccount } from "viem/accounts" +``` + +[Ta funkcja](https://viem.sh/docs/accounts/privateKey) pozwala nam wygenerować informacje o portfelu, w tym adres, odpowiadające kluczowi prywatnemu. + +```typescript +import { holesky } from "viem/chains" +``` + +Aby używać blockchaina w Viem, musisz zaimportować jego definicję. W tym przypadku chcemy połączyć się z testowym łańcuchem bloków [Holesky](https://github.com/eth-clients/holesky). + +```typescript +// W ten sposób dodajemy definicje z .env do process.env. +import * as dotenv from "dotenv" +dotenv.config() +``` + +W ten sposób wczytujemy plik `.env` do środowiska. Potrzebujemy go do klucza prywatnego (zobacz później). + +```typescript +const greeterAddress : Address = "0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6" +const greeterABI = [ + { + "inputs": [ + { + "internalType": "string", + "name": "_greeting", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + . + . + . + { + "inputs": [ + { + "internalType": "string", + "name": "_greeting", + "type": "string" + } + ], + "name": "setGreeting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const +``` + +Aby użyć kontraktu, potrzebujemy jego adresu i [ABI](/glossary/#abi). Podajemy oba tutaj. + +W języku JavaScript (a więc i w TypeScript) nie można przypisać nowej wartości do stałej, ale _można_ zmodyfikować obiekt, który jest w niej przechowywany. Używając sufiksu `as const`, informujemy TypeScript, że sama lista jest stała i nie może być zmieniana. + +```typescript +const publicClient = createPublicClient({ + chain: holesky, + transport: http(), +}) +``` + +Utwórz [klienta publicznego](https://viem.sh/docs/clients/public.html) Viem. Klienci publiczni nie mają dołączonego klucza prywatnego, a zatem nie mogą wysyłać transakcji. Mogą wywoływać [`funkcje widoku`](https://www.tutorialspoint.com/solidity/solidity_view_functions.htm), odczytywać salda kont itp. + +```typescript +const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) +``` + +Zmienne środowiskowe są dostępne w [`process.env`](https://www.totaltypescript.com/how-to-strongly-type-process-env). Jednak TypeScript jest silnie typowany. Zmienna środowiskowa może być dowolnym ciągiem znaków lub być pusta, więc typem zmiennej środowiskowej jest `string | undefined`. Jednak klucz jest zdefiniowany w Viem jako `0x${string}` (`0x` po którym następuje ciąg znaków). W tym miejscu informujemy TypeScript, że zmienna środowiskowa `PRIVATE_KEY` będzie tego typu. Jeśli tak nie będzie, otrzymamy błąd wykonania. + +Funkcja [`privateKeyToAccount`](https://viem.sh/docs/accounts/privateKey) następnie używa tego klucza prywatnego do utworzenia pełnego obiektu konta. + +```typescript +const walletClient = createWalletClient({ + account, + chain: holesky, + transport: http(), +}) +``` + +Następnie używamy obiektu konta do utworzenia [klienta portfela](https://viem.sh/docs/clients/wallet). Ten klient ma klucz prywatny i adres, więc może być używany do wysyłania transakcji. + +```typescript +const greeter = getContract({ + address: greeterAddress, + abi: greeterABI, + client: { public: publicClient, wallet: walletClient }, +}) +``` + +Teraz, gdy mamy już wszystkie wymagania wstępne, możemy wreszcie utworzyć [instancję kontraktu](https://viem.sh/docs/contract/getContract). Będziemy używać tej instancji kontraktu do komunikacji z kontraktem onchain. + +##### Odczytywanie z łańcucha bloków + +```typescript +console.log(`Current greeting:`, await greeter.read.greet()) +``` + +Funkcje kontraktu, które są tylko do odczytu ([`view`](https://www.tutorialspoint.com/solidity/solidity_view_functions.htm) i [`pure`](https://www.tutorialspoint.com/solidity/solidity_pure_functions.htm)), są dostępne w `read`. W tym przypadku używamy jej do uzyskania dostępu do funkcji [`greet`](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=read_contract#cfae3217), która zwraca powitanie. + +JavaScript jest jednowątkowy, więc gdy uruchamiamy długo działający proces, musimy [określić, że robimy to asynchronicznie](https://eloquentjavascript.net/11_async.html#h-XvLsfAhtsE). Wywołanie łańcucha bloków, nawet w przypadku operacji tylko do odczytu, wymaga komunikacji w obie strony między komputerem a węzłem łańcucha bloków. Dlatego w tym miejscu określamy, że kod musi `await` (oczekiwać) na wynik. + +Jeśli interesuje Cię, jak to działa, możesz [przeczytać o tym tutaj](https://www.w3schools.com/js/js_promise.asp), ale w praktyce wystarczy wiedzieć, że należy `await` (oczekiwać) na wyniki, jeśli rozpoczynasz operację, która trwa długo, a każda funkcja, która to robi, musi być zadeklarowana jako `async`. + +##### Emitowanie transakcji + +```typescript +const setGreeting = async (greeting: string): Promise => { +``` + +Jest to funkcja, którą wywołujesz, aby wysłać transakcję zmieniającą powitanie. Ponieważ jest to długa operacja, funkcja jest zadeklarowana jako `async`. Ze względu na wewnętrzną implementację, każda funkcja `async` musi zwracać obiekt `Promise`. W tym przypadku `Promise` oznacza, że nie określamy, co dokładnie zostanie zwrócone w `Promise`. + +```typescript +const txHash = await greeter.write.setGreeting([greeting]) +``` + +Pole `write` instancji kontraktu zawiera wszystkie funkcje, które zapisują do stanu łańcucha bloków (te, które wymagają wysłania transakcji), takie jak [`setGreeting`](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=write_contract#a4136862). Parametry, jeśli istnieją, są podawane w postaci listy, a funkcja zwraca hasz transakcji. + +```typescript + console.log(`Pracuję nad poprawką, zobacz https://eth-holesky.blockscout.com/tx/${txHash}`) + + return txHash +} +``` + +Zgłoś hasz transakcji (jako część adresu URL do eksploratora bloków, aby go wyświetlić) i zwróć go. + +##### Reagowanie na zdarzenia + +```typescript +greeter.watchEvent.SetGreeting({ +``` + +[Funkcja `watchEvent`](https://viem.sh/docs/actions/public/watchEvent) pozwala określić, że funkcja ma być uruchamiana po wyemitowaniu zdarzenia. Jeśli interesuje Cię tylko jeden typ zdarzenia (w tym przypadku `SetGreeting`), możesz użyć tej składni, aby ograniczyć się do tego typu zdarzenia. + +```typescript + onLogs: logs => { +``` + +Funkcja `onLogs` jest wywoływana, gdy pojawiają się wpisy w dzienniku. W Ethereum „log” i „zdarzenie” są zwykle używane zamiennie. + +```typescript +console.log( + `Adres ${logs[0].args.sender} zmienił powitanie na ${logs[0].args.greeting}` +) +``` + +Może być wiele zdarzeń, ale dla uproszczenia interesuje nas tylko pierwsze z nich. `logs[0].args` to argumenty zdarzenia, w tym przypadku `sender` i `greeting`. + +```typescript + if (logs[0].args.sender != account.address) + setGreeting(`${account.address} nalega, aby było to Hello!`) + } +}) +``` + +Jeśli nadawcą _nie jest_ ten serwer, użyj `setGreeting`, aby zmienić powitanie. + +#### `package.json` {#package-json} + +[Ten plik](https://github.com/qbzzt/20240715-server-component/blob/main/package.json) kontroluje konfigurację [Node.js](https://nodejs.org/en). W tym artykule wyjaśniono tylko ważne definicje. + +```json +{ + "main": "dist/index.js", +``` + +Ta definicja określa, który plik JavaScript ma być uruchomiony. + +```json + "scripts": { + "start": "tsc && node dist/app.js", + }, +``` + +Skrypty to różne działania aplikacji. W tym przypadku jedynym, jaki mamy, jest `start`, który kompiluje, a następnie uruchamia serwer. Polecenie `tsc` jest częścią pakietu `typescript` i kompiluje TypeScript do JavaScript. Jeśli chcesz uruchomić go ręcznie, znajduje się on w `node_modules/.bin`. Drugie polecenie uruchamia serwer. + +```json + "type": "module", +``` + +Istnieje wiele typów aplikacji węzła JavaScript. Typ `module` pozwala nam na użycie `await` w kodzie najwyższego poziomu, co jest ważne, gdy wykonujesz wolne (i asynchroniczne) operacje. + +```json + "devDependencies": { + "@types/node": "^20.14.2", + "typescript": "^5.4.5" + }, +``` + +Są to pakiety, które są wymagane tylko do programowania. W tym miejscu potrzebujemy `typescript`, a ponieważ używamy go z Node.js, otrzymujemy również typy dla zmiennych i obiektów węzła, takich jak `process`. [Notacja `^`](https://github.com/npm/node-semver?tab=readme-ov-file#caret-ranges-123-025-004) oznacza tę wersję lub wyższą wersję, która nie zawiera przełomowych zmian. Więcej informacji na temat znaczenia numerów wersji można znaleźć [tutaj](https://semver.org). + +```json + "dependencies": { + "dotenv": "^16.4.5", + "viem": "2.14.1" + } +} +``` + +Są to pakiety wymagane w czasie wykonywania, podczas uruchamiania `dist/app.js`. + +## Wnioski {#conclusion} + +Scentralizowany serwer, który tu stworzyliśmy, wykonuje swoje zadanie, którym jest działanie jako agent dla użytkownika. Każdy, kto chce, aby dapka nadal funkcjonowała i jest gotów wydać gaz, może uruchomić nową instancję serwera z własnym adresem. + +Działa to jednak tylko wtedy, gdy działania scentralizowanego serwera można łatwo zweryfikować. Jeśli scentralizowany serwer ma jakiekolwiek informacje o tajnym stanie lub wykonuje trudne obliczenia, jest to scentralizowany podmiot, któremu trzeba zaufać, aby korzystać z aplikacji, a tego właśnie starają się unikać łańcuchy bloków. W przyszłym artykule planuję pokazać, jak używać [dowodów o wiedzy zerowej](/zero-knowledge-proofs), aby obejść ten problem. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). diff --git a/public/content/translations/pl/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/index.md b/public/content/translations/pl/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/index.md new file mode 100644 index 00000000000..59f07059bd1 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/index.md @@ -0,0 +1,92 @@ +--- +title: "Skonfiguruj web3.js do używania blockchainu Ethereum w JavaScript" +description: "Dowiedz się, jak skonfigurować bibliotekę web3.js do interakcji z blockchainem Ethereum z aplikacji JavaScript." +author: "jdourlens" +tags: [ "web3.js", "JavaScript" ] +skill: beginner +lang: pl +published: 2020-04-11 +source: EthereumDev +sourceUrl: https://ethereumdev.io/setup-web3js-to-use-the-ethereum-blockchain-in-javascript/ +address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +--- + +W tym samouczku zobaczymy, jak zacząć z [web3.js](https://web3js.readthedocs.io/), aby wejść w interakcję z blockchainem Ethereum. Web3.js może być używany zarówno we frontendach, jak i backendach do odczytywania danych z blockchaina, dokonywania transakcji, a nawet wdrażania smart kontraktów. + +Pierwszym krokiem jest dołączenie web3.js do Twojego projektu. Aby użyć go na stronie internetowej, możesz zaimportować bibliotekę bezpośrednio za pomocą CDN, takiego jak JSDeliver. + +```html + +``` + +Jeśli wolisz zainstalować bibliotekę do użycia w backendzie lub w projekcie frontendowym, który używa kompilacji, możesz ją zainstalować za pomocą npm: + +```bash +npm install web3 --save +``` + +Następnie, aby zaimportować Web3.js do skryptu Node.js lub projektu frontendowego Browserify, możesz użyć następującej linii JavaScriptu: + +```js +const Web3 = require("web3") +``` + +Teraz, gdy dołączyliśmy bibliotekę do projektu, musimy ją zainicjować. Twój projekt musi być w stanie komunikować się z blockchainem. Większość bibliotek Ethereum komunikuje się z [węzłem](/developers/docs/nodes-and-clients/) poprzez wywołania RPC. Aby zainicjować naszego dostawcę Web3, utworzymy instancję Web3, przekazując jako konstruktor adres URL dostawcy. Jeśli masz węzeł lub [instancję ganache działającą na twoim komputerze](https://ethereumdev.io/testing-your-smart-contract-with-existing-protocols-ganache-fork/), będzie to wyglądać tak: + +```js +const web3 = new Web3("http://localhost:8545") +``` + +Jeśli chcesz uzyskać bezpośredni dostęp do hostowanego węzła, możesz znaleźć opcje w [węzłach jako usłudze](/developers/docs/nodes-and-clients/nodes-as-a-service). + +```js +const web3 = new Web3("https://cloudflare-eth.com") +``` + +Aby przetestować, czy poprawnie skonfigurowaliśmy naszą instancję Web3, spróbujemy pobrać najnowszy numer bloku za pomocą funkcji `getBlockNumber`. Ta funkcja akceptuje callback jako parametr i zwraca numer bloku jako liczbę całkowitą. + +```js +var Web3 = require("web3") +const web3 = new Web3("https://cloudflare-eth.com") + +web3.eth.getBlockNumber(function (error, result) { + console.log(result) +}) +``` + +Jeśli wykonasz ten program, po prostu wydrukuje on najnowszy numer bloku: szczyt blockchainu. Możesz również użyć wywołań funkcji `await/async`, aby uniknąć zagnieżdżania wywołań zwrotnych w swoim kodzie: + +```js +async function getBlockNumber() { + const latestBlockNumber = await web3.eth.getBlockNumber() + console.log(latestBlockNumber) + return latestBlockNumber +} + +getBlockNumber() +``` + +Możesz zobaczyć wszystkie dostępne funkcje w instancji Web3 w [oficjalnej dokumentacji web3.js](https://docs.web3js.org/). + +Większość bibliotek Web3 jest asynchroniczna, ponieważ w tle biblioteka wykonuje wywołania JSON-RPC do węzła, który odsyła wynik. + + + +Jeśli pracujesz w przeglądarce, niektóre portfele bezpośrednio wstrzykują instancję Web3 i powinieneś starać się jej używać, gdy tylko jest to możliwe, zwłaszcza jeśli planujesz wchodzić w interakcję z adresem Ethereum użytkownika w celu dokonywania transakcji. + +Oto fragment kodu do wykrywania, czy portfel MetaMask jest dostępny, i próby jego włączenia, jeśli tak. Pozwoli to później na odczytanie salda użytkownika i umożliwi mu zatwierdzanie transakcji, które chcesz, aby wykonał na blockchainie Ethereum: + +```js +if (window.ethereum != null) { + state.web3 = new Web3(window.ethereum) + try { + // W razie potrzeby poproś o dostęp do konta + await window.ethereum.enable() + // Konta są teraz ujawnione + } catch (error) { + // Użytkownik odmówił dostępu do konta... + } +} +``` + +Istnieją alternatywy dla web3.js, takie jak [Ethers.js](https://docs.ethers.io/), i są one również powszechnie stosowane. W następnym samouczku zobaczymy, [jak łatwo nasłuchiwać nowych bloków przychodzących na blockchainie i zobaczyć, co zawierają](https://ethereumdev.io/listening-to-new-transactions-happening-on-the-blockchain/). diff --git a/public/content/translations/pl/developers/tutorials/short-abi/index.md b/public/content/translations/pl/developers/tutorials/short-abi/index.md new file mode 100644 index 00000000000..708dc6db4c1 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/short-abi/index.md @@ -0,0 +1,585 @@ +--- +title: "Krótkie ABI w celu optymalizacji Calldata" +description: "Optymalizacja inteligentnych kontraktów dla rollupów optymistycznych" +author: Ori Pomerantz +lang: pl +tags: [ "warstwa 2" ] +skill: intermediate +published: 2022-04-01 +--- + +## Wprowadzenie {#introduction} + +W tym artykule dowiesz się o [rollupach optymistycznych](/developers/docs/scaling/optimistic-rollups), kosztach transakcji na nich oraz o tym, jak odmienna struktura kosztów wymaga od nas optymalizacji pod kątem innych rzeczy niż w sieci głównej Ethereum. +Dowiesz się również, jak wdrożyć tę optymalizację. + +### Pełne ujawnienie {#full-disclosure} + +Jestem pracownikiem zatrudnionym na pełen etat w [Optimism](https://www.optimism.io/), więc przykłady w tym artykule będą działać na Optimism. +Jednakże wyjaśniona tutaj technika powinna działać równie dobrze w przypadku innych rollupów. + +### Terminologia {#terminology} + +W dyskusjach o rollupach termin „warstwa 1” (L1) jest używany w odniesieniu do sieci głównej (Mainnet), produkcyjnej sieci Ethereum. +Termin „warstwa 2” (L2) jest używany w odniesieniu do rollupu lub jakiegokolwiek innego systemu, który opiera się na L1 w kwestii bezpieczeństwa, ale wykonuje większość przetwarzania poza łańcuchem. + +## Jak możemy jeszcze bardziej obniżyć koszt transakcji L2? {#how-can-we-further-reduce-the-cost-of-L2-transactions} + +[Rollupy optymistyczne](/developers/docs/scaling/optimistic-rollups) muszą przechowywać zapis każdej historycznej transakcji, aby każdy mógł je przejrzeć i zweryfikować, czy obecny stan jest prawidłowy. +Najtańszym sposobem na wprowadzenie danych do sieci głównej Ethereum jest zapisanie ich jako calldata. +To rozwiązanie zostało wybrane zarówno przez [Optimism](https://help.optimism.io/hc/en-us/articles/4413163242779-What-is-a-rollup-), jak i [Arbitrum](https://developer.offchainlabs.com/docs/rollup_basics#intro-to-rollups). + +### Koszt transakcji L2 {#cost-of-l2-transactions} + +Koszt transakcji L2 składa się z dwóch składników: + +1. Przetwarzanie na L2, które jest zazwyczaj niezwykle tanie +2. Przechowywanie na L1, które jest powiązane z kosztami gazu w sieci głównej + +W chwili, gdy to piszę, na Optimism koszt gazu L2 wynosi 0,001 [Gwei](/developers/docs/gas/#pre-london). +Z drugiej strony, koszt gazu L1 wynosi około 40 gwei. +[Aktualne ceny można zobaczyć tutaj](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m). + +Jeden bajt calldata kosztuje albo 4 gazu (jeśli jest to zero), albo 16 gazu (jeśli ma inną wartość). +Jedną z najdroższych operacji w EVM jest zapis do pamięci masowej. +Maksymalny koszt zapisu 32-bajtowego słowa do pamięci masowej na L2 wynosi 22100 gazu. Obecnie jest to 22,1 gwei. +Jeśli więc uda nam się zaoszczędzić jeden zerowy bajt calldata, będziemy w stanie zapisać około 200 bajtów do pamięci masowej i nadal wyjdziemy na tym na plus. + +### ABI {#the-abi} + +Zdecydowana większość transakcji uzyskuje dostęp do kontraktu z konta zewnętrznego. +Większość kontraktów jest napisana w Solidity i interpretuje swoje pole danych zgodnie z [binarnym interfejsem aplikacji (ABI)](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). + +Jednak ABI zostało zaprojektowane dla L1, gdzie bajt calldata kosztuje mniej więcej tyle samo co cztery operacje arytmetyczne, a nie dla L2, gdzie bajt calldata kosztuje ponad tysiąc operacji arytmetycznych. +Calldata jest podzielona w następujący sposób: + +| Sekcja | Długość | Bajty | Zmarnowane bajty | Zmarnowany gaz | Niezbędne bajty | Niezbędny gaz | +| ---------------- | ------: | ----: | ---------------: | -------------: | --------------: | ------------: | +| Selektor funkcji | 4 | 0-3 | 3 | 48 | 1 | 16 | +| Zera | 12 | 4-15 | 12 | 48 | 0 | 0 | +| Adres docelowy | 20 | 16-35 | 0 | 0 | 20 | 320 | +| Kwota | 32 | 36-67 | 17 | 64 | 15 | 240 | +| Łącznie | 68 | | | 160 | | 576 | + +Wyjaśnienie: + +- **Selektor funkcji**: Kontrakt ma mniej niż 256 funkcji, więc możemy je rozróżnić za pomocą jednego bajtu. + Te bajty są zazwyczaj niezerowe i dlatego [kosztują szesnaście gazu](https://eips.ethereum.org/EIPS/eip-2028). +- **Zera**: Te bajty są zawsze zerowe, ponieważ dwudziestobajtowy adres nie wymaga trzydziestodwubajtowego słowa, aby go pomieścić. + Bajty, które zawierają zero, kosztują cztery gazu ([zobacz yellow paper](https://ethereum.github.io/yellowpaper/paper.pdf), Dodatek G, + s. 27, wartość dla `G``txdatazero`). +- **Ilość**: Jeśli założymy, że w tym kontrakcie `decimals` wynosi osiemnaście (normalna wartość), a maksymalna ilość tokenów, które transferujemy, wyniesie 1018, otrzymamy maksymalną ilość 1036. + 25615 > 1036, więc piętnaście bajtów wystarczy. + +Strata 160 gazu na L1 jest normalnie znikoma. Transakcja kosztuje co najmniej [21 000 gazu](https://yakkomajuri.medium.com/blockchain-definition-of-the-week-ethereum-gas-2f976af774ed), więc dodatkowe 0,8% nie ma znaczenia. +Jednak na L2 sprawy mają się inaczej. Prawie cały koszt transakcji to zapisanie jej na L1. +Oprócz calldata transakcji, istnieje 109 bajtów nagłówka transakcji (adres docelowy, podpis itp.). +Całkowity koszt wynosi zatem `109*16+576+160=2480`, a my marnujemy około 6,5% tej kwoty. + +## Redukcja kosztów, gdy nie kontrolujesz kontraktu docelowego {#reducing-costs-when-you-dont-control-the-destination} + +Zakładając, że nie masz kontroli nad kontraktem docelowym, nadal możesz użyć rozwiązania podobnego do [tego](https://github.com/qbzzt/ethereum.org-20220330-shortABI). +Przejdźmy do odpowiednich plików. + +### Token.sol {#token-sol} + +[To jest kontrakt docelowy](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/Token.sol). +Jest to standardowy kontrakt ERC-20, z jedną dodatkową funkcją. +Ta funkcja `faucet` pozwala każdemu użytkownikowi otrzymać trochę tokenów do wykorzystania. +Uczyniłoby to produkcyjny kontrakt ERC-20 bezużytecznym, ale ułatwia życie, gdy ERC-20 istnieje tylko w celu ułatwienia testowania. + +```solidity + /** + * @dev Daje wywołującemu 1000 tokenów do zabawy + */ + function faucet() external { + _mint(msg.sender, 1000); + } // function faucet +``` + +### CalldataInterpreter.sol {#calldatainterpreter-sol} + +[To jest kontrakt, który transakcje mają wywoływać z krótszymi calldata](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/CalldataInterpreter.sol). +Przejdźmy przez niego linia po linii. + +```solidity +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + + +import { OrisUselessToken } from "./Token.sol"; +``` + +Potrzebujemy interfejsu kontraktu tokena, aby wiedzieć, jak go wywoływać. + +```solidity +contract CalldataInterpreter { + + OrisUselessToken public immutable token; +``` + +Adres tokena, dla którego jesteśmy proxy. + +```solidity + + /** + * @dev Określ adres tokena + * @param tokenAddr_ adres kontraktu ERC-20 + */ + constructor( + address tokenAddr_ + ) { + token = OrisUselessToken(tokenAddr_); + } // constructor +``` + +Adres tokena jest jedynym parametrem, który musimy określić. + +```solidity + function calldataVal(uint startByte, uint length) + private pure returns (uint) { +``` + +Odczytaj wartość z calldata. + +```solidity + uint _retVal; + + require(length < 0x21, + "calldataVal limit długości to 32 bajty"); + + require(length + startByte <= msg.data.length, + "calldataVal próbuje czytać poza calldatasize"); +``` + +Zamierzamy załadować do pamięci pojedyncze 32-bajtowe (256-bitowe) słowo i usunąć bajty, które nie są częścią pola, które nas interesuje. +Ten algorytm nie działa dla wartości dłuższych niż 32 bajty i oczywiście nie możemy czytać poza końcem calldata. +Na L1 może być konieczne pominięcie tych testów w celu zaoszczędzenia na gazie, ale na L2 gaz jest niezwykle tani, co umożliwia wszelkie testy poprawności, jakie możemy sobie wyobrazić. + +```solidity + assembly { + _retVal := calldataload(startByte) + } +``` + +Moglibyśmy skopiować dane z wywołania do `fallback()` (patrz niżej), ale łatwiej jest użyć [Yul](https://docs.soliditylang.org/en/v0.8.12/yul.html), języka asemblera EVM. + +Tutaj używamy [opcodu CALLDATALOAD](https://www.evm.codes/#35), aby odczytać bajty od `startByte` do `startByte+31` na stos. +Ogólnie rzecz biorąc, składnia opcodu w Yul to `(, ...). + +```solidity + + _retVal = _retVal >> (256-length*8); +``` + +Tylko najbardziej znaczące bajty o długości `length` są częścią pola, więc wykonujemy [przesunięcie w prawo](https://en.wikipedia.org/wiki/Logical_shift), aby pozbyć się pozostałych wartości. +Ma to dodatkową zaletę, że przenosi wartość na prawo od pola, więc jest to sama wartość, a nie wartość pomnożona przez 256coś. + +```solidity + + return _retVal; + } + + + fallback() external { +``` + +Gdy wywołanie do kontraktu Solidity nie pasuje do żadnej z sygnatur funkcji, wywołuje [funkcję `fallback()`](https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function) (zakładając, że taka istnieje). +W przypadku `CalldataInterpreter` _każde_ wywołanie trafia tutaj, ponieważ nie ma innych funkcji `external` ani `public`. + +```solidity + uint _func; + + _func = calldataVal(0, 1); +``` + +Odczytaj pierwszy bajt calldata, który informuje nas o funkcji. +Istnieją dwa powody, dla których funkcja nie byłaby tutaj dostępna: + +1. Funkcje, które są `pure` lub `view`, nie zmieniają stanu i nie kosztują gazu (gdy są wywoływane poza łańcuchem). + Nie ma sensu próbować zmniejszać ich kosztu gazu. +2. Funkcje, które opierają się na [`msg.sender`](https://docs.soliditylang.org/en/v0.8.12/units-and-global-variables.html#block-and-transaction-properties). + Wartością `msg.sender` będzie adres `CalldataInterpreter`, a nie adres wywołującego. + +Niestety, [patrząc na specyfikacje ERC-20](https://eips.ethereum.org/EIPS/eip-20), pozostaje tylko jedna funkcja, `transfer`. +Pozostawia to nam tylko dwie funkcje: `transfer` (ponieważ możemy wywołać `transferFrom`) i `faucet` (ponieważ możemy przelać tokeny z powrotem do tego, kto nas wywołał). + +```solidity + + // Wywołaj metody zmieniające stan tokena, używając + // informacji z calldata + + // faucet + if (_func == 1) { +``` + +Wywołanie `faucet()`, które nie ma parametrów. + +```solidity + token.faucet(); + token.transfer(msg.sender, + token.balanceOf(address(this))); + } +``` + +Po wywołaniu `token.faucet()` otrzymujemy tokeny. Jednak jako kontrakt proxy **nie potrzebujemy** tokenów. +Potrzebuje ich EOA (konto należące do podmiotu zewnętrznego) lub kontrakt, który nas wywołał. +Więc transferujemy wszystkie nasze tokeny do tego, kto nas wywołał. + +```solidity + // transfer (zakładamy, że mamy na to zgodę) + if (_func == 2) { +``` + +Przesyłanie tokenów wymaga dwóch parametrów: adresu docelowego i kwoty. + +```solidity + token.transferFrom( + msg.sender, +``` + +Zezwalamy wywołującym tylko na transfer posiadanych przez nich tokenów + +```solidity + address(uint160(calldataVal(1, 20))), +``` + +Adres docelowy zaczyna się od bajtu nr 1 (bajt nr 0 to funkcja). +Jako adres, ma długość 20 bajtów. + +```solidity + calldataVal(21, 2) +``` + +W przypadku tego konkretnego kontraktu zakładamy, że maksymalna liczba tokenów, jaką ktokolwiek chciałby przenieść, mieści się w dwóch bajtach (mniej niż 65536). + +```solidity + ); + } +``` + +Ogólnie rzecz biorąc, transfer zajmuje 35 bajtów calldata: + +| Sekcja | Długość | Bajty | +| ---------------- | ------: | ----: | +| Selektor funkcji | 1 | 0 | +| Adres docelowy | 32 | 1-32 | +| Kwota | 2 | 33-34 | + +```solidity + } // fallback + +} // kontrakt CalldataInterpreter +``` + +### test.js {#test-js} + +[Ten test jednostkowy JavaScript](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/test/test.js) pokazuje, jak używać tego mechanizmu (i jak zweryfikować jego prawidłowe działanie). +Zakładam, że rozumiesz [chai](https://www.chaijs.com/) i [ethers](https://docs.ethers.io/v5/) i wyjaśniam tylko te części, które dotyczą konkretnie kontraktu. + +```js +const { expect } = require("chai"); + +describe("CalldataInterpreter", function () { + it("Powinien pozwolić nam używać tokenów", async function () { + const Token = await ethers.getContractFactory("OrisUselessToken") + const token = await Token.deploy() + await token.deployed() + console.log("Adres tokena:", token.address) + + const Cdi = await ethers.getContractFactory("CalldataInterpreter") + const cdi = await Cdi.deploy(token.address) + await cdi.deployed() + console.log("Adres CalldataInterpreter:", cdi.address) + + const signer = await ethers.getSigner() +``` + +Zaczynamy od wdrożenia obu kontraktów. + +```javascript + // Pobierz tokeny do zabawy + const faucetTx = { +``` + +Nie możemy używać funkcji wysokiego poziomu, których normalnie byśmy użyli (takich jak `token.faucet()`) do tworzenia transakcji, ponieważ nie przestrzegamy ABI. +Zamiast tego musimy sami zbudować transakcję, a następnie ją wysłać. + +```javascript + to: cdi.address, + data: "0x01" +``` + +Istnieją dwa parametry, które musimy podać dla transakcji: + +1. `to`, adres docelowy. + To jest kontrakt interpretera calldata. +2. `data`, calldata do wysłania. + W przypadku wywołania `faucet`, danymi jest pojedynczy bajt, `0x01`. + +```javascript + + } + await (await signer.sendTransaction(faucetTx)).wait() +``` + +Wywołujemy [metodę `sendTransaction` sygnatariusza](https://docs.ethers.io/v5/api/signer/#Signer-sendTransaction), ponieważ już określiliśmy miejsce docelowe (`faucetTx.to`) i potrzebujemy, aby transakcja została podpisana. + +```javascript +// Sprawdź, czy faucet poprawnie dostarcza tokeny +expect(await token.balanceOf(signer.address)).to.equal(1000) +``` + +Tutaj weryfikujemy saldo. +Nie ma potrzeby oszczędzania gazu na funkcjach `view`, więc po prostu uruchamiamy je normalnie. + +```javascript +// Daj CDI upoważnienie (zatwierdzenia nie mogą być przekazywane przez proxy) +const approveTX = await token.approve(cdi.address, 10000) +await approveTX.wait() +expect(await token.allowance(signer.address, cdi.address)).to.equal(10000) +``` + +Daj interpreterowi calldata upoważnienie do wykonywania transferów. + +```javascript +// Transfer tokenów +const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" +const transferTx = { + to: cdi.address, + data: "0x02" + destAddr.slice(2, 42) + "0100", +} +``` + +Utwórz transakcję transferu. Pierwszy bajt to „0x02”, po nim następuje adres docelowy, a na końcu kwota (0x0100, co w systemie dziesiętnym daje 256). + +```javascript + await (await signer.sendTransaction(transferTx)).wait() + + // Sprawdź, czy mamy o 256 tokenów mniej + expect (await token.balanceOf(signer.address)).to.equal(1000-256) + + // I czy nasz cel je otrzymał + expect (await token.balanceOf(destAddr)).to.equal(256) + }) // it +}) // describe +``` + +## Zmniejszenie kosztów, gdy kontrolujesz kontrakt docelowy {#reducing-the-cost-when-you-do-control-the-destination-contract} + +Jeśli masz kontrolę nad kontraktem docelowym, możesz tworzyć funkcje, które omijają sprawdzanie `msg.sender`, ponieważ ufają interpreterowi calldata. +[Przykład działania można zobaczyć tutaj, w gałęzi `control-contract`](https://github.com/qbzzt/ethereum.org-20220330-shortABI/tree/control-contract). + +Gdyby kontrakt odpowiadał tylko na transakcje zewnętrzne, moglibyśmy sobie poradzić z jednym kontraktem. +Jednakże, złamałoby to [kompozycyjność](/developers/docs/smart-contracts/composability/). +O wiele lepiej jest mieć kontrakt, który odpowiada na normalne wywołania ERC-20, i inny kontrakt, który odpowiada na transakcje z krótkimi danymi wywołania. + +### Token.sol {#token-sol-2} + +W tym przykładzie możemy zmodyfikować `Token.sol`. +Pozwala to na posiadanie wielu funkcji, które może wywoływać tylko proxy. +Oto nowe części: + +```solidity + // Jedyny adres uprawniony do określenia adresu CalldataInterpreter + address owner; + + // Adres CalldataInterpreter + address proxy = address(0); +``` + +Kontrakt ERC-20 musi znać tożsamość autoryzowanego proxy. +Nie możemy jednak ustawić tej zmiennej w konstruktorze, ponieważ nie znamy jeszcze jej wartości. +Ten kontrakt jest tworzony jako pierwszy, ponieważ proxy oczekuje adresu tokena w swoim konstruktorze. + +```solidity + /** + * @dev Wywołuje konstruktor ERC20. + */ + constructor( + ) ERC20("Oris useless token-2", "OUT-2") { + owner = msg.sender; + } +``` + +Adres twórcy (o nazwie `owner`) jest tutaj przechowywany, ponieważ jest to jedyny adres uprawniony do ustawienia proxy. + +```solidity + /** + * @dev Ustawia adres dla proxy (CalldataInterpreter). + * Może być wywołane tylko raz przez właściciela + */ + function setProxy(address _proxy) external { + require(msg.sender == owner, "Może być wywołane tylko przez właściciela"); + require(proxy == address(0), "Proxy jest już ustawione"); + + proxy = _proxy; + } // funkcja setProxy +``` + +Proxy ma uprzywilejowany dostęp, ponieważ może omijać kontrole bezpieczeństwa. +Aby upewnić się, że możemy zaufać proxy, pozwalamy tylko `owner` na wywołanie tej funkcji, i to tylko raz. +Gdy `proxy` ma rzeczywistą wartość (niezerową), wartość ta nie może ulec zmianie, więc nawet jeśli właściciel zdecyduje się zbuntować lub jego mnemonik zostanie ujawniony, nadal jesteśmy bezpieczni. + +```solidity + /** + * @dev Niektóre funkcje mogą być wywoływane tylko przez proxy. + */ + modifier onlyProxy { +``` + +Jest to [funkcja `modifier`](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm), która modyfikuje działanie innych funkcji. + +```solidity + require(msg.sender == proxy); +``` + +Najpierw zweryfikuj, czy zostaliśmy wywołani przez proxy i nikogo innego. +Jeśli nie, `revert`. + +```solidity + _; + } +``` + +Jeśli tak, uruchom funkcję, którą modyfikujemy. + +```solidity + /* Funkcje, które pozwalają proxy na faktyczne pośredniczenie dla kont */ + + function transferProxy(address from, address to, uint256 amount) + public virtual onlyProxy() returns (bool) + { + _transfer(from, to, amount); + return true; + } + + function approveProxy(address from, address spender, uint256 amount) + public virtual onlyProxy() returns (bool) + { + _approve(from, spender, amount); + return true; + } + + function transferFromProxy( + address spender, + address from, + address to, + uint256 amount + ) public virtual onlyProxy() returns (bool) + { + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } +``` + +Są to trzy operacje, które normalnie wymagają, aby wiadomość pochodziła bezpośrednio od podmiotu transferującego tokeny lub zatwierdzającego upoważnienie. +Tutaj mamy wersję proxy tych operacji, która: + +1. Jest modyfikowana przez `onlyProxy()`, więc nikt inny nie może ich kontrolować. +2. Otrzymuje adres, który normalnie byłby `msg.sender` jako dodatkowy parametr. + +### CalldataInterpreter.sol {#calldatainterpreter-sol-2} + +Interpreter calldata jest prawie identyczny z powyższym, z wyjątkiem tego, że funkcje przekazywane przez proxy otrzymują parametr `msg.sender` i nie ma potrzeby posiadania upoważnienia do `transferu`. + +```solidity + // transfer (nie ma potrzeby posiadania upoważnienia) + if (_func == 2) { + token.transferProxy( + msg.sender, + address(uint160(calldataVal(1, 20))), + calldataVal(21, 2) + ); + } + + // zatwierdzenie + if (_func == 3) { + token.approveProxy( + msg.sender, + address(uint160(calldataVal(1, 20))), + calldataVal(21, 2) + ); + } + + // transferFrom + if (_func == 4) { + token.transferFromProxy( + msg.sender, + address(uint160(calldataVal( 1, 20))), + address(uint160(calldataVal(21, 20))), + calldataVal(41, 2) + ); + } +``` + +### Test.js {#test-js-2} + +Jest kilka zmian między poprzednim kodem testującym a tym. + +```js +const Cdi = await ethers.getContractFactory("CalldataInterpreter") +const cdi = await Cdi.deploy(token.address) +await cdi.deployed() +await token.setProxy(cdi.address) +``` + +Musimy poinformować kontrakt ERC-20, któremu proxy ma ufać + +```js +console.log("Adres CalldataInterpreter:", cdi.address) + +// Potrzebujemy dwóch sygnatariuszy do weryfikacji upoważnień +const signers = await ethers.getSigners() +const signer = signers[0] +const poorSigner = signers[1] +``` + +Aby sprawdzić `approve()` i `transferFrom()`, potrzebujemy drugiego sygnatariusza. +Nazywamy go `poorSigner`, ponieważ nie dostaje żadnych naszych tokenów (musi mieć oczywiście ETH). + +```js +// Transfer tokenów +const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" +const transferTx = { + to: cdi.address, + data: "0x02" + destAddr.slice(2, 42) + "0100", +} +await (await signer.sendTransaction(transferTx)).wait() +``` + +Ponieważ kontrakt ERC-20 ufa proxy (`cdi`), nie potrzebujemy upoważnienia do przekazywania transferów. + +```js +// zatwierdzenie i transferFrom +const approveTx = { + to: cdi.address, + data: "0x03" + poorSigner.address.slice(2, 42) + "00FF", +} +await (await signer.sendTransaction(approveTx)).wait() + +const destAddr2 = "0xE1165C689C0c3e9642cA7606F5287e708d846206" + +const transferFromTx = { + to: cdi.address, + data: "0x04" + signer.address.slice(2, 42) + destAddr2.slice(2, 42) + "00FF", +} +await (await poorSigner.sendTransaction(transferFromTx)).wait() + +// Sprawdź, czy kombinacja zatwierdzenia / transferFrom została wykonana poprawnie +expect(await token.balanceOf(destAddr2)).to.equal(255) +``` + +Przetestuj dwie nowe funkcje. +Zauważ, że `transferFromTx` wymaga dwóch parametrów adresu: dającego upoważnienie i odbiorcy. + +## Wnioski {#conclusion} + +Zarówno [Optimism](https://medium.com/ethereum-optimism/the-road-to-sub-dollar-transactions-part-2-compression-edition-6bb2890e3e92), jak i [Arbitrum](https://developer.offchainlabs.com/docs/special_features) szukają sposobów na zmniejszenie rozmiaru calldata zapisywanych w L1, a tym samym kosztów transakcji. +Jednak jako dostawcy infrastruktury poszukujący ogólnych rozwiązań, nasze możliwości są ograniczone. +Jako deweloper dApp, masz wiedzę specyficzną dla aplikacji, co pozwala na znacznie lepszą optymalizację calldata, niż moglibyśmy to zrobić w rozwiązaniu ogólnym. +Mamy nadzieję, że ten artykuł pomoże Ci znaleźć idealne rozwiązanie dla Twoich potrzeb. + +[Zobacz więcej mojej pracy tutaj](https://cryptodocguy.pro/). + diff --git a/public/content/translations/pl/developers/tutorials/smart-contract-security-guidelines/index.md b/public/content/translations/pl/developers/tutorials/smart-contract-security-guidelines/index.md index 62eec372652..f0d3396026b 100644 --- a/public/content/translations/pl/developers/tutorials/smart-contract-security-guidelines/index.md +++ b/public/content/translations/pl/developers/tutorials/smart-contract-security-guidelines/index.md @@ -1,21 +1,18 @@ --- -title: Wskazówki dotyczące bezpieczeństwa kontraktów inteligentnych -description: Lista kontrolna wytycznych bezpieczeństwa do rozważenia podczas tworzenia aplikacji zdecentralizowanych +title: "Wskazówki dotyczące bezpieczeństwa kontraktów inteligentnych" +description: "Lista kontrolna wytycznych bezpieczeństwa do rozważenia podczas tworzenia aplikacji zdecentralizowanych" author: "Trailofbits" -tags: - - "solidity" - - "inteligentne kontrakty" - - "ochrona" +tags: [ "solidity", "smart kontrakty", "bezpieczeństwo" ] skill: intermediate lang: pl published: 2020-09-06 -source: Tworzenie bezpiecznych kontraktów +source: Building secure contracts sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/development-guidelines/guidelines.md --- Postępuj zgodnie z tymi ogólnymi zaleceniami, aby tworzyć bezpieczniejsze inteligentne kontrakty. -## Wytyczne dotyczące projektowania {#design-guidelines} +## Wytyczne projektowe {#design-guidelines} Projekt kontraktu powinien być omówiony z wyprzedzeniem, przed napisaniem jakiejkolwiek linijki kodu. @@ -23,72 +20,72 @@ Projekt kontraktu powinien być omówiony z wyprzedzeniem, przed napisaniem jaki Dokumentacja może być pisana na różnych poziomach i powinna być aktualizowana w trakcie realizacji umów: -- **Prosty opis systemu w języku angielskim**, przedstawiający działanie kontraktów i wszelkie założenia dotyczące bazy kodu. -- **Diagramy schematów i architektury**, w tym interakcje kontraktów i maszyna stanu systemu. [Drukarki Slither](https://github.com/crytic/slither/wiki/Printer-documentation) mogą pomóc w wygenerowaniu tych schematów. -- **Dokładna dokumentacja kodu**, [format Natspec](https://solidity.readthedocs.io/en/develop/natspec-format.html) może być używany do Solidity. +- **Prosty opis systemu w języku angielskim**, opisujący działanie kontraktów i wszelkie założenia dotyczące bazy kodu. +- **Schematy i diagramy architektury**, w tym interakcje kontraktów i maszyna stanu systemu. [Slither printers](https://github.com/crytic/slither/wiki/Printer-documentation) mogą pomóc w generowaniu tych schematów. +- **Dokładna dokumentacja kodu**, dla Solidity można użyć [formatu Natspec](https://docs.soliditylang.org/en/develop/natspec-format.html). -### Obliczenia on-chain vs off-chain {#on-chain-vs-off-chain-computation} +### Obliczenia on-chain a off-chain {#onchain-vs-offchain-computation} -- **Zachowaj jak najwięcej kodu off-chain.** Zatrzymaj niewielką warstwę on-chain. Wstępnie przetwarzaj dane z kodem off-chain w taki sposób, aby weryfikacja on-chain była prosta. Potrzebujesz uporządkowanej listy? Posortuj listę off-chain, a następnie sprawdź tylko jej kolejność on-chain. +- **Jak najwięcej kodu trzymaj off-chain.** Utrzymuj jak najmniejszą warstwę on-chain. Wstępnie przetwarzaj dane za pomocą kodu off-chain w taki sposób, aby weryfikacja on-chain była prosta. Potrzebujesz uporządkowanej listy? Posortuj listę off-chain, a następnie sprawdź tylko jej kolejność on-chain. -### Możliwość uaktualnienia {#upgradeability} +### Możliwość aktualizacji {#upgradeability} -Omówiliśmy różne rozwiązania dotyczące możliwości uaktualnień w [poście na blogu](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). Dokonaj rozważnego wyboru, czy wspierać możliwość uaktualniania, czy nie, przed napisaniem jakiegokolwiek kodu. Decyzja wpłynie na sposób, w jaki ustrukturyzujesz kod. Generalnie zalecamy: +Omówiliśmy różne rozwiązania dotyczące możliwości aktualizacji w [naszym wpisie na blogu](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). Dokonaj rozważnego wyboru, czy wspierać możliwość uaktualniania, czy nie, przed napisaniem jakiegokolwiek kodu. Decyzja wpłynie na to, jak ustrukturyzujesz swój kod. Generalnie zalecamy: -- **Przedkładanie [migracji kontraktu](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) nad możliwość uaktualnienia.** System migracji ma wiele takich samych zalet, jak możliwość uaktualnienia, bez ich wad. -- **Używanie wzorca separacji danych zamiast wzorca delegatecalproxy.** Jeśli projekt ma wyraźną separację abstrakcji, możliwość uaktualnienia przy użyciu separacji danych będzie wymagać tylko kilku dostosowań. Delegatecallproxy wymaga wiedzy specjalistycznej o EVM i jest wysoce podatny na błędy. -- **Dokumentowanie procedury migracji/uaktualnienia przed wdrożeniem.** Jeśli będziesz musiał reagować w stresie bez żadnych wytycznych, popełnisz błędy. Zapisz procedurę do wykonania z wyprzedzeniem. Powinna ona obejmować: +- **Preferowanie [migracji kontraktów](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) zamiast możliwości aktualizacji.** Systemy migracji mają wiele tych samych zalet co systemy z możliwością aktualizacji, a przy tym są pozbawione ich wad. +- **Stosowanie wzorca separacji danych zamiast wzorca delegatecallproxy.** Jeśli Twój projekt ma wyraźną separację abstrakcji, możliwość aktualizacji z wykorzystaniem separacji danych będzie wymagać tylko kilku dostosowań. Delegatecallproxy wymaga wiedzy specjalistycznej o EVM i jest wysoce podatny na błędy. +- **Udokumentuj procedurę migracji/aktualizacji przed wdrożeniem.** Jeśli będziesz musiał(a) reagować w stresie bez żadnych wytycznych, popełnisz błędy. Zapisz procedurę do wykonania z wyprzedzeniem. Powinna ona obejmować: - Wywołania inicjujące nowe kontrakty - Gdzie są przechowywane klucze i jak uzyskać dostęp do nich - Jak sprawdzić wdrożenie! Opracowanie i przetestowanie skryptu po wdrożeniu. -## Wytyczne dotyczące wdrażania {#implementation-guidelines} +## Wytyczne dotyczące implementacji {#implementation-guidelines} -**Poszukaj prostoty.** Zawsze używaj najprostszego rozwiązania, które pasuje do Twojego celu. Każdy członek twojego zespołu powinien być w stanie zrozumieć Twoje rozwiązanie. +**Dąż do prostoty.** Zawsze używaj najprostszego rozwiązania, które odpowiada Twoim celom. Każdy członek twojego zespołu powinien być w stanie zrozumieć Twoje rozwiązanie. -### Skład funkcji {#function-composition} +### Składanie funkcji {#function-composition} Architektura Twojej bazy kodu powinna ułatwić sprawdzenie twojego kodu. Unikaj wyborów architektonicznych, które zmniejszają zdolność rozumowania o jego poprawności. -- **Podziel logikę swojego systemu** poprzez wiele umów lub grupowanie podobnych funkcji (na przykład uwierzytelniające, arytmetyczne, ...). -- **Pisz małe funkcje o wyraźnym celu celu.** To ułatwi sprawdzenie i umożliwi testowanie poszczególnych komponentów. +- **Podziel logikę swojego systemu** na wiele kontraktów lub grupuj podobne funkcje (np. uwierzytelnianie, arytmetyka itp.). +- **Pisz małe funkcje o jasno określonym celu.** Ułatwi to przegląd i pozwoli na testowanie poszczególnych komponentów. ### Dziedziczenie {#inheritance} -- **Zachowaj dziedziczenie do zarządzania.** Dziedzictwo powinno być używane do dzielenia logiki, jednak Twój projekt powinien mieć na celu zminimalizowanie głębokości i szerokości drzewa dziedziczenia. -- **Użyj [drukarki dziedziczenia Slither'a](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph), aby sprawdzić hierarchię kontraktów.** Drukarka dziedziczenia pomoże Ci sprawdzić rozmiar hierarchii. +- **Utrzymuj dziedziczenie na łatwym do zarządzania poziomie.** Dziedziczenie powinno służyć do podziału logiki, jednak projekt powinien dążyć do zminimalizowania głębokości i szerokości drzewa dziedziczenia. +- **Użyj [inheritance printer](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) Slithera, aby sprawdzić hierarchię kontraktów.** Narzędzie to pomoże Ci przeanalizować rozmiar hierarchii. ### Zdarzenia {#events} -- **Rejestruj wszystkie kluczowe operacje.** Zdarzenia pomogą debugować kontrakt podczas jego oprawcowywania i będą go monitorować po wdrożeniu. +- **Rejestruj wszystkie kluczowe operacje.** Zdarzenia pomogą w debugowaniu kontraktu podczas jego tworzenia i monitorowaniu go po wdrożeniu. -### Unikanie znanych pułapek {#avoid-known-pitfalls} +### Unikaj znanych pułapek {#avoid-known-pitfalls} -- **Bądź świadomy najczęstszych problemów z bezpieczeństwem.** Istnieje wiele zasobów online do poznania wspólnych problemów, takich jak [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Zajmij Ether](https://capturetheether.com/)lub [Nie tak inteligentne kontrakty](https://github.com/crytic/not-so-smart-contracts/). -- **Zwróć uwagę na sekcje ostrzeżeń w [dokumentacji Solidity](https://solidity.readthedocs.io/en/latest/).** Sekcje z ostrzeżeniami poinformują Cię o nieoczywistym zachowaniu języka. +- **Bądź świadomy(-a) najczęstszych problemów z bezpieczeństwem.** Istnieje wiele zasobów online, z których można dowiedzieć się o powszechnych problemach, takich jak [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Capture the Ether](https://capturetheether.com/) lub [Not so smart contracts](https://github.com/crytic/not-so-smart-contracts/). +- **Zwróć uwagę na sekcje z ostrzeżeniami w [dokumentacji Solidity](https://docs.soliditylang.org/en/latest/).** Sekcje z ostrzeżeniami poinformują Cię o nieoczywistym zachowaniu języka. ### Zależności {#dependencies} - **Używaj dobrze przetestowanych bibliotek.** Importowanie kodu z dobrze przetestowanych bibliotek zmniejszy prawdopodobieństwo, że napiszesz kod z błędami. Jeśli chcesz napisać kontrakt ERC20, użyj [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). -- **Użyj menedżera zależności; unikaj kopiowania kodu.** Jeśli opierasz się na źródle zewnętrznym, musisz na bieżąco aktualizować je w stosunku do źródła oryginalnego. +- **Używaj menedżera zależności; unikaj kopiowania kodu.** Jeśli polegasz na zewnętrznym źródle, musisz je na bieżąco aktualizować zgodnie z oryginalnym źródłem. -### Testy i weryfikacja {#testing-and-verification} +### Testowanie i weryfikacja {#testing-and-verification} -- **Zapisz dokładne testy jednostkowe.** Rozległy zestaw testowy ma kluczowe znaczenie dla budowy oprogramowania wysokiej jakości. -- **Napisz niestandardowe kontrole i właściwości dla narzędzi [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) i [Manticore](https://github.com/trailofbits/manticore).** Automatyczne narzędzia pomogą zapewnić bezpieczeństwo umowy. Przejrzyj resztę tego przewodnika, aby dowiedzieć się, jak pisać skuteczne kontrole i właściwości. -- **Użyj [crytic.io](https://crytic.io/).** Crytic integruje się z Githubem, zapewnia dostęp do prywatnych detektorów Slither, i uruchamia niestandardowe kontrole właściwości z Echidny. +- **Pisz dokładne testy jednostkowe.** Rozbudowany pakiet testów ma kluczowe znaczenie dla tworzenia oprogramowania wysokiej jakości. +- **Pisz niestandardowe testy i właściwości dla narzędzi [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) i [Manticore](https://github.com/trailofbits/manticore).** Zautomatyzowane narzędzia pomogą zapewnić bezpieczeństwo Twojego kontraktu. Przejrzyj resztę tego przewodnika, aby dowiedzieć się, jak pisać skuteczne kontrole i właściwości. +- **Użyj [crytic.io](https://crytic.io/).** Crytic integruje się z GitHubem, zapewnia dostęp do prywatnych detektorów Slither i uruchamia niestandardowe testy właściwości z Echidny. ### Solidity {#solidity} -- **Favor Solidity 0.5 ponad 0.4 i 0.6.** Naszym zdaniem Solidity 0.5 jest bezpieczniejszy i ma lepsze wbudowane praktyki niż 0.4. Solidity 0.6 okazała się zbyt niestabilna do produkcji i wymaga czasu, aby dojrzeć. -- **Użyj stabilnej wersji do kompilacji; użyj najnowszej wersji, aby sprawdzić ostrzeżenia.** Sprawdź, czy Twój kod nie ma zgłoszonych problemów z najnowszą wersją kompilatora. Solidity ma jednak szybki cykl wydawniczy i ma historię błędów kompilatora, więc nie zalecamy wdrażania najnowszej wersji (zobacz [zalecenie wersji Solc](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33)). -- **Nie używaj wbudowanego asemblera.** Asemblacja wymaga wiedzy fachowej na temat EVM. Nie pisz kodu EVM, jeśli nie _opanowałeś_ żółtej księgi. +- **Preferuj Solidity 0.5 zamiast 0.4 i 0.6.** Naszym zdaniem Solidity 0.5 jest bezpieczniejszy i ma lepsze wbudowane praktyki niż 0.4. Solidity 0.6 okazała się zbyt niestabilna do produkcji i wymaga czasu, aby dojrzeć. +- **Użyj stabilnej wersji do kompilacji; użyj najnowszej wersji, aby sprawdzić ostrzeżenia.** Sprawdź, czy Twój kod nie ma zgłoszonych problemów z najnowszą wersją kompilatora. Jednakże Solidity ma szybki cykl wydawniczy i historię błędów kompilatora, dlatego nie zalecamy najnowszej wersji do wdrożenia (zobacz [rekomendację wersji solc od Slithera](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33)). +- **Nie używaj asemblera wstawkowego.** Używanie asemblera wymaga specjalistycznej wiedzy na temat EVM. Nie pisz kodu EVM, jeśli nie _opanowałeś(-aś)_ do perfekcji żółtej księgi. ## Wytyczne dotyczące wdrażania {#deployment-guidelines} Po opracowaniu i wdrożeniu kontraktu: -- **Monitoruj swoje kontrakty.** Obserwuj dzienniki i bądź gotowy do reagowania w przypadku naruszenia kontraktu lub portfela. -- **Dodaj swoje dane kontaktowe do [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** Ta lista pomaga firmom zewnętrznym skontaktować się z Tobą w przypadku wykrycia luki w zabezpieczeniach. +- **Monitoruj swoje kontrakty.** Obserwuj logi i bądź gotów(-owa) do reakcji w przypadku naruszenia bezpieczeństwa kontraktu lub portfela. +- **Dodaj swoje dane kontaktowe do [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** Ta lista pomaga stronom trzecim skontaktować się z Tobą w przypadku odkrycia luki w zabezpieczeniach. - **Zabezpiecz portfele uprzywilejowanych użytkowników.** Postępuj zgodnie z naszymi [najlepszymi praktykami](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/), jeśli przechowujesz klucze w portfelach sprzętowych. -- **Opracuj plan reakcji na incydent.** Weź pod uwagę, że Twoje inteligentne kontrakty mogą zostać naruszone. Nawet jeśli twoje kontrakty są wolne od błędów, atakujący może przejąć kontrolę nad kluczami właściciela umowy. +- **Opracuj plan reakcji na incydenty.** Weź pod uwagę, że Twoje inteligentne kontrakty mogą zostać naruszone. Nawet jeśli twoje kontrakty są wolne od błędów, atakujący może przejąć kontrolę nad kluczami właściciela umowy. diff --git a/public/content/translations/pl/developers/tutorials/stealth-addr/index.md b/public/content/translations/pl/developers/tutorials/stealth-addr/index.md new file mode 100644 index 00000000000..7b341dc5cf0 --- /dev/null +++ b/public/content/translations/pl/developers/tutorials/stealth-addr/index.md @@ -0,0 +1,443 @@ +--- +title: "Korzystanie z ukrytych adresów" +description: "Ukryte adresy pozwalają użytkownikom na anonimowe przesyłanie aktywów. Po przeczytaniu tego artykułu będziesz w stanie: wyjaśnić, czym są ukryte adresy i jak działają, zrozumieć, jak używać ukrytych adresów w sposób zachowujący anonimowość, oraz napisać aplikację internetową, która używa ukrytych adresów." +author: Ori Pomerantz +tags: + [ + "Ukryty adres", + "prywatność", + "kryptografia", + "rust", + "wasm" + ] +skill: intermediate +published: 2025-11-30 +lang: pl +sidebarDepth: 3 +--- + +Jesteś Billem. Z powodów, których nie będziemy tu omawiać, chcesz przekazać darowiznę na kampanię „Alicja na królową świata” i chcesz, aby Alicja wiedziała, że to Ty przekazałeś darowiznę, aby mogła Cię nagrodzić, jeśli wygra. Niestety, jej zwycięstwo nie jest gwarantowane. Istnieje konkurencyjna kampania „Karolina na cesarzową Układu Słonecznego”. Jeśli Karolina wygra i dowie się, że wsparłeś Alicję, będziesz w kłopotach. Więc nie możesz po prostu przelać 200 ETH ze swojego konta na konto Alicji. + +Rozwiązaniem jest [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564). Ten ERC wyjaśnia, jak używać [ukrytych adresów](https://nerolation.github.io/stealth-utils) do anonimowych transferów. + +**Ostrzeżenie**: Kryptografia stojąca za ukrytymi adresami jest, o ile nam wiadomo, solidna. Istnieją jednak potencjalne ataki typu side-channel. [Poniżej](#go-wrong) zobaczysz, co możesz zrobić, aby zmniejszyć to ryzyko. + +## Jak działają ukryte adresy {#how} + +Ten artykuł spróbuje wyjaśnić działanie ukrytych adresów na dwa sposoby. Pierwszy to [jak z nich korzystać](#how-use). Ta część jest wystarczająca do zrozumienia reszty artykułu. Następnie znajduje się [wyjaśnienie matematyki stojącej za tym mechanizmem](#how-math). Jeśli interesujesz się kryptografią, przeczytaj również tę część. + +### Wersja prosta (jak używać ukrytych adresów) {#how-use} + +Alicja tworzy dwa klucze prywatne i publikuje odpowiadające im klucze publiczne (które można połączyć w jeden meta-adres o podwójnej długości). Bill również tworzy klucz prywatny i publikuje odpowiadający mu klucz publiczny. + +Używając klucza publicznego jednej strony i klucza prywatnego drugiej, można uzyskać wspólny sekret znany tylko Alicji i Billowi (nie można go uzyskać z samych kluczy publicznych). Używając tego wspólnego sekretu, Bill uzyskuje ukryty adres i może na niego wysyłać aktywa. + +Alicja również uzyskuje adres ze wspólnego sekretu, ale ponieważ zna klucze prywatne do opublikowanych przez siebie kluczy publicznych, może również uzyskać klucz prywatny, który pozwala jej wypłacić środki z tego adresu. + +### Matematyka (dlaczego ukryte adresy działają w ten sposób) {#how-math} + +Standardowe ukryte adresy używają [kryptografii krzywych eliptycznych (ECC)](https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/#elliptic-curves-building-blocks-of-a-better-trapdoor), aby uzyskać lepszą wydajność przy mniejszej liczbie bitów klucza, zachowując jednocześnie ten sam poziom bezpieczeństwa. Jednak w większości możemy to zignorować i udawać, że używamy zwykłej arytmetyki. + +Istnieje liczba, którą wszyscy znają, _G_. Można mnożyć przez _G_. Ale ze względu na naturę ECC, praktycznie niemożliwe jest dzielenie przez _G_. Sposób, w jaki ogólnie działa kryptografia klucza publicznego w Ethereum, polega na tym, że można użyć klucza prywatnego, _Ppriv_, do podpisywania transakcji, które są następnie weryfikowane przez klucz publiczny, _Ppub = GPpriv_. + +Alicja tworzy dwa klucze prywatne, _Kpriv_ i _Vpriv_. _Kpriv_ będzie używany do wydawania pieniędzy z ukrytego adresu, a _Vpriv_ do przeglądania adresów należących do Alicji. Alicja następnie publikuje klucze publiczne: _Kpub = GKpriv_ i _Vpub = GVpriv_ + +Bill tworzy trzeci klucz prywatny, _Rpriv_, i publikuje _Rpub = GRpriv_ w centralnym rejestrze (Bill mógłby również wysłać go do Alicji, ale zakładamy, że Karolina podsłuchuje). + +Bill oblicza _RprivVpub = GRprivVpriv_, co, jak oczekuje, Alicja również zna (wyjaśniono poniżej). Ta wartość nazywana jest _S_, wspólnym sekretem. Daje to Billowi klucz publiczny, _Ppub = Kpub+G\*hasz(S)_. Na podstawie tego klucza publicznego może obliczyć adres i wysłać na niego dowolne zasoby. W przyszłości, jeśli Alicja wygra, Bill może podać jej _Rpriv_, aby udowodnić, że zasoby pochodzą od niego. + +Alicja oblicza _RpubVpriv = GRprivVpriv_. Daje jej to ten sam wspólny sekret, _S_. Ponieważ zna klucz prywatny, _Kpriv_, może obliczyć _Ppriv = Kpriv+hasz(S)_. Ten klucz pozwala jej na dostęp do aktywów pod adresem wynikającym z _Ppub = GPpriv = GKpriv+G\*hasz(S) = Kpub+G\*hasz(S)_. + +Mamy oddzielny klucz do przeglądania, aby umożliwić Alicji zlecenie usług firmie Dave's World Domination Campaign Services. Alicja jest skłonna pozwolić Dave'owi poznać adresy publiczne i informować ją, gdy dostępne będą kolejne pieniądze, ale nie chce, aby wydawał on pieniądze z jej kampanii. + +Ponieważ przeglądanie i wydawanie używają oddzielnych kluczy, Alicja może dać Dave'owi _Vpriv_. Wtedy Dave może obliczyć _S = RpubVpriv = GRprivVpriv_ i w ten sposób uzyskać klucze publiczne (_Ppub = Kpub+G\*hasz(S)_). Ale bez _Kpriv_ Dave nie może uzyskać klucza prywatnego. + +Podsumowując, oto wartości znane przez różnych uczestników. + +| Alicja | Opublikowane | Bill | Dave | | +| ------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------- | +| G | G | G | G | | +| _Kpriv_ | – | – | – | | +| _Vpriv_ | – | – | _Vpriv_ | | +| _Kpub = GKpriv_ | _Kpub_ | _Kpub_ | _Kpub_ | | +| _Vpub = GVpriv_ | _Vpub_ | _Vpub_ | _Vpub_ | | +| – | – | _Rpriv_ | – | | +| _Rpub_ | _Rpub_ | _Rpub = GRpriv_ | _Rpub_ | | +| _S = RpubVpriv = GRprivVpriv_ | – | _S = RprivVpub = GRprivVpriv_ | _S = _RpubVpriv_ = GRprivVpriv_ | | +| _Ppub = Kpub+G\*hasz(S)_ | – | _Ppub = Kpub+G\*hasz(S)_ | _Ppub = Kpub+G\*hasz(S)_ | | +| _Adres=f(Ppub)_ | – | _Adres=f(Ppub)_ | _Adres=f(Ppub)_ | _Adres=f(Ppub)_ | +| _Ppriv = Kpriv+hasz(S)_ | – | – | – | | + +## Kiedy ukryte adresy zawodzą {#go-wrong} + +_Na blockchainie nie ma żadnych tajemnic_. Chociaż ukryte adresy mogą zapewnić Ci prywatność, jest ona podatna na analizę ruchu. Jako trywialny przykład wyobraź sobie, że Bill zasila adres i natychmiast wysyła transakcję w celu opublikowania wartości _Rpub_. Bez _Vpriv_ Alicji nie możemy być pewni, że jest to ukryty adres, ale tak należy zakładać. Następnie widzimy inną transakcję, która przenosi całe ETH z tego adresu na adres funduszu kampanii Alicji. Możemy nie być w stanie tego udowodnić, ale jest prawdopodobne, że Bill właśnie przekazał darowiznę na kampanię Alicji. Karolina z pewnością by tak pomyślała. + +Bill może łatwo oddzielić publikację _Rpub_ od zasilenia ukrytego adresu (wykonać je w różnym czasie, z różnych adresów). To jednak nie wystarczy. Wzorzec, którego szuka Karolina, polega na tym, że Bill zasila adres, a następnie fundusz kampanii Alicji wypłaca z niego środki. + +Jednym z rozwiązań jest to, aby kampania Alicji nie wypłacała pieniędzy bezpośrednio, ale używała ich do zapłaty stronie trzeciej. Jeśli kampania Alicji wyśle 10 ETH do Dave's World Domination Campaign Services, Karolina będzie wiedziała tylko, że Bill przekazał darowiznę jednemu z klientów Dave'a. Jeśli Dave ma wystarczającą liczbę klientów, Karolina nie będzie w stanie stwierdzić, czy Bill przekazał darowiznę Alicji, która z nią konkuruje, czy Adamowi, Albertowi lub Abigail, na których Karolinie nie zależy. Alicja może dołączyć do płatności zahaszowaną wartość, a następnie dostarczyć Dave'owi jej preobraz, aby udowodnić, że była to jej darowizna. Alternatywnie, jak wspomniano powyżej, jeśli Alicja da Dave'owi swoje _Vpriv_, on już wie, od kogo pochodzi płatność. + +Głównym problemem tego rozwiązania jest to, że wymaga ono od Alicji dbania o tajemnicę, gdy ta tajemnica przynosi korzyści Billowi. Alicja może chcieć utrzymać swoją reputację, aby przyjaciel Billa, Bob, również przekazał jej darowiznę. Ale możliwe jest również, że nie będzie jej przeszkadzało zdemaskowanie Billa, ponieważ wtedy będzie się on bał, co się stanie, jeśli Karolina wygra. Bill może w końcu udzielić Alicji jeszcze większego wsparcia. + +### Używanie wielu warstw ukrytych {#multi-layer} + +Zamiast polegać na Alicji w kwestii zachowania prywatności Billa, Bill może zrobić to sam. Może wygenerować wiele meta-adresów dla fikcyjnych osób, Boba i Belli. Następnie Bill wysyła ETH do Boba, a „Bob” (który w rzeczywistości jest Billem) wysyła je do Belli. „Bella” (również Bill) wysyła je do Alicji. + +Karolina wciąż może przeprowadzić analizę ruchu i zobaczyć potok od Billa do Boba, do Belli, do Alicji. Jednakże, jeśli „Bob” i „Bella” również używają ETH do innych celów, nie będzie wyglądało na to, że Bill przekazał cokolwiek Alicji, nawet jeśli Alicja natychmiast wypłaci środki z ukrytego adresu na swój znany adres kampanii. + +## Pisanie aplikacji z ukrytymi adresami {#write-app} + +Ten artykuł wyjaśnia aplikację z ukrytymi adresami [dostępną na GitHub](https://github.com/qbzzt/251022-stealth-addresses.git). + +### Narzędzia {#tools} + +Istnieje [biblioteka ukrytych adresów w TypeScript](https://github.com/ScopeLift/stealth-address-sdk), której moglibyśmy użyć. Jednak operacje kryptograficzne mogą być intensywne dla procesora. Wolę je implementować w języku kompilowanym, takim jak [Rust](https://rust-lang.org/), i używać [WASM](https://webassembly.org/) do uruchamiania kodu w przeglądarce. + +Będziemy używać [Vite](https://vite.dev/) i [React](https://react.dev/). Są to standardowe narzędzia branżowe; jeśli ich nie znasz, możesz skorzystać z [tego samouczka](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/). Aby używać Vite, potrzebujemy Node. + +### Zobacz ukryte adresy w akcji {#in-action} + +1. Zainstaluj niezbędne narzędzia: [Rust](https://rust-lang.org/tools/install/) i [Node](https://nodejs.org/en/download). + +2. Sklonuj repozytorium GitHub. + + ```sh + git clone https://github.com/qbzzt/251022-stealth-addresses.git + cd 251022-stealth-addresses + ``` + +3. Zainstaluj wymagania wstępne i skompiluj kod Rust. + + ```sh + cd src/rust-wasm + rustup target add wasm32-unknown-unknown + cargo install wasm-pack + wasm-pack build --target web + ``` + +4. Uruchom serwer WWW. + + ```sh + cd ../.. + npm install + npm run dev + ``` + +5. Przejdź do [aplikacji](http://localhost:5173/). Ta strona aplikacji ma dwie ramki: jedną dla interfejsu użytkownika Alicji, a drugą dla Billa. Te dwie ramki nie komunikują się ze sobą; znajdują się na tej samej stronie tylko dla wygody. + +6. Jako Alicja kliknij **Wygeneruj ukryty meta-adres**. Wyświetli to nowy ukryty adres i odpowiadające mu klucze prywatne. Skopiuj ukryty meta-adres do schowka. + +7. Jako Bill, wklej nowy ukryty meta-adres i kliknij **Wygeneruj adres**. Otrzymasz adres do zasilenia dla Alicji. + +8. Skopiuj adres i klucz publiczny Billa i wklej je w polu „Klucz prywatny dla adresu wygenerowanego przez Billa” w interfejsie użytkownika Alicji. Po wypełnieniu tych pól zobaczysz klucz prywatny umożliwiający dostęp do aktywów pod tym adresem. + +9. Możesz użyć [kalkulatora online](https://iancoleman.net/ethereum-private-key-to-address/), aby upewnić się, że klucz prywatny odpowiada adresowi. + +### Jak działa program {#how-the-program-works} + +#### Komponent WASM {#wasm} + +Kod źródłowy, który kompiluje się do WASM, jest napisany w języku [Rust](https://rust-lang.org/). Możesz go zobaczyć w [`src/rust_wasm/src/lib.rs`](https://github.com/qbzzt/251022-stealth-addresses/blob/main/src/rust-wasm/src/lib.rs). Ten kod jest przede wszystkim interfejsem między kodem JavaScript a [biblioteką `eth-stealth-addresses`](https://github.com/kassandraoftroy/eth-stealth-addresses). + +**`Cargo.toml`** + +[`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html) w Rust jest analogiczny do [`package.json`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) w JavaScript. Zawiera informacje o pakiecie, deklaracje zależności itp. + +```toml +[package] +name = "rust-wasm" +version = "0.1.0" +edition = "2024" + +[dependencies] +eth-stealth-addresses = "0.1.0" +hex = "0.4.3" +wasm-bindgen = "0.2.104" +getrandom = { version = "0.2", features = ["js"] } +``` + +Pakiet [`getrandom`](https://docs.rs/getrandom/latest/getrandom/) musi generować wartości losowe. Nie można tego zrobić czysto algorytmicznymi środkami; wymaga to dostępu do procesu fizycznego jako źródła entropii. Ta definicja określa, że uzyskamy tę entropię, pytając przeglądarkę, w której działamy. + +```toml +console_error_panic_hook = "0.1.7" +``` + +[Ta biblioteka](https://docs.rs/console_error_panic_hook/latest/console_error_panic_hook/) dostarcza nam bardziej znaczących komunikatów o błędach, gdy kod WASM wpadnie w panikę i nie może kontynuować. + +```toml +[lib] +crate-type = ["cdylib", "rlib"] +``` + +Typ wyjściowy wymagany do wyprodukowania kodu WASM. + +**`lib.rs`** + +To jest właściwy kod Rust. + +```rust +use wasm_bindgen::prelude::*; +``` + +Definicje do stworzenia pakietu WASM z Rusta. Są one udokumentowane [tutaj](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/index.html). + +```rust +use eth_stealth_addresses::{ + generate_stealth_meta_address, + generate_stealth_address, + compute_stealth_key +}; +``` + +Funkcje, których potrzebujemy z [biblioteki `eth-stealth-addresses`](https://github.com/kassandraoftroy/eth-stealth-addresses). + +```rust +use hex::{decode,encode}; +``` + +Rust zazwyczaj używa tablic bajtów ([arrays](https://doc.rust-lang.org/std/primitive.array.html)) (`[u8; ]`) dla wartości. Ale w JavaScript zazwyczaj używamy ciągów szesnastkowych. [Biblioteka `hex`](https://docs.rs/hex/latest/hex/) tłumaczy dla nas z jednej reprezentacji na drugą. + +```rust +#[wasm_bindgen] +``` + +Generuj powiązania WASM, aby móc wywołać tę funkcję z JavaScript. + +```rust +pub fn wasm_generate_stealth_meta_address() -> String { +``` + +Najprostszym sposobem na zwrócenie obiektu z wieloma polami jest zwrócenie ciągu znaków JSON. + +```rust + let (address, spend_private_key, view_private_key) = + generate_stealth_meta_address(); +``` + +Funkcja [`generate_stealth_meta_address`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.generate_stealth_meta_address.html) zwraca trzy pola: + +- Meta-adres (_Kpub_ i _Vpub_) +- Klucz prywatny do przeglądania (_Vpriv_) +- Klucz prywatny do wydawania (_Kpriv_) + +Składnia [tupli](https://doc.rust-lang.org/std/primitive.tuple.html) pozwala nam ponownie rozdzielić te wartości. + +```rust + format!("{{\"address\":\"{}\",\"view_private_key\":\"{}\",\"spend_private_key\":\"{}\"}}", + encode(address), + encode(view_private_key), + encode(spend_private_key) + ) +} +``` + +Użyj makra [`format!`](https://doc.rust-lang.org/std/fmt/index.html), aby wygenerować ciąg znaków w formacie JSON. Użyj [`hex::encode`](https://docs.rs/hex/latest/hex/fn.encode.html), aby zamienić tablice na ciągi szesnastkowe. + +```rust +fn str_to_array(s: &str) -> Option<[u8; N]> { +``` + +Ta funkcja zamienia ciąg szesnastkowy (dostarczony przez JavaScript) na tablicę bajtów. Używamy jej do parsowania wartości dostarczonych przez kod JavaScript. Ta funkcja jest skomplikowana ze względu na sposób, w jaki Rust obsługuje tablice i wektory. + +Wyrażenie `` nazywane jest [generykiem](https://doc.rust-lang.org/book/ch10-01-syntax.html). `N` jest parametrem, który kontroluje długość zwracanej tablicy. Funkcja jest w rzeczywistości wywoływana jako `str_to_array::`, gdzie `n` to długość tablicy. + +Wartość zwracana to `Option<[u8; N]>`, co oznacza, że zwracana tablica jest [opcjonalna](https://doc.rust-lang.org/std/option/). Jest to typowy wzorzec w Rust dla funkcji, które mogą zakończyć się niepowodzeniem. + +Na przykład, jeśli wywołamy `str_to_array::10("bad060a7")`, funkcja ma zwrócić tablicę dziesięciu wartości, ale dane wejściowe mają tylko cztery bajty. Funkcja musi zakończyć się niepowodzeniem i robi to, zwracając `None`. Wartością zwrotną dla `str_to_array::4("bad060a7")` byłoby `Some<[0xba, 0xd0, 0x60, 0xa7]>`. + +```rust + // decode returns Result, _> + let vec = decode(s).ok()?; +``` + +Funkcja [`hex::decode`](https://docs.rs/hex/latest/hex/fn.decode.html) zwraca `Result, FromHexError>`. Typ [`Result`](https://doc.rust-lang.org/std/result/) może zawierać pomyślny wynik (`Ok(value)`) lub błąd (`Err(error)`). + +Metoda `.ok()` zamienia `Result` na `Option`, której wartością jest albo wartość `Ok()`, jeśli operacja się powiedzie, albo `None`, jeśli nie. Na koniec, [operator znaku zapytania](https://doc.rust-lang.org/std/option/#the-question-mark-operator-) przerywa bieżącą funkcję i zwraca `None`, jeśli `Option` jest puste. W przeciwnym razie odpakowuje wartość i zwraca ją (w tym przypadku, aby przypisać wartość do `vec`). + +Wygląda to na dziwnie zawiłą metodę obsługi błędów, ale `Result` i `Option` zapewniają, że wszystkie błędy są obsługiwane, w ten czy inny sposób. + +```rust + if vec.len() != N { return None; } +``` + +Jeśli liczba bajtów jest nieprawidłowa, jest to błąd i zwracamy `None`. + +```rust + // try_into consumes vec and attempts to make [u8; N] + let array: [u8; N] = vec.try_into().ok()?; +``` + +Rust ma dwa typy tablic. [Tablice](https://doc.rust-lang.org/std/primitive.array.html) mają stały rozmiar. [Wektory](https://doc.rust-lang.org/std/vec/index.html) mogą rosnąć i maleć. `hex::decode` zwraca wektor, ale biblioteka `eth_stealth_addresses` chce otrzymywać tablice. [`.try_into()`](https://doc.rust-lang.org/std/convert/trait.TryInto.html#required-methods) konwertuje wartość na inny typ, na przykład wektor na tablicę. + +```rust + Some(array) +} +``` + +Rust nie wymaga użycia słowa kluczowego [`return`](https://doc.rust-lang.org/std/keyword.return.html) przy zwracaniu wartości na końcu funkcji. + +```rust +#[wasm_bindgen] +pub fn wasm_generate_stealth_address(stealth_address: &str) -> Option { +``` + +Ta funkcja otrzymuje publiczny meta-adres, który zawiera zarówno _Vpub_, jak i _Kpub_. Zwraca ukryty adres, klucz publiczny do opublikowania (_Rpub_) oraz jednobajtową wartość skanowania, która przyspiesza identyfikację, które opublikowane adresy mogą należeć do Alicji. + +Wartość skanowania jest częścią wspólnego sekretu (_S = GRprivVpriv_). Ta wartość jest dostępna dla Alicji, a jej sprawdzenie jest znacznie szybsze niż sprawdzenie, czy _f(Kpub+G\*hasz(S))_ jest równe opublikowanemu adresowi. + +```rust + let (address, r_pub, scan) = + generate_stealth_address(&str_to_array::<66>(stealth_address)?); +``` + +Używamy biblioteki [`generate_stealth_address`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.generate_stealth_address.html). + +```rust + format!("{{\"address\":\"{}\",\"rPub\":\"{}\",\"scan\":\"{}\"}}", + encode(address), + encode(r_pub), + encode(&[scan]) + ).into() +} +``` + +Przygotuj ciąg wyjściowy zakodowany w formacie JSON. + +```rust +#[wasm_bindgen] +pub fn wasm_compute_stealth_key( + address: &str, + bill_pub_key: &str, + view_private_key: &str, + spend_private_key: &str +) -> Option { + . + . + . +} +``` + +Ta funkcja używa biblioteki [`compute_stealth_key`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.compute_stealth_key.html) do obliczenia klucza prywatnego do wypłaty z adresu (_Rpriv_). To obliczenie wymaga następujących wartości: + +- Adres (_Adres=f(Ppub)_) +- Klucz publiczny wygenerowany przez Billa (_Rpub_) +- Klucz prywatny do przeglądania (_Vpriv_) +- Klucz prywatny do wydawania (_Kpriv_) + +```rust +#[wasm_bindgen(start)] +``` + +[`#[wasm_bindgen(start)]`](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-rust-exports/start.html) określa, że funkcja jest wykonywana po zainicjowaniu kodu WASM. + +```rust +pub fn main() { + console_error_panic_hook::set_once(); +} +``` + +Ten kod określa, że dane wyjściowe paniki są wysyłane do konsoli JavaScript. Aby zobaczyć to w działaniu, użyj aplikacji i podaj Billowi nieprawidłowy meta-adres (wystarczy zmienić jedną cyfrę szesnastkową). W konsoli JavaScript zobaczysz następujący błąd: + +``` +rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/subtle-2.6.1/src/lib.rs:701:9: +assertion `left == right` failed + left: 0 + right: 1 +``` + +Po którym następuje ślad stosu. Następnie podaj Billowi prawidłowy meta-adres, a Alicji nieprawidłowy adres lub nieprawidłowy klucz publiczny. Zobaczysz następujący błąd: + +``` +rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/eth-stealth-addresses-0.1.0/src/lib.rs:78:9: +klucze nie generują ukrytego adresu +``` + +Ponownie, po którym następuje ślad stosu. + +#### Interfejs użytkownika {#ui} + +Interfejs użytkownika jest napisany przy użyciu [React](https://react.dev/) i serwowany przez [Vite](https://vite.dev/). Możesz dowiedzieć się o nich, korzystając z [tego samouczka](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/). Nie ma tu potrzeby używania [WAGMI](https://wagmi.sh/), ponieważ nie wchodzimy w bezpośrednią interakcję z blockchainem ani portfelem. + +Jedyną nieoczywistą częścią interfejsu użytkownika jest łączność z WASM. Oto jak to działa. + +**`vite.config.js`** + +Ten plik zawiera [konfigurację Vite](https://vite.dev/config/). + +```js +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import wasm from "vite-plugin-wasm"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), wasm()], +}) +``` + +Potrzebujemy dwóch wtyczek Vite: [react](https://www.npmjs.com/package/@vitejs/plugin-react) i [wasm](https://github.com/Menci/vite-plugin-wasm#readme). + +**`App.jsx`** + +Ten plik jest głównym komponentem aplikacji. Jest to kontener, który zawiera dwa komponenty: `Alice` i `Bill`, interfejsy użytkownika dla tych użytkowników. Istotną częścią dla WASM jest kod inicjalizacyjny. + +```jsx +import init from './rust-wasm/pkg/rust_wasm.js' +``` + +Gdy używamy [`wasm-pack`](https://rustwasm.github.io/docs/wasm-pack/), tworzy on dwa pliki, których tu używamy: plik wasm z właściwym kodem (tutaj, `src/rust-wasm/pkg/rust_wasm_bg.wasm`) oraz plik JavaScript z definicjami do jego użycia (tutaj, `src/rust_wasm/pkg/rust_wasm.js`). Domyślny eksport tego pliku JavaScript to kod, który musi zostać uruchomiony, aby zainicjować WASM. + +```jsx +function App() { + . + . + . + useEffect(() => { + const loadWasm = async () => { + try { + await init(); + setWasmReady(true) + } catch (err) { + console.error('Error loading wasm:', err) + alert("Wasm error: " + err) + } + } + + loadWasm() + }, [] + ) +``` + +Hak [`useEffect`](https://react.dev/reference/react/useEffect) pozwala określić funkcję, która jest wykonywana, gdy zmieniają się zmienne stanu. Tutaj lista zmiennych stanu jest pusta (`[]`), więc ta funkcja jest wykonywana tylko raz, gdy strona się ładuje. + +Funkcja efektu musi natychmiast zwrócić wartość. Aby użyć kodu asynchronicznego, takiego jak `init` WASM (który musi załadować plik `.wasm` i dlatego wymaga czasu), definiujemy wewnętrzną funkcję [`async`](https://en.wikipedia.org/wiki/Async/await) i uruchamiamy ją bez `await`. + +**`Bill.jsx`** + +To jest interfejs użytkownika dla Billa. Ma jedną akcję: tworzenie adresu na podstawie ukrytego meta-adresu dostarczonego przez Alicję. + +```jsx +import { wasm_generate_stealth_address } from './rust-wasm/pkg/rust_wasm.js' +``` + +Oprócz domyślnego eksportu, kod JavaScript wygenerowany przez `wasm-pack` eksportuje funkcję dla każdej funkcji w kodzie WASM. + +```jsx +