Bitcoin Smart Contract 101
Affronteremo la teoria e la pratica che ci permette di utilizzare il linguaggio Bitcoin Script per creare uno Smart Contract che consegna i suoi bitcoin solo a chi conosce una password.
Il codice Bitcoin Script che scriveremo e', anche se banale, uno Smart Contract!

TL;DR
Entrare in Hansel, eseguire
cd p2sh_password
./main.sh passwordSceltaDaHansel passwordTentataDaGretel
# per attivare il debugger
DEBUG=1 ./main.sh passwordSceltaDaHansel passwordTentataDaGretel
interpretare l'stdout ed i sorgenti dello script per capire cosa succede 🔦
Teoria di Smart Contract Bitcoin
Prima di procedere siamo costretti ad introdurre tre aspetti fondamentali
i passaggi necessari per sviluppare lo Smart Contract
cosa sono le UTXO
cosa significa PS2H
Bitcoin Smart Contract development process
Paragonare il processo da svolgere per creare ed eseguire uno Smart Contract (SC) Bitcoin al processo di una web app e' arduo, proviamoci!
(SC build/compile) Trasformare il redeem script
Nella sua rappresentazione esadecimale
In Script Hash tramite l'applicazione di SHA256+RIPEMD-160
(SC deploy) Pubblicazione di una transazione che invia bitcoin all'indirizzo (4.3) vincolandoci dei bitcoin.
L'esecuzione dello Smart Contract avviene quando si vuole accedere ai fondi - eg. inviandoli ad un nuovo indirizzo Bitcoin - a lui assegnati: si crea una transazione contenente il sorgente del redeem script assieme ai valori di input e la si invia ai nodi della rete.
Se il sorgente del redeem script presentato per l'esecuzione corrisponde allo Script Hash dal quale e' stato derivato il Bitcoin address, e la sua esecuzione utilizzando i valori di input ha esito positivo, abbiamo a disposizione i bitcoin assegnati allo Smart Contract e possiamo consegnarli ad un altro indirizzo Bitcoin.
Nei passaggi seguenti alterneremo teoria e coding pratico, gli snippet che trovate colorati eseguiteli dentro Hansel o Gretel.
UTXO - Unspent Transaction Output
Un concetto, anomalo rispetto ai sistemi di pagamento ai quali siamo abituati, riguarda la gestione del saldo in Bitcoin.
Parlando di pagamenti classici, quando ne riceviamo uno, che sia un bonifico o contante, l'ammontare ricevuto va a sommarsi ad un conto unico al quale abbiamo accesso. Quando dobbiamo inviare denaro preleviamo dal conto unico la quantita' che ci interessa e la consegnamo al beneficiario.
In Bitcoin l'ammontare di un pagamento ricevuto non va ad unirsi ad un conto unico, rimane indipendente, per questo si utilizza il termine UTXO. Quando vogliamo creare un pagamento in Bitcoin, invece che prelevare dal conto, si seleziona una gruppo di UTXO i quali saldi sono sufficienti per colmare il pagamento verso il beneficiario desiderato.
Potenzialmente, ed e' anche prassi diffusa e caldamente consigliata, tutte le volte che ricevete un pagamento potete generare un indirizzo Bitcoin dedicato. Essendo le UTXO visibili pubblicamente sulla blockchain di Bitcoin, la differrenzazione dei beneficiari - anche facenti capo ad una sola entita' - permette di migliorare la privacy finanziaria.
P2SH - Pay to Script Hash
In Bitcoin, nel momento che si crea una UTXO, si deve indicare il beneficiario associandovi un identificativo chiamato Bitcoin address.
Esistono differenti tipologie di Bitcoin address, P2SH e' una di queste.
Il beneficiario di una UTXO P2SH e' un listato di codice Bitcoin Script.
PS2H e' l'acronimo di Pay to Script Hash
Tramite i passaggi che vedremo piu' avanti il codice sorgente dello script viene trasformato in Script Hash e successivamente in Bitcoin address.
Grazie a questo approccio solo chi e' a conoscenza del codice sorgente dello script, e degli eventuali parametri di input, potra' riscattare i bitcoin che hanno come beneficiario tale script.
Identificare lo use case
Dopo aver sottratto con un sotterfugio i bitcoin dalla strega, Hansel decide di bloccare la parte destinata a Gretel utilizzando una password.
Per far questo Hansel crea un address P2SH prevedendo
come parametri di input un unico valore, lo SHA256 della loro parola segreta che risulta essere "fegatini"
come business logic (redeem script) l'esecuzione di un ulteriore SHA256 sul parametro di input e il confronto del risultato con il valore SHA256(SHA256('fegatini')) da lui precalcolato
Solo chi fornisce la giusta password può sbloccare interamente il tesoro!
Riuscirà la nostra Gretel a ricordarsi dei fegatini, sbloccare i bitcoin e vivere felice e contenta con Hansel e suo padre taglialegna a bordo di una LAMBO? 🚘
Specifiche in pseudo codifica
Abbiamo detto che Hansel vuole realizzare uno script che verifica se e' stato fornito un parametro di input che corrisponde ad un determinato digest.
A grandi linee potremmo rappresentare la funzione che verifica la password cosi'
function is_password_valid(password_sha256) {
password_valid = SHA256(SHA256('fegatini'))
return SHA256(password_sha256) === password_valid)
}
Il corpo della nostra funzione diventerebbe qualcosa del genere
'fegatini' SHA256 SHA256 password_valid
password_sha256 SHA256 password_valid is_equal
Il primo doppio SHA256 e' costante quindi possiamo calcolarlo
PWD_DOUBLE_SHA256=`printf 'fegatini' | sha256sum | xxd -r -p | sha256sum -b | awk '{print $1}'`
echo $PWD_DOUBLE_SHA256
Il corpo della nostra funzione diventa quindi
cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d7 password_valid
password_sha256 SHA256 password_valid is_equal
per essere piu' concisi potremmo
password_sha256 SHA256 cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d7 is_equal
password_sha256
SHA256
cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d7
is_equal
password_sha256
OP_SHA256
cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d7
OP_EQUAL
ScriptSig design - Suddivisione dello script in due parti
Business logic imposta denominata redeem script
Come detto in precedenza nel redeem script non dobbiamo descrivere i parametri di input, quindi sara' composto da
OP_SHA256
cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d7
OP_EQUAL
OP_SHA256
, il quale ricade nella sezione crypto, ha il compito di effettuare un'operazione di pop (estrazione dello stack), applicare la funzione crittografica SHA256 ed effettuare l'operazione di push (inserimento nello stack) del risultato.
Successivamente abbiamoOP_EQUAL
facente parte delle opcodes di Bitwise logic.
OP_EQUAL
esegue due volte l'operazione di pop. Successivamente esegue l'operazione di push con valore 1 se i valori estratti tramite pop sono uguali oppure 0 se sono diversi.
Salviamolo in una variabile per comodita'
REDEEM_SCRIPT="OP_SHA256 $PWD_DOUBLE_SHA256 OP_EQUAL"
Parametri di input del redeem script necessari ad eseguire la business logic
Come descritto poco sopra, la transazione è bloccata da una password che Gretel deve forinire.
PWD_SHA256=`printf 'fegatini' | sha256sum | awk '{print $1}'`
echo $PWD_SHA256
con il quale otteniamo 273c25751f15926d6064916b8765461d77a6d525ee3fd25a37b88755c6d4db20
Verifica funzionamento redeem script con btcc/btcdeb
Per una rapida verifica possiamo dare in pasto a btcc redeem script e parametri di input.
Successivamente possiamo verificare tutta l'esecuzione con l'ausilio di btcdeb.
btcc e' un Bitcoin Script compiler
COMPILED=`btcc $PWD_SHA256 $REDEEM_SCRIPT`
btcdeb e' un Bitcoin Script debugger
btcdeb $COMPILED
A sinistra vi comparira' una rappresentazione dello script di Hansel, compreso dei parametri di input; sulla destra viene visualizzato lo stack che all'avvio di ogni Smart Contract Bitcoin e' vuoto.
Digitate
step
e premete invio per eseguire lo script un passaggio alla volta!
Per uscire da btcdeb usate la shortcut
CTRL+D
Trasformare la business logic (redeem script) in esadecimale poi in Script Hash ed infine in indirizzo Bitcoin
Trasformare la business logic (redeem script) in esadecimale
Possiamo usare btcc, questa volta pero' utilizzeremo solo il redeem script senza il parametro di input
REDEEM_SCRIPT_COMPILED=`btcc $REDEEM_SCRIPT`
echo $REDEEM_SCRIPT_COMPILED
otteniamo a820cef813adf3b25b5f92ab0ced01fcbaa5bc6a6cdb64693566ca775f44192799d787
SHA256+RIPEMD-160
SCRIPT_SHA256=`printf $REDEEM_SCRIPT_COMPILED | xxd -r -p | openssl sha256 | sed 's/^.* //'`
SCRIPT_RIPEMD160=`printf $SCRIPT_SHA256 | xxd -r -p | openssl ripemd160 | sed 's/^.* //'`
echo $SCRIPT_RIPEMD160
Risultato 0482e32347749e785e203e1c663b190c1db89071
.
Indirizzo Bitcoin
Per completare il Bitcoin address bisogna prependere un prefisso e codificare il tutto in Base58Check.
Il prefisso serve ad indicare se operiamo in mainnet o testnet/regtest e che tipo di Bitcoin address stiamo utilizzando.
Il playground opera in regtest, il prefisso che ci interessa e' Testnet script hash che corrisponde al valore esadecimale c4
.
Possiamo svolgere quindi l'encoding utilizzando base58
P2SH_ADDR=`printf c4$SCRIPT_RIPEMD160 | xxd -p -r | base58 -c`
echo $P2SH_ADDR
e finalmente ottenere il nostro indirizzo P2SH!
2Msf5VFsuGZBthnwXvUGxajtJKgiGd5GDQi
Pubblicazione di una transazione che invia bitcoin all'indirizzo Bitcoin vincolando la UTXO allo Script Hash
Adesso abbiamo bisogno di inviare bitcoin al nostro indirizzo P2SH.
bitcoin-cli generatetoaddress 101 $P2SH_ADDR
Aprendo http://localhost:8094/regtest/address/2Msf5VFsuGZBthnwXvUGxajtJKgiGd5GDQi possiamo verificare di aver ricevuto UTXO al nostro address.
Aprendo dal blockchain regtest explorer una qualsiasi delle transazioni associate possiamo verificare che lo Script Hash e' quello desiderato ovvero 0482e32347749e785e203e1c663b190c1db89071

Esecuzione dello Smart Contract
Siamo arrivati all'ultimo passaggio! L'esecuzione dello Smart Contract!
Adesso dobbiamo creare una transazione che, fornendo password e redeem script, permette di utilizzare la UTXO associata al P2SH ed invia i bitcoin ad un nuovo indirizzo.
Indirizzo del beneficiario
Partiamo con il passaggio semplice, creiamo un indirizzo
BENEFICIARIO=`bitcoin-cli getnewaddress`
Selezione della transazione che contiene la UTXO P2SH
Adesso dobbiamo selezionare la transazione, fra tutte quelle ricevute dal nostro indirizzo P2SH, che ha raggiunto la coinbase maturity.
bitcoin-cli importaddress $P2SH_ADDR fegatini
TXID_WITH_MATURITY=`bitcoin-cli listunspent 100 101 "[\"$P2SH_ADDR\"]" | jq -r '.[0].txid'`
Creazione della transazione che esegue lo Smart Contract
Adesso viene il bello! Dobbiamo costruire una transazione che fa uso di
La UTXO di TXID_WITH_MATURITY
REDEEM_SCRIPT_COMPILED
BENEFICIARIO
A scopo dimostrativo abbiamo predisposto un file bash che svolge i passaggi necessari
cd /opt/wald/p2sh_password
SC_RAW_TX=`./create_raw_tx.sh $TXID_WITH_MATURITY $PWD_SHA256 $REDEEM_SCRIPT_COMPILED $BENEFICIARIO`
echo $SC_RAW_TX
L'output del file bash e' la transazione, gia' pronta nel suo formato esadecimale.
QA transazione che esegue Smart Contract prima di inviarla ai nodi
Ci viene in soccorso btcdeb!
RAW_TX_WITH_MATURITY=`bitcoin-cli getrawtransaction $TXID_WITH_MATURITY`
btcdeb --txin=$RAW_TX_WITH_MATURITY --tx=$SC_RAW_TX
Invio della transazione alla rete
La transazione da inviare potere recuperarla con
echo $SC_RAW_TX
Questo passaggio si puo' fare utilizzando la chiamata RPC sendrawtransaction
oppure tramite http://localhost:8094/regtest/tx/push.
Mining di blocchi per confermare la transazione e farla uscire dalla mempool
Attualmente la transazione si trova in mempool, possiamo visualizzare la mempool tramite i link qui sulla sinistra.
Per confermare la transazione e farla uscire dalla mempool bastera' minare un blocco.
Last updated
Was this helpful?