chia-blockchain/chia/wallet/puzzles/did_innerpuz.clvm

184 lines
6.5 KiB
Plaintext

(mod (MOD_HASH MY_PUBKEY RECOVERY_DID_LIST_HASH NUM_VERIFICATIONS_REQUIRED mode amount message my_id my_puzhash parent_innerpuzhash_amounts_for_recovery_ids pubkey recovery_list_reveal)
;message is the new puzzle in the recovery and standard spend cases
;MOD_HASH, MY_PUBKEY, RECOVERY_DID_LIST_HASH are curried into the puzzle
;EXAMPLE SOLUTION (0xcafef00d 0x12341234 0x923bf9a7856b19d335a65f12d68957d497e1f0c16c0e14baf6d120e60753a1ce 2 1 100 (q "source code") 0xdeadbeef 0xcafef00d ((0xdadadada 0xdad5dad5 200) () (0xfafafafa 0xfaf5faf5 200)) 0xfadeddab (0x22222222 0x33333333 0x44444444))
(include condition_codes.clvm)
(defmacro and ARGS
(if ARGS
(qq (if (unquote (f ARGS))
(unquote (c and (r ARGS)))
()
))
1)
)
(defmacro not (ARGS)
(qq (if (unquote ARGS) 0 1))
)
(defun is-in-list (atom items)
;; returns 1 iff `atom` is in the list of `items`
(if items
(if (= atom (f items))
1
(is-in-list atom (r items))
)
0
)
)
; takes a lisp tree and returns the hash of it
(defun sha256tree1 (TREE)
(if (l TREE)
(sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
(sha256 1 TREE)
)
)
;; utility function used by `curry_args`
(defun fix_curry_args (items core)
(if items
(qq (c (q . (unquote (f items))) (unquote (fix_curry_args (r items) core))))
core
)
)
; (curry_args sum (list 50 60)) => returns a function that is like (sum 50 60 ...)
(defun curry_args (func list_of_args) (qq (a (q . (unquote func)) (unquote (fix_curry_args list_of_args (q . 1))))))
;; (curry sum 50 60) => returns a function that is like (sum 50 60 ...)
(defun curry (func . args) (curry_args func args))
;; hash a tree with escape values representing already-hashed subtrees
;; This optimization can be useful if you know the puzzle hash of a sub-expression.
;; You probably actually want to use `curry_and_hash` though.
(defun sha256tree_esc_list
(TREE LITERALS)
(if (l TREE)
(sha256 2 (sha256tree_esc_list (f TREE) LITERALS) (sha256tree_esc_list (r TREE) LITERALS))
(if (is-in-list TREE LITERALS)
TREE
(sha256 1 TREE)
)
)
)
;; hash a tree with escape values representing already-hashed subtrees
;; This optimization can be useful if you know the tree hash of a sub-expression.
(defun sha256tree_esc
(TREE . LITERAL)
(sha256tree_esc_list TREE LITERAL)
)
;recovery message module - gets values curried in to make the puzzle
;TODO - this should probably be imported
(defun make_message_puzzle (recovering_coin newpuz pubkey)
(qq (q . (((unquote CREATE_COIN_ANNOUNCEMENT) (unquote recovering_coin)) ((unquote AGG_SIG_UNSAFE) (unquote pubkey) (unquote newpuz)))))
)
(defun-inline create_consume_message (coin_id my_id new_innerpuz pubkey)
(list ASSERT_COIN_ANNOUNCEMENT (sha256 (sha256 coin_id (sha256tree1 (make_message_puzzle my_id new_innerpuz pubkey))) my_id))
)
;; return the puzzle hash for a cc with the given `genesis-coin-checker-hash` & `inner-puzzle`
(defun-inline create_fullpuzhash (mod_hash mod_hash_hash genesis_id inner_puzzle_hash)
(sha256tree_esc (curry mod_hash mod_hash_hash genesis_id inner_puzzle_hash)
mod_hash
mod_hash_hash
inner_puzzle_hash)
)
(defun-inline create_coin_ID_for_recovery (mod_hash mod_hash_hash did parent innerpuzhash amount)
(sha256 parent (create_fullpuzhash mod_hash mod_hash_hash did innerpuzhash) amount)
)
(defmacro recreate_self (my_puzhash amount)
(qq (c CREATE_COIN (c (unquote my_puzhash) (c (unquote amount) ()))))
)
(defmacro create_new_coin (amount new_puz)
(qq (c CREATE_COIN (c (unquote new_puz) (c (unquote amount) ()))))
)
(defun check_messages_from_identities (mod_hash mod_hash_hash num_verifications_required identities my_id output new_puz parent_innerpuzhash_amounts_for_recovery_ids pubkey num_verifications)
(if identities
(if (f parent_innerpuzhash_amounts_for_recovery_ids)
(check_messages_from_identities
mod_hash
mod_hash_hash
num_verifications_required
(r identities)
my_id
(c
(create_consume_message
; create coin_id from DID
(create_coin_ID_for_recovery
mod_hash
mod_hash_hash
(f identities)
(f (f parent_innerpuzhash_amounts_for_recovery_ids))
(f (r (f parent_innerpuzhash_amounts_for_recovery_ids)))
(f (r (r (f parent_innerpuzhash_amounts_for_recovery_ids)))))
my_id
new_puz
pubkey)
output)
new_puz
(r parent_innerpuzhash_amounts_for_recovery_ids)
pubkey
(+ num_verifications 1)
)
(check_messages_from_identities
mod_hash
mod_hash_hash
num_verifications_required
(r identities)
my_id
output
new_puz
(r parent_innerpuzhash_amounts_for_recovery_ids)
pubkey
num_verifications
)
)
;if we're out of identites to check for, return our output
(if (> num_verifications num_verifications_required)
(c (list AGG_SIG_UNSAFE pubkey new_puz) output)
(if (= num_verifications num_verifications_required)
(c (list AGG_SIG_UNSAFE pubkey new_puz) output)
(x "not enough verifications")
)
)
)
)
;Spend modes:
;0 = normal spend
;1 = attest
;2 (or anything else) = recovery
;MAIN
(if mode
(if (= mode 1)
; mode one - create message
(list (recreate_self my_puzhash amount) (list CREATE_COIN message 0) (list AGG_SIG_ME MY_PUBKEY (sha256tree1 (list my_puzhash amount message))))
; mode two - recovery
; check that recovery list is not empty
(if recovery_list_reveal
(if (= (sha256tree1 recovery_list_reveal) RECOVERY_DID_LIST_HASH)
(check_messages_from_identities MOD_HASH (sha256tree1 MOD_HASH) NUM_VERIFICATIONS_REQUIRED recovery_list_reveal my_id (list (create_new_coin amount message)) message parent_innerpuzhash_amounts_for_recovery_ids pubkey 0)
(x)
)
(x)
)
)
; mode zero - normal spend
(list (create_new_coin amount message) (list AGG_SIG_ME MY_PUBKEY (sha256tree1 (list amount message))))
)
)