Kompletní průvodce vývojem blockchainu BSV v plném rozsahu

Tento příspěvek byl poprvé publikován na médiu.

V této příručce se naučíte technologický zásobník Web3, který vám umožní vytvářet decentralizované aplikace s plným zásobníkem na blockchainu Bitcoin SV. Projdeme celým procesem budování plného stacku decentralizovaného Tic-Tac-Toe, včetně:

  • Napište chytrou smlouvu.
  • Nasadit smlouvu
  • Přidat front-end (Reagovat)
  • Integrujte svou peněženku

Na konci budete mít plně funkční aplikaci Tic-Tac-Toe běžící na bitcoinech.

Prezentační obrázek Tic-Tac-Toe

Co budeme používat

Pojďme si projít hlavní kusy, které budeme používat, a jak se vejdou do stohu.

1. Rámec skriptu

sCrypt je framework TypeScript pro vývoj chytrých kontraktů na bitcoiny. Nabízí kompletní technickou sadu:

  • jazyk sCrypt: vložený jazyk eDSL (Domain Specific Language) založený na TypeScriptu, který umožňuje vývojářům psát chytré smlouvy přímo v TypeScriptu. Vývojáři se nemusí učit nový programovací jazyk Web3, jako je Solidity, a mohou znovu používat své oblíbené nástroje, jako jsou IDE a NPM.
  • knihovna (scrypt-ts): komplexní a stručná knihovna navržená pro aplikace JavaScript na straně klienta, jako je React, Vue, Angular nebo Svelte, pro interakci s Bitcoin SV Blockchain a jeho ekosystémem.
  • sCrypt CLI: CLI pro snadné vytváření, kompilaci a publikování projektů sCrypt. CLI poskytuje projektové lešení osvědčených postupů.

 2. Vaše peněženka

Vaše peněženka je open-source digitální peněženka pro BSV a 1Sat Ordinals, která umožňuje přístup k decentralizovaným aplikacím vyvinutým na Bitcoin SV. Yours Wallet generuje a spravuje soukromé klíče pro své uživatele neopatrovatelským způsobem, čímž zajišťuje, že uživatelé mají plnou kontrolu nad svými finančními prostředky a transakcemi. Tyto klíče lze použít v peněžence k bezpečnému ukládání finančních prostředků a autorizaci transakcí.

 3. REACT

React.js, často jednoduše označovaný jako React, je knihovna JavaScript vyvinutá společností Facebook. Primárně se používá pro vytváření uživatelských rozhraní (UI) pro webové aplikace. Zjednodušuje proces vytváření dynamických a interaktivních webových aplikací a nadále zdánlivě dominuje front-endovému prostoru.

Co budeme stavět

Postavíme velmi jednoduchou hru Tic-Tac-Toe na řetězu. K inicializaci chytré smlouvy používá bitcoinové adresy dvou hráčů (Alice a Bob). Každý vsadí stejnou částku a uzamkne ji ve smlouvě. Vítěz bere všechny bitcoiny uzamčené ve smlouvě. Pokud nikdo nevyhraje a dojde k remíze, mohou si oba hráči vybrat polovinu peněz. Tic-Tac-Toe, letitá strategická a dovednostní hra, si nyní našla cestu do blockchainu díky síle sCryptu.

Předpoklady

  1. Nainstalujte node.js a npm (node.js ≥ verze 16)
  2. Nainstalujte Git
  3. Vaše peněženka Rozšíření Chrome nainstalované ve vašem prohlížeči
  4. Nainstalujte sCrypt CLI
npm install -g scrypt-cli

Začínáme

Pojďme jednoduše vytvořit nový projekt React.

Nejprve vytvořte nový projekt React s šablonou TypeScript.

npx vytvořit-react-app tic-tac-toe --šablonový strojopis

Poté změňte adresář na adresář projektu tic-tac-toe a také spusťte příkaz init v CLI, abyste do svého projektu přidali podporu sCrypt.

cd tic-tac-toe npx scrypt-cli@latest init

Smlouva tic-tac-toe

Dále vytvoříme smlouvu na src/contracts/tictactoe.ts:

import { prop, method, SmartContract, PubKey, FixedArray, Claim, Sig, Utils, toByteString, hash160, hash256, fill, ContractTransaction, MethodCallOptions, bsv } od "scrypt-ts";

exportní třída TicTacToe rozšiřuje SmartContract {
    @podpěra()
    Alice: PubKey;
    @podpěra()
    poskakovat: PubKey;
    @podpěra(True)
    jeAliceTurn: booleovský;
    @podpěra(True)
    deska: FixedArray 9>;
    statické pouze pro čtení PRÁZDNÝ: bigint = 0n;
    statické pouze pro čtení ALICE: bigint = 1n;
    statické pouze pro čtení BOB: bigint = 2n; konstruktor(Alice: PubKey, poskakovat: PubKey) { super(...argumenty) this.alice = alice; this.bob = bob; this.isAliceTurn = true; this.board = fill(TicTacToe.EMPTY, 9); }
    
    @metoda()
    na veřejnosti hýbat se(n: bigint, sig: Sig) {
        // kontrola pozice `n`
        tvrdit(n >= 0n && n 9n);
        // kontrola podpisu `sig`
        nechat hráč: PubKey = this.isAliceTurn ? this.alice : this.bob; tvrdit(this.checkSig(sig, hráč), `checkSig se nezdařil, pubkey: ${player}`);
        // aktualizujte stavové vlastnosti, abyste provedli přesun
        sustain(this.board[číslo(n)] === TicTacToe.PRÁZDNÝ, `board na pozici ${n} není prázdný: ${this.board[Číslo(n)]}");
        nechat hrát = this.isAliceTurn ? TicTacToe.ALICE : TicTacToe.BOB; this.board[Number(n)] = play; this.isAliceTurn = !this.isAliceTurn;
        
        // sestavení transakčních výstupů
        nechat výstupy = toByteString('');
        if (this.won(play)) { outputs = Utils.buildPublicKeyHashOutput(hash160(player), this.ctx.utxo.value); }
        jinak pokud (this.full()) {
            const poloviční částka = this.ctx.utxo.value / 2n;
            const aliceOutput = Utils.buildPublicKeyHashOutput(hash160(this.alice), halfAmount);
            const bobOutput = Utils.buildPublicKeyHashOutput(hash160(this.bob), halfAmount); výstupy = aliceOutput + bobOutput; }
        jiný {
            // vytvoří výstup, který obsahuje poslední stav smlouvy.
            výstupy = this.buildStateOutput(this.ctx.utxo.value); }
        if (this.changeAmount > 0n) { outputs += this.buildChangeOutput(); }
        // ujistěte se, že transakce obsahuje očekávané výstupy sestavené výše
        sustain(this.ctx.hashOutputs === hash256(výstupy), "check hashOutputs failed"); }
    
    @metoda()    vyhrál(hrát: bigint): boolean { let vedení: FixedArraybigint, 3>, 8> = [ [0n, 1n, 2n], [3n, 4n, 5n], [6n, 7n, 8n], [0n, 3n, 6n], [1n, 4n, 7n], [2n, 5n, 8n], [0n, 4n, 8n], [2n, 4n, 6n]];
        nechat anyLine = nepravdivý;
        for (nechat i = 0; i 8; i++) {
            nechat řádek = pravdivý;
            for (nechat j = 0; j 3; j++) { line = line && this.board[Number(lines[i][j])] === play; } anyLine = anyLine || čára; }
        zpáteční anyLine; }
    
    @metoda()    plný(): boolean {
        nechat plný = pravdivý;
        for (nechat i = 0; i 9; i++) { full = full && this.board[i] !== TicTacToe.EMPTY; }
        zpáteční plný; } }

Nemovitosti

Smlouva Tic-Tac-Toe obsahuje několik základních vlastností, které definují její funkčnost:

  1. Alice a Bob: Veřejné klíče dvou hráčů.
  2. is_alice_turn: Booleovský příznak udávající, kdo je na tahu.
  3. deska: Reprezentace herního plánu, uložená jako pole pevné velikosti.
  4. Konstanty: Tři statické vlastnosti definující herní symboly a prázdná políčka.

Stavitel

konstruktor(Alice: PubKey, poskakovat: PubKey) { super(...argumenty) this.alice = alice; this.bob = bob; this.isAliceTurn = pravdivý; this.board = fill(TicTacToe.EMPTY, 9); }

Po nasazení konstruktor inicializuje smlouvu s veřejnými klíči Alice a Boba. Navíc nastaví prázdnou herní desku, aby nastartoval hru.

Veřejné metody

Každá smlouva musí mít alespoň jednu veřejnou @metodu. Je označen modifikátorem public a nevrací žádnou hodnotu. Je viditelný mimo smlouvu a funguje jako hlavní metoda do smlouvy (jako hlavní v C a Java).

Veřejná metoda ve smlouvě je move(), která umožňuje hráčům provádět tahy na šachovnici. Tato metoda ověřuje tahy, kontroluje podpis hráče, aktualizuje stav hry a určuje výsledek hry.

Ověření podpisu

Jakmile je herní smlouva nasazena, kdokoli ji může zobrazit a potenciálně s ní pracovat. Potřebujeme ověřovací mechanismus, který zajistí, že pouze požadovaný hráč může aktualizovat smlouvu, pokud je na řadě. Toho je dosaženo pomocí digitálních podpisů.

Pouze oprávněný hráč může během svého tahu provést tah, ověřený prostřednictvím jejich příslušného veřejného klíče uloženého ve smlouvě.

// kontrola podpisu `sig`
nechat hráč: PubKey = this.isAliceTurn ? this.alice : this.bob; tvrdit(this.checkSig(sig, hráč), `checkSig se nezdařil, pubkey: ${player}`);

Neveřejné metody

Smlouva zahrnuje dvě neveřejné metody won() a full(), které jsou odpovědné za určení, zda hráč vyhrál hru a zda je hrací deska plná, což vede k remíze.

Tx Builder: buildTxForMove

Bitcoinová transakce může mít více vstupů a výstupů. Při volání smlouvy potřebujeme vytvořit transakci.

Zde jsme implementovali přizpůsobení tvůrce transakcí pro metodu move(), jak je uvedeno níže:

statický buildTxForMove(
    proud: Piškvorky,
    možnosti: MethodCallOptions ,
    n: bigint ): Slibuji {
    const play = current.isAliceTurn ? TicTacToe.ALICE : TicTacToe.BOB;
    const dalsiInstance = aktualni.dalsi(); nextInstance.board[Number(n)] = play; nextInstance.isAliceTurn = !current.isAliceTurn;
    const unsignedTx: bsv.Transaction = nový bsv.Transaction().addInput( current.buildContractInput(options.fromUTXO) );
    if (nextInstance.won(play)) {
      const script = Utils.buildPublicKeyHashScript( hash160(current.isAliceTurn ? current.alice : current.bob) ); unsignedTx.addOutput(
        nový bsv.Transaction.Output({
          skript: bsv.Script.fromHex(script),
          satoshis: aktuální zůstatek,        })      );
      if (options.changeAddress) { unsignedTx.change(options.changeAddress); }
      zpáteční Promise.resolve({
        tx: unsignedTx,
        atInputIndex: 0,
        další: [], }); }
    if (nextInstance.full()) {
      const poloviční Částka = aktuální.zůstatek / 2; unsignedTx .addOutput(
          nový bsv.Transaction.Output({
            skript: bsv.Script.fromHex( Utils.buildPublicKeyHashScript(hash160(current.alice)) ),
            satoshis: halfAmount, }) ) .addOutput(
          nový bsv.Transaction.Output({
            skript: bsv.Script.fromHex( Utils.buildPublicKeyHashScript(hash160(current.bob)) ),
            satoshis: poloviční částka, }) );
      if (options.changeAddress) { unsignedTx.change(options.changeAddress); }
      zpáteční Promise.resolve({
        tx: unsignedTx,
        atInputIndex: 0,
        další: [], }); } unsignedTx.setOutput(0, () => {
      vrátit nový bsv.Transaction.Output({
        skript: nextInstance.lockingScript,
        satoshis: aktuální zůstatek,      }); });
    if (options.changeAddress) { unsignedTx.change(options.changeAddress); }
    const nexts = [ { instance: nextInstance, atOutputIndex: 0, zůstatek: aktuální.zůstatek, }, ]; return Promise.resolve({
      tx: unsignedTx,
      atInputIndex: 0, další,
      další: další[0], }); }

Integrujte front-end (React)

Poté, co sepíšeme/otestujeme naši smlouvu, můžeme ji integrovat s front-endem, aby uživatelé mohli hrát naši hru.

Nejprve zkompilujme smlouvu a získejte soubor json artefaktu smlouvy spuštěním příkazu níže:

npx scrypt-cli@nejnovější sestavit

Snímek obrazovky kóduSnímek obrazovky kódu

V adresáři artefaktů byste měli vidět soubor artefaktů tictactoe.json. Lze jej použít k inicializaci smlouvy na frontendu.

import { Piškvorky } od './contracts/tictactoe';
import artefakt od '../artifacts/tictactoe.json'; TicTacToe.loadArtifact(artifact);

Nainstalujte a financovejte Peněženku

Před nasazením smlouvy musíme nejprve připojit peněženku. Používáme Yours Wallet, peněženku podobnou MetaMask.

Po instalaci peněženky klikněte na tlačítko nastavení v pravém horním rohu pro přepnutí na testnet. Poté zkopírujte adresu své peněženky a přejděte na náš faucet, abyste ji mohli financovat.

Snímek obrazovky webu sCryptSnímek obrazovky webu sCrypt

Připojte se k peněžence

Zavoláme requestAuth(), abychom požádali o připojení k peněžence. Pokud uživatel žádost schválí, máme nyní plný přístup k peněžence. Můžeme například zavolat getDefaultPubKey(), abychom získali jeho veřejný klíč.

const přihlášení do peněženky = async () => {
    vyzkoušet {
      const poskytovatel = nový DefaultProvider({
          síť: bsv.Networks.testnet });
      const signer = new PandaSigner(poskytovatel); signerRef.current = signer;
      
      const { isAuthenticated, error } = čekej signer.requestAuth()
      if (!isAuthenticated) {
        hodit nový Chyba(chyba) } setConnected(true);
      const alicPubkey = čekej signer.getDefaultPubKey(); setAlicePubkey(toHex(alicPubkey))
      // Vyzvat uživatele k přepnutí účtů
    } úlovek (chyba) { console.error("pandaLogin se nezdařilo", chyba); upozornění ("pandaLogin se nezdařilo") } };

Inicializujte smlouvu

Získali jsme smluvní třídu Piškvorky načtením souboru artefaktu smlouvy. Když uživatel klikne na Začít tlačítko, smlouva je inicializována veřejnými klíči dvou hráčů Alice a Bob. Veřejný klíč lze získat voláním etDefaultPubKey()z Signeru.

Následující kód inicializuje smlouvu.

const [alicePubkey, setAlicePubkey] = useState("");
const [bobPubkey, setBobPubkey] = useState(""); ...
const startGame = async (částka: číslo) => { zkusit {
   const signer = signerRef.current as PandaSigner;
    const instance = nový TicTacToe( PubKey(toHex(alicePubkey)), PubKey(toHex(bobPubkey)));
    čekej instance.connect(signer); } úlovek(e) { console.error('deploy TicTacToe selže', e) upozornění ('deploy TicTacToe selže') } };

Zavolejte na smlouvu

Nyní můžeme začít hrát hru. Každý pohyb je výzvou ke smlouvě a spouští změnu stavu smlouvy.

const { tx: callTx } = čekej p2pkh.methods.unlock( (sigResponses: SignatureResponse[]) => findSig(sigResponses, $publickey), $publickey, {
        pubKeyOrAddrToSign: $publickey.toAddress() } as MethodCallOptions );

Po dokončení front-endu můžete jednoduše spustit:

Npm Začít

Nyní si jej můžete prohlédnout na `http://localhost:3000/` ve vašem prohlížeči.

GIF Tic-Tac-ToeGIF Tic-Tac-Toe

Proč investovat do čističky vzduchu?

Gratulujeme! Právě jste vytvořili svůj první full stack dApp na bitcoinech. Nyní můžete hrát piškvorky nebo postavit svou oblíbenou hru na bitcoinech. Teď by byl dobrý čas dát si šampaňské, pokud jste to ještě neudělali :).

Jednu hru si můžete prohlédnout zde:

YouTube VideoYouTube Video

Veškerý kód lze nalézt v tomto repozitáři github.

Standardně nasazujeme smlouvu na testnet. Můžete jej snadno změnit na mainnet.

Sledujte: sCrypt Hackathon 2024 (17. března 2024, PM)

YouTube VideoYouTube Video

Jste v blockchainu noví? Podívejte se na sekci Blockchain pro začátečníky od CoinGeek, nejlepšího průvodce zdroji, kde se dozvíte více o technologii blockchain.

Zdroj: https://coingeek.com/the-complete-guide-to-full-stack-bsv-blockchain-development/