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 =btc -build-file %/lib/btc/hoon
=bwsl -build-file %/lib/btc-wallet-store/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 =val0 200.000
=val1 500.000 =val1 500.000
=val2 30 =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 =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 =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]] =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]] =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 eny1 923 ~ 100 outputs]) inputs)
(~(single-random-draw sut:bwsl [w eny2 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) def ~(. (default-agent this %|) bowl)
hc ~(. +> bowl) hc ~(. +> bowl)
:: ::
++ on-init ++ on-initb
^- (quip card _this) ^- (quip card _this)
~& > '%btc-wallet-hook initialized' ~& > '%btc-wallet-hook initialized'
:_ this(fam-limit.state fam-limit:defaults) :_ this(fam-limit.state fam-limit:defaults)

View File

@ -128,16 +128,43 @@
:: ::
%generate-address %generate-address
(generate-address +.act) (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 %generate-txbu
=+ w=(~(get by walts) xpub.act) =+ uw=(~(get by walts) xpub.act)
?~ w ~&(>>> "btc-wallet-store: non-existent xpub" `state) ?~ uw
=/ t=(unit txbu) ~|("btc-wallet-store: non-existent xpub" !!)
%~ select-utxos sut ?. scanned.u.uw
[u.w eny.bowl last-block payee.act feyb.act txos.act] ~|("btc-wallet-store: wallet not scanned yet" !!)
?~ t ~&(>>> "btc-wallet-store: insufficient balance" `state) =/ [tb=(unit txbu) chng=(unit sats)]
:_ state %~ with-change sut
~[(send-update [%generate-txbu xpub.act u.t])] [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 %add-history-entry
:: TODO :: TODO
@ -294,6 +321,7 @@
:: ::
++ generate-address ++ generate-address
|= [=xpub =chyg =peta] |= [=xpub =chyg =peta]
^- (quip card _state)
=+ uw=(~(get by walts) xpub) =+ uw=(~(get by walts) xpub)
?~ uw ?~ uw
~|("btc-wallet-store: non-existent xpub" !!) ~|("btc-wallet-store: non-existent xpub" !!)

View File

@ -71,6 +71,30 @@
(fall max-gap max-gap:defaults) (fall max-gap max-gap:defaults)
(fall confs confs: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) :: wad: door for processing walts (wallets)
:: parameterized on a walt and it's chyg account :: 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)] |_ [w=walt eny=@uvJ last-block=@ud payee=(unit ship) =feyb txos=(list txo)]
++ meta-weight 10 ++ meta-weight 10
++ output-weight 31 ++ output-weight 31
++ n-txos (lent txos)
:: ::
++ target-value ++ target-value
^- sats ^- sats
@ -146,9 +171,10 @@
|=([a=sats b=sats] (add a b)) |=([a=sats b=sats] (add a b))
:: ::
++ base-weight ++ base-weight
|= num-txos=@ud
^- vbytes ^- vbytes
%+ add meta-weight %+ add meta-weight
(mul (lent txos) output-weight) (mul num-txos output-weight)
:: ::
++ input-weight ++ input-weight
^- vbytes ^- vbytes
@ -156,10 +182,15 @@
~|("Only bech32 wallets supported" !!) ~|("Only bech32 wallets supported" !!)
102 102
:: ::
++ min-tx-fee
^- sats
%+ mul feyb
(add (base-weight 1) input-weight)
::
++ total-vbytes ++ total-vbytes
|= selected=(list input) |= selected=(list input)
^- vbytes ^- vbytes
%+ add base-weight %+ add (base-weight n-txos)
(mul input-weight (lent selected)) (mul input-weight (lent selected))
:: value of an input after fee :: value of an input after fee
:: 0 if net is <= 0 :: 0 if net is <= 0
@ -169,15 +200,32 @@
=/ cost (mul input-weight feyb) =/ cost (mul input-weight feyb)
?: (lte val cost) 0 ?: (lte val cost) 0
(sub val cost) (sub val cost)
::
:: +spendable: whether utxo has enough confs to spend :: +spendable: whether utxo has enough confs to spend
:: ::
++ spendable ++ spendable
|= =utxo:btc ^- ? |= =utxo:btc ^- ?
(gte (num-confs last-block utxo) confs.w) (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. :: Uses naive random selection. Should switch to branch-and-bound later.
:: ::
++ select-utxos ++ select-utxos
|^ ^- (unit =txbu) |^ ^- (unit txbu)
=/ is=(unit (list input)) =/ is=(unit (list input))
%- single-random-draw %- single-random-draw
%- zing %- zing
@ -209,7 +257,7 @@
|= is=(list input) |= is=(list input)
^- (unit (list input)) ^- (unit (list input))
=/ rng ~(. og eny) =/ 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] =| [select=(list input) total=sats:btc]
|- ?: =(~ is) ~ |- ?: =(~ is) ~
=^ n rng (rads:rng (lent is)) =^ n rng (rads:rng (lent is))