Begin using btcws.

This change begins using the btcws package for marshaling custom
commands used for websocket connections to btcd.
This commit is contained in:
Josh Rickmar 2013-11-06 11:23:30 -05:00
parent f3408bad91
commit e65206f752
4 changed files with 87 additions and 50 deletions

94
cmd.go
View file

@ -18,7 +18,6 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/conformal/btcjson" "github.com/conformal/btcjson"
@ -26,6 +25,7 @@ import (
"github.com/conformal/btcwallet/tx" "github.com/conformal/btcwallet/tx"
"github.com/conformal/btcwallet/wallet" "github.com/conformal/btcwallet/wallet"
"github.com/conformal/btcwire" "github.com/conformal/btcwire"
"github.com/conformal/btcws"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
@ -244,12 +244,13 @@ func GetCurBlock() (bs wallet.BlockStamp, err error) {
} }
n := <-NewJSONID n := <-NewJSONID
msg := btcjson.Message{ cmd := btcws.NewGetBestBlockCmd(fmt.Sprintf("btcwallet(%v)", n))
Jsonrpc: "1.0", mcmd, err := cmd.MarshalJSON()
Id: fmt.Sprintf("btcwallet(%v)", n), if err != nil {
Method: "getbestblock", return wallet.BlockStamp{
Height: int32(btcutil.BlockHeightUnknown),
}, errors.New("cannot ask for best block")
} }
m, _ := json.Marshal(msg)
c := make(chan *struct { c := make(chan *struct {
hash *btcwire.ShaHash hash *btcwire.ShaHash
@ -294,7 +295,7 @@ func GetCurBlock() (bs wallet.BlockStamp, err error) {
replyHandlers.Unlock() replyHandlers.Unlock()
// send message // send message
btcdMsgs <- m btcdMsgs <- mcmd
// Block until reply is ready. // Block until reply is ready.
if reply := <-c; reply != nil { if reply := <-c; reply != nil {
@ -402,17 +403,17 @@ func (w *BtcWallet) RescanToBestBlock() {
} }
n := <-NewJSONID n := <-NewJSONID
params := []interface{}{ cmd, err := btcws.NewRescanCmd(fmt.Sprintf("btcwallet(%v)", n),
beginBlock, beginBlock, w.ActivePaymentAddresses())
w.ActivePaymentAddresses(), if err != nil {
log.Errorf("cannot create rescan request: %v", err)
return
} }
m := &btcjson.Message{ mcmd, err := cmd.MarshalJSON()
Jsonrpc: "1.0", if err != nil {
Id: fmt.Sprintf("btcwallet(%v)", n), log.Errorf("cannot create rescan request: %v", err)
Method: "rescan", return
Params: params,
} }
msg, _ := json.Marshal(m)
replyHandlers.Lock() replyHandlers.Lock()
replyHandlers.m[n] = func(result interface{}, e *btcjson.Error) bool { replyHandlers.m[n] = func(result interface{}, e *btcjson.Error) bool {
@ -443,21 +444,36 @@ func (w *BtcWallet) RescanToBestBlock() {
} }
replyHandlers.Unlock() replyHandlers.Unlock()
btcdMsgs <- msg btcdMsgs <- mcmd
} }
// ActivePaymentAddresses returns the second parameter for all rescan // SortedActivePaymentAddresses returns a slice of all active payment
// commands. The returned slice maps between payment address strings and // addresses in an account.
// the block height to begin rescanning for transactions to that address. func (w *BtcWallet) SortedActivePaymentAddresses() []string {
func (w *BtcWallet) ActivePaymentAddresses() []string { w.mtx.RLock()
defer w.mtx.RUnlock()
infos := w.GetSortedActiveAddresses()
addrs := make([]string, len(infos))
for i, addr := range infos {
addrs[i] = addr.Address
}
return addrs
}
// ActivePaymentAddresses returns a set of all active pubkey hashes
// in an account.
func (w *BtcWallet) ActivePaymentAddresses() map[string]struct{} {
w.mtx.RLock() w.mtx.RLock()
defer w.mtx.RUnlock() defer w.mtx.RUnlock()
infos := w.GetActiveAddresses() infos := w.GetActiveAddresses()
addrs := make([]string, len(infos)) addrs := make(map[string]struct{}, len(infos))
for i := range infos { for _, info := range infos {
addrs[i] = infos[i].Address addrs[info.Address] = struct{}{}
} }
return addrs return addrs
@ -472,15 +488,14 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
n := w.NewBlockTxSeqN n := w.NewBlockTxSeqN
w.mtx.RUnlock() w.mtx.RUnlock()
m := &btcjson.Message{ cmd := btcws.NewNotifyNewTXsCmd(fmt.Sprintf("btcwallet(%d)", n),
Jsonrpc: "1.0", []string{addr})
Id: fmt.Sprintf("btcwallet(%d)", n), mcmd, err := cmd.MarshalJSON()
Method: "notifynewtxs", if err != nil {
Params: []interface{}{addr}, log.Errorf("cannot request transaction notifications: %v", err)
} }
msg, _ := json.Marshal(m)
btcdMsgs <- msg btcdMsgs <- mcmd
} }
// ReqSpentUtxoNtfn sends a message to btcd to request updates for when // ReqSpentUtxoNtfn sends a message to btcd to request updates for when
@ -493,18 +508,15 @@ func (w *BtcWallet) ReqSpentUtxoNtfn(u *tx.Utxo) {
n := w.SpentOutpointSeqN n := w.SpentOutpointSeqN
w.mtx.RUnlock() w.mtx.RUnlock()
m := &btcjson.Message{ cmd := btcws.NewNotifySpentCmd(fmt.Sprintf("btcwallet(%d)", n),
Jsonrpc: "1.0", (*btcwire.OutPoint)(&u.Out))
Id: fmt.Sprintf("btcwallet(%d)", n), mcmd, err := cmd.MarshalJSON()
Method: "notifyspent", if err != nil {
Params: []interface{}{ log.Errorf("cannot create spent request: %v", err)
u.Out.Hash.String(), return
u.Out.Index,
},
} }
msg, _ := json.Marshal(m)
btcdMsgs <- msg btcdMsgs <- mcmd
} }
// spentUtxoHandler is the handler function for btcd spent UTXO notifications // spentUtxoHandler is the handler function for btcd spent UTXO notifications

View file

@ -139,7 +139,7 @@ func GetAddressesByAccount(reply chan []byte, msg *btcjson.Message) {
var result []string var result []string
if w := wallets.m[account]; w != nil { if w := wallets.m[account]; w != nil {
result = w.ActivePaymentAddresses() result = w.SortedActivePaymentAddresses()
} else { } else {
ReplyError(reply, msg.Id, &btcjson.ErrWalletInvalidAccountName) ReplyError(reply, msg.Id, &btcjson.ErrWalletInvalidAccountName)
return return

View file

@ -25,6 +25,7 @@ import (
"github.com/conformal/btcjson" "github.com/conformal/btcjson"
"github.com/conformal/btcwallet/wallet" "github.com/conformal/btcwallet/wallet"
"github.com/conformal/btcwire" "github.com/conformal/btcwire"
"github.com/conformal/btcws"
"net" "net"
"net/http" "net/http"
"sync" "sync"
@ -562,11 +563,13 @@ func BtcdConnect(reply chan error) {
// be tracked against chain notifications from this btcd connection. // be tracked against chain notifications from this btcd connection.
func BtcdHandshake(ws *websocket.Conn) { func BtcdHandshake(ws *websocket.Conn) {
n := <-NewJSONID n := <-NewJSONID
msg := btcjson.Message{ cmd := btcws.NewGetCurrentNetCmd(fmt.Sprintf("btcwallet(%v)", n))
Method: "getcurrentnet", mcmd, err := cmd.MarshalJSON()
Id: fmt.Sprintf("btcwallet(%v)", n), if err != nil {
log.Errorf("Cannot complete btcd handshake: %v", err)
ws.Close()
return
} }
m, _ := json.Marshal(&msg)
correctNetwork := make(chan bool) correctNetwork := make(chan bool)
@ -594,7 +597,7 @@ func BtcdHandshake(ws *websocket.Conn) {
} }
replyHandlers.Unlock() replyHandlers.Unlock()
btcdMsgs <- m btcdMsgs <- mcmd
if !<-correctNetwork { if !<-correctNetwork {
log.Error("btcd and btcwallet running on different Bitcoin networks") log.Error("btcd and btcwallet running on different Bitcoin networks")

View file

@ -775,14 +775,16 @@ func (w *Wallet) addr160ForIdx(idx int64) (addressHashKey, error) {
// a complete wallet. // a complete wallet.
type AddressInfo struct { type AddressInfo struct {
Address string Address string
AddrHash string
FirstBlock int32 FirstBlock int32
Compressed bool Compressed bool
} }
// GetActiveAddresses returns all wallet addresses that have been // GetSortedActiveAddresses returns all wallet addresses that have been
// requested to be generated. These do not include pre-generated // requested to be generated. These do not include pre-generated
// addresses. // addresses. Use this when ordered addresses are needed. Otherwise,
func (w *Wallet) GetActiveAddresses() []*AddressInfo { // GetActiveAddresses is preferred.
func (w *Wallet) GetSortedActiveAddresses() []*AddressInfo {
addrs := make([]*AddressInfo, 0, w.highestUsed+1) addrs := make([]*AddressInfo, 0, w.highestUsed+1)
for i := int64(-1); i <= w.highestUsed; i++ { for i := int64(-1); i <= w.highestUsed; i++ {
addr160, err := w.addr160ForIdx(i) addr160, err := w.addr160ForIdx(i)
@ -798,6 +800,25 @@ func (w *Wallet) GetActiveAddresses() []*AddressInfo {
return addrs return addrs
} }
// GetActiveAddresses returns a map between active payment addresses
// and their full info. These do not include pre-generated addresses.
// If addresses must be sorted, use GetSortedActiveAddresses.
func (w *Wallet) GetActiveAddresses() map[string]*AddressInfo {
addrs := make(map[string]*AddressInfo)
for i := int64(-1); i <= w.highestUsed; i++ {
addr160, err := w.addr160ForIdx(i)
if err != nil {
return addrs
}
addr := w.addrMap[addr160]
info, err := addr.info(w.Net())
if err == nil {
addrs[info.Address] = info
}
}
return addrs
}
type walletFlags struct { type walletFlags struct {
useEncryption bool useEncryption bool
watchingOnly bool watchingOnly bool
@ -1181,6 +1202,7 @@ func (a *btcAddress) info(net btcwire.BitcoinNet) (*AddressInfo, error) {
return &AddressInfo{ return &AddressInfo{
Address: address, Address: address,
AddrHash: string(a.pubKeyHash[:]),
FirstBlock: a.firstBlock, FirstBlock: a.firstBlock,
Compressed: a.flags.compressed, Compressed: a.flags.compressed,
}, nil }, nil