refactor UTXO selection

This commit is contained in:
timlucmiptev 2020-12-08 10:33:24 +02:00 committed by ixv
parent 63dd964a1b
commit a8cd63265d
4 changed files with 92 additions and 16 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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" !!)

View File

@ -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))