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
106
cmd.go
106
cmd.go
|
@ -32,6 +32,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
satoshiPerBTC = 100000000
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNoWallet = errors.New("Wallet file does not exist.")
|
ErrNoWallet = errors.New("Wallet file does not exist.")
|
||||||
)
|
)
|
||||||
|
@ -39,6 +43,12 @@ var (
|
||||||
var (
|
var (
|
||||||
log seelog.LoggerInterface = seelog.Default
|
log seelog.LoggerInterface = seelog.Default
|
||||||
cfg *config
|
cfg *config
|
||||||
|
curHeight = struct {
|
||||||
|
sync.RWMutex
|
||||||
|
h int64
|
||||||
|
}{
|
||||||
|
h: btcutil.BlockHeightUnknown,
|
||||||
|
}
|
||||||
wallets = struct {
|
wallets = struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
m map[string]*BtcWallet
|
m map[string]*BtcWallet
|
||||||
|
@ -185,6 +195,82 @@ func OpenWallet(cfg *config, account string) (*BtcWallet, error) {
|
||||||
return w, nil
|
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() {
|
func (w *BtcWallet) Track() {
|
||||||
seq.Lock()
|
seq.Lock()
|
||||||
n := seq.n
|
n := seq.n
|
||||||
|
@ -225,7 +311,7 @@ func (w *BtcWallet) RescanForAddress(addr string, blocks ...int) {
|
||||||
msg, _ := json.Marshal(m)
|
msg, _ := json.Marshal(m)
|
||||||
|
|
||||||
replyHandlers.Lock()
|
replyHandlers.Lock()
|
||||||
replyHandlers.m[n] = func(result interface{}) bool {
|
replyHandlers.m[n] = func(result, e interface{}) bool {
|
||||||
// TODO(jrick)
|
// TODO(jrick)
|
||||||
|
|
||||||
// btcd returns a nil result when the rescan is complete.
|
// btcd returns a nil result when the rescan is complete.
|
||||||
|
@ -254,12 +340,26 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
|
||||||
btcdMsgs <- msg
|
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.
|
// TODO(jrick): btcd also sends the block hash in the reply.
|
||||||
// Do we want it saved as well?
|
// Do we want it saved as well?
|
||||||
v, ok := result.(map[string]interface{})
|
v, ok := result.(map[string]interface{})
|
||||||
if !ok {
|
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
|
return false
|
||||||
}
|
}
|
||||||
sender58, ok := v["sender"].(string)
|
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)
|
json.Unmarshal(msg, &v)
|
||||||
params := v["params"].([]interface{})
|
params := v["params"].([]interface{})
|
||||||
var wname string
|
var wname string
|
||||||
|
conf := 1
|
||||||
if len(params) > 0 {
|
if len(params) > 0 {
|
||||||
if s, ok := params[0].(string); ok {
|
if s, ok := params[0].(string); ok {
|
||||||
wname = s
|
wname = s
|
||||||
|
@ -252,13 +253,20 @@ func GetBalance(reply chan []byte, msg []byte) {
|
||||||
ReplyError(reply, v["id"], &InvalidParams)
|
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()
|
wallets.RLock()
|
||||||
w := wallets.m[wname]
|
w := wallets.m[wname]
|
||||||
wallets.RUnlock()
|
wallets.RUnlock()
|
||||||
var result interface{}
|
var result interface{}
|
||||||
if w != nil {
|
if w != nil {
|
||||||
result = 0 // TODO(jrick)
|
result = w.CalculateBalance(conf)
|
||||||
ReplySuccess(reply, v["id"], result)
|
ReplySuccess(reply, v["id"], result)
|
||||||
} else {
|
} else {
|
||||||
e := WalletInvalidAccountName
|
e := WalletInvalidAccountName
|
||||||
|
|
|
@ -33,7 +33,8 @@ var (
|
||||||
// Channel to close to notify that connection to btcd has been lost.
|
// Channel to close to notify that connection to btcd has been lost.
|
||||||
btcdDisconnected = make(chan int)
|
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)
|
btcdMsgs = make(chan []byte, 100)
|
||||||
|
|
||||||
// Adds a frontend listener channel
|
// Adds a frontend listener channel
|
||||||
|
@ -51,9 +52,9 @@ var (
|
||||||
// handler function to route the reply to.
|
// handler function to route the reply to.
|
||||||
replyHandlers = struct {
|
replyHandlers = struct {
|
||||||
sync.Mutex
|
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()
|
replyHandlers.Unlock()
|
||||||
if f != nil {
|
if f != nil {
|
||||||
go func() {
|
go func() {
|
||||||
if f(m["result"]) {
|
if f(m["result"], m["error"]) {
|
||||||
replyHandlers.Lock()
|
replyHandlers.Lock()
|
||||||
delete(replyHandlers.m, routeId)
|
delete(replyHandlers.m, routeId)
|
||||||
replyHandlers.Unlock()
|
replyHandlers.Unlock()
|
||||||
|
|
Loading…
Reference in a new issue