Advertisement
Guest User

Untitled

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