Reply with correct account balance for getbalance requests.
This commit is contained in:
parent
290fdb5427
commit
24d6168709
3 changed files with 119 additions and 10 deletions
110
cmd.go
110
cmd.go
|
@ -32,13 +32,23 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
satoshiPerBTC = 100000000
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoWallet = errors.New("Wallet file does not exist.")
|
||||
)
|
||||
|
||||
var (
|
||||
log seelog.LoggerInterface = seelog.Default
|
||||
cfg *config
|
||||
log seelog.LoggerInterface = seelog.Default
|
||||
cfg *config
|
||||
curHeight = struct {
|
||||
sync.RWMutex
|
||||
h int64
|
||||
}{
|
||||
h: btcutil.BlockHeightUnknown,
|
||||
}
|
||||
wallets = struct {
|
||||
sync.RWMutex
|
||||
m map[string]*BtcWallet
|
||||
|
@ -185,6 +195,82 @@ func OpenWallet(cfg *config, account string) (*BtcWallet, error) {
|
|||
return w, nil
|
||||
}
|
||||
|
||||
func getCurHeight() (height int64) {
|
||||
curHeight.RLock()
|
||||
height = curHeight.h
|
||||
curHeight.RUnlock()
|
||||
if height != btcutil.BlockHeightUnknown {
|
||||
return height
|
||||
} else {
|
||||
seq.Lock()
|
||||
n := seq.n
|
||||
seq.n++
|
||||
seq.Unlock()
|
||||
|
||||
m, err := btcjson.CreateMessageWithId("getblockcount",
|
||||
fmt.Sprintf("btcwallet(%v)", n))
|
||||
if err != nil {
|
||||
// Can't continue.
|
||||
return btcutil.BlockHeightUnknown
|
||||
}
|
||||
|
||||
c := make(chan int64)
|
||||
|
||||
replyHandlers.Lock()
|
||||
replyHandlers.m[n] = func(result, e interface{}) bool {
|
||||
if e != nil {
|
||||
c <- btcutil.BlockHeightUnknown
|
||||
return true
|
||||
}
|
||||
if balance, ok := result.(float64); ok {
|
||||
c <- int64(balance)
|
||||
} else {
|
||||
c <- btcutil.BlockHeightUnknown
|
||||
}
|
||||
return true
|
||||
}
|
||||
replyHandlers.Unlock()
|
||||
|
||||
// send message
|
||||
btcdMsgs <- m
|
||||
|
||||
// Block until reply is ready.
|
||||
height = <-c
|
||||
curHeight.Lock()
|
||||
if height > curHeight.h {
|
||||
curHeight.h = height
|
||||
} else {
|
||||
height = curHeight.h
|
||||
}
|
||||
curHeight.Unlock()
|
||||
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
func (w *BtcWallet) CalculateBalance(confirmations int) float64 {
|
||||
var bal int64 // Measured in satoshi
|
||||
|
||||
height := getCurHeight()
|
||||
if height == btcutil.BlockHeightUnknown {
|
||||
return 0.
|
||||
}
|
||||
|
||||
w.UtxoStore.RLock()
|
||||
for _, u := range w.UtxoStore.s.Confirmed {
|
||||
if int(height-u.Height) >= confirmations {
|
||||
bal += u.Amt
|
||||
}
|
||||
}
|
||||
for _, u := range w.UtxoStore.s.Unconfirmed {
|
||||
if int(height-u.Height) >= confirmations {
|
||||
bal += u.Amt
|
||||
}
|
||||
}
|
||||
w.UtxoStore.RUnlock()
|
||||
return float64(bal) / satoshiPerBTC
|
||||
}
|
||||
|
||||
func (w *BtcWallet) Track() {
|
||||
seq.Lock()
|
||||
n := seq.n
|
||||
|
@ -225,7 +311,7 @@ func (w *BtcWallet) RescanForAddress(addr string, blocks ...int) {
|
|||
msg, _ := json.Marshal(m)
|
||||
|
||||
replyHandlers.Lock()
|
||||
replyHandlers.m[n] = func(result interface{}) bool {
|
||||
replyHandlers.m[n] = func(result, e interface{}) bool {
|
||||
// TODO(jrick)
|
||||
|
||||
// btcd returns a nil result when the rescan is complete.
|
||||
|
@ -254,12 +340,26 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
|
|||
btcdMsgs <- msg
|
||||
}
|
||||
|
||||
func (w *BtcWallet) NewBlockTxHandler(result interface{}) bool {
|
||||
func (w *BtcWallet) NewBlockTxHandler(result, e interface{}) bool {
|
||||
if e != nil {
|
||||
if v, ok := e.(map[string]interface{}); ok {
|
||||
if msg, ok := v["message"]; ok {
|
||||
log.Errorf("Tx Handler: Error received from btcd: %s", msg)
|
||||
return false
|
||||
}
|
||||
}
|
||||
log.Errorf("Tx Handler: Error is non-nil but cannot be parsed.")
|
||||
}
|
||||
|
||||
// TODO(jrick): btcd also sends the block hash in the reply.
|
||||
// Do we want it saved as well?
|
||||
v, ok := result.(map[string]interface{})
|
||||
if !ok {
|
||||
log.Error("Tx Handler: Unexpected result type.")
|
||||
// The first result sent from btcd is nil. This could be used to
|
||||
// indicate that the request for notifications succeeded.
|
||||
if result != nil {
|
||||
log.Errorf("Tx Handler: Unexpected result type %T.", result)
|
||||
}
|
||||
return false
|
||||
}
|
||||
sender58, ok := v["sender"].(string)
|
||||
|
|
10
cmdmgr.go
10
cmdmgr.go
|
@ -245,6 +245,7 @@ func GetBalance(reply chan []byte, msg []byte) {
|
|||
json.Unmarshal(msg, &v)
|
||||
params := v["params"].([]interface{})
|
||||
var wname string
|
||||
conf := 1
|
||||
if len(params) > 0 {
|
||||
if s, ok := params[0].(string); ok {
|
||||
wname = s
|
||||
|
@ -252,13 +253,20 @@ func GetBalance(reply chan []byte, msg []byte) {
|
|||
ReplyError(reply, v["id"], &InvalidParams)
|
||||
}
|
||||
}
|
||||
if len(params) > 1 {
|
||||
if f, ok := params[1].(float64); ok {
|
||||
conf = int(f)
|
||||
} else {
|
||||
ReplyError(reply, v["id"], &InvalidParams)
|
||||
}
|
||||
}
|
||||
|
||||
wallets.RLock()
|
||||
w := wallets.m[wname]
|
||||
wallets.RUnlock()
|
||||
var result interface{}
|
||||
if w != nil {
|
||||
result = 0 // TODO(jrick)
|
||||
result = w.CalculateBalance(conf)
|
||||
ReplySuccess(reply, v["id"], result)
|
||||
} else {
|
||||
e := WalletInvalidAccountName
|
||||
|
|
|
@ -33,7 +33,8 @@ var (
|
|||
// Channel to close to notify that connection to btcd has been lost.
|
||||
btcdDisconnected = make(chan int)
|
||||
|
||||
// Channel to send messages btcwallet does not understand to btcd.
|
||||
// Channel to send messages btcwallet does not understand and requests
|
||||
// from btcwallet to btcd.
|
||||
btcdMsgs = make(chan []byte, 100)
|
||||
|
||||
// Adds a frontend listener channel
|
||||
|
@ -51,9 +52,9 @@ var (
|
|||
// handler function to route the reply to.
|
||||
replyHandlers = struct {
|
||||
sync.Mutex
|
||||
m map[uint64]func(interface{}) bool
|
||||
m map[uint64]func(interface{}, interface{}) bool
|
||||
}{
|
||||
m: make(map[uint64]func(interface{}) bool),
|
||||
m: make(map[uint64]func(interface{}, interface{}) bool),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -231,7 +232,7 @@ func ProcessBtcdNotificationReply(b []byte) {
|
|||
replyHandlers.Unlock()
|
||||
if f != nil {
|
||||
go func() {
|
||||
if f(m["result"]) {
|
||||
if f(m["result"], m["error"]) {
|
||||
replyHandlers.Lock()
|
||||
delete(replyHandlers.m, routeId)
|
||||
replyHandlers.Unlock()
|
||||
|
|
Loading…
Reference in a new issue