Add support for running wallet on testnet3.

Websocket connections to btcd will be closed if btcd and btcwallet are
running on different networks.
This commit is contained in:
Josh Rickmar 2013-10-07 12:35:32 -04:00
parent 1d6741eb05
commit 3c4ff4b0f4
5 changed files with 98 additions and 17 deletions

View file

@ -22,6 +22,7 @@ import (
"fmt"
"github.com/conformal/btcjson"
"github.com/conformal/btcwallet/wallet"
"github.com/conformal/btcwire"
"sync"
"time"
)
@ -568,22 +569,37 @@ func SendMany(reply chan []byte, msg *btcjson.Message) {
// All three parameters are required, and must be of type string. If
// the wallet specified by account already exists, an invalid account
// name error is returned to the client.
//
// Wallets will be created on MainNet, or TestNet3 if btcwallet is run with
// the --testnet option.
func CreateEncryptedWallet(reply chan []byte, msg *btcjson.Message) {
params, ok := msg.Params.([]interface{})
e := &InvalidParams
if !ok {
log.Error("CreateEncryptedWallet: Cannot parse parameters.")
ReplyError(reply, msg.Id, e)
return
}
var wname string
if len(params) != 3 {
ReplyError(reply, msg.Id, &InvalidParams)
e.Message = "Incorrect number of parameters"
ReplyError(reply, msg.Id, e)
return
}
wname, ok1 := params[0].(string)
desc, ok2 := params[1].(string)
pass, ok3 := params[2].(string)
if !ok1 || !ok2 || !ok3 {
ReplyError(reply, msg.Id, &InvalidParams)
wname, ok := params[0].(string)
if !ok {
e.Message = "Account is not a string"
ReplyError(reply, msg.Id, e)
return
}
desc, ok := params[1].(string)
if !ok {
e.Message = "Description is not a string"
ReplyError(reply, msg.Id, e)
return
}
pass, ok := params[2].(string)
if !ok {
e.Message = "Passphrase is not a string"
ReplyError(reply, msg.Id, e)
return
}
@ -597,7 +613,13 @@ func CreateEncryptedWallet(reply chan []byte, msg *btcjson.Message) {
}
wallets.RUnlock()
w, err := wallet.NewWallet(wname, desc, []byte(pass))
var net btcwire.BitcoinNet
if cfg.TestNet3 {
net = btcwire.TestNet3
} else {
net = btcwire.MainNet
}
w, err := wallet.NewWallet(wname, desc, []byte(pass), net)
if err != nil {
log.Error("Error creating wallet: " + err.Error())
ReplyError(reply, msg.Id, &InternalError)

View file

@ -45,6 +45,7 @@ type config struct {
DataDir string `short:"D" long:"datadir" description:"Directory to store wallets and transactions"`
Username string `short:"u" long:"username" description:"Username for btcd authorization"`
Password string `short:"P" long:"password" description:"Password for btcd authorization"`
TestNet3 bool `long:"testnet" description:"Use the test network"`
}
// btcwalletHomeDir returns an OS appropriate home directory for btcwallet.

View file

@ -61,7 +61,8 @@ var (
// replyHandlers maps between a sequence number (passed as part of
// the JSON Id field) and a function to handle a reply or notification
// from btcd. As requests are received, this map is checked for a
// handler function to route the reply to.
// handler function to route the reply to. If the function returns
// true, the handler is removed from the map.
replyHandlers = struct {
sync.Mutex
m map[uint64]func(interface{}, *btcjson.Error) bool
@ -178,8 +179,9 @@ func frontendReqsNotifications(ws *websocket.Conn) {
// websocket and sends messages that btcwallet does not understand to
// btcd. Unlike FrontendHandler, exactly one BtcdHandler goroutine runs.
func BtcdHandler(ws *websocket.Conn) {
// Notification channel to return from listener goroutine when
// btcd disconnects.
disconnected := make(chan int)
defer func() {
close(disconnected)
}()
@ -214,6 +216,7 @@ func BtcdHandler(ws *websocket.Conn) {
case r := <-btcdMsgs:
if err := websocket.Message.Send(ws, r); err != nil {
// btcd disconnected.
log.Error("Unable to send message to btcd: %v", err)
return
}
}
@ -446,13 +449,67 @@ func BtcdConnect(reply chan error) {
close(handlerClosed)
}()
BtcdHandshake(btcdws)
<-handlerClosed
reply <- ErrConnLost
}
// BtcdHandshake first checks that the websocket connection between
// btcwallet and btcd is valid, that is, that there are no mismatching
// settings between the two processes (such as running on different
// Bitcoin networks). If the sanity checks pass, all wallets are set to
// be tracked against chain notifications from this btcd connection.
func BtcdHandshake(ws *websocket.Conn) {
seq.Lock()
n := seq.n
seq.n++
seq.Unlock()
msg := btcjson.Message{
Method: "getcurrentnet",
Id: fmt.Sprintf("btcwallet(%v)", n),
}
m, _ := json.Marshal(&msg)
correctNetwork := make(chan bool)
replyHandlers.Lock()
replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) bool {
fmt.Println("got reply")
fnet, ok := result.(float64)
if !ok {
log.Error("btcd handshake: result is not a number")
ws.Close()
correctNetwork <- false
return true
}
var walletNetwork btcwire.BitcoinNet
if cfg.TestNet3 {
walletNetwork = btcwire.TestNet3
} else {
walletNetwork = btcwire.MainNet
}
correctNetwork <- btcwire.BitcoinNet(fnet) == walletNetwork
// No additional replies expected, remove handler.
return true
}
replyHandlers.Unlock()
btcdMsgs <- m
if !<-correctNetwork {
log.Error("btcd and btcwallet running on different Bitcoin networks")
ws.Close()
return
}
// Begin tracking wallets against this btcd instance.
wallets.RLock()
for _, w := range wallets.m {
w.Track()
}
wallets.RUnlock()
<-handlerClosed
reply <- ErrConnLost
}

View file

@ -353,7 +353,7 @@ type Wallet struct {
// desc's binary representation must not exceed 32 and 256 bytes,
// respectively. All address private keys are encrypted with passphrase.
// The wallet is returned unlocked.
func NewWallet(name, desc string, passphrase []byte) (*Wallet, error) {
func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet) (*Wallet, error) {
if binary.Size(name) > 32 {
return nil, errors.New("name exceeds 32 byte maximum size")
}
@ -382,7 +382,7 @@ func NewWallet(name, desc string, passphrase []byte) (*Wallet, error) {
// compat with armory.
w := &Wallet{
version: 0, // TODO(jrick): implement versioning
net: btcwire.MainNet,
net: net,
flags: walletFlags{
useEncryption: true,
watchingOnly: false,

View file

@ -18,6 +18,7 @@ package wallet
import (
"crypto/rand"
"github.com/conformal/btcwire"
"github.com/davecgh/go-spew/spew"
"os"
"reflect"
@ -78,7 +79,7 @@ func TestBtcAddressSerializer(t *testing.T) {
}
func TestWalletCreationSerialization(t *testing.T) {
w1, err := NewWallet("banana wallet", "A wallet for testing.", []byte("banana"))
w1, err := NewWallet("banana wallet", "A wallet for testing.", []byte("banana"), btcwire.MainNet)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
}