tx-engine.hoon 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181
  1. /= emission /common/schedule
  2. /= mine /common/pow
  3. /= * /common/zeke
  4. /= * /common/zoon
  5. :: tx-engine: this contains all transaction types and logic related to dumbnet.
  6. ::
  7. :: the most notable thing about how this library is written are the types. we use
  8. :: a namespacing scheme for functions that are primarily about particular types inside
  9. :: of the namespace for that type, as suggested by Ted in urbit/#6881. that is:
  10. ::
  11. :: ++ list
  12. :: =< form
  13. :: |%
  14. :: ++ form |$ [a] $?(~ [i=a t=$])
  15. :: ++ flop |*(...)
  16. :: ++ turn |*(...)
  17. :: ...
  18. :: --
  19. ::
  20. :: we refer to these types as 'B-types'
  21. ::
  22. =>
  23. ~% %dumb-transact ..stark-engine-jet-hook ~
  24. |%
  25. +| %misc-types
  26. ::
  27. :: size in bits. this is not a blockchain constant, its just an alias
  28. :: to make it clear what the atom represents and theres not a better spot
  29. :: for it.
  30. +$ size @bits
  31. ::
  32. :: $blockchain-constants
  33. ::
  34. :: type to hold all the blockchain constants. provided for convenience
  35. :: when using non-default constants.
  36. +$ blockchain-constants
  37. $+ blockchain-constants
  38. $~ :* :: max block size in bits
  39. max-block-size=`@`8.000.000
  40. :: actual number of blocks, not 2017 by counting from 0
  41. blocks-per-epoch=2.016
  42. :: 14 days measured in seconds, 1.209.600
  43. target-epoch-duration=^~(:(mul 14 24 60 60))
  44. :: how long to wait before changing candidate block timestamp
  45. update-candidate-timestamp-interval=~m2
  46. :: how far in the future to accept a timestamp on a block
  47. max-future-timestamp=^~((mul 60 120))
  48. :: how many blocks in the past to look at to compute median timestamp from
  49. :: which a new block's timestamp must be after to be considered valid
  50. min-past-blocks=11
  51. ::TODO determine appropriate genesis target
  52. genesis-target-atom=^~((div max-tip5-atom:tip5 (bex 14)))
  53. ::TODO determine a real max-target-atom. BTC uses 32 leading zeroes
  54. max-target-atom=max-tip5-atom:tip5
  55. :: whether or not to check the pow of blocks
  56. check-pow-flag=&
  57. :: minimum range of coinbase timelock
  58. coinbase-timelock-min=100
  59. :: pow puzzle length
  60. pow-len=pow-len
  61. :: how many ways the coinbase may be split
  62. max-coinbase-split=2
  63. :: first month block height. enforces lock on first month coins.
  64. first-month-coinbase-min=4.383
  65. ==
  66. $: max-block-size=size
  67. blocks-per-epoch=@
  68. target-epoch-duration=@
  69. update-candidate-timestamp-interval=@dr
  70. max-future-timestamp=@
  71. min-past-blocks=@
  72. genesis-target-atom=@
  73. max-target-atom=@
  74. check-pow-flag=?
  75. coinbase-timelock-min=@
  76. pow-len=@
  77. max-coinbase-split=@
  78. first-month-coinbase-min=@
  79. ==
  80. --
  81. ::
  82. :: tx-engine
  83. ::
  84. :: contains the tx engine. the default sample for the door is mainnet constants,
  85. :: pass something else in if you need them (and make sure to use the same door
  86. :: for all calls into this library).
  87. ~% %tx-engine +> ~
  88. |_ blockchain-constants
  89. +| %constants
  90. :: one quarter epoch duration - used in target adjustment calculation
  91. ++ quarter-ted ^~((div target-epoch-duration 4))
  92. :: 4x epoch duration - used in target adjustment calculation
  93. ++ quadruple-ted ^~((mul target-epoch-duration 4))
  94. ++ genesis-target ^~((chunk:bignum genesis-target-atom)) ::TODO set this
  95. ++ max-target ^~((chunk:bn max-target-atom))
  96. +| %simple-tx-engine-types
  97. +$ block-commitment hash
  98. +$ tx-id hash
  99. +$ coins @ud :: the smallest unit, i.e. atoms.
  100. +$ page-number @ud
  101. ++ bn bignum
  102. +$ page-summary :: used for status updates
  103. $: digest=block-id
  104. timestamp=@
  105. epoch-counter=@
  106. target=bignum:bn
  107. accumulated-work=bignum:bn
  108. height=page-number
  109. parent=block-id
  110. ==
  111. ::
  112. +| %complex-tx-engine-types
  113. ++ btc-hash
  114. =< form
  115. |%
  116. ++ form
  117. $+ btc-hash
  118. [@ux @ux @ux @ux @ux @ux @ux @ux]
  119. ++ hashable |=(=form leaf+form)
  120. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  121. --
  122. ::
  123. ++ block-id
  124. =< form
  125. |%
  126. ++ form hash
  127. ++ to-list to-list:hash
  128. ++ based based:hash
  129. ++ max-size max-size:hash
  130. --
  131. :: $hash: output of tip:zoon arm
  132. ++ hash
  133. =< form
  134. |%
  135. ++ form
  136. $+ noun-digest
  137. [@ux @ux @ux @ux @ux]
  138. ::
  139. ++ to-b58 |=(has=form `cord`(crip (en-base58 (digest-to-atom:tip5 has))))
  140. ++ from-b58 |=(=cord `form`(atom-to-digest:tip5 (de-base58 (trip cord))))
  141. ::
  142. :: +max-size: max size of hash in bits, obtained by running:
  143. :: (compute-size-jam [(dec p) (sub p 2) (sub p 3) (sub p 4) (sub p 5)])
  144. ++ max-size
  145. ^- size
  146. `size``@`403
  147. ::
  148. :: +validate: checks if elements of hash are in base field.
  149. ++ based
  150. |= has=form
  151. ^- ?
  152. =+ [a=@ b=@ c=@ d=@ e=@]=has
  153. ?& (^based a)
  154. (^based b)
  155. (^based c)
  156. (^based d)
  157. (^based e)
  158. ==
  159. ::
  160. ++ to-list
  161. |= bid=form
  162. ^- (list @)
  163. =+ [a=@ b=@ c=@ d=@ e=@]=bid
  164. [a b c d e ~]
  165. --
  166. ::
  167. ++ proof
  168. =< form
  169. |%
  170. +$ form ^proof
  171. ::
  172. :: +max-size: max size of proof in bits. We upper bound it to
  173. :: 125kb or 125000 bytes or 1000000 bits
  174. ++ max-size
  175. ^- size
  176. `size``@`1.000.000
  177. ::
  178. ++ hash |=(=form (hash-proof form))
  179. --
  180. ::
  181. ++ schnorr-pubkey
  182. =< form
  183. |%
  184. +$ form a-pt:curve:cheetah
  185. ::
  186. ++ based
  187. |= =form
  188. ^- ?
  189. (a-pt-based:curve:cheetah form)
  190. ::
  191. ++ validate
  192. |= =form
  193. (in-g:affine:curve:cheetah form)
  194. ::
  195. ++ to-b58 |=(sop=form `cord`(a-pt-to-base58:cheetah sop))
  196. ++ from-b58 |=(=cord `form`(base58-to-a-pt:cheetah cord))
  197. ++ to-lock |=(sop=form (new:lock sop))
  198. ++ hash |=(=form (hash-hashable:tip5 leaf+form))
  199. --
  200. ++ schnorr-seckey
  201. =< form
  202. |%
  203. +$ form sk:belt-schnorr:cheetah
  204. ::
  205. ++ from-atom
  206. |= sk=@ux
  207. ^- form
  208. (atom-to-t8:belt-schnorr:cheetah sk)
  209. ::
  210. ++ to-atom
  211. |= sk=form
  212. (t8-to-atom:belt-schnorr:cheetah sk)
  213. --
  214. ++ schnorr-signature
  215. =< form
  216. |%
  217. +$ form
  218. [chal=chal:belt-schnorr:cheetah sig=sig:belt-schnorr:cheetah]
  219. ::
  220. ++ based
  221. |= =form
  222. ?& (based:belt-schnorr:cheetah chal.form)
  223. (based:belt-schnorr:cheetah sig.form)
  224. ==
  225. ::
  226. ++ hashable |=(=form leaf+form)
  227. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  228. --
  229. :: $signature: multisigs, with a single sig as a degenerate case
  230. ++ signature
  231. =< form
  232. |%
  233. +$ form (z-map schnorr-pubkey schnorr-signature)
  234. ::
  235. ++ based
  236. |= =form
  237. ^- ?
  238. %+ levy ~(tap z-by form)
  239. |= [pubkey=schnorr-pubkey sig=schnorr-signature]
  240. ?& (based:schnorr-pubkey pubkey)
  241. (based:schnorr-signature sig)
  242. ==
  243. ++ hashable
  244. |= =form
  245. ^- hashable:tip5
  246. ?~ form leaf+form
  247. :+ [hash+(hash:schnorr-pubkey p.n.form) (hashable:schnorr-signature q.n.form)]
  248. $(form l.form)
  249. $(form r.form)
  250. ::
  251. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  252. --
  253. ::
  254. :: $source: commitment to sources of an note
  255. ::
  256. :: for an ordinary note, this is a commitment to the notes that spend into a
  257. :: given note. for a coinbase, this is the hash of the previous block (this avoids
  258. :: a hash loop in airwalk)
  259. ::
  260. :: so you should be able to walk backwards through the sources of any transaction,
  261. :: and the notes that spent into that, and the notes that spent into those, etc,
  262. :: until you reach coinbase(s) at the end of that walk.
  263. ++ source
  264. =< form
  265. |%
  266. +$ form [p=^hash is-coinbase=?]
  267. ::
  268. ++ from-b58
  269. |= [h=@t c=?]
  270. %* . *form
  271. p (from-b58:^hash h)
  272. is-coinbase c
  273. ==
  274. ::
  275. ++ hashable
  276. |= =form
  277. ^- hashable:tip5
  278. :- hash+p.form
  279. leaf+is-coinbase.form
  280. ::
  281. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  282. --
  283. ::
  284. :: $nname: unique note identifier
  285. ::
  286. :: first hash is a commitment to the note's .lock and whether or
  287. :: not it has a timelock.
  288. ::
  289. :: second hash is a commitment to the note's source and actual
  290. :: timelock
  291. ::
  292. :: there are also stubs for pacts, which are currently unimplemented.
  293. :: but they are programs that must return %& in order for the note
  294. :: to be spendable, and are included in the name of the note. right
  295. :: now, pacts are ~ and always return %&.
  296. ::
  297. ::TODO for dumbnet, this will be [hash hash ~] but eventually we want (list hash)
  298. ::which should be thought of as something like a top level domain, subdomain, etc.
  299. ++ nname
  300. =< form
  301. ~% %nname ..nname ~
  302. |%
  303. +$ form [^hash ^hash ~]
  304. ::
  305. ++ new
  306. =< default
  307. |%
  308. ++ default
  309. |= [owners=lock =source =timelock]
  310. ^- form
  311. =/ first-name
  312. %- hash-hashable:tip5
  313. :* leaf+& :: outcome of first pact
  314. leaf+!=(~ timelock) :: does it have a timelock?
  315. hash+(hash:lock owners) :: owners of note
  316. leaf+~ :: first pact
  317. ==
  318. =/ last-name
  319. %- hash-hashable:tip5
  320. :* leaf+& :: outcome of second pact
  321. (hashable:^source source) :: source of note
  322. hash+(hash:^timelock timelock) :: timelock of note
  323. leaf+~ :: second pact
  324. ==
  325. [first-name last-name ~]
  326. ::
  327. ++ simple
  328. |= [owners=lock =source]
  329. ^- form
  330. (new owners source *timelock)
  331. --
  332. ::
  333. ++ from-b58
  334. |= [first=@t last=@t]
  335. ^- form
  336. :~ (from-b58:^hash first)
  337. (from-b58:^hash last)
  338. ==
  339. ::
  340. ++ to-b58
  341. |= nom=form
  342. ^- [first=@t last=@t]
  343. :- (to-b58:^hash -.nom)
  344. (to-b58:^hash +<.nom)
  345. ::
  346. ++ based
  347. |= =form
  348. ?& (based:^hash -.form)
  349. (based:^hash -.+.form)
  350. ==
  351. ::
  352. ++ hashable
  353. |= =form
  354. ^- hashable:tip5
  355. [[%hash -.form] [%hash +<.form] [%leaf +>.form]]
  356. ::
  357. ++ hash
  358. ~/ %hash
  359. |= =form
  360. (hash-hashable:tip5 (hashable form))
  361. -- ::+name
  362. ::
  363. :: $page: a block
  364. ::
  365. :: .digest: block hash, hash of +.page
  366. :: .pow: stark seeded by hash of +>.page
  367. :: .parent: .digest of parent block
  368. :: .tx-ids: ids of txs included in block
  369. :: .coinbase: $coinbase-split
  370. :: .timestamp:
  371. :: time from (arbitrary time) in seconds. not exact.
  372. :: practically, it will never exceed the goldilocks prime.
  373. :: .epoch-counter: how many blocks in current epoch (0 to 2015)
  374. :: .target: target for current epoch
  375. :: .accumulated-work: sum of work over the chain up to this point
  376. :: .height: page number of block
  377. :: .msg: optional message as a (list belt)
  378. ::
  379. :: if you're wondering where the nonce is, its in the %puzzle
  380. :: of a $proof.
  381. ::
  382. :: fields for the commitment are ordered from most frequently updated
  383. :: to least frequently updated for merkleizing efficiency - except for
  384. :: .parent, in order to allow for PoW-chain proofs to be as small as
  385. :: possible.
  386. ++ page
  387. =< form
  388. |%
  389. +$ form
  390. $+ page
  391. $: digest=block-id
  392. :: everything below this is what is hashed for the digest: +.page
  393. pow=$+(pow (unit proof))
  394. :: everything below this is what is hashed for the block commitment: +>.page
  395. parent=block-id ::TODO sam's comment on why this is here
  396. tx-ids=(z-set tx-id)
  397. coinbase=coinbase-split
  398. timestamp=@
  399. epoch-counter=@ud
  400. target=bignum:bn
  401. accumulated-work=bignum:bn
  402. height=page-number
  403. msg=page-msg
  404. ==
  405. ::
  406. :: +new: builds a minimally populated page given a parent page and key
  407. ::
  408. :: when a $page is built with +new, it is the minimal amount of state
  409. :: needed to call +block-commitment on it and then pass that commit
  410. :: to the miner to start mining on an empty block.
  411. ::
  412. :: genesis block should be built with new-genesis
  413. ::
  414. :: while we store target and accumulated-work as bignums, we
  415. :: do not yet employ bignum arithmetic
  416. ::
  417. :: We assume that par is a valid block that was obtained from
  418. :: the node's blockmap. The other arguments in the sample are
  419. :: also validated in the context in +new is called, so we skip
  420. :: validation. Notably, shares is obtained from the mining state,
  421. :: where it was validated in +set-shares.
  422. ++ new-candidate
  423. |= [par=form now=@da target-bn=bignum:bn shares=(z-map lock @)]
  424. ^- form
  425. =/ accumulated-work=bignum:bn
  426. %- chunk:bn
  427. (add (merge:bn (compute-work target-bn)) (merge:bn accumulated-work.par))
  428. =/ epoch-counter=@
  429. ?: =(+(epoch-counter.par) blocks-per-epoch) 0
  430. +(epoch-counter.par)
  431. =/ height=@ +(height.par)
  432. %* . *form
  433. ::minimum information needed to generate a valid block commitment, so
  434. ::that a miner can start mining on an empty block.
  435. height height
  436. parent digest.par
  437. timestamp (time-in-secs now)
  438. epoch-counter epoch-counter
  439. target target-bn
  440. accumulated-work accumulated-work
  441. coinbase %+ new:coinbase-split
  442. (emission-calc:coinbase height)
  443. shares
  444. ==
  445. ::
  446. :: +new-genesis: builds a minimally populated $page suitable to mine as genesis block.
  447. ::
  448. ++ new-genesis
  449. |= [tem=genesis-template timestamp=@da]
  450. ^- form
  451. :: explicitly writing out the bunts is unnecessary, but we want to make it clear
  452. :: that each of these choices was deliberate rather than unfinished
  453. %* . *form
  454. pow *(unit proof) :: pow is uninitialized because it needs to be mined
  455. tx-ids *(z-set tx-id)
  456. timestamp (time-in-secs timestamp)
  457. epoch-counter *@
  458. target genesis-target
  459. accumulated-work (compute-work genesis-target)
  460. coinbase *(z-map lock coins) :: ensure coinbase is unspendable
  461. height *page-number
  462. parent (hash:btc-hash btc-hash.tem)
  463. msg message.tem
  464. ==
  465. ::
  466. ::
  467. :: +block-commitment: hash commitment of block contents for miner
  468. ::
  469. :: this hashes everything after the .pow
  470. ++ hashable-block-commitment
  471. |= =form
  472. ^- hashable:tip5
  473. |^
  474. :* hash+parent.form
  475. hash+(hash-hashable:tip5 (hashable-tx-ids tx-ids.form))
  476. hash+(hash:coinbase-split coinbase.form)
  477. leaf+timestamp.form
  478. leaf+epoch-counter.form
  479. leaf+target.form
  480. leaf+accumulated-work.form
  481. leaf+height.form
  482. leaf+msg.form
  483. ==
  484. ::
  485. ++ hashable-tx-ids
  486. |= tx-ids=(z-set tx-id)
  487. ^- hashable:tip5
  488. ?~ tx-ids leaf+tx-ids
  489. :+ hash+n.tx-ids
  490. $(tx-ids l.tx-ids)
  491. $(tx-ids r.tx-ids)
  492. --
  493. ::
  494. ++ block-commitment
  495. |= =form
  496. (hash-hashable:tip5 (hashable-block-commitment form))
  497. ::
  498. ++ check-digest
  499. |= pag=form
  500. ^- ?
  501. ?& (based:block-id digest.pag)
  502. =(digest.pag (compute-digest pag))
  503. ==
  504. ::
  505. :: Hash pow with hash-proof and hash the rest of the page.
  506. ++ compute-digest
  507. |= pag=form
  508. ^- block-id
  509. %- hash-hashable:tip5
  510. :- ?~ pow.pag leaf+~
  511. [leaf+~ hash+(hash-proof u.pow.pag)]
  512. (hashable-block-commitment pag)
  513. ::
  514. :: +time-in-secs: returns @da in seconds.
  515. ++ time-in-secs
  516. |= now=@da
  517. ^- @
  518. =/ tar=tarp (yell now)
  519. ;: add
  520. (mul d.tar day:yo) :: seconds in a day
  521. (mul h.tar hor:yo) :: seconds in an hour
  522. (mul m.tar mit:yo) :: seconds in a minute
  523. s.tar :: seconds in a second
  524. ==
  525. ::
  526. :: +compute-size:
  527. ::
  528. :: this is equal to the size of the jammed $page plus the size of all the
  529. :: transactions (which are not inlined in the block, so must also be passed
  530. :: in). we pass in raw-txs instead of txs because this is utilized when building
  531. :: candidate blocks, and so the txs will not be available in the $consensus-state.
  532. ++ compute-size
  533. |= [pag=form raw-txs=(z-map tx-id raw-tx)]
  534. ^- size
  535. ;: add
  536. :: max size of digest in bits, we need to check against upper bound because
  537. :: a digest cannot be calculated without pow
  538. max-size:block-id
  539. :: max size of proof is 90 kb or 90000 bytes or 720000 bits
  540. max-size:proof
  541. :: size of page in number of bits. note that we do not include the digest
  542. :: or powork.
  543. (compute-size-jam `*`+>.pag)
  544. ::
  545. %+ roll
  546. ~(tap z-in tx-ids.pag)
  547. |= [id=tx-id sum-sizes=size]
  548. %+ add sum-sizes
  549. (compute-size:raw-tx (~(got z-by raw-txs) id))
  550. ==
  551. ::
  552. ++ to-local-page
  553. |= pag=form
  554. ^- local-page
  555. pag(pow (bind pow.pag |=(p=proof (jam p))))
  556. ::
  557. :: +compute-work: how much heaviness a block contribute to .accumulated-work
  558. ::
  559. :: see GetBlockProof in https://github.com/bitcoin/bitcoin/blob/master/src/chain.cpp
  560. :: last changed in commit 306ccd4927a2efe325c8d84be1bdb79edeb29b04 for the source
  561. :: of this formula.
  562. ::
  563. :: while we store target and work as bignums, we do not yet utilize bignum arithmetic.
  564. ++ compute-work
  565. |= target-bn=bignum:bn
  566. ^- bignum:bn
  567. =/ target-atom=@ (merge:bn target-bn)
  568. (chunk:bn (div max-target-atom +(target-atom)))
  569. ::
  570. ++ to-page-summary
  571. |= pag=form
  572. ^- page-summary
  573. :* digest.pag
  574. timestamp.pag
  575. epoch-counter.pag
  576. target.pag
  577. accumulated-work.pag
  578. height.pag
  579. parent.pag
  580. ==
  581. ::
  582. :: +compare-heaviness: %.y if first page is heavier, %.n otherwise
  583. ::
  584. :: second arg is $local-page since that is always how this is done right now.
  585. ++ compare-heaviness
  586. |= [pag1=form pag2=local-page]
  587. ^- ?
  588. %+ gth (merge:bn accumulated-work.pag1)
  589. (merge:bn accumulated-work.pag2)
  590. --
  591. ::
  592. :: A locally-stored page. The only difference from +page is that pow is jammed
  593. :: to save space. Must be converted into a +page (ie cue the pow) for hashing.
  594. ++ local-page
  595. =< form
  596. |%
  597. +$ form
  598. $+ local-page
  599. $: digest=block-id
  600. pow=$+(pow (unit @))
  601. parent=block-id
  602. tx-ids=(z-set tx-id)
  603. coinbase=coinbase-split
  604. timestamp=@
  605. epoch-counter=@ud
  606. target=bignum:bn
  607. accumulated-work=bignum:bn
  608. height=page-number
  609. msg=page-msg
  610. ==
  611. ::
  612. ++ to-page
  613. |= lp=form
  614. ^- page
  615. lp(pow (biff pow.lp |=(j=@ ((soft proof) (cue j)))))
  616. --
  617. ::
  618. :: +page-msg: (list belt) that enforces that each elt is a belt
  619. ++ page-msg
  620. =< form
  621. |%
  622. +$ form (list belt)
  623. ::
  624. ++ new |=(msg=cord (form (rip-correct 5 msg)))
  625. ++ validate
  626. |= tap=(list belt)
  627. ^- ?
  628. (levy tap |=(t=@ (based t)))
  629. ::
  630. ++ hash
  631. |= =form
  632. ^- ^hash
  633. (hash-hashable:tip5 leaf+form)
  634. --
  635. ::
  636. :: +genesis-seal: information to identify the correct genesis block
  637. ::
  638. :: before nockchain is launched, a bitcoin block height and message
  639. :: hash will be publicly released. the height is the height at which
  640. :: nockchain will be launched. the "correct" genesis block will
  641. :: be identified by matching the message hash with the hash of the
  642. :: message in the genesis block, and then confirming that the parent
  643. :: of the genesis block is a hash built from the message, the height,
  644. :: and the hash of the bitcoin block at that height.
  645. ::
  646. :: the height and message hash are known as the "genesis seal".
  647. ::
  648. ++ genesis-seal
  649. =< form
  650. |%
  651. +$ form
  652. %- unit
  653. $: block-height=belt
  654. msg-hash=hash
  655. ==
  656. ::
  657. ++ new
  658. |= [height=page-number msg-hash=@t]
  659. ^- form
  660. `[height (from-b58:hash msg-hash)]
  661. --
  662. ::
  663. :: $genesis-template:
  664. ::
  665. :: supplies the block hash and height of the Bitcoin block which must be
  666. :: used for the genesis block. note that the hash is a SHA256, while we
  667. :: want a 5-tuple $noun-digest. we call +new in this core with the raw
  668. :: atom representing the SHA256 hash, which then converts it into a 5-tuple.
  669. ::
  670. ++ genesis-template
  671. =< form
  672. |%
  673. +$ form
  674. $: =btc-hash
  675. block-height=@ :: interpreted as a belt
  676. message=page-msg
  677. ==
  678. ::
  679. ++ new
  680. |= [=btc-hash block-height=@ message=cord]
  681. ^- form
  682. =/ split-msg (new:page-msg message)
  683. [btc-hash block-height split-msg]
  684. ::
  685. ++ hashable
  686. |= =form
  687. ^- hashable:tip5
  688. [leaf+btc-hash.form leaf+block-height.form hash+(hash:page-msg message.form)]
  689. ::
  690. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  691. --
  692. ::
  693. ++ inputs
  694. =< form
  695. ~% %inputs ..inputs ~
  696. |%
  697. +$ form (z-map nname input)
  698. ::
  699. ++ new
  700. =< default
  701. |%
  702. ++ default
  703. |= =input
  704. ^- form
  705. (~(put z-by *form) [name.note.input input])
  706. ::
  707. ++ multi
  708. |= ips=(list input)
  709. ^- form
  710. %- ~(gas z-by *form)
  711. %+ turn ips
  712. |= inp=input
  713. [name.note.inp inp]
  714. --
  715. ::
  716. ++ names
  717. |= ips=form
  718. ^- (z-set nname)
  719. ~(key z-by ips)
  720. ::
  721. ++ roll-fees
  722. |= ips=form
  723. ^- coins
  724. %+ roll ~(val z-by ips)
  725. |= [inp=input fees=coins]
  726. (add fee.spend.inp fees)
  727. ::
  728. ++ roll-timelocks
  729. |= ips=form
  730. ^- timelock-range
  731. %+ roll ~(val z-by ips)
  732. |= [ip=input range=timelock-range]
  733. %+ merge:timelock-range
  734. range
  735. (fix-absolute:timelock timelock.note.ip origin-page.note.ip)
  736. ::
  737. :: +validate: calls validate:input on each input, and checks key/value
  738. ++ validate
  739. ~/ %validate
  740. |= ips=form
  741. ^- ?
  742. ?: =(ips *form) %.n :: tx with no inputs are not allowed.
  743. %+ levy ~(tap z-by ips)
  744. |= [name=nname inp=input]
  745. ?& (validate:input inp)
  746. =(name name.note.inp)
  747. ==
  748. ::
  749. ++ based
  750. ~/ %based
  751. |= ips=form
  752. ^- ?
  753. ?: =(ips *form)
  754. %&
  755. %+ levy ~(tap z-by ips)
  756. |= [name=nname inp=input]
  757. ?& (based:input inp)
  758. (based:nname name)
  759. ==
  760. ::
  761. ++ hashable
  762. |= =form
  763. ^- hashable:tip5
  764. ?~ form leaf+form
  765. :+ [(hashable:nname p.n.form) (hashable:input q.n.form)]
  766. $(form l.form)
  767. $(form r.form)
  768. ::
  769. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  770. --
  771. ::
  772. ++ outputs
  773. =< form
  774. ~% %outputs ..outputs ~
  775. |%
  776. +$ form (z-map lock output) :: lock is the recipient
  777. ::
  778. ++ new
  779. ~/ %new
  780. |= [ips=inputs new-page-number=page-number]
  781. ^- form
  782. ?: =(ips *inputs) !! :: zero utxo tx not allowed
  783. =| children=form
  784. =/ inputs=(list input) ~(val z-by ips)
  785. |-
  786. ?~ inputs
  787. (birth-children children new-page-number)
  788. ?. (validate:input i.inputs)
  789. ~& >>>
  790. :* %failed-spend-validate
  791. "note name "
  792. name.note.i.inputs
  793. " signature "
  794. signature.spend.i.inputs
  795. ==
  796. !!
  797. =/ seed-list=(list seed) ~(tap z-in seeds.spend.i.inputs)
  798. |-
  799. ?~ seed-list
  800. ^$(inputs t.inputs)
  801. =. children (add-seed children i.seed-list)
  802. $(seed-list t.seed-list)
  803. ::
  804. :: +validate: calls validate:output on each output, and checks key/value
  805. ++ validate
  806. ~/ %validate
  807. |= ops=form
  808. ^- ?
  809. %+ levy ~(tap z-by ops)
  810. |= [loc=lock out=output]
  811. ?& (validate:output out)
  812. =(loc lock.note.out)
  813. ==
  814. ::
  815. :: +add-seed: adds seed to $outputs of a tx
  816. ::
  817. :: this iterates over the children and checks to see if any of them
  818. :: have the same $lock as the seed. if so, add the seed to that child.
  819. :: otherwise, create a new child that contains the seed.
  820. ++ add-seed
  821. |= [children=form sed=seed]
  822. ^+ children
  823. ?: (~(has z-by children) recipient.sed)
  824. =/ child=output (~(got z-by children) recipient.sed)
  825. ?: (~(has z-in seeds.child) sed)
  826. ~& >>> "can't add same seed to an output more than once"
  827. !!
  828. =. seeds.child (~(put z-in seeds.child) sed)
  829. (~(put z-by children) recipient.sed child)
  830. =/ child=output
  831. %* . *output
  832. seeds (~(put z-in *seeds) sed)
  833. ==
  834. (~(put z-by children) recipient.sed child)
  835. ::
  836. ++ birth-children
  837. |= [children=form new-page-number=page-number]
  838. ^+ children
  839. |^
  840. =. children
  841. %- ~(run z-by children)
  842. |= child=output
  843. =. origin-page.note.child new-page-number
  844. :: to avoid a hash-loop, we hash the tails of the seeds
  845. =. source.note.child (compute-source:output child)
  846. =. child
  847. %+ roll ~(tap z-in seeds.child)
  848. |= [=seed chi=_child]
  849. =? timelock.note.chi !=(~ timelock-intent.seed)
  850. (reconcile timelock.note.child timelock-intent.seed)
  851. =. assets.note.chi (add gift.seed assets.note.chi)
  852. =. lock.note.chi recipient.seed
  853. chi
  854. ::
  855. =. name.note.child
  856. %- new:nname
  857. :* lock.note.child
  858. source.note.child
  859. timelock.note.child
  860. ==
  861. child
  862. children
  863. ::
  864. ++ reconcile
  865. |= [a=timelock b=timelock-intent]
  866. ^- timelock
  867. ?~ b a
  868. =/ b-timelock=timelock (convert-from-intent:timelock b)
  869. ?~ a b-timelock
  870. ?:(=(a b-timelock) a !!)
  871. -- ::+birth-children
  872. -- ::+outputs
  873. ::
  874. :: +raw-tx: a tx as found in the mempool, i.e. the wire format of a tx.
  875. ::
  876. :: in order for a raw-tx to grow up to become a tx, it needs to be included in
  877. :: a block. some of the data of a tx cannot be known until we know which block
  878. :: it is in. a raw-tx is all the data we can know about a transaction without
  879. :: knowing which block it is in. when a miner reads a raw-tx from the mempool,
  880. :: it should first run validate:raw-tx on it to check that the inputs are signed.
  881. :: then the miner can begin deciding how
  882. ::TODO we might want an unsigned version of this as well
  883. ++ raw-tx
  884. =< form
  885. ~% %raw-tx ..raw-tx ~
  886. |%
  887. +$ form
  888. $: id=tx-id :: hash of +.raw-tx
  889. =inputs
  890. :: the "union" of the ranges of valid page-numbers
  891. :: in which all inputs of the tx are able to spend,
  892. :: as enforced by their timelocks
  893. =timelock-range
  894. :: the sum of all fees paid by all inputs
  895. total-fees=coins
  896. ==
  897. ++ new
  898. =< default
  899. ~% %new ..new ~
  900. |%
  901. ++ default
  902. ~/ %default
  903. |= ips=inputs
  904. ^- form
  905. =/ raw-tx=form
  906. %* . *form
  907. inputs ips
  908. total-fees (roll-fees:inputs ips)
  909. timelock-range (roll-timelocks:inputs ips)
  910. ==
  911. =. raw-tx raw-tx(id (compute-id raw-tx))
  912. ?> (validate raw-tx)
  913. raw-tx
  914. :: +simple-from-note: send all assets from note to recipient
  915. ++ simple-from-note
  916. =< default
  917. |%
  918. ++ default
  919. |= [recipient=lock not=nnote sk=schnorr-seckey]
  920. ^- form
  921. %- new
  922. %- new:inputs
  923. %- simple-from-note:new:input
  924. :+ recipient
  925. not
  926. sk
  927. :: +with-refund: send all assets from note to recipient, remainder to owner
  928. ++ with-refund
  929. |= [recipient=lock gift=coins fees=coins not=nnote sk=schnorr-seckey]
  930. ^- form
  931. %- new
  932. %- new:inputs
  933. %- with-refund:simple-from-note:new:input
  934. :* recipient
  935. gift
  936. fees
  937. not
  938. sk
  939. ==
  940. --
  941. --
  942. ::
  943. ++ compute-id
  944. |= raw=form
  945. ^- tx-id
  946. %- hash-hashable:tip5
  947. :+ (hashable:inputs inputs.raw)
  948. (hashable:timelock-range timelock-range.raw)
  949. leaf+total-fees.raw
  950. ::
  951. ++ based
  952. ~/ %based
  953. |= raw=form
  954. ^- ?
  955. ?& (based:hash id.raw)
  956. (based:inputs inputs.raw)
  957. (based:timelock-range timelock-range.raw)
  958. (^based total-fees.raw)
  959. ==
  960. ::
  961. ++ validate
  962. ~/ %validate
  963. |= raw=form
  964. ^- ?
  965. =/ check-inputs (validate:inputs inputs.raw)
  966. =/ check-fees =(total-fees.raw (roll-fees:inputs inputs.raw))
  967. =/ check-timelock =(timelock-range.raw (roll-timelocks:inputs inputs.raw))
  968. =/ check-field (based:hash id.raw)
  969. =/ check-id =(id.raw (compute-id raw))
  970. :: %- %- slog
  971. :: :~ leaf+"validate-raw-tx"
  972. :: leaf+"inputs: {<check-inputs>}"
  973. :: leaf+"fees: {<check-fees>}"
  974. :: leaf+"timelock: {<check-timelock>}"
  975. :: leaf+"field: {<check-field>}"
  976. :: leaf+"id: {<check-id>}"
  977. :: ==
  978. ?& check-inputs
  979. check-fees
  980. check-timelock
  981. check-field
  982. check-id
  983. ==
  984. ::
  985. ++ inputs-names
  986. |= raw=form
  987. ^- (z-set nname)
  988. (names:inputs inputs.raw)
  989. ::
  990. :: +compute-size: returns size in number of bits
  991. ++ compute-size
  992. |= raw=form
  993. ^- size
  994. (compute-size-jam `*`raw)
  995. --
  996. ::
  997. :: $tx: once a raw-tx is being included in a block, it becomes a tx
  998. ++ tx
  999. =< form
  1000. ~% %tx ..tx ~
  1001. |%
  1002. +$ form
  1003. $: [raw-tx] :: this makes it so the head of a tx is a raw-tx
  1004. total-size=size :: the size of the raw-tx
  1005. =outputs
  1006. ==
  1007. ::
  1008. ++ new
  1009. ~/ %new
  1010. |= [raw=raw-tx new-page-number=page-number]
  1011. ^- form
  1012. =/ ops=outputs
  1013. (new:outputs inputs.raw new-page-number)
  1014. %* . *form
  1015. id id.raw
  1016. inputs inputs.raw
  1017. timelock-range timelock-range.raw
  1018. total-fees total-fees.raw
  1019. outputs ops
  1020. total-size (compute-size:raw-tx raw)
  1021. ==
  1022. ::
  1023. ++ validate
  1024. ~/ %validate
  1025. |= [tx=form new-page-number=page-number]
  1026. ^- ?
  1027. ?& (validate:raw-tx -.tx) :: inputs, total-fees, timelock-range, id
  1028. (validate:outputs outputs.tx)
  1029. =(total-size.tx (compute-size tx))
  1030. ==
  1031. ::
  1032. ++ compute-size
  1033. |= tx=form
  1034. ^- size
  1035. (compute-size:raw-tx -.tx)
  1036. -- ::+tx
  1037. ::
  1038. :: $timelock-intent: enforces $timelocks in output notes from $seeds
  1039. ::
  1040. :: the difference between $timelock and $timelock-intent is that $timelock-intent
  1041. :: permits the values ~ and [~ ~ ~] while $timelock does not permit [~ ~ ~].
  1042. :: the reason for this is that a non-null timelock intent forces the output
  1043. :: note to have this timelock. so a ~ means it does not enforce any timelock
  1044. :: restriction on the output note, while [~ ~ ~] means that the output note
  1045. :: must have a timelock of ~.
  1046. ++ timelock-intent
  1047. =< form
  1048. ~% %timelock-intent ..timelock-intent ~
  1049. |%
  1050. +$ form
  1051. %- unit :: a value of ~ indicates "no intent"
  1052. $: absolute=timelock-range :: a range of absolute page-numbers
  1053. ::
  1054. :: a range of relative diffs between the page-number of the note
  1055. :: and the range of absolute page-numbers in which the note may spend
  1056. relative=timelock-range
  1057. ==
  1058. ::
  1059. ++ based
  1060. ~/ %based
  1061. |= =form
  1062. ?~ form
  1063. %&
  1064. ?& (based:timelock-range absolute.u.form)
  1065. (based:timelock-range relative.u.form)
  1066. ==
  1067. ::
  1068. ++ hashable
  1069. ~/ %hashable
  1070. |= =form
  1071. ^- hashable:tip5
  1072. ?~ form leaf+~
  1073. :+ leaf+~
  1074. (hashable:timelock-range absolute.u.form)
  1075. (hashable:timelock-range relative.u.form)
  1076. ::
  1077. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1078. --
  1079. ::
  1080. :: $timelock: an absolute and relative range of page numbers this note may be spent
  1081. ++ timelock
  1082. =< form
  1083. ~% %timelock ..timelock ~
  1084. |%
  1085. :: A timelock, in terms of values, is a $timelock-intent that does not permit [~ ~ ~]
  1086. +$ form $|(timelock-intent |=(timelock-intent !=(+< [~ ~ ~])))
  1087. ::
  1088. ++ convert-from-intent
  1089. |= int=timelock-intent
  1090. ^- form
  1091. ?: =(int [~ ~ ~]) *form
  1092. int
  1093. ::
  1094. :: +fix-absolute: produce absolute timelock from relative timelock and page number
  1095. ++ fix-absolute
  1096. |= [til=form page-num=page-number]
  1097. ^- timelock-range
  1098. ?~ til *timelock-range
  1099. =/ make-absolute |=(relative=page-number (add relative page-num))
  1100. =/ absolutification=timelock-range
  1101. ?: =(*timelock-range relative.u.til) *timelock-range
  1102. =/ min=(unit page-number)
  1103. (bind min.relative.u.til make-absolute)
  1104. =/ max=(unit page-number)
  1105. (bind max.relative.u.til make-absolute)
  1106. (new:timelock-range [min max])
  1107. (merge:timelock-range absolutification absolute.u.til)
  1108. ::
  1109. ++ hash
  1110. ~/ %hash
  1111. |= =form
  1112. (hash-hashable:tip5 (hashable:timelock-intent form))
  1113. --
  1114. ::
  1115. :: $timelock-range: unit range of pages
  1116. ::
  1117. :: the union of all valid ranges in which all inputs of a tx may spend
  1118. :: given their timelocks. for the dumbnet, we only permit at most one utxo
  1119. :: with a non-null timelock-range per transaction.
  1120. ++ timelock-range
  1121. =< form
  1122. |%
  1123. +$ form [min=(unit page-number) max=(unit page-number)]
  1124. ::
  1125. :: +new: constructor for $timelock-range
  1126. ++ new
  1127. |= [min=(unit page-number) max=(unit page-number)]
  1128. ^- form
  1129. [min max]
  1130. ::
  1131. :: +check: check that a $page-number is in a $timelock-range
  1132. ++ check
  1133. |= [tir=form new-page-number=page-number]
  1134. ^- ?
  1135. ?: =(tir *form) %.y
  1136. =/ min-ok=?
  1137. ?~ min.tir %.y
  1138. (gte new-page-number u.min.tir)
  1139. =/ max-ok=?
  1140. ?~ max.tir %.y
  1141. (lte new-page-number u.max.tir)
  1142. &(min-ok max-ok)
  1143. ::
  1144. ++ merge
  1145. |= [a=form b=form]
  1146. ^- form
  1147. ?: =(a *form)
  1148. ?: =(b *form)
  1149. *form
  1150. b
  1151. ?: =(b *form)
  1152. a
  1153. =/ min=(unit page-number)
  1154. ?~ min.a
  1155. ?~ min.b
  1156. *(unit page-number)
  1157. min.b
  1158. ?~ min.b
  1159. min.a
  1160. `(max u.min.a u.min.b)
  1161. =/ max=(unit page-number)
  1162. ?~ max.a
  1163. ?~ max.b
  1164. *(unit page-number)
  1165. max.b
  1166. ?~ max.b
  1167. max.a
  1168. `(^min u.max.a u.max.b)
  1169. (new [min max])
  1170. ::
  1171. ++ based
  1172. |= =form
  1173. ^- ?
  1174. ?& ?~(min.form %& (^based u.min.form))
  1175. ?~(max.form %& (^based u.max.form))
  1176. ==
  1177. ::
  1178. ++ hashable
  1179. |= =form
  1180. ^- hashable:tip5
  1181. :- ?~(min.form %leaf^~ [%leaf^~ leaf+u.min.form])
  1182. ?~(max.form %leaf^~ [%leaf^~ leaf+u.max.form])
  1183. ::
  1184. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1185. --
  1186. ::
  1187. :: $lock: m-of-n signatures needed to spend a note
  1188. ::
  1189. :: m (the number of sigs needed) and n (the number of possible signers)
  1190. :: must both fit in an 8-bit number, and not be 0. so 1 <= n,m <= 255. While
  1191. :: a lock may only be "unlocked" if m =<n, we do permit constructing m>n
  1192. :: with an issued warning, since this may happen when constructing a
  1193. :: transaction piece-by-piece.
  1194. ::
  1195. :: TODO: disambiguate intermediate locks and final locks for validation.
  1196. ++ lock
  1197. =< form
  1198. ~% %lock ..lock ~
  1199. |%
  1200. +$ form
  1201. $~ [m=1 pubkeys=*(z-set schnorr-pubkey)]
  1202. [m=@udD pubkeys=(z-set schnorr-pubkey)]
  1203. ::
  1204. ++ validate
  1205. |= =form
  1206. ^- ?
  1207. ?& (validate-intermediate form)
  1208. (lte m.form ~(wyt z-in pubkeys.form))
  1209. ==
  1210. ::
  1211. ++ validate-intermediate
  1212. |= form
  1213. ^- ?
  1214. =/ num-keys=@ ~(wyt z-in pubkeys)
  1215. ::
  1216. :: validate:schnorr-pubkey is computationally intensive,
  1217. :: do not call this in performance sensistive code
  1218. =/ check-a-pt=?
  1219. %+ levy ~(tap z-in pubkeys)
  1220. validate:schnorr-pubkey
  1221. :: we do not check m <= num-keys here because we allow constructing a tx
  1222. :: piece by piece
  1223. ?& check-a-pt
  1224. (lte m 255)
  1225. !=(m 0)
  1226. (lte num-keys 255)
  1227. !=(num-keys 0)
  1228. ==
  1229. ::
  1230. ++ check
  1231. |= =form
  1232. ^- ^form
  1233. ?. (validate-intermediate form)
  1234. !!
  1235. form
  1236. ::
  1237. :: +based: checks if all components of lock struct are in based field. called
  1238. :: on the block receiver side. we skip validating that the pubkeys are valid
  1239. :: curve points because it is costly. in cases where checking validity is just
  1240. :: as fast as checking for field membership, we check for validity.
  1241. ++ based
  1242. |= =form
  1243. ?. (lte m.form 255)
  1244. %|
  1245. ?. (lte ~(wyt z-in pubkeys.form) 255)
  1246. %|
  1247. %+ levy ~(tap z-in pubkeys.form)
  1248. |= pt=schnorr-pubkey
  1249. ?& (a-pt-based:curve:cheetah pt)
  1250. :: this extra validity check costs nothing, so we throw it in
  1251. :: even though both %.n and %.y are belts.
  1252. =(%.n inf.pt)
  1253. ==
  1254. ::
  1255. ++ new
  1256. =< default
  1257. |%
  1258. ++ default
  1259. |= key=schnorr-pubkey
  1260. %- check
  1261. :* m=1
  1262. pubkeys=(~(put z-in *(z-set schnorr-pubkey)) key)
  1263. ==
  1264. ::
  1265. :: +m-of-n: m signers required of n=#keys.
  1266. ++ m-of-n
  1267. |= [m=@ud keys=(z-set schnorr-pubkey)]
  1268. %- check
  1269. =/ n=@ ~(wyt z-in keys)
  1270. ?> ?& (lte m 255)
  1271. (lte n 255)
  1272. !=(m 0) :: 0-sigs not allowed
  1273. !=(n 0) :: need at least 1 signer
  1274. ==
  1275. ~? >>> (lth n m)
  1276. """
  1277. warning: lock requires more signatures {(scow %ud m)} than there
  1278. are in .pubkeys: {(scow %ud n)}
  1279. """
  1280. [m=m pubkeys=keys]
  1281. --
  1282. ::
  1283. :: +join: union of several $locks
  1284. ++ join
  1285. |= [m=@udD locks=(list form)]
  1286. ^- form
  1287. %- check
  1288. =/ new-keys=(z-set schnorr-pubkey)
  1289. %+ roll locks
  1290. |= [loc=form keys=(z-set schnorr-pubkey)]
  1291. (~(uni z-in keys) pubkeys.loc)
  1292. (m-of-n:new m new-keys)
  1293. ::
  1294. ++ set-m
  1295. |= [lock=form new-m=@ud]
  1296. ^+ lock
  1297. %- check
  1298. =/ n=@ ~(wyt z-in pubkeys.lock)
  1299. ?> ?& (lte new-m 255)
  1300. !=(new-m 0)
  1301. ==
  1302. ~? >>> (lth n new-m)
  1303. """
  1304. warning: lock requires more signatures {(scow %ud new-m)} than there
  1305. are in .pubkeys: {(scow %ud n)}
  1306. """
  1307. lock(m new-m)
  1308. ::
  1309. ++ signers
  1310. |%
  1311. ++ add
  1312. =< default
  1313. |%
  1314. ++ default
  1315. |= [lock=form new-key=schnorr-pubkey]
  1316. ^+ lock
  1317. %- check
  1318. ?: (~(has z-in pubkeys.lock) new-key)
  1319. ~& >>> "signer {<new-key>} already exists in lock"
  1320. lock
  1321. =/ new-keys=(z-set schnorr-pubkey)
  1322. (~(put z-in pubkeys.lock) new-key)
  1323. ?> (lte ~(wyt z-in new-keys) 255)
  1324. %_ lock
  1325. pubkeys new-keys
  1326. ==
  1327. ++ multi
  1328. |= [lock=form new-keys=(z-set schnorr-pubkey)]
  1329. ^+ lock
  1330. %- check
  1331. %- ~(rep z-in new-keys)
  1332. |= [new-key=schnorr-pubkey new-lock=_lock]
  1333. (default new-lock new-key)
  1334. --
  1335. ::
  1336. ++ remove
  1337. =< default
  1338. |%
  1339. ++ default
  1340. |= [lock=form no-key=schnorr-pubkey]
  1341. ^+ lock
  1342. %- check
  1343. ?. (~(has z-in pubkeys.lock) no-key)
  1344. ~& >>> "key {<no-key>} does not exist in lock"
  1345. lock
  1346. =/ new-keys=(z-set schnorr-pubkey)
  1347. (~(del z-in pubkeys.lock) no-key)
  1348. =/ num-keys=@ ~(wyt z-in new-keys)
  1349. ~? >>> (lth num-keys m.lock)
  1350. """
  1351. warning: lock requires more signatures {(scow %ud m.lock)} than there
  1352. are in .pubkeys: {(scow %ud num-keys)}
  1353. """
  1354. lock(pubkeys new-keys)
  1355. ::
  1356. ++ multi
  1357. |= [lock=form no-keys=(z-set schnorr-pubkey)]
  1358. ^+ lock
  1359. %- check
  1360. %- ~(rep z-in no-keys)
  1361. |= [no-key=schnorr-pubkey new-lock=_lock]
  1362. (default new-lock no-key)
  1363. --
  1364. --
  1365. ::
  1366. ++ from-b58
  1367. |= [m=@ pks=(list @t)]
  1368. ^- form
  1369. %- check
  1370. %+ m-of-n:new m
  1371. %- ~(gas z-in *(z-set schnorr-pubkey))
  1372. %+ turn pks
  1373. |= pk=@t
  1374. (from-b58:schnorr-pubkey pk)
  1375. ++ to-b58
  1376. |= loc=form
  1377. ^- [m=@udD pks=(list @t)]
  1378. :- m.loc
  1379. (turn ~(tap z-in pubkeys.loc) to-b58:schnorr-pubkey)
  1380. ::
  1381. ++ hashable
  1382. |= =form
  1383. ^- hashable:tip5
  1384. |^
  1385. [leaf+m.form (hashable-pubkeys pubkeys.form)]
  1386. ::
  1387. ++ hashable-pubkeys
  1388. |= pubkeys=(z-set schnorr-pubkey)
  1389. ^- hashable:tip5
  1390. ?~ pubkeys leaf+pubkeys
  1391. :+ hash+(hash:schnorr-pubkey n.pubkeys)
  1392. $(pubkeys l.pubkeys)
  1393. $(pubkeys r.pubkeys)
  1394. --
  1395. ::
  1396. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1397. --
  1398. ::
  1399. :: $nnote: Nockchain note. A UTXO.
  1400. ++ nnote
  1401. =< form
  1402. ~% %nnote ..nnote ~
  1403. |%
  1404. +$ form
  1405. $: $: version=%0 :: utxo version number
  1406. :: the page number in which the note was added to the balance.
  1407. ::NOTE while for dumbnet this could be block-id instead, and that
  1408. ::would simplify some code, for airwalk this would lead to a hashloop
  1409. origin-page=page-number
  1410. :: a note with a null timelock has no page-number restrictions
  1411. :: on when it may be spent
  1412. =timelock
  1413. ==
  1414. ::
  1415. name=nname
  1416. =lock
  1417. =source
  1418. assets=coins
  1419. ==
  1420. ::
  1421. ++ based
  1422. ~/ %based
  1423. |= =form
  1424. ?& (based:nname name.form)
  1425. (based:lock lock.form)
  1426. (based:^hash p.source.form)
  1427. (^based assets.form)
  1428. ==
  1429. ::
  1430. ++ hashable
  1431. ~/ %hashable
  1432. |= =form
  1433. ^- hashable:tip5
  1434. :- :+ leaf+version.form
  1435. leaf+origin-page.form
  1436. hash+(hash:timelock timelock.form)
  1437. :^ hash+(hash:nname name.form)
  1438. hash+(hash:lock lock.form)
  1439. hash+(hash:source source.form)
  1440. leaf+assets.form
  1441. ::
  1442. ++ hash
  1443. ~/ %hash
  1444. |= =form
  1445. %- hash-hashable:tip5
  1446. (hashable form)
  1447. --
  1448. ::
  1449. :: $coinbase: mining reward. special kind of note
  1450. ::
  1451. ++ coinbase
  1452. =< form
  1453. |%
  1454. ++ form
  1455. $~ %* . *nnote
  1456. timelock coinbase-timelock
  1457. is-coinbase.source %.y
  1458. ==
  1459. nnote
  1460. ::
  1461. ++ validate
  1462. |= [pag=page =form]
  1463. ^- ?
  1464. ?. ?& is-coinbase.source.form
  1465. =(p.source.form parent.pag)
  1466. ==
  1467. %.n
  1468. ?: (lth height.pag first-month-coinbase-min)
  1469. =(first-month-coinbase-timelock timelock.form)
  1470. =(coinbase-timelock timelock.form)
  1471. ::
  1472. :: +new: make coinbase for page. not for genesis.
  1473. ++ new
  1474. |= [pag=page lok=lock]
  1475. =/ reward=coins (~(got z-by coinbase.pag) lok)
  1476. ^- form
  1477. =/ =timelock
  1478. ?: (lth height.pag first-month-coinbase-min)
  1479. first-month-coinbase-timelock
  1480. coinbase-timelock
  1481. =/ note=nnote
  1482. %* . *nnote
  1483. assets reward
  1484. lock lok
  1485. timelock timelock
  1486. origin-page height.pag
  1487. name (name-from-parent-hash lok parent.pag height.pag timelock)
  1488. ::
  1489. :: this uses the ID of the parent block to avoid a hashloop in airwalk
  1490. source [parent.pag %.y]
  1491. ==
  1492. ?. (validate pag note)
  1493. ~| %invalid-coinbase
  1494. !!
  1495. note
  1496. ::
  1497. :: +name-from-parent-hash: the name of a coinbase with given owner and parent block.
  1498. ++ name-from-parent-hash
  1499. |= [owners=lock parent-hash=hash height-page=@ =timelock]
  1500. ^- nname
  1501. (new:nname owners [parent-hash %.y] timelock)
  1502. ::
  1503. ++ coinbase-timelock
  1504. ^- timelock
  1505. `[*timelock-range (new:timelock-range [`coinbase-timelock-min ~])]
  1506. ::
  1507. ++ first-month-coinbase-timelock
  1508. ^- timelock
  1509. `[*timelock-range (new:timelock-range [`4.383 ~])]
  1510. ::
  1511. ++ emission-calc
  1512. |= =page-number
  1513. ^- coins
  1514. (schedule:emission `@`page-number)
  1515. --
  1516. ::
  1517. ++ shares
  1518. =< form
  1519. |%
  1520. +$ form $+(shares (z-map lock @))
  1521. ::
  1522. ++ validate
  1523. |= =form
  1524. ?& (lte ~(wyt z-by form) max-coinbase-split)
  1525. ::
  1526. %+ levy ~(tap z-by form)
  1527. |= [=lock s=@]
  1528. ?& !=(s 0)
  1529. (validate:^lock lock)
  1530. ==
  1531. ==
  1532. --
  1533. ::
  1534. :: $coinbase-split: total number of nicks split between mining pubkeys
  1535. ::
  1536. :: despite also being a (z-map lock @), this is not the same thing as .shares
  1537. :: from the mining state. this is the actual number of coins split between the
  1538. :: locks, while .shares is a proportional split used to calculate the actual
  1539. :: number.
  1540. ++ coinbase-split
  1541. =< form
  1542. |%
  1543. +$ form (z-map lock coins)
  1544. ::
  1545. :: +new: construct a coinbase with assets and shares
  1546. :: we assume $shares are already validated inside of the mining state
  1547. ++ new
  1548. |= [assets=coins shares=(z-map lock @)]
  1549. ^- form
  1550. =/ locks=(list lock) ~(tap z-in ~(key z-by shares))
  1551. ?: =(1 (lent locks))
  1552. :: if there is only one pubkey, there is no need to compute a split.
  1553. (~(put z-by *form) (snag 0 locks) assets)
  1554. ::
  1555. =/ split=(list [=lock share=@ =coins])
  1556. %+ turn ~(tap z-by shares)
  1557. |=([=lock s=@] [lock s 0])
  1558. ::
  1559. =| recursion-depth=@
  1560. =/ remaining-coins=coins assets
  1561. =/ total-shares=@
  1562. %+ roll split
  1563. |= [[=lock share=@ =coins] sum=@]
  1564. (add share sum)
  1565. |-
  1566. ?: =(0 remaining-coins)
  1567. (~(gas z-by *form) (turn split |=([l=lock s=@ t=coins] [l t])))
  1568. ?: (gth recursion-depth 2)
  1569. :: we only allow two rounds of recursion to shave microseconds
  1570. :: if any coins are left, we distribute them to the first share
  1571. =/ final-split=(list [lock coins])
  1572. (turn split |=([l=lock s=@ t=coins] [l t]))
  1573. =/ first=[l=lock c=coins] (snag 0 final-split)
  1574. =. c.first (add c.first remaining-coins)
  1575. =. final-split [first (slag 1 final-split)]
  1576. (~(gas z-by *form) final-split)
  1577. :: for each share, calculate coins = (share * total-coins) / total-shares
  1578. :: and track remainders for redistribution
  1579. =/ new-split=(list [=lock share=@ total=coins this=coins])
  1580. %+ turn split
  1581. |= [=lock share=@ current-coins=coins]
  1582. =/ coins-for-share=coins
  1583. (div (mul share remaining-coins) total-shares)
  1584. [lock share (add current-coins coins-for-share) coins-for-share]
  1585. :: calculate what's left to distribute
  1586. =/ distributed=coins
  1587. %+ roll new-split
  1588. |= [[=lock s=@ c=coins this=coins] sum=coins]
  1589. (add this sum)
  1590. ?: =(0 distributed)
  1591. :: if no coins were distributed this round, just give the remainder to
  1592. :: the first share
  1593. =/ final-split=(list [lock coins])
  1594. (turn new-split |=([l=lock s=@ t=coins h=coins] [l t]))
  1595. =/ first=[l=lock c=coins] (snag 0 final-split)
  1596. =. c.first (add c.first remaining-coins)
  1597. =. final-split [first (slag 1 final-split)]
  1598. (~(gas z-by *form) final-split)
  1599. =/ still-remaining=@ (sub remaining-coins distributed)
  1600. %= $
  1601. split (turn new-split |=([l=lock s=@ t=coins h=coins] [l s t]))
  1602. remaining-coins still-remaining
  1603. recursion-depth +(recursion-depth)
  1604. ==
  1605. ::
  1606. :: +based: checks that coinbase split is in base field.
  1607. :: Called by the receiver of a block. In cases where checking for validity
  1608. :: costs the same amount as checking if in field, we check for validity.
  1609. ++ based
  1610. |= =form
  1611. ?. (lte ~(wyt z-by form) max-coinbase-split)
  1612. %|
  1613. %+ levy ~(tap z-by form)
  1614. |= [=lock =coins]
  1615. =/ based-print
  1616. ;: (cury cat 3)
  1617. 'based-split-check: '
  1618. 'coin-not-zero: '
  1619. ?:(!=(0 coins) 'yes' 'no')
  1620. ' coins-based: '
  1621. ?:((^based coins) 'yes' 'no')
  1622. ' lock-based: '
  1623. ?:((based:^lock lock) 'yes' 'no')
  1624. ==
  1625. ~> %slog.[3 based-print]
  1626. ?& !=(0 coins)
  1627. (^based coins)
  1628. (based:^lock lock)
  1629. ==
  1630. ::
  1631. ++ hashable
  1632. |= =form
  1633. ^- hashable:tip5
  1634. ?~ form leaf+form
  1635. :+ [(hashable:lock p.n.form) leaf+q.n.form]
  1636. $(form l.form)
  1637. $(form r.form)
  1638. ::
  1639. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1640. --
  1641. ::
  1642. :: $seed: carrier of a quantity of assets from an $input to an $output
  1643. ++ seed
  1644. =< form
  1645. |%
  1646. +$ form
  1647. $: :: if non-null, enforces that output note must have precisely
  1648. :: this source
  1649. output-source=(unit source)
  1650. :: the .lock of the output note
  1651. recipient=lock
  1652. :: if non-null, enforces that output note must have precisely
  1653. :: this timelock (though [~ ~ ~] means ~). null means there
  1654. :: is no intent.
  1655. =timelock-intent
  1656. :: quantity of assets gifted to output note
  1657. gift=coins
  1658. :: check that parent hash of every seed is the hash of the
  1659. :: parent note
  1660. parent-hash=^hash
  1661. ==
  1662. ++ new
  1663. =< default
  1664. |%
  1665. ++ default
  1666. |= $: output-source=(unit source)
  1667. recipient=lock
  1668. =timelock-intent
  1669. gift=coins
  1670. parent-hash=^hash
  1671. ==
  1672. %* . *form
  1673. output-source output-source
  1674. recipient recipient
  1675. timelock-intent timelock-intent
  1676. gift gift
  1677. parent-hash parent-hash
  1678. ==
  1679. :: +simple: helper constructor with no timelock intent or output source
  1680. ++ simple
  1681. =< default
  1682. |%
  1683. ++ default
  1684. |= [recipient=lock gift=coins parent-hash=^hash]
  1685. ^- form
  1686. (new *(unit source) recipient *timelock-intent gift parent-hash)
  1687. ::
  1688. :: +from-note: seed sending all coins from a $ to recipient
  1689. ++ from-note
  1690. |= [recipient=lock note=nnote]
  1691. ^- form
  1692. (simple recipient assets.note (hash:nnote note))
  1693. --
  1694. :: delete this? there is no difference between multi and simple cases
  1695. ++ multisig
  1696. =< default
  1697. |%
  1698. ++ default
  1699. |= [recipients=lock gift=coins parent-hash=^hash]
  1700. ^- form
  1701. (new *(unit source) recipients *timelock-intent gift parent-hash)
  1702. ::
  1703. ++ from-note
  1704. |= [recipients=lock note=nnote]
  1705. ^- form
  1706. (multisig recipients assets.note (hash:nnote note))
  1707. --
  1708. --
  1709. ::
  1710. ++ based
  1711. |= =form
  1712. ^- ?
  1713. =/ based-output-source
  1714. ?~ output-source.form
  1715. %&
  1716. (based:^hash p.u.output-source.form)
  1717. ?& based-output-source
  1718. (based:lock recipient.form)
  1719. (based:timelock-intent timelock-intent.form)
  1720. (^based gift.form)
  1721. (based:^hash parent-hash.form)
  1722. ==
  1723. ::
  1724. :: +hashable: we don't include output-source since it could create a hash loop
  1725. ++ hashable
  1726. |= sed=form
  1727. ^- hashable:tip5
  1728. :^ (hashable:lock recipient.sed)
  1729. (hashable:timelock-intent timelock-intent.sed)
  1730. leaf+gift.sed
  1731. hash+parent-hash.sed
  1732. ::
  1733. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1734. --
  1735. ::
  1736. ++ seeds
  1737. =< form
  1738. ~% %seeds ..seeds ~
  1739. |%
  1740. +$ form (z-set seed)
  1741. ::
  1742. ++ new
  1743. =< default
  1744. |%
  1745. ++ default
  1746. |= seds=(list seed)
  1747. ^- form
  1748. (~(gas z-in *form) seds)
  1749. :: +new-simple-from-note-with-refund: sends gift to recipient and remainder to owner of note
  1750. ++ simple-from-note-with-refund
  1751. =< default
  1752. |%
  1753. :: +default:
  1754. ::
  1755. :: while the sample has a .fee, this is just to account for the size of
  1756. :: the refund. the .fee is stored one level up, in $spend. since this is
  1757. :: a constructor for building a tx with only one note, we necessarily
  1758. :: need to take the fee into account here.
  1759. ++ default
  1760. |= [recipient=lock gift=coins fee=coins note=nnote]
  1761. ^- form
  1762. (with-choice recipient gift fee note lock.note)
  1763. ::
  1764. :: +with-choice: choose the refund address
  1765. ++ with-choice
  1766. |= $: recipient=lock
  1767. gift=coins
  1768. fee=coins
  1769. note=nnote
  1770. refund-address=lock
  1771. ==
  1772. ^- form
  1773. ?> (lte (add gift fee) assets.note)
  1774. =/ refund=coins (sub assets.note (add gift fee))
  1775. =/ gift-seed=seed
  1776. (simple:new:seed recipient gift (hash:nnote note))
  1777. =/ refund-seed=seed
  1778. (multisig:new:seed refund-address refund (hash:nnote note))
  1779. =/ seed-list=(list seed)
  1780. :: if there is no refund, don't use the refund seed
  1781. ?: =(0 refund) ~[gift-seed]
  1782. ~[gift-seed refund-seed]
  1783. (new seed-list)
  1784. --
  1785. --
  1786. ::
  1787. ++ based
  1788. |= =form
  1789. ^- ?
  1790. %+ levy ~(tap z-in form)
  1791. |= s=seed
  1792. (based:seed s)
  1793. ::
  1794. ++ hashable
  1795. |= =form
  1796. ^- hashable:tip5
  1797. ?~ form leaf+form
  1798. :+ (hashable:seed n.form)
  1799. $(form l.form)
  1800. $(form r.form)
  1801. ::
  1802. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1803. --
  1804. ::
  1805. :: $spend: a signed collection of seeds used in an $input
  1806. ::
  1807. :: .signature: expected to be on the hash of the spend's seeds
  1808. ::
  1809. :: .seeds: the individual transfers to individual output notes
  1810. :: that the spender is authorizing
  1811. ++ spend
  1812. =< form
  1813. ~% %spend ..spend ~
  1814. |%
  1815. +$ form
  1816. $: signature=(unit signature)
  1817. :: everything below here is what is hashed for the signature
  1818. =seeds
  1819. fee=coins
  1820. ==
  1821. ::
  1822. ++ new
  1823. =< default
  1824. |%
  1825. ++ default
  1826. |= [=seeds fee=coins]
  1827. %* . *form
  1828. seeds seeds
  1829. fee fee
  1830. ==
  1831. ::
  1832. :: +simple-from-note: generates a $spend sending all assets to recipient from note
  1833. ++ simple-from-note
  1834. =< default
  1835. |%
  1836. ++ default
  1837. |= [recipient=lock note=nnote]
  1838. ^- form
  1839. =; sed=seed (new (~(put z-in *seeds) sed) 0)
  1840. (from-note:simple:new:seed recipient note)
  1841. ::
  1842. :: +with-refund: returns unspent assets to note owner
  1843. ++ with-refund
  1844. =< default
  1845. |%
  1846. ++ default
  1847. |= [recipient=lock gift=coins fee=coins note=nnote]
  1848. ^- form
  1849. =; seds=seeds (new seds fee)
  1850. (simple-from-note-with-refund:new:seeds recipient gift fee note)
  1851. ::
  1852. :: +with-choice: choose which address receives the refund
  1853. ++ with-choice
  1854. |= $: recipient=lock
  1855. gift=coins
  1856. fee=coins
  1857. note=nnote
  1858. refund-address=lock
  1859. ==
  1860. ^- form
  1861. =; seds=seeds (new seds fee)
  1862. %- with-choice:simple-from-note-with-refund:new:seeds
  1863. [recipient gift fee note refund-address]
  1864. --
  1865. --
  1866. --
  1867. ::
  1868. :: +sign: add a single signature to the seeds
  1869. ::
  1870. :: .sen: the $spend we are signing
  1871. :: .sk: the secret key being used to sign
  1872. ++ sign
  1873. ~/ %sign
  1874. |= [sen=form sk=schnorr-seckey]
  1875. ^+ sen
  1876. :: we must derive the pubkey from the seckey
  1877. =/ pk=schnorr-pubkey
  1878. %- ch-scal:affine:curve:cheetah
  1879. :* (t8-to-atom:belt-schnorr:cheetah sk)
  1880. a-gen:curve:cheetah
  1881. ==
  1882. =/ sig=schnorr-signature
  1883. %+ sign:affine:belt-schnorr:cheetah
  1884. sk
  1885. (leaf-sequence:shape (sig-hash sen))
  1886. ?: =(~ signature.sen)
  1887. %_ sen
  1888. signature `(~(put z-by *signature) pk sig)
  1889. ==
  1890. %_ sen
  1891. signature `(~(put z-by (need signature.sen)) pk sig)
  1892. ==
  1893. ::
  1894. :: +verify: verify the .signature and each seed has correct parent-hash
  1895. ++ verify
  1896. ~/ %verify
  1897. |= [sen=form parent-note=nnote]
  1898. ^- ?
  1899. ?~ signature.sen %.n
  1900. =/ parent-hash=hash (hash:nnote parent-note)
  1901. :: check that parent hash of each seed matches the note's hash
  1902. ?. (~(all z-in seeds.sen) |=(sed=seed =(parent-hash.sed parent-hash)))
  1903. %.n
  1904. ::
  1905. =/ have-pks=(z-set schnorr-pubkey) ~(key z-by u.signature.sen)
  1906. :: are there at least as many sigs as m.lock?
  1907. ?: (lth ~(wyt z-in have-pks) m.lock.parent-note)
  1908. %.n
  1909. :: check that the keys in .signature are a subset of the keys in the lock
  1910. ?. =((~(int z-in pubkeys.lock.parent-note) have-pks) have-pks)
  1911. :: =/ base58-have-pks=(list @t)
  1912. :: %+ turn ~(tap z-by have-pks)
  1913. :: to-b58:schnorr-pubkey
  1914. :: =/ base58-pubkeys=(list @t)
  1915. :: %+ turn ~(tap z-by pubkeys.lock.parent-note)
  1916. :: to-b58:schnorr-pubkey
  1917. :: intersection of pubkeys in .lock and pubkeys in .signature does not equal
  1918. :: the pubkeys in .signature
  1919. :: ~& >> "invalid signatures"
  1920. :: ~& >> "have-pks: {<base58-have-pks>}"
  1921. :: ~& >> "pubkeys.lock.parent-note: {<base58-pubkeys>}"
  1922. %.n
  1923. :: we have enough signatures, they're all from the set of pubkeys required
  1924. :: by the lock, so now we can actually verify them.
  1925. ::
  1926. :: we validate all signatures, even if there are more than m, since
  1927. :: saying a transaction is valid with invalid signatures just seems wrong.
  1928. %- ~(all z-in have-pks)
  1929. |= pk=schnorr-pubkey
  1930. %: verify:affine:belt-schnorr:cheetah
  1931. pk
  1932. (leaf-sequence:shape (sig-hash sen))
  1933. (~(got z-by u.signature.sen) pk)
  1934. ==
  1935. ::
  1936. ++ based
  1937. |= sen=form
  1938. ^- ?
  1939. =/ check-sig=?
  1940. ?~(signature.sen %& (based:signature u.signature.sen))
  1941. ?. check-sig
  1942. %|
  1943. ?& (^based fee.sen)
  1944. (based:seeds seeds.sen)
  1945. ==
  1946. ::
  1947. ++ hashable
  1948. |= sen=form
  1949. ^- hashable:tip5
  1950. :+ ?~(signature.sen %leaf^~ [%leaf^~ (hashable:signature u.signature.sen)])
  1951. (hashable:seeds seeds.sen)
  1952. leaf+fee.sen
  1953. ::
  1954. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  1955. ::
  1956. :: +sig-hash: the hash used for signing and verifying
  1957. ++ sig-hash
  1958. |= sen=form
  1959. ^- hash
  1960. %- hash-hashable:tip5
  1961. [(hashable:seeds seeds.sen) leaf+fee.sen]
  1962. --
  1963. ::
  1964. :: $input: note transfering assets to outputs within a tx
  1965. ::
  1966. :: .note: the note that is transferring assets to outputs within the tx.
  1967. :: the note must exist in the balance in order for it to spend, and it must
  1968. :: be removed from the balance atomically as it spends.
  1969. ::
  1970. :: .spend: authorized commitment to the recipient notes that the input is
  1971. :: transferring assets to and amount of assets given to each output.
  1972. ++ input
  1973. =< form
  1974. ~% %input ..input ~
  1975. |%
  1976. +$ form [note=nnote =spend]
  1977. ::
  1978. ++ new
  1979. =< default
  1980. |%
  1981. ++ default
  1982. |= [not=nnote =seeds fee=coins sk=schnorr-seckey]
  1983. ^- form
  1984. =/ sen
  1985. %+ sign:spend
  1986. (new:spend seeds fee)
  1987. sk
  1988. [not sen]
  1989. ::
  1990. :: +simple-from-note: send all assets in note to recipient
  1991. ++ simple-from-note
  1992. =< default
  1993. |%
  1994. ++ default
  1995. |= [recipient=lock not=nnote sk=schnorr-seckey]
  1996. ^- form
  1997. =/ sen=spend (simple-from-note:new:spend recipient not)
  1998. =. sen
  1999. %+ sign:spend
  2000. sen
  2001. sk
  2002. [not sen]
  2003. ::
  2004. ++ with-refund
  2005. =< default
  2006. |%
  2007. ++ default
  2008. |= [recipient=lock gift=coins fee=coins not=nnote sk=schnorr-seckey]
  2009. ^- form
  2010. =/ sen=spend
  2011. (with-refund:simple-from-note:new:spend recipient gift fee not)
  2012. =. sen
  2013. %+ sign:spend
  2014. sen
  2015. sk
  2016. [not sen]
  2017. ::
  2018. ++ with-choice
  2019. |= $: recipient=lock
  2020. gift=coins
  2021. fee=coins
  2022. not=nnote
  2023. sk=schnorr-seckey
  2024. refund-address=lock
  2025. ==
  2026. ^- form
  2027. =/ sen=spend
  2028. %- with-choice:with-refund:simple-from-note:new:spend
  2029. [recipient gift fee not refund-address]
  2030. =. sen
  2031. %+ sign:spend
  2032. sen
  2033. sk
  2034. [not sen]
  2035. --
  2036. --
  2037. --
  2038. ::
  2039. :: +validate: verifies whether an $input's .spend is valid by checking the sigs
  2040. ++ validate
  2041. ~/ %validate
  2042. |= inp=form
  2043. ^- ?
  2044. =/ check-spend=? (verify:spend spend.inp note.inp)
  2045. =/ check-gifts-and-fee=?
  2046. =/ gifts-and-fee=coins
  2047. %+ add fee.spend.inp
  2048. %+ roll ~(tap z-in seeds.spend.inp)
  2049. |= [=seed acc=coins]
  2050. :(add acc gift.seed)
  2051. =(gifts-and-fee assets.note.inp)
  2052. :: total gifts and fee is = assets in the note (coin scarcity)
  2053. :: ~& >>
  2054. :: :* %validate-input
  2055. :: spend+check-spend
  2056. :: gifts-and-fees+check-gifts-and-fee
  2057. :: ==
  2058. ?&(check-spend check-gifts-and-fee)
  2059. ::
  2060. ++ based
  2061. ~/ %based
  2062. |= inp=form
  2063. &((based:nnote note.inp) (based:spend spend.inp))
  2064. ::
  2065. ++ hashable
  2066. |= inp=form
  2067. ^- hashable:tip5
  2068. :- (hashable:nnote note.inp)
  2069. (hashable:spend spend.inp)
  2070. ::
  2071. ++ hash |=(=form (hash-hashable:tip5 (hashable form)))
  2072. --
  2073. ::
  2074. :: $output: recipient of assets transferred by some inputs in a tx
  2075. ::
  2076. :: .note: the recipient of assets transferred by some inputs in a tx,
  2077. :: and is added to the balance atomically with it receiving assets.
  2078. ::
  2079. :: .seeds: the "carrier" for the individual asset gifts it receives from
  2080. :: each input that chose to spend into it.
  2081. ++ output
  2082. =< form
  2083. ~% %output ..output ~
  2084. |%
  2085. +$ form [note=nnote =seeds]
  2086. ::
  2087. :: +compute-source: computes the source for the note from .seeds
  2088. ::
  2089. :: not to be used for coinbases - use new:coinbase
  2090. ++ compute-source
  2091. |= out=form
  2092. ^- source
  2093. :_ %.n :: is-coinbase
  2094. (hash:seeds seeds.out)
  2095. ::
  2096. ++ validate
  2097. ~/ %validate
  2098. |= out=form
  2099. ^- ?
  2100. =/ source-check=?
  2101. %+ levy ~(tap z-in seeds.out)
  2102. |= =seed
  2103. ?~ output-source.seed %.y
  2104. =(u.output-source.seed source.note.out)
  2105. =/ assets-check=?
  2106. =/ calc-assets=coins
  2107. %+ roll ~(tap z-in seeds.out)
  2108. |= [=seed acc=coins]
  2109. (add gift.seed acc)
  2110. =(calc-assets assets.note.out)
  2111. &(source-check assets-check)
  2112. --
  2113. ::
  2114. :: $tx-acc: accumulator for updating balance while processing txs
  2115. ::
  2116. :: ephemeral struct for incrementally updating balance per tx in a page,
  2117. :: and for accumulating fees and size per tx processed, to be checked
  2118. :: against the coinbase assets and max-page-size
  2119. ++ tx-acc
  2120. =< form
  2121. ~% %tx-acc ..tx-acc ~
  2122. |%
  2123. +$ form
  2124. $: balance=(z-map nname nnote)
  2125. fees=coins
  2126. =size
  2127. txs=(z-set tx)
  2128. ==
  2129. ::
  2130. :: +new: pass in the balance of the parent block to initialize the accumulator for current block
  2131. ++ new
  2132. ~/ %new
  2133. |= bal=(unit (z-map nname nnote))
  2134. :: the unit stuff is to account for the genesis block
  2135. %* . *form
  2136. balance ?~ bal *(z-map nname nnote)
  2137. u.bal
  2138. ==
  2139. ::
  2140. ++ process
  2141. ~/ %process
  2142. |= [tx-acc=form =tx new-page-number=page-number]
  2143. ^- (unit form)
  2144. %- mole
  2145. |.
  2146. ?. (validate:^tx tx new-page-number)
  2147. ~> %slog.[0 leaf+"tx invalid"] !!
  2148. ::
  2149. :: process outputs
  2150. =. balance.tx-acc
  2151. %+ roll ~(val z-by outputs.tx)
  2152. |= [op=output bal=_balance.tx-acc]
  2153. ?: (~(has z-by bal) name.note.op)
  2154. ~> %slog.[0 leaf+"tx output already exists in balance"]
  2155. !!
  2156. (~(put z-by bal) name.note.op note.op)
  2157. ::
  2158. :: process inputs
  2159. =/ [tic=timelock-range tac=form]
  2160. %+ roll ~(val z-by inputs.tx)
  2161. |= [ip=input tic=timelock-range tac=_tx-acc]
  2162. ?. =(`note.ip (~(get z-by balance.tx-acc) name.note.ip))
  2163. ~> %slog.[0 leaf+"tx input does not exist in balance"]
  2164. !!
  2165. =. balance.tac (~(del z-by balance.tac) name.note.ip)
  2166. =. fees.tac (add fees.tac fee.spend.ip)
  2167. =. tic
  2168. %+ merge:timelock-range tic
  2169. %+ fix-absolute:timelock
  2170. timelock.note.ip
  2171. origin-page.note.ip
  2172. [tic tac]
  2173. ::
  2174. ?. (check:timelock-range tic new-page-number)
  2175. ~> %slog.[0 leaf+"failed timelock check"] !!
  2176. ::
  2177. %_ tac
  2178. txs (~(put z-in txs.tac) tx)
  2179. ==
  2180. --
  2181. --