tx-engine.hoon 55 KB

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