Skip to content

Commit

Permalink
add unspentoutput method to utxo clients
Browse files Browse the repository at this point in the history
  • Loading branch information
loongy committed Sep 4, 2020
1 parent 9be1252 commit bd49e9c
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
10 changes: 9 additions & 1 deletion api/utxo/utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,17 @@ type Client interface {
// Output returns the transaction output identified by the given outpoint.
// It also returns the number of confirmations for the output. If the output
// cannot be found before the context is done, or the output is invalid,
// then an error should be returned.
// then an error should be returned. This method will not error, even if the
// output has been spent.
Output(context.Context, Outpoint) (Output, pack.U64, error)

// UnspentOutput returns the unspent transaction output identified by the
// given outpoint. It also returns the number of confirmations for the
// output. If the output cannot be found before the context is done, the
// output is invalid, or the output has been spent, then an error should be
// returned.
UnspentOutput(context.Context, Outpoint) (Output, pack.U64, error)

// SubmitTx to the underlying chain. If the transaction cannot be found
// before the context is done, or the transaction is invalid, then an error
// should be returned.
Expand Down
36 changes: 35 additions & 1 deletion chain/bitcoin/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (client *client) Output(ctx context.Context, outpoint utxo.Outpoint) (utxo.
hash := chainhash.Hash{}
copy(hash[:], outpoint.Hash)
if err := client.send(ctx, &resp, "getrawtransaction", hash.String(), 1); err != nil {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"gettxout\": %v", err)
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"getrawtransaction\": %v", err)
}
if outpoint.Index.Uint32() >= uint32(len(resp.Vout)) {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad index: %v is out of range", outpoint.Index)
Expand All @@ -136,6 +136,40 @@ func (client *client) Output(ctx context.Context, outpoint utxo.Outpoint) (utxo.
return output, pack.NewU64(resp.Confirmations), nil
}

// UnspentOutput returns the unspent transaction output identified by the
// given outpoint. It also returns the number of confirmations for the
// output. If the output cannot be found before the context is done, the
// output is invalid, or the output has been spent, then an error should be
// returned.
func (client *client) UnspentOutput(ctx context.Context, outpoint utxo.Outpoint) (utxo.Output, pack.U64, error) {
resp := btcjson.GetTxOutResult{}
hash := chainhash.Hash{}
copy(hash[:], outpoint.Hash)
if err := client.send(ctx, &resp, "gettxout", hash.String(), outpoint.Index.Uint32()); err != nil {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"gettxout\": %v", err)
}
amount, err := btcutil.NewAmount(resp.Value)
if err != nil {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad amount: %v", err)
}
if amount < 0 {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad amount: %v", amount)
}
if resp.Confirmations < 0 {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad confirmations: %v", resp.Confirmations)
}
pubKeyScript, err := hex.DecodeString(resp.ScriptPubKey.Hex)
if err != nil {
return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad pubkey script: %v", err)
}
output := utxo.Output{
Outpoint: outpoint,
Value: pack.NewU256FromU64(pack.NewU64(uint64(amount))),
PubKeyScript: pack.NewBytes(pubKeyScript),
}
return output, pack.NewU64(uint64(resp.Confirmations)), nil
}

// SubmitTx to the Bitcoin network.
func (client *client) SubmitTx(ctx context.Context, tx utxo.Tx) error {
serial, err := tx.Serialize()
Expand Down
9 changes: 8 additions & 1 deletion chain/bitcoin/bitcoin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ var _ = Describe("Bitcoin", func() {
output2, _, err := client.Output(context.Background(), output.Outpoint)
Expect(err).ToNot(HaveOccurred())
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())
output2, _, err = client.UnspentOutput(context.Background(), output.Outpoint)
Expect(err).ToNot(HaveOccurred())
Expect(reflect.DeepEqual(output, output2)).To(BeTrue())

// Build the transaction by consuming the outputs and spending
// them to a set of recipients.
Expand Down Expand Up @@ -122,11 +125,15 @@ var _ = Describe("Bitcoin", func() {
confs, err := client.Confirmations(context.Background(), txHash)
Expect(err).ToNot(HaveOccurred())
log.Printf(" %v/3 confirmations", confs)
if confs >= 3 {
if confs >= 1 {
break
}
time.Sleep(10 * time.Second)
}
ctxWithTimeout, cancelCtxWithTimeout := context.WithTimeout(context.Background(), time.Second)
defer cancelCtxWithTimeout()
_, _, err = client.UnspentOutput(ctxWithTimeout, output.Outpoint)
Expect(err).To(HaveOccurred())

// Check that we can load the output and that it is equal.
// Otherwise, something strange is happening with the RPC
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6Ro
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
Expand Down Expand Up @@ -117,9 +118,13 @@ github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+q
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
Expand Down Expand Up @@ -172,6 +177,7 @@ github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3E
github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
Expand Down Expand Up @@ -602,13 +608,15 @@ github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
Expand All @@ -632,6 +640,7 @@ github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFC
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down

0 comments on commit bd49e9c

Please sign in to comment.