logo
Objavljeno datuma

Bitcoin script: P2PK, P2PKH, P2MS, P2SH

6 minuta čitanja
Autori
  • avatar
    Ime
    Vladimir Stevic
    X

Uvod

U jednom od prehodnih članaka ušli smo u svijet bitcoin script-te, te objasnili šta ona znači i kako se izvršava. Ovdje ćemo navesti osnovne skripte koje se koriste u Bitcoin-u, te pokušati definisati za svaku skriptu za zaključavanje, otključavanje i izvršenje same skripte. Izvršenje zapravo predstavlja validaciju koju node u blockchain network-u izvršava da bi validirao transakciju.

Pay To Pubkey (P2PK)

U P2PK transakciji korisnik zaključava bitcoin sa javnim ključem primaoca, a primalac koristi svoj privatni ključ da kreira potpis (signature) kojim otključava sredstva.

Locking Script (scriptPubKey):

<public_key> OP_CHECKSIG

Unlocking Script (scriptSig):

<signature>

Izvršenje:

  1. Push-amo signature u stack:

    Stack: [<signature>]
    
  2. Push-amo public key u stack:

    Stack: [<signature>, <public_key>]
    
  3. OP_CHECKSIG:

    • Skida (pop) signature i public key sa stack-a.
    • Provjerava da li je signature validan za dati public key.
      • Ako je validan, vraća 1 (true) na stack.
      • Ako nije validan, vraća 0 (false) na stack.
    Stack: [1]
    

Ako je vraćen 1, transakcija je uspješno otključana i sredstva se mogu koristiti.


Pay To Pubkey Hash (P2PKH) 1

U prethodnom primjeru vidjeli smo da primalac mora dostaviti pošaljiocu javni ključ. Ovdje u P2PKH, primalac dostavlja hash-ovan (SHA-256 i RIPEMD-160) javnu ključ, dakle on ostaje i dalje anoniman. Ovo omogućava dodatnu sigurnost i smanjuje veličinu transakcije. Međutim, ovo sada malo komplikuje skriptu.

Locking Script (scriptPubKey):

OP_DUP OP_HASH160 <pub_key_hash> OP_EQUALVERIFY OP_CHECKSIG

Unlocking Script (scriptSig):

<signature> <public_key>

Izvršenje:

  1. Push-amo signature u stack:

    Stack: [<signature>]
    
  2. Push-amo public key u stack:

    Stack: [<signature>, <public_key>]
    
  3. OP_DUP: Duplicira javni ključ na vrhu stack-a:

    Stack: [<signature>, <public_key>, <public_key>]
    
  4. OP_HASH160:

    • Hash-uje posljednji public key koristeći SHA-256 i RIPEMD-160.
    • Zamjeni taj public key sa njegovim hash-om.
    Stack: [<signature>, <public_key>, <pub_key_hash>]
    
  5. Push-amo pub_key_hash (iz locking skripte) u stack:

    Stack: [<signature>, <public_key>, <pub_key_hash>, <pub_key_hash>]
    
  6. OP_EQUALVERIFY:

    • Skida dva hash-a sa vrha stack-a i provjerava da li su jednaki.
    • Ako jesu, nastavlja; ako nisu, transakcija nije validna.
    Stack: [<signature>, <public_key>]
    
  7. OP_CHECKSIG:

    • Skida signature i public key sa stack-a i provjerava da li je potpis validan za dati javni ključ.
    • Ako jeste, vraća 1 na stack.
    Stack: [1]
    

Ako se vraća 1, transakcija je validna. Dodatno, vidimo da je javni ključ ostao anoniman prilikom slanja, međutim kada želimo iskoristiti poslati output kao input, moramo priložiti raw javni ključ. Zbog ovoga dobra praksa u Bitcoin-u je da prilikom pravljenja svake nove transakcije generišemo novi key pair (novi javni i privatni ključ).


Pay To Multisig (P2MS)

Kod P2MS transakcija, više korisnika mora potpisati transakciju da bi bila validna. Na primjer, moguće je kreirati transakciju gdje su potrebna dva potpisa (od ukupno tri ključa).

Locking Script (scriptPubKey):

M <public_key1> <public_key2> <public_key3> N OP_CHECKMULTISIG

Unlocking Script (scriptSig):

0 <signature1> <signature2>

Prva vrijednost 0 je dummy vrijednost zbog greške (bug) u Bitcoin Script-u.

Izvršenje:

  1. Push-amo sve podatke u stack:

    Stack: [0, <signature1>, <signature2>, M, <public_key1>, <public_key2>, <public_key3>, N]
    
  2. OP_CHECKMULTISIG:

    • Skida posljednji element (N = 3) i vadi tri javna ključa sa stack-a.
    Stack: [0, <signature1>, <signature2>, M]
    
    • Skida minimalan broj potpisa (M = 2) i dva potpisa sa stack-a (i dummy 0 zbog greške).
    Stack: []
    
    • Provjerava svaki potpis sa odgovarajućim javnim ključem.
    • Ako su potpisi validni, vraća 1 u stack.
    Stack: [1]
    

Ako se vraća 1, transakcija je validna. Ovdje dodatno moramo navesti jedan problem - što više javnih ključeva u skripti imamo ona postaje sve veća i veća. Ovo utiče na FEE i sam prostor u block-u.


Pay To Script Hash (P2SH) 2

U prethodnom primjeru vidimo da P2MS može postati izuzetno veliki. P2SH omogućava da se cijelokupna skripta hash-uje kako bi bila kompaktnija i fleksibilnija. Umjesto da se direktno koristi locking skripta, skripta se prvo hash-uje, a tek zatim koristi. Kada korisnik želi potrošiti bitcoin, mora pružiti originalnu skriptu i potrebne podatke da bi dokazao vlasništvo.

Locking Script (scriptPubKey):

OP_HASH160 <script_hash> OP_EQUAL
  • script_hash je hash originalne locking skripte (koja može biti bilo koja skripta, kao što je iz prethodno primjera za multisig - M <public_key1> <public_key2> <public_key3> N OP_CHECKMULTISIG").

Unlocking Script (scriptSig):

<signature> <signature> <serialized_script>

Gdje je serialized_script originalna locking skripta, u našem slučaju dakle serijalizovana skripta: M <public_key1> <public_key2> <public_key3> N OP_CHECKMULTISIG

Izvršenje:

  1. Push-amo sve podatke iz unlocking skripte, te s obzirom da je u pitanju P2SH pravimo kopiju:

    Stack: [<signature>, <signature>, <serialized_script>]
    
  2. OP_HASH160:

    • Kopira originalni stack za kasniju upotrebu
    • Iz orginalnog stack-a skida serialized_script i hash-uje ga koristeći SHA-256 i RIPEMD-160.
    • Vraća hash na stack.
    Stack: [<signature>, <signature>, <script_hash>]
    Stack kopija: [<signature>, <signature>, <serialized_script>]
    
  3. Push-amo script_hash iz locking skripte na stack:

    Stack: [<signature>, <signature>, <script_hash>, <script_hash>]
    Stack kopija: [<signature>, <signature>, <serialized_script>]
    
  4. OP_EQUAL:

    • Skida dva script_hash-a sa stack-a i provjerava da li su jednaki.
    • Ako jesu skripta je izvršena.
    Stack: [<signature>, <signature>, 1] - završeno
    Stack kopija: [<signature>, <signature>, <serialized_script>]
    
  5. Izvršava originalnu skriptu (koja je de-serializovana):

    • Kada je originalni stack izvršen, sad prelazimo na kopiju
    • Sada, s obzirom da je P2SH, deseralizuje se "serialized_script"
    Stack kopija: [<signature>, <signature>, M, <public_key1>, <public_key2>, <public_key3>, N OP_CHECKMULTISIG]
    

Skripta se sada nastavlja izvršavati kao regularna P2MS sa potpisima, provjeravajući da li su potpisi validni. Kao u primjeru iz P2MS.

Footnotes

  1. Sa P2PKH prvi put vidimo bitcoin "adrese" koje sada više nisu prosto public key. U ovom slučaju one počinju sa brojem jedan, primjer: "12higDjoCCNXSA95xZMWUdPvXNmkAduhWv"

  2. Primjer ovih adresa je "342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey", one počinju sa brojem 3.