Advertisement
Guest User

Untitled

a guest
Oct 16th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.57 KB | None | 0 0
  1. /*
  2. It's multi-sig wallet that isn't storing public keys on chain, but rather
  3. computes merkle tree root hash out of them. It attempts to minimize
  4. storage that is used, in expense of storage to store the code and
  5. gas required to check proofs. It isn't finished and doesn't work on testnet.
  6. I guess due to tight gas credit. Still worth submitting.
  7.  
  8. Initially public keys are set in stateinit as numbered list. The first thing
  9. that is done is converting them into roothash. To build proof client may pull
  10. keys that went into building the tree from stateinit, or from internal
  11. op_set_new_numkeys message.
  12.  
  13. When order with attached list of signatures (along with proofs) arrives
  14. key numbers are used to flip bits in confirmations bitset. Once required
  15. number of bits is collected order's tx is sent.
  16.  
  17. Sequence numbers are attached to new orders, rather than individual
  18. transactions. Order body is not stored on chain and required to be sent
  19. with each message. There is no 'expiration' dict for garbage collection,
  20. but rather a mechanism to point contract to expired order
  21. so related data can be removed.
  22.  
  23. It currently supports up to 253 keys, but can be extended further.
  24.  
  25. The file below contains contract code, then fift primitives to serialize
  26. messages and construct proofs, then there are tests (line 561) that
  27. describe order lifecycle and state transitions, and testnet example.
  28. */
  29.  
  30. "Asm.fif" include
  31.  
  32. 0 constant OK
  33. 34 constant ERR_SIGNATURE_INVALID
  34. 35 constant ERR_SIGNATURE_KEY_INVALID
  35. 36 constant ERR_SIGNATURE_MISSING
  36. 37 constant ERR_SIGNATURE_REPLAY
  37. 40 constant ERR_ORDER_NOT_FOUND
  38. 41 constant ERR_ORDER_EXPIRED
  39. 50 constant ERR_NUMKEYS_COUNT
  40. 60 constant ERR_OP_UNKNOWN
  41. 61 constant ERR_MSG_TYPE_UNKNOWN
  42. 70 constant ERR_UNREACHABLE
  43.  
  44. -1 constant MSG_TYPE_EXTERNAL
  45. 0 constant MSG_TYPE_INTERNAL
  46. 85143 constant MSG_TYPE_SEQNO
  47. 101736 constant MSG_TYPE_N
  48. 116780 constant MSG_TYPE_ROOTHASH
  49. 72782 constant MSG_TYPE_CONFIRMS_FOR
  50.  
  51. 100001 constant OP_SET_NEW_NUMKEYS
  52. 100002 constant OP_DELETE_CONFIRMS_FOR
  53.  
  54. x{8_} constant EMPTY_SLICE
  55.  
  56. {
  57. MINMAX NEWC 256 STU 256 STU ENDC HASHCU
  58. } : HASH2
  59.  
  60.  
  61. // MERKLE
  62. {
  63. DUP TLEN EXPLODEVAR
  64. <{ DUP 1 INT GREATER }> PUSHCONT <{
  65. ROTREV
  66. HASH2
  67. OVER DEC ROLLREVX
  68. DEC
  69. }> PUSHCONT WHILE
  70. DROP
  71. } : MERKLE:GET_ROOTHASH
  72.  
  73.  
  74. // ITER
  75. { // s
  76. LDREF SWAP CTOS SWAP // iter, s'
  77. } : ITER:LD
  78.  
  79. { // s
  80. 1 LDU SWAP <{ // s'
  81. ITER:LD // iter, s'
  82. }> PUSHCONT <{
  83. EMPTY_SLICE PUSHSLICE SWAP
  84. }> PUSHCONT IFELSE
  85. } : ITER:LD_NULLREF
  86.  
  87. {
  88. DUP SBITS ISZERO SWAP SREFS ISZERO AND
  89. } : ITER:IS_EMPTY
  90.  
  91. { // iter
  92. DUP SBITS <{ // iter
  93. TRUE // iter, true
  94. }> PUSHCONT <{ // iter
  95. DUP SREFS 1 INT EQUAL <{ // iter
  96. LDREF ENDS CTOS TRUE // list_next, true
  97. }> PUSHCONT <{ // iter
  98. ENDS FALSE // false
  99. }> PUSHCONT IFELSE
  100. }> PUSHCONT IFELSE
  101. } : ITER:NEXT
  102.  
  103.  
  104. // HHASH_ITER
  105. {
  106. ITER:LD_NULLREF
  107. } : HHASH_ITER:LD
  108.  
  109. {
  110. ITER:NEXT <{ // s
  111. 256 LDU SWAP TRUE // s, x, true
  112. }> PUSHCONT <{ //
  113. FALSE // false
  114. }> PUSHCONT IFELSE
  115. } : HHASH_ITER:NEXT
  116.  
  117. { // hhash_iter, hash
  118. SWAP // hash, hhash_iter
  119. <{ HHASH_ITER:NEXT }> PUSHCONT <{ // hhash_iter', hhash
  120. ROT HASH2 SWAP // hash', hhash_iter
  121. }> PUSHCONT WHILE
  122. } : HHASH_ITER:HASH_WITH
  123.  
  124.  
  125. // SIG
  126. { 0 INDEX } : SIG:GET_SIGNATURE
  127. { 1 INDEX } : SIG:GET_KEY
  128. { 2 INDEX } : SIG:GET_KEY_NO
  129. { 3 INDEX } : SIG:GET_ROOTHASH
  130.  
  131. { // s
  132. 512 INT LDSLICEX // s_sig, s'
  133. DUP 264 INT PLDSLICEX HASHSU ROTREV // hash, signature, s
  134. 256 LDU 8 LDU HHASH_ITER:LD // hash, signature, key, no, hhash_iter, s'
  135. s0 s5 XCHG // s', signature, key, no, hhash_iter, hash
  136. HHASH_ITER:HASH_WITH // s', signature, key, no, roothash
  137. 4 TUPLE SWAP // sig, s
  138. } : SIG:LD
  139.  
  140. { // sig, order_hash
  141. OVER SIG:GET_SIGNATURE // sig, order_hash, signature
  142. ROT SIG:GET_KEY // order_hash, signature, key
  143. CHKSIGNU
  144. } : SIG:CHK_SIGNATURE
  145.  
  146. { // sig, roothash
  147. SWAP SIG:GET_ROOTHASH EQUAL
  148. } : SIG:CHK_ROOTHASH
  149.  
  150.  
  151. // SIG_ITER
  152. { // s
  153. ITER:LD_NULLREF
  154. } : SIG_ITER:LD
  155.  
  156. {
  157. ITER:NEXT <{ // s
  158. SIG:LD SWAP TRUE // s, sig, true
  159. }> PUSHCONT <{ //
  160. FALSE // false
  161. }> PUSHCONT IFELSE
  162. } : SIG_ITER:NEXT
  163.  
  164. {
  165. ITER:IS_EMPTY
  166. } : SIG_ITER:IS_EMPTY
  167.  
  168.  
  169. // NUMKEY
  170. { 0 INDEX } : NUMKEY:GET_KEY
  171. { 1 INDEX } : NUMKEY:GET_NO
  172. { 2 INDEX } : NUMKEY:GET_HASH
  173.  
  174. { // s
  175. 264 INT LDSLICEX SWAP HASHSU SWAP // hash, s
  176. } : NUMKEY:LD_HASH
  177.  
  178. { // s
  179. 264 INT LDSLICEX SWAP // s', s_numkey
  180. DUP HASHSU SWAP 256 LDU 8 LDU ENDS // s, hash, key, no
  181. ROT 3 TUPLE SWAP // numkey, s
  182. } : NUMKEY:LD
  183.  
  184.  
  185. // NUMKEY_ITER
  186. {
  187. ITER:LD
  188. } : NUMKEY_ITER:LD
  189.  
  190. { // numkey_iter
  191. NIL SWAP // hashes[], numkey_iter
  192. <{ ITER:NEXT }> PUSHCONT <{ // hashes[], numkey_iter'
  193. NUMKEY:LD_HASH // hashes[], hash, numkey_iter'
  194. ROTREV TPUSH SWAP // hashes[]', numkey_iter
  195. }> PUSHCONT WHILE // hashes[]
  196. } : NUMKEY_ITER:GET_HASHES
  197.  
  198.  
  199. // ORDER
  200. { 0 INDEX } : ORDER:GET_SEQNO
  201. { 1 INDEX } : ORDER:GET_EXP
  202. { 2 INDEX } : ORDER:GET_MODE
  203. { 3 INDEX } : ORDER:GET_TX
  204. { 4 INDEX } : ORDER:GET_HASH
  205.  
  206. { // s
  207. 72 INT 1 INT SPLIT SWAP // s', s_order
  208. DUP HASHSU SWAP // s, hash, s_order
  209. 32 LDU 32 LDU 8 LDU LDREF ENDS // s, hash, seqno, exp, mode, tx
  210. 4 ROLL 5 TUPLE SWAP // order, s
  211. } : ORDER:LD
  212.  
  213. {
  214. ORDER:GET_EXP NOW LEQ
  215. } : ORDER:IS_EXPIRED
  216.  
  217.  
  218. // CONFIRMS
  219. { 0 INT } : CONFIRMS:NONE
  220. { OR } : CONFIRMS:MERGE_WITH
  221. { POW2 OR } : CONFIRMS:SET_FOR
  222. { ISZERO } : CONFIRMS:IS_NONE
  223.  
  224. { // confirms
  225. 0 INT 0 INT // confirms, exp, count
  226. s2 PUSH UBITSIZE <{ // confirms, exp, count
  227. OVER POW2 s3 PUSH // confirms, exp, count, 2^exp, confirms
  228. AND SGN // confirms, exp, count, 0/1
  229. ADD // confirms, exp, count'
  230. SWAP INC SWAP // confirms, exp', count
  231. }> PUSHCONT REPEAT
  232. ROTREV 2DROP // count
  233. } : CONFIRMS:GET_COUNT
  234.  
  235. { // confirms, b
  236. OVER UBITSIZE SWAP // confirms, size, b
  237. 8 STU // confirms, b
  238. OVER UBITSIZE STUX // b'
  239. } : CONFIRMS:ST
  240.  
  241. { // s
  242. 8 LDU SWAP LDUX // confirms, s'
  243. } : CONFIRMS:LD
  244.  
  245.  
  246. // STATE
  247. { 0 INDEX } : STATE:GET_SEQNO { 0 SETINDEX } : STATE:SET_SEQNO
  248. { 1 INDEX } : STATE:GET_N { 1 SETINDEX } : STATE:SET_N
  249. { 2 INDEX } : STATE:GET_ROOTHASH { 2 SETINDEX } : STATE:SET_ROOTHASH
  250. { 3 INDEX } : STATE:GET_CONFIRMS_DICT { 3 SETINDEX } : STATE:SET_CONFIRMS_DICT
  251.  
  252. {
  253. DUP STATE:GET_SEQNO INC STATE:SET_SEQNO
  254. } : STATE:INC_SEQNO
  255.  
  256. { // state, order_hash
  257. SWAP STATE:GET_CONFIRMS_DICT // order_hash, confirms_dict
  258. 256 INT DICTUGET ERR_ORDER_NOT_FOUND THROWIFNOT // s_confirms
  259. CONFIRMS:LD ENDS // confirms
  260. } : STATE:GET_CONFIRMS_FOR
  261.  
  262. { // state, order_hash, confirms
  263. NEWC CONFIRMS:ST SWAP // state, b, order_hash
  264. s2 PUSH STATE:GET_CONFIRMS_DICT // state, order_hash, b, confirms_dict
  265. 256 INT DICTUADDB ERR_UNREACHABLE THROWIFNOT // state, confirms_dict'
  266. STATE:SET_CONFIRMS_DICT // state'
  267. } : STATE:STORE_CONFIRMS_FOR
  268.  
  269. { // state, order_hash
  270. OVER STATE:GET_CONFIRMS_DICT // state, order_hash, confirms_dict
  271. 256 INT DICTUDELGET ERR_ORDER_NOT_FOUND THROWIFNOT // state, confirms_dict', s_confirms
  272. CONFIRMS:LD ENDS // state, confirms_dict, confirms
  273. ROTREV STATE:SET_CONFIRMS_DICT // confirms, state'
  274. } : STATE:DELGET_CONFIRMS_FOR
  275.  
  276. { // state, order_hash
  277. OVER STATE:GET_CONFIRMS_DICT // state, order_hash, confirms_dict
  278. 256 INT DICTUDEL ERR_ORDER_NOT_FOUND THROWIFNOT // state, confirms_dict'
  279. STATE:SET_CONFIRMS_DICT // state'
  280. } : STATE:DELETE_CONFIRMS_FOR
  281.  
  282. { // state, n, numkey_iter
  283. NUMKEY_ITER:GET_HASHES // state, n, numkey_hashes[]
  284. OVER OVER TLEN GREATER ERR_NUMKEYS_COUNT THROWIF // state, n, numkey_hashes[]
  285. MERKLE:GET_ROOTHASH // state, n, roothash
  286. ROTREV STATE:SET_N // roothash, state'
  287. SWAP STATE:SET_ROOTHASH // state'
  288. NEWDICT STATE:SET_CONFIRMS_DICT // state'
  289. } : STATE:SET_NEW_NUMKEYS
  290.  
  291. {
  292. SWAP 4 UNPACKFIRST 5 0 REVERSE
  293. 32 STU 8 STU 256 STU STDICT
  294. } : STATE:ST
  295.  
  296.  
  297. // STATE_INIT
  298. { 1 INDEX } : STATE_INIT:GET_N
  299. { 2 INDEX } : STATE_INIT:GET_NUMKEY_ITER
  300.  
  301. {
  302. 1 INT
  303. SWAP DUP STATE_INIT:GET_N
  304. SWAP STATE_INIT:GET_NUMKEY_ITER NUMKEY_ITER:GET_HASHES MERKLE:GET_ROOTHASH
  305. NEWDICT
  306. 4 TUPLE
  307. } : STATE_INIT:GET_STATE_1
  308.  
  309.  
  310. // C4
  311. { 0 INDEX } : C4:GET_SEQNO
  312.  
  313. {
  314. C4:GET_SEQNO ISZERO
  315. } : C4:IS_STATE_INIT
  316.  
  317. {
  318. 32 LDU
  319. OVER ISZERO <{
  320. 8 LDU NUMKEY_ITER:LD
  321. 3 ROLLREV 3 TUPLE SWAP
  322. }> PUSHCONT <{
  323. 8 LDU 256 LDU LDDICT
  324. 4 ROLLREV 4 TUPLE SWAP
  325. }> PUSHCONT IFELSE
  326. } : C4:LD
  327.  
  328. <{
  329. SETCP0
  330.  
  331. DUP MSG_TYPE_EXTERNAL INT EQUAL <{ // msg, msg_type_external
  332. DROP c4 PUSHCTR CTOS C4:LD ENDS // msg, c4
  333.  
  334. DUP C4:IS_STATE_INIT <{ // msg, state_init
  335. // init state transition
  336. NIP // state_init
  337. ACCEPT
  338. STATE_INIT:GET_STATE_1 // state
  339. NEWC STATE:ST ENDC c4 POP
  340. }> PUSHCONT IFJMP
  341.  
  342. SWAP ORDER:LD SIG_ITER:LD ENDS // state, order, sig_iter
  343.  
  344. OVER ORDER:IS_EXPIRED <{
  345. // new already expired order
  346. s2 PUSH STATE:GET_SEQNO
  347. s2 PUSH ORDER:GET_SEQNO
  348. EQUAL ERR_ORDER_EXPIRED THROWIF
  349.  
  350. // removing expired order require message with 0 signatures
  351. // so not to confuse with successfully sent transaction
  352. SIG_ITER:IS_EMPTY ERR_ORDER_EXPIRED THROWIFNOT
  353.  
  354. // another requirement is that it actually exists // state, order
  355. ORDER:GET_HASH STATE:DELETE_CONFIRMS_FOR
  356. ACCEPT NEWC STATE:ST ENDC c4 POP
  357. }> PUSHCONT IFJMP // state, order, sig_iter
  358.  
  359. s2 PUSH STATE:GET_SEQNO s2 PUSH ORDER:GET_SEQNO EQUAL <{
  360. ROT STATE:INC_SEQNO ROTREV // state', order, sig_iter
  361. CONFIRMS:NONE // state, order, sig_iter, confirms_bfr
  362. }> PUSHCONT <{ // state, order, sig_iter
  363. ROT s2 PUSH ORDER:GET_HASH STATE:DELGET_CONFIRMS_FOR 3 ROLLREV // state', order, sig_iter, confirms_bfr
  364. }> PUSHCONT IFELSE
  365.  
  366. DUP 4 ROLLREV 4 ROLLREV // confirms_bfr, confirms_aft, state', order, sig_iter
  367. DUP SIG_ITER:IS_EMPTY ERR_SIGNATURE_MISSING THROWIF
  368.  
  369. <{ SIG_ITER:NEXT }> PUSHCONT <{ // ... , state, order, sig_iter', sig
  370. DUP s3 PUSH ORDER:GET_HASH // ... , state, order, sig_iter, sig, sig, order_hash
  371. SIG:CHK_SIGNATURE ERR_SIGNATURE_INVALID THROWIFNOT // ... , state, order, sig_iter, sig
  372. DUP s4 PUSH STATE:GET_ROOTHASH // ... , state, order, sig_iter, sig, sig, roothash
  373. SIG:CHK_ROOTHASH ERR_SIGNATURE_KEY_INVALID THROWIFNOT // ... , state, order, sig_iter, sig
  374. 4 ROLL SWAP SIG:GET_KEY_NO CONFIRMS:SET_FOR // confirms_bfr, state, order, sig_iter, confirms_aft'
  375. // s4 PUSH ISZERO NOT <{ 1 THROW }> PUSHCONT IF // to see gas
  376. DUP s5 PUSH NEQ <{ ACCEPT }> PUSHCONT IF // confirms_bfr, state, order, sig_iter, confirms_aft
  377. 3 ROLLREV // confirms_bfr, confirms_aft, state, order, sig_iter
  378. }> PUSHCONT WHILE // confirms_bfr, confirms_aft, state, order
  379.  
  380. 3 ROLL 3 ROLL // state, order, confirms_bfr, confirms_aft
  381. 2DUP EQUAL ERR_SIGNATURE_REPLAY THROWIF
  382. NIP
  383.  
  384. DUP CONFIRMS:GET_COUNT s3 PUSH STATE:GET_N LESS <{ // state, order, confirms
  385. SWAP ORDER:GET_HASH SWAP // state, order_hash, confirms
  386. STATE:STORE_CONFIRMS_FOR // state'
  387. }> PUSHCONT <{ // state, order, confirms
  388. DROP // state, order
  389. DUP ORDER:GET_TX SWAP ORDER:GET_MODE SENDRAWMSG // state
  390. }> PUSHCONT IFELSE
  391.  
  392. NEWC STATE:ST ENDC c4 POP
  393. }> PUSHCONT IFJMP
  394.  
  395. // DUP MSG_TYPE_INTERNAL INT EQUAL <{ // msg, msg_type_internal
  396. // DROP // msg
  397. //
  398. // c4 PUSHCTR CTOS C4:LD ENDS SWAP // state, msg
  399. // 32 LDU // state, op_code, msg
  400. //
  401. // OVER OP_SET_NEW_NUMKEYS INT EQUAL <{
  402. // NIP 8 LDU NUMKEYS:LD ENDS // state, n, numkeys
  403. // STATE:SET_NEW_NUMKEYS // state'
  404. // NEWC STATE:ST ENDC c4 POP
  405. // }> PUSHCONT IFJMP
  406. //
  407. // OVER OP_DELETE_CONFIRMS_FOR INT EQUAL <{
  408. // NIP 256 LDU ENDS // state, order_hash
  409. // STATE:DELETE_CONFIRMS_FOR // state'
  410. // NEWC STATE:ST ENDC c4 POP
  411. // }> PUSHCONT IFJMP
  412. //
  413. // ERR_OP_UNKNOWN THROW
  414. // }> PUSHCONT IFJMP
  415.  
  416. DUP MSG_TYPE_SEQNO INT EQUAL <{
  417. DROP c4 PUSHCTR CTOS C4:LD ENDS
  418. STATE:GET_SEQNO
  419. }> PUSHCONT IFJMP
  420.  
  421. DUP MSG_TYPE_N INT EQUAL <{
  422. DROP c4 PUSHCTR CTOS C4:LD ENDS
  423. STATE:GET_N
  424. }> PUSHCONT IFJMP
  425.  
  426. DUP MSG_TYPE_ROOTHASH INT EQUAL <{
  427. DROP c4 PUSHCTR CTOS C4:LD ENDS
  428. STATE:GET_ROOTHASH
  429. }> PUSHCONT IFJMP
  430.  
  431. DUP MSG_TYPE_CONFIRMS_FOR INT EQUAL <{ // order_hash, msg_type_confirms_for
  432. DROP c4 PUSHCTR CTOS C4:LD ENDS
  433. STATE:GET_CONFIRMS_FOR
  434. }> PUSHCONT IFJMP
  435.  
  436. ERR_MSG_TYPE_UNKNOWN THROW
  437. }>c constant contract-code
  438.  
  439. { // leafs, hash
  440. explode // h1, [], ... hn, l
  441. { dup 1 > } {
  442. -rot
  443. over tuple? { , } {
  444. dup tuple? { swap , } {
  445. minmax <b swap 256 u, swap 256 u, b> hashu
  446. } cond
  447. } cond
  448. over 1 - -roll
  449. 1 -
  450. } while
  451. drop
  452. } : merkle-hhash
  453.  
  454. { // b, null|cell
  455. dup null? {
  456. drop 0 1 u,
  457. } {
  458. swap 1 1 u, swap ref,
  459. } cond // b'
  460. } : nullref,
  461.  
  462. {
  463. dup sbits 0= { // s
  464. dup srefs 0= { false } {
  465. ref@+ swap s> <s true
  466. } cond
  467. } { true } cond
  468. } : iter-next@+
  469.  
  470. { // keys[]
  471. dup count 0= abort"empty list of keys"
  472.  
  473. 0 swap { // i, keys[]
  474. over 3 mod 0= { <b -rot } if // b_prev, b, i, keys[]
  475. over over over [] // ..., b, i, keys[], no, key
  476. 4 roll // ..., i, keys[], no, key, b
  477. swap B, swap 8 u, -rot // ..., b', i, keys[]
  478. swap 1 + swap // ..., b, i', keys[]
  479. } over count times // b1, ... bn, i, keys[]
  480.  
  481. drop { b> ref, } swap 3 /c 1 - times
  482. b> // numkeys
  483. } : numkeys
  484.  
  485. { // t
  486. dup count 0= {
  487. drop null
  488. } {
  489. 0 swap { // i, hhash[]
  490. over 3 mod 0= { <b -rot } if // b_prev, b, i, hhash[]
  491. 2dup swap [] // ..., b, i, hhash[], hhash
  492. 3 roll // ..., i, hhash[], hhash, b
  493. swap 256 u, -rot // ..., b', i, hhash[]
  494. swap 1 + swap // ..., b, i', hhash[]
  495. } over count times // b1, ... bn, i, hhash[]
  496.  
  497. drop { b> ref, } swap 3 /c 1 - times
  498. b> // hhash_list
  499. } cond
  500. } : hhash-list
  501.  
  502. { // numbered_keys, key
  503. 256 B>u@ swap // key', numbered_keys
  504. | swap <s { iter-next@+ } { // key, leafs[], s
  505. 256 u@+ swap // key, leafs[], s', key_n
  506. dup 4 pick = {
  507. drop swap | , swap // key, leafs[]', s
  508. 8 u@+ swap 3 -roll // no, key, leafs[], s'
  509. } { // ..., key, leafs[], s, numbered_key
  510. swap 8 u@+ // ..., key, leafs[], key_n, no, s'
  511. 3 0 reverse // ..., key, leafs[], s, no, key_n
  512. <b swap 256 u, swap 8 u, b> hashu // ..., key, leafs[], s, merkle_leaf
  513. 1 2 exch2 , swap // ..., key, leafs[]', s
  514. } cond
  515. } while // no, key, leafs[], s
  516.  
  517. s> merkle-hhash // no, key, hhash[]
  518. hhash-list -rot // hhash_list, no, key
  519. <b swap 256 u, swap 8 u, swap nullref, b> // proof
  520. } : numkeys-proof-for
  521.  
  522. { // signature, proof
  523. swap <b swap B, swap <s s, b>
  524. } : sig
  525.  
  526. { // sig[]
  527. dup count 0= {
  528. drop null
  529. } {
  530. 0 swap { // i, sig[]
  531. <b -rot // b_prev, b, i, sig[]
  532. 2dup swap [] // ..., b, i, sig[], sig
  533. 3 roll // ..., i, sig[], sig, b
  534. swap <s s, -rot // ..., b', i, sig[]
  535. swap 1 + swap // ..., b, i', sig[]
  536. } over count times // b1, ... bn, i, sig[]
  537.  
  538. drop { b> ref, } swap 1 - times
  539. b> // sig_list
  540. } cond
  541. } : sig-list
  542.  
  543. { // seqno, exp, mode, tx<>
  544. 4 0 reverse
  545. <b swap 32 u, swap 32 u, swap 8 u, swap ref, b>
  546. } : order
  547.  
  548. { // order, pvtkey, proof
  549. rot hashu rot // proof, order_hash, pvtkey
  550. ed25519_sign_uint swap // signature, proof
  551. sig
  552. } : order-sign
  553.  
  554. // comment next line to run tests // /*
  555. // /*
  556.  
  557. "TonUtil.fif" include
  558.  
  559. { // n
  560. | swap { newkeypair drop , } swap times // pvtkeys[]
  561. } : test-pvtkeys
  562.  
  563. { // prefix, n
  564. | swap {
  565. over "_key" $+ over count 1 + (.) $+ +".pk" load-generate-keypair nip ,
  566. } swap times nip // pvtkeys[]
  567. } : test-pvtkeys-saved
  568.  
  569. { // pvtkeys[]
  570. explode {
  571. swap priv>pub
  572. over -roll
  573. } over times tuple // keys[]
  574. } : priv[]>pub[]
  575.  
  576. { // pvtkeys[], n
  577. over explode {
  578. swap
  579. priv>pub
  580. over -roll
  581. } over times tuple numkeys -rot // numkeys, pvtkeys[], n
  582. [] priv>pub // numkeys, key_n
  583. numkeys-proof-for // proof_n
  584. } : test-proof-n
  585.  
  586. { // order, pvtkeys[], n
  587. 2dup test-proof-n -rot // order, proof_n, pvtkeys[], n
  588. [] swap // order, pvtkey_n, proof_n
  589. order-sign // sig
  590. } : test-sign-n
  591.  
  592. { // order, pvtkeys[], n[]
  593. explode {
  594. dup 2 + pick over 2 + pick // order, pvtkeys[], n1, ... n, l, order, pvtkeys[]
  595. 3 roll // order, pvtkeys[], n1, ... l, order, pvtkeys[], n
  596. test-sign-n // order, pvtkeys[], n1, ... l, sig_n
  597. over -roll
  598. } over times tuple nip // order, sig[]
  599.  
  600. sig-list swap // order, sig-list
  601. <b swap <s s, swap nullref, b>
  602. } : test-message
  603.  
  604. {
  605. <b 0 32 u, b>
  606. } : test-init-message
  607.  
  608. { // pvtkeys[]
  609. priv[]>pub[]
  610. dup count 2 / 1 + swap // n, keys[]
  611. numkeys swap // keys, n
  612. <b 0 32 u, swap 8 u, swap ref, b>
  613. } : test-init-c4
  614.  
  615. { // state, msg, t_delta
  616. | 0 , 1 , 2 , swap now + , 1 tuple // state, msg, c7
  617. -rot <s -1 rot // c7, msg{}, -1, state<>
  618. contract-code <s swap 4 roll // c7, msg{}, -1, code{}, state<>
  619. runvmctx // 0 (, error_code) state'
  620. over 0 = { swap } { 3 0 reverse drop } cond // state, exit_code
  621. } : test-run-external
  622.  
  623.  
  624. 7 test-pvtkeys constant users7
  625. users7 test-init-c4
  626.  
  627. test-init-message
  628. 0 test-run-external 0<> abort"init"
  629.  
  630. 1 now 60 + 0 <b b{001100} s, b> order constant order1
  631.  
  632. // order1 collected 1 signature
  633. order1 users7 | 0 , test-message
  634. 0 test-run-external OK <> abort"order1()+0"
  635.  
  636. // order1 collected 4 signatures and is sent
  637. order1 users7 | 1 , 2 , 3 , test-message
  638. 0 test-run-external OK <> abort"order1(0)+1,2,3"
  639.  
  640.  
  641. // order1 5th signature is rejected
  642. order1 users7 | 4 , test-message
  643. 0 test-run-external ERR_ORDER_NOT_FOUND <> abort"order1(0,1,2,3)+4 ERR_ORDER_NOT_FOUND"
  644.  
  645.  
  646. 2 now 60 + 0 <b b> order constant order2
  647. 3 now 60 + 0 <b b> order constant order3
  648.  
  649. // order2 collected 3 signatures
  650. order2 users7 | 1 , 2 , 3 , test-message
  651. 0 test-run-external OK <> abort"order2()+1,2,3"
  652.  
  653. // order3 has 4 signatures and is sent
  654. order3 users7 | 1 , 2 , 3 , 4 , test-message
  655. 0 test-run-external OK <> abort"order3()+1,2,3,4"
  656.  
  657. // order2 collected 4th signature and is sent
  658. order2 users7 | 4 , test-message
  659. 0 test-run-external OK <> abort"order2(1,2,3)+4"
  660.  
  661. // order2 is already sent
  662. order2 users7 | 0 , test-message
  663. 0 test-run-external ERR_ORDER_NOT_FOUND <> abort"order2(1,2,3,4)+0 ERR_ORDER_NOT_FOUND"
  664.  
  665. // order3 is already sent
  666. order3 users7 | 0 , test-message
  667. 0 test-run-external ERR_ORDER_NOT_FOUND <> abort"order3(1,2,3,4)+0 ERR_ORDER_NOT_FOUND"
  668.  
  669.  
  670. 4 now 60 + 0 <b b> order constant order4
  671. 4 now 60 + 0 <b b{00} s, b> order constant order4-alt
  672.  
  673. // order4 collected 1 signature
  674. order4 users7 | 1 , test-message
  675. 0 test-run-external OK <> abort"order4()+1"
  676.  
  677. // alternative order4 is now rejected, but throws a bit confusing error
  678. order4-alt users7 | 2 , test-message
  679. 0 test-run-external ERR_ORDER_NOT_FOUND <> abort"order4-alt()+2 ERR_ORDER_NOT_FOUND"
  680.  
  681.  
  682. 5 now 60 - 0 <b b> order constant order5-exp
  683. 5 now 60 + 0 <b b> order constant order5
  684.  
  685. // order5-exp is expired to begin with
  686. order5-exp users7 | 1 , test-message
  687. 0 test-run-external ERR_ORDER_EXPIRED <> abort"order5-exp()+1 ERR_ORDER_EXPIRED"
  688.  
  689. // order5 collected 1 signature
  690. order5 users7 | 1 , test-message
  691. 0 test-run-external OK <> abort"order5()+1"
  692.  
  693. // 90s later order5 additional signature is rejected
  694. order5 users7 | 2 , test-message
  695. 90 test-run-external ERR_ORDER_EXPIRED <> abort"order5(1)+2 +90s ERR_ORDER_EXPIRED"
  696.  
  697. // but it's removed by empty message containing no signatures
  698. order5 users7 | test-message
  699. 90 test-run-external OK <> abort"order5(1) +90s"
  700.  
  701.  
  702. 6 now 60 + 0 <b b> order constant order6
  703.  
  704. // message without signatures is accepted for expired order only
  705. order6 users7 | test-message
  706. 0 test-run-external ERR_SIGNATURE_MISSING <> abort"order6() ERR_SIGNATURE_MISSING"
  707.  
  708. // that wasn't already sent
  709. order1 users7 | test-message
  710. 90 test-run-external ERR_ORDER_NOT_FOUND <> abort"order1(0,1,2,3) +90s ERR_ORDER_NOT_FOUND"
  711.  
  712. // after order6 is signed by user1
  713. order6 users7 | 1 , test-message
  714. 0 test-run-external OK <> abort"order6()+1"
  715.  
  716. // user1's signature cannot be replayed on it's own
  717. order6 users7 | 1 , test-message
  718. 0 test-run-external ERR_SIGNATURE_REPLAY <> abort"order6(1)+1 ERR_SIGNATURE_REPLAY"
  719.  
  720. // but can be replayed as part of another list of signatures
  721. order6 users7 | 1 , 2 , 3 , test-message
  722. 0 test-run-external OK <> abort"order6(1)+1,2"
  723.  
  724. // because that message changed confirmations count
  725. order6 users7 | 2 , 3 , test-message
  726. 0 test-run-external ERR_SIGNATURE_REPLAY <> abort"order6(1,2,3)+2,3 ERR_SIGNATURE_REPLAY"
  727.  
  728.  
  729. drop
  730.  
  731. // comment next line to get testnet example
  732. // /*
  733.  
  734. { // name, count
  735. over swap test-pvtkeys-saved // name, pvtkeys[]
  736. dup priv[]>pub[] // name, pvtkeys[], keys
  737. dup count 2 / 1 + swap // name, pvtkeys[], keys, n
  738. numkeys swap
  739. <b 0 32 u, swap 8 u, swap ref, b> // name, pvtkeys[], state
  740. <b b{0011} s, contract-code ref, swap ref, dictnew dict, b> // name, pvtkeys[], state_init
  741. | 0 , over hashu , swap // name, pvtkeys[], state_init, address
  742. -rot pair swap // name, testnet_wallet, state_init
  743.  
  744. <b
  745. b{1000100} s,
  746. 2 pick second unpair addr,
  747. b{000010} s,
  748. swap <s s,
  749. b{0} s,
  750. b> 2 boc+>B // name, testnet_wallet, boc
  751. rot +".boc" B>file // testnet_wallet
  752. } : testnet-wallet
  753.  
  754. { // wallet_dest, amount
  755. swap second // amount, dest
  756. <b
  757. b{01} s,
  758. false 1 i, // bounce
  759. b{000100} s,
  760. swap unpair addr, // dest addr
  761. swap Gram, // amount
  762. 0 9 64 32 + + 1+ 1+ u,
  763. 0 32 u,
  764. "TX" $,
  765. b>
  766. } : testnet-tx
  767.  
  768. { // tx, seqno
  769. <b swap 32 u, now 7200 + 32 u, 3 8 u, swap ref, b>
  770. } : testnet-order
  771.  
  772. { // order, src_wallet, user_n[]
  773. over first // order, src_wallet, user_n[], pvtkeys[]
  774. 3 roll 3 0 reverse // src_wallet, order, pvtkeys[], user_n[]
  775. test-message // src_wallet, msg_tail
  776. swap second // msg_tail. src
  777. <b b{1000100} s, swap unpair addr, 0 Gram, b{00} s, swap <s s, b> // msg
  778. } : testnet-message
  779.  
  780.  
  781. "wallet1" 3 testnet-wallet constant wallet1
  782. "wallet2" 15 testnet-wallet constant wallet2
  783.  
  784. wallet1 second unpair 7 smca>$ constant wallet1-addr7
  785. wallet2 second unpair 7 smca>$ constant wallet2-addr7
  786.  
  787. cr
  788. cr
  789. "lite-client -c 'sendfile wallet1.boc'" type cr
  790. "lite-client -c 'last' -c 'getaccount " type wallet1-addr7 type "'" type cr
  791. "lite-client -c 'last' -c 'runmethod " type wallet1-addr7 type " seqno'" type cr
  792. cr
  793. "lite-client -c 'sendfile wallet2.boc'" type cr
  794. "lite-client -c 'last' -c 'getaccount " type wallet2-addr7 type "'" type cr
  795. "lite-client -c 'last' -c 'runmethod " type wallet2-addr7 type " seqno'" type cr
  796. cr
  797. cr
  798.  
  799. 2 constant wallet1-seqno
  800. 7 constant wallet2-seqno
  801.  
  802. "wallet1_" now (.) $+ constant wallet1-msg-filebase
  803. wallet2 "2" $>GR testnet-tx wallet1-seqno testnet-order constant wallet1-msg
  804. wallet1-msg wallet1 | 0 , 1 , testnet-message 2 boc+>B wallet1-msg-filebase +"_u0u1.boc" B>file
  805.  
  806. "lite-client -c 'sendfile " type wallet1-msg-filebase +"_u0u1.boc'" type cr
  807. " send 2 Gram from wallet1 to wallet2" type cr
  808. cr
  809.  
  810. "wallet2_" now (.) $+ constant wallet2-msg-filebase
  811. wallet1 "1" $>GR testnet-tx wallet2-seqno testnet-order constant wallet2-msg
  812. wallet2-msg wallet2 | 0 , 1 , testnet-message 2 boc+>B wallet2-msg-filebase +"_u0u1.boc" B>file
  813. wallet2-msg wallet2 | 2 , 3 , testnet-message 2 boc+>B wallet2-msg-filebase +"_u2u3.boc" B>file
  814. wallet2-msg wallet2 | 10 , 11 , 12 , 13 , testnet-message 2 boc+>B wallet2-msg-filebase +"_u10u11u12u13.boc" B>file
  815.  
  816. "lite-client -c 'sendfile " type wallet2-msg-filebase +"_u0u1.boc'" type cr
  817. "lite-client -c 'sendfile " type wallet2-msg-filebase +"_u2u3.boc'" type cr
  818. "lite-client -c 'sendfile " type wallet2-msg-filebase +"_u10u11u12u13.boc'" type cr
  819. " send 1 Gram from wallet2 to wallet1" type cr
  820. cr
  821.  
  822.  
  823. // comment next line to run heavier tests
  824. /*
  825.  
  826. // wallet can support up to 253 keys (it should be 255, but due to some overflow...)
  827. 253 test-pvtkeys constant users253
  828. users253 test-init-c4
  829.  
  830. // and it takes 600k gas to compute merkle tree root hash
  831. test-init-message
  832. 0 test-run-external 0<> abort"init"
  833.  
  834. 1 now 60 + 0 <b b> order constant order1_253
  835. 2 now 60 + 0 <b b> order constant order2_253
  836.  
  837. // checking individual signature is 37k
  838. order1_253 users253 | 0 , test-message
  839. 0 test-run-external OK <> abort"order1_253()+0"
  840.  
  841. // 1.4kk to check half of the signatures
  842. order1_253 users253 | { dup count 1 + , } users253 count 2 / times test-message
  843. 0 test-run-external OK <> abort"order1_253(0)+1...127"
  844.  
  845. // or 2.7kk to check them all
  846. order2_253 users253 | { dup count , } users253 count times test-message
  847. 0 test-run-external OK <> abort"order2_253()+0...252"
  848.  
  849. drop
  850.  
  851. // */
  852.  
  853. contract-code
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement