Az ASC1 és a TEAL

„Vajúdnak a hegyek: nevetséges kisegér születik”

Horatius

Bástya elvtárs: Mi ez?

Pelikán: Narancs.

Bástya elvtárs: Narancs?!

Pelikán: Az új magyar narancs.
Kicsit sárgább, kicsit savanyúbb, de a mienk.

Bacsó Péter: A tanú

ASC1: Algorand Smart Contract on Layer 1

TEAL: Transaction Execution Approval Language

Tartalom

A TEAL jellemzői

Egy mindent engedélyező szerződés

Téma és variációk: szerződés, egy bemenettel

Téma és variációk: szerződés hash preimage használatával

Téma és variációk: fogadás hash preimage használatával

Aláírás delegálása

A TEAL jellemzői

A TEAL alacsony szintű, assembler-szerű nyelv, melyben leírható, hogy egy fizetési művelet végrehajtása előtt milyen további logikai feltételek vizsgálatára kerüljön sor. A TEAL program végeredménye 0 vagy 1 a stack-en, amely tiltja vagy engedélyezi a tranzakció végrehajtását. A TEAL lefordításával előálló file kétféleképpen építhető be a fizetési műveletekbe:

Fontos tudnunk, a TEAL kód egyik estben sem lesz a blokkláncon tárolva. Az ASC1 TEAL kód mindig a tranzakció része.

A TEAL-t végrehajtó gép jellemzői:

Adattípusok:

Adatkonverziók:

Megjegyzés: az sha256 bemenete []byte, kimenete [32]byte. A hash-en végezhető művelet az egyenlőség vizsgálata (==) vagy a nem egyenlőség viszgálata (!=). A btoi függvényt a hash eredményére alkalmazva a fg. hibával elszáll, ugyanis a [32]byte hash tömb hosszabb 8-nál. Emiatt a TEAL-ben a Bitcoin-hoz hasonló „bányászati” logika nem írható le.

Műveletek:

Függvények:

uint megadása a TEAL-ben:

[]byte megadása a TEAL-ben:

Megjegyzés:

[]byte => hexadecimális konverzió:


$ python
"ABC".encode('hex')
'414243'

[]byte => base64 konverzió:


$ printf "ABC" | base64
QUJD

base64 => []byte konverzió:


$ printf "QUJD" | base64 -d
ABC

uint64 => base64 konverzió, ill. base64 => uint64 konverzió:


$ python
Python 2.7.15+ (default, Oct  7 2019, 17:39:04) 
>>> import hashlib
>>> import base64
>>> import struct
>>> i=1234
>>> struct.pack(">H", i)
'\x04\xd2'
>>> base64.b64encode(struct.pack(">H", i))
'BNI='
>>> base64.b64decode('BNI=')
'\x04\xd2'
>>> 

$ python3
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
>>> import base64
>>> import math
>>> i=1234
>>> base64.b64encode(i.to_bytes(math.ceil(i.bit_length()/8),'big'))
b'BNI='
>>> base64.b64decode('BNI=')
b'\x04\xd2'
>>> 

Egy mindent engedélyező szerződés

A legegyszerűbb szerződés TEAL nyelven mindent engedélyez azzal, hogy 1-et tesz föl a stack-re:


$ nano p1.teal
// mindent engedélyez
int 1

A szerződés a következőképpen fordítható le:


$ ./goal clerk compile p1.teal
p1.teal: 6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY

A lefordított kód a .tok file-ba kerül. A .tok file tartalma:


$ hexdump -C p1.teal.tok
00000000  01 20 01 01 22                                    |. .."|
00000005

A kód disassemblálható (visszafordítható) a -D kapcsolóval:


$ ./goal clerk compile -D p1.teal.tok
// version 1
intcblock 1
intc_0

A kód mint szerződés egy fizetési műveletbe úgy iktatható be, hogy a küldő címe helyett (-f (addr)) a --from-program (teal-program) parancsrészt adjuk meg, továbbá megadjuk a számla zárási címet ("close" address) is a -c-vel:


$ ./goal account list -w w1 -d data
Please enter the password for wallet 'w1': 
[offline]	Unnamed-2	GCDEMV3UUGUAVCWPU3PSG4ONB2AGJNNFYD32VYPOOYQYJAYNGV55EAW2EQ	898000 microAlgos
	                   0 units    (creator , ID 1081)
[offline]	Unnamed-0	I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM	97458533 microAlgos	*Default
[offline]	Unnamed-1	QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E	1998258 microAlgos

$ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program p1.teal -d data -o p1.txn
$ ./goal clerk inspect p1.txn
p1.txn[0]
{
  "lsig": {
    "l": "// version 1\nintcblock 1\nintc_0\n"
  },
  "txn": {
    "amt": 12,
    "close": "I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM",
    "fee": 1000,
    "fv": 755692,
    "gen": "betanet-v1.0",
    "gh": "mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0=",
    "lv": 756692,
    "note": "vT7z5d+SHrs=",
    "rcv": "QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E",
    "snd": "6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY",
    "type": "pay"
  }
}

Látható, hogy így az "snd" mezőbe a szerződés címe kerül. Megjelenik továbbá a tranzakcióban a "lsig" JSON mező, amelyen belül a "l" mezőben a TEAL-lel leírt logika található. Az "l" utáni tartalom nem más, mint a TEAL bytekód vissza-assemblált listája.

A szerződés logikájának a működését a "dryrun" paranccsal lehet tesztelni:


$ ./goal clerk dryrun -t p1.txn -d data
tx[0] cost=2 trace:
  1 intcblock => <empty stack>
  4 intc_0 => 1 0x1

 - pass -
$ 

A "pass" azt mutatja, hogy a szerződés engedélyezi a fizetési műveletet, ami nem más, mint 12 /uAlgo küldése a 6Z3C... címről a QNEO... címre. A tranzakció a rawsend paranccsal küldhető el az Algorand hálózatnak:


$ ./goal clerk rawsend -f p1.txn -d data
Raw transaction ID MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA issued
Transaction MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA still pending as of round 755809
Transaction MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA committed in round 755811

Ha az Algoexplorer-rel megnézzük, hogy a szerződés címén milyen tranzakciók voltak, azt látjuk, hogy 3 hónapja már valaki feltöltötte ezt a szereződést 100 Algóval, most pedig kiürítettük:


TRANSACTION DETAILS

TxID    MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA
Block   755811
Age     7 minutes ago                        
From    6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY 
To      QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E
        Close: I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM
Value   0.000012 Algos
        100.945588 Algos
Fee     0.001 Algos


TxID    D3CX2LW4RIKCLQY66P7VMXFOLXC5KPSQC7JTXAI7ZS75DQHWFPUQ
Block   123979
Age     3 months ago
From    E6JSNTY4PVCY3IRZ6XEDHEO6VIHCQ5KGXCIQKFQCMB2N6HXRY4IB43VSHI
To      6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY
        Close:
Value   100 Algos
        0 Algos 
Fee     0.01 Algos

Nézzük meg, mi történik, ha még egyszer elküldjük a tranzakciót:


$ ./goal clerk rawsend -f p1.txn -d data
Warning: Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction already in ledger: MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA
Encountered errors in sending 1 transactions:
  MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA: HTTP 400 Bad Request: TransactionPool.Remember: transaction already in ledger: MIH2IB3L4QNI7IZXE24JTNA4PGLTPZMVIOVOM72Y4VRLJIQHCYOA
Rejected transactions written to p1.txn.rej

Hibát kapunk, mert ez a tranzació már bekerült a blokkláncba. Ugyanazt a tranzakció kétszer nem kerülhet be a blokkláncba, mert a tranzakció ugyanazzal a hash-sel rendelkezik, és emiatt ugyanaz lenne a tranzakció azonosítója.

Ha újra létrehozzuk a tranzakciót, és ezt az új tranzakciót elküldjük a hálózatnak, akkor "overspend" hibát kapunk, hiszen a szerződéshez tartozó címen már nem található semmilyen forrás, lenulláztuk az előző tranzakció során:


$ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program p1.teal -d data -o p1.txn
$ ./goal clerk rawsend -f p1.txn -d data
Warning: Couldn't broadcast tx with algod: HTTP 400 Bad Request: TransactionPool.Remember: transaction 5IYNA47EIREPARMXLAQVYBDWAM4MR2746NIJVLXMFEG6YKCQYTKQ: overspend (account 6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY, data {_struct:{} Status:Offline MicroAlgos:{Raw:0} RewardsBase:0 RewardedMicroAlgos:{Raw:0} VoteID:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] SelectionID:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] VoteFirstValid:0 VoteLastValid:0 VoteKeyDilution:0 AssetParams:map[] Assets:map[]}, tried to spend {1000})

Töltsük fel a szerződéshez tartozó címet 1 Algóval, majd küldjük el ismét a tranzakciót:


$ ./goal clerk send -a 1000000 -f I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM -t 6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY -d data
Please enter the password for wallet 'w1': 
Sent 1000000 MicroAlgos from account I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM to address 6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY, transaction ID: LPSSKQ7S6AZJF3T6JBFLCUXVSSRXOGNBUOE6OWWKJSPBFLBUOPTA. Fee set to 1000
Transaction LPSSKQ7S6AZJF3T6JBFLCUXVSSRXOGNBUOE6OWWKJSPBFLBUOPTA still pending as of round 756180
Transaction LPSSKQ7S6AZJF3T6JBFLCUXVSSRXOGNBUOE6OWWKJSPBFLBUOPTA committed in round 756182
$ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program p1.teal -d data -o p1.txn
$ ./goal clerk rawsend -f p1.txn -d data
Raw transaction ID XA6WNAIBL7SJ6RRHFVROQ3KYCX7A3EM6TUAU3FXIZHBAZVJ2TIQA issued
Transaction XA6WNAIBL7SJ6RRHFVROQ3KYCX7A3EM6TUAU3FXIZHBAZVJ2TIQA still pending as of round 756187
Transaction XA6WNAIBL7SJ6RRHFVROQ3KYCX7A3EM6TUAU3FXIZHBAZVJ2TIQA committed in round 756189
$ 

Ha az Algoexplorer-rel megnézzük, hogy a legutolsó tranzakció során mi történt, a következőket látjuk:


TxID:          XA6WNAIBL7SJ6RRHFVROQ3KYCX7A3EM6TUAU3FXIZHBAZVJ2TIQA
Status:        Completed
Block:         756189
Sender:        6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY
Receiver:      QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E
Amount:        0.000012 Algos
Fee:           0.001 Algos
Sender balance:0 Algos
First round:   756185
Last round:    757185
Close address: I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM
Close amount:  0.998988 Algos
Type:          pay
Created at:    Tue Dec 03 2019 16:52:35 GMT+0100 (közép-európai téli idő)

Téma és variációk: szerződés, egy bemenettel

A TEAL-ben megírt logikának a "send" során argumentumok, azaz bemeneti paraméterek is megadhatók. Írjunk most egy olyan szerződést, amely a megfelelő argumentum megadásával teszi lehetővé a költést. A lenti TEAL program az arg_0 bemeneti paramétert uint64 típussá alakítja át, majd összehasonlítja a 42-vel. A stack-en akkor lesz 1, ha az uint64(par_0) és a 42 egyenlő.


$ nano ex1.teal
arg_0
btoi
int 42
==

A paramétereket a "goal clerk send"-ben base64 alakban kell megadni. Az uint64 tipusú 42 átkódolása base64 alakra:


>>> i=42
>>> base64.b64encode(i.to_bytes(math.ceil(i.bit_length()/8),'big'))
b'Kg=='
>>> 

A tranzakció ugyanúgy állítható össze, mint az előző példában. Új elem a parancssorban az "--argb64 Kg==". A tranzakció vizsgálatakor (goal clerk inspect) az "lsig" JSON objektumban az "arg" a bemenő paramétereket tartalmazza, az "l" pedig a TEAL program disassemblált listája.


$ ./goal clerk send -a 1234 -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E --from-program ex1.teal -d data -o ex1.txn --argb64 Kg==
$

$ ./goal clerk inspect ex1.txn
ex1.txn[0]
{
  "lsig": {
    "arg": [
      "Kg=="
    ],
    "l": "// version 1\nintcblock 42\narg_0\nbtoi\nintc_0\n==\n"
  },
  "txn": {
    "amt": 1234,
    "close": "QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E",
    "fee": 1000,
    "fv": 736944,
    "gen": "betanet-v1.0",
    "gh": "mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0=",
    "lv": 737944,
    "note": "py5LutuV0/c=",
    "rcv": "QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E",
    "snd": "72BTTM2ZWYFGYQ75BDCW45GKLRZHDGLMSFXVXWGOZYV26MKLGGQSDNR7MU",
    "type": "pay"
  }
}

$ ./goal clerk dryrun -t ex1.txn -d data
tx[0] cost=5 trace:
  1 intcblock => <empty stack>
  4 arg_0 => 2a
  5 btoi => 42 0x2a
  6 intc_0 => 42 0x2a
  7 == => 1 0x1

 - pass -
$

$ ./goal clerk send -a 1001234 -f I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM -t 72BTTM2ZWYFGYQ75BDCW45GKLRZHDGLMSFXVXWGOZYV26MKLGGQSDNR7MU -d data
Please enter the password for wallet 'w1': 
Sent 1001234 MicroAlgos from account I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM to address 72BTTM2ZWYFGYQ75BDCW45GKLRZHDGLMSFXVXWGOZYV26MKLGGQSDNR7MU, transaction ID: 45MHTV37Y55ZIBTKYUEIYO4KKFTCHGJSYIZNHOXTUDJIGJNHBYWA. Fee set to 1000
Transaction 45MHTV37Y55ZIBTKYUEIYO4KKFTCHGJSYIZNHOXTUDJIGJNHBYWA still pending as of round 737013
Transaction 45MHTV37Y55ZIBTKYUEIYO4KKFTCHGJSYIZNHOXTUDJIGJNHBYWA still pending as of round 737015
Transaction 45MHTV37Y55ZIBTKYUEIYO4KKFTCHGJSYIZNHOXTUDJIGJNHBYWA committed in round 737016
$

$ ./goal clerk rawsend -f ex1.txn -d data
Raw transaction ID 3RXEU4VXQAJ2SDFDOTRFAU5S2BJAV3VOWMCWGHZJB5JCRJCTFELQ issued
Transaction 3RXEU4VXQAJ2SDFDOTRFAU5S2BJAV3VOWMCWGHZJB5JCRJCTFELQ still pending as of round 737023
Transaction 3RXEU4VXQAJ2SDFDOTRFAU5S2BJAV3VOWMCWGHZJB5JCRJCTFELQ committed in round 737025
$ 

Megjegyzés: Megírhattuk volna a szerződést úgy is, hogy két []byte tömb között történjen az összehasonlítás. Ekkor:


$ nano ex1a.teal
arg_0
byte 0x3432  // "42"
==
$ 

$ printf 42 | base64
NDI=
$ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program ex1a.teal -d data -o ex1a.txn --argb64 NDI=
$ ./goal clerk dryrun -t ex1a.txn -d data
tx[0] cost=4 trace:
  1 bytecblock => <empty stack>
  6 arg_0 => 3432
  7 bytec_0 => 3432
  8 == => 1 0x1

 - pass -
$

Téma és variációk: szerződés hash preimage használatával

Legyen az sha256 preimage egyetlen szóköz karakter.

Az sha256(" ") base64 alakjának kiszámítása Python2-ben:


$ python
>>> import hashlib
>>> import base64
>>> base64.b64encode(hashlib.sha256(" ").digest(), )
'Nqnn8clbgv+5l0PgxcTOldg8mkMKrFn4TvPL+rYUUGg='
>>>

A TEAL kód, és lefordítása:


$ nano ex2.teal
//# preimage in arg_0 is " "
arg_0
sha256
byte base64 Nqnn8clbgv+5l0PgxcTOldg8mkMKrFn4TvPL+rYUUGg=
==
$

$ ./goal clerk compile ex2.teal
ex2.teal: EOWMS2Z5YWXALIJBQ5V7LOG36K2IRCCLQCDNXCQRMR7VOREE7AZX6KOW6U
$ ls ex2.*
ex2.teal  ex2.teal.tok
$ ./goal clerk compile -D ex2.teal.tok
// version 1
bytecblock 0x36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068
arg_0
sha256
bytec_0
==

A " " hash preimage base64-es alakja:


$ printf " " | base64
IA==
$

A tranzakció, amely a szerződésből próbál költeni:


$ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program ex2.teal -d data -o ex2.txn --argb64 IA== 

$ ./goal clerk dryrun -t ex2.txn -d data
tx[0] cost=11 trace:
  1 bytecblock => <empty stack>
 36 arg_0 => 20
 37 sha256 => 36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068
 38 bytec_0 => 36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068
 39 == => 1 0x1

 - pass -
$

Mint az előző példában, most is fel kell tölteni a szerződést a goal clerk send paranccsal. Ezt követően a goal clerk rawsend paranccsal küldhető el a tranzakció az Algorand hálózatnak.


$ ./goal clerk send -a 100000 -f I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM -t EOWMS2Z5YWXALIJBQ5V7LOG36K2IRCCLQCDNXCQRMR7VOREE7AZX6KOW6U -d data
Please enter the password for wallet 'w1': 
Sent 100000 MicroAlgos from account I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM to address EOWMS2Z5YWXALIJBQ5V7LOG36K2IRCCLQCDNXCQRMR7VOREE7AZX6KOW6U, transaction ID: S5ECADUE3K3Q7G5VD34FGYHHU4BEC4N4U6HCRQLPCLSOTJD5DLBQ. Fee set to 1000
Transaction S5ECADUE3K3Q7G5VD34FGYHHU4BEC4N4U6HCRQLPCLSOTJD5DLBQ still pending as of round 751240
Transaction S5ECADUE3K3Q7G5VD34FGYHHU4BEC4N4U6HCRQLPCLSOTJD5DLBQ committed in round 751242

$ ./goal clerk rawsend -f ex2.txn -d data
Raw transaction ID G7GY6RLD6SNUDC3IIGS5I35BBNE3OJGBBDVAGIQPXFH7KLCY63MA issued
Transaction G7GY6RLD6SNUDC3IIGS5I35BBNE3OJGBBDVAGIQPXFH7KLCY63MA still pending as of round 751261
Transaction G7GY6RLD6SNUDC3IIGS5I35BBNE3OJGBBDVAGIQPXFH7KLCY63MA committed in round 751263

Megjegyzés: Ha preimage-nek a "" üres stringet választottuk volna, akkor azt nem tudtuk volna megadni --argb64 paraméterként.

Téma és variációk: fogadás hash preimage használatával

Képzeljük el, hogy szeretnénk az Algorand blokkláncon fogadást kötni arra vonatkozóan, hogy vajon az FTC vagy a Vasas győz-e a következő rangadón. A fogadóiroda előre létre tud hozni nekünk egy szerződést arra a csapatra vonatkozóan, amelyre fogadni szeretnénk. A fogadóiroda el tudja helyezni a szerződésben az következő adatok hash-ét:

sha256("XXX győzött"+"dátum"+"a mi nyilvános kulcsunk"+"titok"), ahol a titok 32 kvázi-véletlen byte,

majd elküldi nekünk a szerződés címét. Ezt követően a szerződésre el tudjuk küldeni a fogadás díját, és a fogadóiroda is el tudja küldeni a szerződésnek a nyeremény összegét.

Ha nyertünk, akkor a fogadóiroda elküldi nekünk a hash preimage-et, vagyis a "XXX győzött"+"dátum"+"a mi nyilvános kulcsunk"+"titok" üzenetet. Ennek birtokában fel tudjuk venni a szerdődésre átutalt nyereményt. Persze, más is képes lenne erre, ha megtudja a hash preimage-et! (Kérdés: lehet-e olyan szerződést írni, amelyből csak a nyertes képes felvenni a nyereményt?)

A hash preimage és a hash kialakítása Python-ban:


$ python
>>> import hashlib
>>> import base64
>>>
>>> import os
>>> a=os.urandom(32)
>>> a.encode('base64')
'WxsT3Syh2yGp3pKkynTf1vc8YufC0raLMKQm5o8/Pn4=\n'
>>> 
>>> b="FTC won"
>>> b
'FTC won'
>>>
>>> import time
>>> ts=time.time()
>>> ts
1575364156.828548
>>>
>>> import datetime
>>> c=datetime.datetime.fromtimestamp(ts)
>>> c
datetime.datetime(2019, 12, 3, 10, 9, 16, 828548)
>>> c.isoformat()
'2019-12-03T10:09:16.828548'
>>> d=c.isoformat()
>>> a
'[\x1b\x13\xdd,\xa1\xdb!\xa9\xde\x92\xa4\xcat\xdf\xd6\xf7<b\xe7\xc2\xd2\xb6\x8b0\xa4&\xe6\x8f?>~'
>>> b
'FTC won'
>>> d
'2019-12-03T10:09:16.828548'
>>> e=b+" "+d+" "+a
>>> e
'FTC won 2019-12-03T10:09:16.828548 [\x1b\x13\xdd,\xa1\xdb!\xa9\xde\x92\xa4\xcat\xdf\xd6\xf7<b\xe7\xc2\xd2\xb6\x8b0\xa4&\xe6\x8f?>~'
>>> base64.b64encode(e)
'RlRDIHdvbiAyMDE5LTEyLTAzVDEwOjA5OjE2LjgyODU0OCBbGxPdLKHbIanekqTKdN/W9zxi58LStoswpCbmjz8+fg=='
>>> 
>>> 
>>> hashlib.sha256(e).digest().encode('base64')
'c6cDNFNf6zN4fAkUt2fH/qCywJN4HLFTPvmJj7IDA/Y=\n'
>>> hashlib.sha256(e).hexdigest()
'73a70334535feb33787c0914b767c7fea0b2c093781cb1533ef9898fb20303f6'
>>>

A TEAL-ben megírt szerződés:


$ nano ex4.teal
// preimage in arg_0 is 'FTC won 2019-12-03T10:09:16.828548 [\x1b\x13\xdd,\xa1\xdb!\xa9\xde\x92\xa4\xcat\xdf\xd6\xf7<b\xe7\xc2\xd2\xb6\x8b0\xa4&\xe6\x8f?>~'
// preimage in base64 is  RlRDIHdvbiAyMDE5LTEyLTAzVDEwOjA5OjE2LjgyODU0OCBbGxPdLKHbIanekqTKdN/W9zxi58LS\ntoswpCbmjz8+fg==
arg_0
sha256
byte 0x73a70334535feb33787c0914b767c7fea0b2c093781cb1533ef9898fb20303f6
==
$

A szerződés lefordítása és a tranzakció kialakítása:


$ ./goal clerk compile ex4.teal
ex4.teal: C7E4FFVJP3WDMEN3QXYBTTO6K6ZDCWYTTCDLELJDYKUPJJPD7MMMEH7L7Q
$

$ $ ./goal clerk send -a 12 -t QNEOAAHOHK5CUVZVJEA4HBLIXIXFVDC6R7JXSK5Y6HHLQW3VOJWAR2AT5E -c I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM --from-program ex4.teal -d data -o ex4.txn --argb64 RlRDIHdvbiAyMDE5LTEyLTAzVDEwOjA5OjE2LjgyODU0OCBbGxPdLKHbIanekqTKdN/W9zxi58LStoswpCbmjz8+fg==
$

A szerződés tesztelése:


$ ./goal clerk dryrun -t ex4.txn -d data
tx[0] cost=11 trace:
  1 bytecblock => <empty stack>
 36 arg_0 => 46544320776f6e20323031392d31322d30335431303a30393a31362e383238353438205b1b13dd2ca1db21a9de92a4ca74dfd6f73c62e7c2d2b68b30a426e68f3f3e7e
 37 sha256 => 73a70334535feb33787c0914b767c7fea0b2c093781cb1533ef9898fb20303f6
 38 bytec_0 => 73a70334535feb33787c0914b767c7fea0b2c093781cb1533ef9898fb20303f6
 39 == => 1 0x1

 - pass -
$

A tranzakció tényleges próbája előtt a szerződés címére pénzt kell küldeni:


$ ./goal clerk send -t C7E4FFVJP3WDMEN3QXYBTTO6K6ZDCWYTTCDLELJDYKUPJJPD7MMMEH7L7Q -f I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM -a 1000000 -d data
Please enter the password for wallet 'w1': 
Sent 1000000 MicroAlgos from account I7TXJS23FOZZIDFTSQUMRVLFXNG7HCY6ZRGCQULOCMRM47M6I6PEGESSFM to address C7E4FFVJP3WDMEN3QXYBTTO6K6ZDCWYTTCDLELJDYKUPJJPD7MMMEH7L7Q, transaction ID: MHFG2GBERNRLHCMI4HJF53E7IGV6WUSVP4SC7B6AB26GLEPF556Q. Fee set to 1000
Transaction MHFG2GBERNRLHCMI4HJF53E7IGV6WUSVP4SC7B6AB26GLEPF556Q still pending as of round 752735
Transaction MHFG2GBERNRLHCMI4HJF53E7IGV6WUSVP4SC7B6AB26GLEPF556Q still pending as of round 752737
Transaction MHFG2GBERNRLHCMI4HJF53E7IGV6WUSVP4SC7B6AB26GLEPF556Q committed in round 752738

Ezután a tranzakció a "goal clerk rawsend" paranccsal elküldhető az Algroand hálózatnak:


$ ./goal clerk rawsend -f ex4.txn -d data
Raw transaction ID QARL4277KR2M2DFZMYCZCVGSHDRKYAMQDXDWES4ANT3NZ4IF5BCQ issued
Transaction QARL4277KR2M2DFZMYCZCVGSHDRKYAMQDXDWES4ANT3NZ4IF5BCQ still pending as of round 752748
Transaction QARL4277KR2M2DFZMYCZCVGSHDRKYAMQDXDWES4ANT3NZ4IF5BCQ committed in round 752750
$ 

Megtörténik a szerződés címén lévő pénz átutalása a "-t" és "-c" után megadott címekre. ("To", ill. "Close" address)

Aláírás delegálása

A TEAL másik használati módja az, hogy aláírjuk a lefordított TEAL programot valamelyik címhez tartozó titkos kulccsal. Ezek utan az adott címről történő műveletek esetén a TEAL-ben leírt logika is lefuttatásra kerül. A folyamat hasonló a szerződésnél látotthoz, csak itt az lsig JSON objektumot alkotó elemek:

Lássunk egy egyszerű példát! Küldjünk 1 /uAlgót a JW6L... címről a OSWE... címre:


$ ./goal clerk send -a 1 -f JW6L2ZCQT3UIQH5AFM3CVW3C7M3QFYHXA3EU4WHREOATRWMXP6MBFNKILM -t OSWEIKXSTSVH7KV65N24USUNANXRKGACZEG3ZF2U6UCPCSAY4WRBWAKYYU -o tx1.txn -d data_testnet
Please enter the password for wallet 'w1': 
$

Legyen a plusz logikai feltétel megvalósító TEAL program az alábbi:


$ cat p0.teal
// version 1
int 1
int 2
==
$

Fordítsuk le a TEAL logikát, és írjuk alá a TEAL logikai feltételt a küldő címhez tartozó privát kuccsal:


$ ./goal clerk compile p0.teal -s -o p0.lsig -w w2 -a JW6L2ZCQT3UIQH5AFM3CVW3C7M3QFYHXA3EU4WHREOATRWMXP6MBFNKILM -d data_testnet
Please enter the password for wallet 'w2': 
$ ./goal clerk inspect p0.lsig
Cannot decode transactions from p0.lsig: msgpack decode error [pos 3]: no matching struct field found when decoding stream map with key l
$ hexdump -C p0.lsig
00000000  82 a1 6c c4 08 01 20 02  01 02 22 23 12 a3 73 69  |..l... ..."#..si|
00000010  67 c4 40 22 54 01 61 92  8e d7 69 84 09 20 09 87  |g.@"T.a...i.. ..|
00000020  99 dd ee 14 2c 07 07 31  72 bb 1d e1 ca 64 ae 32  |....,..1r....d.2|
00000030  19 93 85 bf 4f c2 61 28  06 57 fb 11 23 2e ba c9  |....O.a(.W..#...|
00000040  81 2d 3c 46 bd 44 c2 65  17 ca c9 ef fc 3a 4a f7  |.-<F.D.e.....:J.|
00000050  42 ec 0d                                          |B..|
00000053
$ 

Írjuk alá a küldési tranzakciót a logikai feltétellel, és vizsgáljuk meg az így létrejött tranzakciót:


$ ./goal clerk sign -L p0.lsig -i tx1.txn -o stx1.txn -d data_testnet
$ ./goal clerk inspect stx1.txn
stx1.txn[0]
{
  "lsig": {
    "l": "// version 1\nintcblock 1 2\nintc_0\nintc_1\n==\n",
    "sig": "IlQBYZKO12mECSAJh5nd7hQsBwcxcrsd4cpkrjIZk4W/T8JhKAZX+xEjLrrJgS08Rr1EwmUXysnv/DpK90LsDQ=="
  },
  "txn": {
    "amt": 1,
    "fee": 1000,
    "fv": 3487330,
    "gen": "testnet-v1.0",
    "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "lv": 3488330,
    "note": "P0EZtPxSHiI=",
    "rcv": "OSWEIKXSTSVH7KV65N24USUNANXRKGACZEG3ZF2U6UCPCSAY4WRBWAKYYU",
    "snd": "JW6L2ZCQT3UIQH5AFM3CVW3C7M3QFYHXA3EU4WHREOATRWMXP6MBFNKILM",
    "type": "pay"
  }
}

$

Látható, hogy a "lsig" JSON struktúrában az "l" és a "sig" elemek vannak jelen, ahol az "l" a TEAL bytekód disassemblált alakja, a "sig" pedig egy aláírás, amely a JW6L... címhez tartozó privát kulccsal írja alá a TEAL byte kódot.

Nézzük meg szimuláció szintjén, mi történne, ha elküldenénk ezt a tranzakciót az Algorand hálózatnak:



$ ./goal clerk dryrun -t stx1.txn -d data_testnet
tx[0] cost=4 trace:
  1 intcblock => <empty stack>
  5 intc_0 => 1 0x1
  6 intc_1 => 2 0x2
  7 == => 0 0x0

REJECT
$ 

A logika természetesen elutasítja a tranzakció végrehajtását, mert az 1 és a 2 nem egyenlő egymással.

Ugyanez a tranzakció a logikai feltétel nélkül a következőképpen nézne ki:


$ ./goal clerk sign -i tx1.txn -o stx1m.txn -w w2 -d data_testnet
Please enter the password for wallet 'w2': 
lipi@lipi-VirtualBox:~/node$ ./goal clerk inspect stx1m.txn
stx1m.txn[0]
{
  "sig": "C1oisZrc/L93JL1We6MKcTy5xPUc51MKyhELaDnWqfHm3M0bPhG1rfTqYHODgfeOnc26pKFKYYRj/fmRr6O2Aw==",
  "txn": {
    "amt": 1,
    "fee": 1000,
    "fv": 3487330,
    "gen": "testnet-v1.0",
    "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "lv": 3488330,
    "note": "P0EZtPxSHiI=",
    "rcv": "OSWEIKXSTSVH7KV65N24USUNANXRKGACZEG3ZF2U6UCPCSAY4WRBWAKYYU",
    "snd": "JW6L2ZCQT3UIQH5AFM3CVW3C7M3QFYHXA3EU4WHREOATRWMXP6MBFNKILM",
    "type": "pay"
  }
}

$ ./goal clerk dryrun  -t stx1m.txn -d data_testnet
$

Kérdése van? Írjon!