tx-engine.hoon 56 KB

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