From a8cd63265df27b0dc618ed07ca0b3bcf79628546 Mon Sep 17 00:00:00 2001 From: timlucmiptev Date: Tue, 8 Dec 2020 10:33:24 +0200 Subject: [PATCH] refactor UTXO selection --- UTXO-select.md | 6 ++--- app/btc-wallet-hook.hoon | 2 +- app/btc-wallet-store.hoon | 44 ++++++++++++++++++++++++------ lib/btc-wallet-store.hoon | 56 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/UTXO-select.md b/UTXO-select.md index b5cc96160..9a7224262 100644 --- a/UTXO-select.md +++ b/UTXO-select.md @@ -4,7 +4,7 @@ Creates dummy inputs and outputs. Builds a TX with them. ``` =btc -build-file %/lib/btc/hoon =bwsl -build-file %/lib/btc-wallet-store/hoon -=u (utxo:btc [pos=0 (hash256:btc [wid=32 dat=0xc493.f6f1.4668.5f76.b44f.0c77.ca88.120c.b8bc.89f5.34fe.69b6.8288.27b9.74e6.8849]) height=3 value=0]) +=u (utxo:btc [pos=0 (hash256:btc [wid=32 dat=0xc493.f6f1.4668.5f76.b44f.0c77.ca88.120c.b8bc.89f5.34fe.69b6.8288.27b9.74e6.8849]) height=3 value=0 ~]) =val0 200.000 =val1 500.000 =val2 30 @@ -12,10 +12,10 @@ Creates dummy inputs and outputs. Builds a TX with them. =eny1 0v3uc.iuebi.5qilc.l8d87.c1k6n.7iksq.nkobs.8s5he.raq40.9ff0b.5tj3u.kjtg7.aq59e.hatv7.oioam.mlsr4.pqqcd.cnbjn.pnpi2.1m5rt.k4scg =eny2 0v1gt.mc4ca.lfs0m.q1dal.lqobu.mmlbd.2umnp.lj9dr.4pf4s.pvclr.dps96.4a6i8.rt6n9.krp0r.11kqu.ckqe4.1tmat.gr754.463aj.a4b41.jj7qg +=w *walt:bwsl +=w w(bipt %bip84, confs 6) =inputs ~[[u(value val0) %0 0] [u(value val1) %0 2] [u(value val2) %0 1] [u(value val3) %1 2]] =outputs ~[[[%bech32 'bc1q59u5epktervh6fxqay2dlph0wxu9hjnx6v8n66'] value=200.100] [[%bech32 'bc1qlwd7mw33uea5m8r2lsnsrkc7gp2qynrxsfxpfm'] value=200.000]] -=w *walt:bwsl -=w w(bipt %bip84) (~(single-random-draw sut:bwsl [w eny1 923 ~ 100 outputs]) inputs) (~(single-random-draw sut:bwsl [w eny2 923 ~ 100 outputs]) inputs) diff --git a/app/btc-wallet-hook.hoon b/app/btc-wallet-hook.hoon index 344d00d72..ab6f22181 100644 --- a/app/btc-wallet-hook.hoon +++ b/app/btc-wallet-hook.hoon @@ -55,7 +55,7 @@ def ~(. (default-agent this %|) bowl) hc ~(. +> bowl) :: -++ on-init +++ on-initb ^- (quip card _this) ~& > '%btc-wallet-hook initialized' :_ this(fam-limit.state fam-limit:defaults) diff --git a/app/btc-wallet-store.hoon b/app/btc-wallet-store.hoon index 41a8cba30..214fbf404 100644 --- a/app/btc-wallet-store.hoon +++ b/app/btc-wallet-store.hoon @@ -128,16 +128,43 @@ :: %generate-address (generate-address +.act) + :: TODO: end to end tests + :: %generate-txbu + :: - get txbu and change amount + :: - if txbu is blank, fail + :: - if change is blank, send txbu as update + :: - if change: + :: - generate new change address + :: - add that address+change value to the txbu + :: - send txbu update + :: - send address update + :: - send a request for info on the address (watch it) :: %generate-txbu - =+ w=(~(get by walts) xpub.act) - ?~ w ~&(>>> "btc-wallet-store: non-existent xpub" `state) - =/ t=(unit txbu) - %~ select-utxos sut - [u.w eny.bowl last-block payee.act feyb.act txos.act] - ?~ t ~&(>>> "btc-wallet-store: insufficient balance" `state) - :_ state - ~[(send-update [%generate-txbu xpub.act u.t])] + =+ uw=(~(get by walts) xpub.act) + ?~ uw + ~|("btc-wallet-store: non-existent xpub" !!) + ?. scanned.u.uw + ~|("btc-wallet-store: wallet not scanned yet" !!) + =/ [tb=(unit txbu) chng=(unit sats)] + %~ with-change sut + [u.uw eny.bowl last-block payee.act feyb.act txos.act] + ?~ tb ~&(>>> "btc-wallet-store: insufficient balance" `state) + :: if no change, just return txbu + :: + ?~ chng + [~[(send-update [%generate-txbu xpub.act u.tb])] state] + =/ [addr=address:btc =idx w=walt] + ~(gen-address wad u.uw %1) + =+ new-txbu=(~(add-output txb u.tb) addr u.chng) + :_ state(walts (~(put by walts) xpub.act w)) + :~ (send-update [%generate-txbu xpub.act new-txbu]) + (send-update [%generate-address xpub.act addr ~]) + %+ send-request ~[requests-path] + :* %address-info last-block + addr xpub.act %1 idx + == + == :: %add-history-entry :: TODO @@ -294,6 +321,7 @@ :: ++ generate-address |= [=xpub =chyg =peta] + ^- (quip card _state) =+ uw=(~(get by walts) xpub) ?~ uw ~|("btc-wallet-store: non-existent xpub" !!) diff --git a/lib/btc-wallet-store.hoon b/lib/btc-wallet-store.hoon index 6ceba5c69..ccb4a2de6 100644 --- a/lib/btc-wallet-store.hoon +++ b/lib/btc-wallet-store.hoon @@ -71,6 +71,30 @@ (fall max-gap max-gap:defaults) (fall confs confs:defaults) == +:: txb: transaction builder helpers +:: +++ txb + |_ t=txbu + ++ value + ^- [in=sats out=sats] + :- %+ roll + %+ turn txis.t + |=(=txi value.utxo.txi) + add + %+ roll + (turn txos.t |=(=txo value.txo)) + add + :: + ++ fee + =/ [in=sats out=sats] value + (sub in out) + :: + ++ add-output + |= [=address:btc value=sats] + ^- txbu + =/ ntxo=txo [address value] + t(txos [ntxo txos.t]) + -- :: wad: door for processing walts (wallets) :: parameterized on a walt and it's chyg account :: @@ -139,6 +163,7 @@ |_ [w=walt eny=@uvJ last-block=@ud payee=(unit ship) =feyb txos=(list txo)] ++ meta-weight 10 ++ output-weight 31 + ++ n-txos (lent txos) :: ++ target-value ^- sats @@ -146,9 +171,10 @@ |=([a=sats b=sats] (add a b)) :: ++ base-weight + |= num-txos=@ud ^- vbytes %+ add meta-weight - (mul (lent txos) output-weight) + (mul num-txos output-weight) :: ++ input-weight ^- vbytes @@ -156,10 +182,15 @@ ~|("Only bech32 wallets supported" !!) 102 :: + ++ min-tx-fee + ^- sats + %+ mul feyb + (add (base-weight 1) input-weight) + :: ++ total-vbytes |= selected=(list input) ^- vbytes - %+ add base-weight + %+ add (base-weight n-txos) (mul input-weight (lent selected)) :: value of an input after fee :: 0 if net is <= 0 @@ -169,15 +200,32 @@ =/ cost (mul input-weight feyb) ?: (lte val cost) 0 (sub val cost) + :: :: +spendable: whether utxo has enough confs to spend :: ++ spendable |= =utxo:btc ^- ? (gte (num-confs last-block utxo) confs.w) + :: +with-change: + :: - choose UTXOs, if there are enough + :: - return txbu and amount of change (if any) + :: + ++ with-change + ^- [tb=(unit txbu) chng=(unit sats)] + =+ tb=select-utxos + ?~ tb [~ ~] + =+ fee=~(fee txb u.tb) + =/ costs=sats :: cost of this tx + sending another + %+ add min-tx-fee + (mul feyb vbytes.u.tb) + ?. (gth fee costs) + [tb ~] + :- tb + `(sub fee costs) :: Uses naive random selection. Should switch to branch-and-bound later. :: ++ select-utxos - |^ ^- (unit =txbu) + |^ ^- (unit txbu) =/ is=(unit (list input)) %- single-random-draw %- zing @@ -209,7 +257,7 @@ |= is=(list input) ^- (unit (list input)) =/ rng ~(. og eny) - =/ target (add target-value (mul feyb base-weight)) :: add base fees to target + =/ target (add target-value (mul feyb (base-weight n-txos))) :: add base fees to target =| [select=(list input) total=sats:btc] |- ?: =(~ is) ~ =^ n rng (rads:rng (lent is))