diff --git a/backend/btcd_backend.go b/backend/btcd_backend.go index 988a7fc..5b9c5fc 100644 --- a/backend/btcd_backend.go +++ b/backend/btcd_backend.go @@ -57,9 +57,9 @@ const ( // BtcdBackend is meants to connect to a personal Btcd node (because public nodes don't expose the // API we need). There's no TLS support. If your node is not co-located with Beancounter, we // recommend wrapping your connection in a ssh or other secure tunnel. -func NewBtcdBackend(hostPort, user, pass string, network utils.Network) (*BtcdBackend, error) { +func NewBtcdBackend(host, port, user, pass string, network utils.Network) (*BtcdBackend, error) { connCfg := &rpcclient.ConnConfig{ - Host: hostPort, + Host: fmt.Sprintf("%s:%s", host, port), User: user, Pass: pass, HTTPPostMode: true, // Bitcoin core only supports HTTP POST mode diff --git a/backend/electrum/blockchain.go b/backend/electrum/blockchain.go index 6795adc..f313dcc 100644 --- a/backend/electrum/blockchain.go +++ b/backend/electrum/blockchain.go @@ -139,6 +139,7 @@ func NewNode(addr, port string, network utils.Network) (*Node, error) { } if port[0] == 't' { + // TCP var p string if len(port) == 1 { p = defaultTCP @@ -147,6 +148,7 @@ func NewNode(addr, port string, network utils.Network) (*Node, error) { } t, err = NewTCPTransport(fmt.Sprintf("%s:%s", a, p)) } else if port[0] == 's' { + // TLS var p string if len(port) == 1 { p = defaultSSL @@ -154,6 +156,8 @@ func NewNode(addr, port string, network utils.Network) (*Node, error) { p = port[1:] } t, err = NewSSLTransport(fmt.Sprintf("%s:%s", a, p)) + } else { + panic(fmt.Sprintf("port (%s) must start with t or s", port)) } if err != nil { diff --git a/main.go b/main.go index b3eefff..6057e62 100644 --- a/main.go +++ b/main.go @@ -7,9 +7,7 @@ import ( "github.com/square/beancounter/blockfinder" "log" "math" - "net" "os" - "strconv" "strings" "time" @@ -37,7 +35,7 @@ var ( findBlock = app.Command("find-block", "Finds the block height for a given date/time.") findBlockTimestamp = findBlock.Arg("timestamp", "Date/time to resolve. E.g. \"2006-01-02 15:04:05 MST\"").Required().String() findBlockBackend = findBlock.Flag("backend", "electrum | btcd | electrum-recorder | btcd-recorder | fixture").Default("electrum").Enum("electrum", "btcd", "electrum-recorder", "btcd-recorder", "fixture") - findBlockAddr = findBlock.Flag("addr", "Backend to connect to initially. Defaults to a hardcoded node for Electrum and localhost for Btcd.").PlaceHolder("HOST:PORT").TCP() + findBlockAddr = findBlock.Flag("addr", "Backend to connect to initially. Defaults to a hardcoded node for Electrum and localhost for Btcd.").PlaceHolder("HOST:PORT").String() findBlockRpcUser = findBlock.Flag("rpcuser", "RPC username").PlaceHolder("USER").String() findBlockRpcPass = findBlock.Flag("rpcpass", "RPC password").PlaceHolder("PASSWORD").String() findBlockFixtureFile = findBlock.Flag("fixture-file", "Fixture file to use for recording or replaying data.").PlaceHolder("FILEPATH").String() @@ -48,7 +46,7 @@ var ( computeBalanceM = computeBalance.Flag("m", "number of signatures (quorum)").Short('m').Default("1").Int() computeBalanceN = computeBalance.Flag("n", "number of public keys").Short('n').Default("1").Int() computeBalanceBackend = computeBalance.Flag("backend", "electrum | btcd | electrum-recorder | btcd-recorder | fixture").Default("electrum").Enum("electrum", "btcd", "electrum-recorder", "btcd-recorder", "fixture") - computeBalanceAddr = computeBalance.Flag("addr", "Backend to connect to initially. Defaults to a hardcoded node for Electrum and localhost for Btcd.").PlaceHolder("HOST:PORT").TCP() + computeBalanceAddr = computeBalance.Flag("addr", "Backend to connect to initially. Defaults to a hardcoded node for Electrum and localhost for Btcd.").PlaceHolder("HOST:PORT").String() computeBalanceRpcUser = computeBalance.Flag("rpcuser", "RPC username").PlaceHolder("USER").String() computeBalanceRpcPass = computeBalance.Flag("rpcpass", "RPC password").PlaceHolder("PASSWORD").String() computeBalanceFixtureFile = computeBalance.Flag("fixture-file", "Fixture file to use for recording or replaying data.").PlaceHolder("FILEPATH").String() @@ -252,14 +250,14 @@ func findBlockBuildBackend(network Network) (backend.Backend, error) { var err error switch *findBlockBackend { case "electrum": - addr, port := getServer(network, *findBlockAddr) + addr, port := GetDefaultServer(network, Electrum, *findBlockAddr) b, err = backend.NewElectrumBackend(addr, port, network) if err != nil { return nil, err } case "btcd": - b, err = backend.NewBtcdBackend((**findBlockAddr).String(), *findBlockRpcUser, - *findBlockRpcPass, network) + addr, port := GetDefaultServer(network, Btcd, *findBlockAddr) + b, err = backend.NewBtcdBackend(addr, port, *findBlockRpcUser, *findBlockRpcPass, network) if err != nil { return nil, err } @@ -267,7 +265,7 @@ func findBlockBuildBackend(network Network) (backend.Backend, error) { if *findBlockFixtureFile == "" { panic("electrum-recorder backend requires output --fixture-file.") } - addr, port := getServer(network, *findBlockAddr) + addr, port := GetDefaultServer(network, Electrum, *findBlockAddr) b, err = backend.NewElectrumBackend(addr, port, network) if err != nil { return nil, err @@ -277,8 +275,8 @@ func findBlockBuildBackend(network Network) (backend.Backend, error) { if *findBlockFixtureFile == "" { panic("btcd-recorder backend requires output --fixture-file.") } - b, err = backend.NewBtcdBackend((*findBlockAddr).String(), *findBlockRpcUser, - *findBlockRpcPass, network) + addr, port := GetDefaultServer(network, Btcd, *findBlockAddr) + b, err = backend.NewBtcdBackend(addr, port, *findBlockRpcUser, *findBlockRpcPass, network) if err != nil { return nil, err } @@ -303,14 +301,14 @@ func computeBalanceBuildBackend(network Network) (backend.Backend, error) { var err error switch *computeBalanceBackend { case "electrum": - addr, port := getServer(network, *computeBalanceAddr) + addr, port := GetDefaultServer(network, Electrum, *computeBalanceAddr) b, err = backend.NewElectrumBackend(addr, port, network) if err != nil { return nil, err } case "btcd": - b, err = backend.NewBtcdBackend((*computeBalanceAddr).String(), *computeBalanceRpcUser, - *computeBalanceRpcPass, network) + addr, port := GetDefaultServer(network, Btcd, *computeBalanceAddr) + b, err = backend.NewBtcdBackend(addr, port, *computeBalanceRpcUser, *computeBalanceRpcPass, network) if err != nil { return nil, err } @@ -318,7 +316,7 @@ func computeBalanceBuildBackend(network Network) (backend.Backend, error) { if *computeBalanceFixtureFile == "" { panic("electrum-recorder backend requires output --fixture-file.") } - addr, port := getServer(network, *computeBalanceAddr) + addr, port := GetDefaultServer(network, Electrum, *computeBalanceAddr) b, err = backend.NewElectrumBackend(addr, port, network) if err != nil { return nil, err @@ -328,8 +326,8 @@ func computeBalanceBuildBackend(network Network) (backend.Backend, error) { if *computeBalanceFixtureFile == "" { panic("btcd-recorder backend requires output --fixture-file.") } - b, err = backend.NewBtcdBackend((*computeBalanceAddr).String(), *computeBalanceRpcUser, - *computeBalanceRpcPass, network) + addr, port := GetDefaultServer(network, Btcd, *computeBalanceAddr) + b, err = backend.NewBtcdBackend(addr, port, *computeBalanceRpcUser, *computeBalanceRpcPass, network) if err != nil { return nil, err } @@ -347,19 +345,3 @@ func computeBalanceBuildBackend(network Network) (backend.Backend, error) { } return b, err } - -// pick a default server for each network if none provided -// TODO: default server should be localhost for Btcd backend. -func getServer(network Network, addr *net.TCPAddr) (string, string) { - if addr != nil { - return addr.IP.String(), strconv.Itoa(addr.Port) - } - switch network { - case "mainnet": - return "electrum.petrkr.net", "s50002" - case "testnet": - return "electrum_testnet_unlimited.criptolayer.net", "s50102" - default: - panic("unreachable") - } -} diff --git a/utils/utils.go b/utils/utils.go index 680c2ef..b6a6a6f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "net" "github.com/btcsuite/btcd/chaincfg" ) @@ -24,6 +25,14 @@ func Max(num uint32, nums ...uint32) uint32 { } type Network string +type Backend string + +const ( + Mainnet Network = "mainnet" + Testnet Network = "testnet" + Electrum Backend = "electrum" + Btcd Backend = "btcd" +) // ChainConfig returns a given chaincfg.Params for a given Network func (n Network) ChainConfig() *chaincfg.Params { @@ -94,7 +103,34 @@ func VerifyMandN(m int, n int) error { return nil } -const ( - Mainnet Network = "mainnet" - Testnet Network = "testnet" -) +// Picks a default server for electrum or localhost for btcd +// Returns a pair of hostname:port (or pseudo-port for electrum) +func GetDefaultServer(network Network, backend Backend, addr string) (string, string) { + if addr != "" { + host, port, err := net.SplitHostPort(addr) + PanicOnError(err) + return host, port + } + switch backend { + case Electrum: + switch network { + case "mainnet": + return "electrum.petrkr.net", "s50002" + case "testnet": + return "electrum_testnet_unlimited.criptolayer.net", "s50102" + default: + panic("unreachable") + } + case Btcd: + switch network { + case "mainnet": + return "localhost", "8334" + case "testnet": + return "localhost", "18334" + default: + panic("unreachable") + } + default: + panic("unreachable") + } +} diff --git a/utils/utils_test.go b/utils/utils_test.go index 70a159a..e5d1592 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -76,3 +76,29 @@ func TestVerifyMandN(t *testing.T) { assert.Nil(t, VerifyMandN(5, 20)) assert.Nil(t, VerifyMandN(20, 20)) } + +func TestGetDefaultServer(t *testing.T) { + host, port := GetDefaultServer(Testnet, Electrum, "foobar:s1234") + assert.Equal(t, "foobar", host) + assert.Equal(t, "s1234", port) + + host, port = GetDefaultServer(Testnet, Electrum, "192.0.2.5:s1234") + assert.Equal(t, "192.0.2.5", host) + assert.Equal(t, "s1234", port) + + host, port = GetDefaultServer(Testnet, Electrum, "[2001:db8::1]:s1234") + assert.Equal(t, "2001:db8::1", host) + assert.Equal(t, "s1234", port) + + host, port = GetDefaultServer(Testnet, Btcd, "foobar:1234") + assert.Equal(t, "foobar", host) + assert.Equal(t, "1234", port) + + host, port = GetDefaultServer(Testnet, Electrum, "") + assert.NotEqual(t, "localhost", host) + assert.Equal(t, "s50102", port) + + host, port = GetDefaultServer(Testnet, Btcd, "") + assert.Equal(t, "localhost", host) + assert.Equal(t, "18334", port) +}