diff --git a/bchain/coins/bch/bcashrpc.go b/bchain/coins/bch/bcashrpc.go index cb23030e..bb4292d1 100644 --- a/bchain/coins/bch/bcashrpc.go +++ b/bchain/coins/bch/bcashrpc.go @@ -30,10 +30,10 @@ func NewBCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp return s, nil } +// Initialize initializes BCashRPC instance. func (b *BCashRPC) Initialize() error { - b.Mempool = bchain.NewUTXOMempool(b) - chainName, err := b.GetBlockChainInfo() + chainName, err := b.GetChainInfoAndInitializeMempool() if err != nil { return err } diff --git a/bchain/coins/btc/bitcoinrpc.go b/bchain/coins/btc/bitcoinrpc.go index 2ad04021..8a54927d 100644 --- a/bchain/coins/btc/bitcoinrpc.go +++ b/bchain/coins/btc/bitcoinrpc.go @@ -19,17 +19,19 @@ import ( // BitcoinRPC is an interface to JSON-RPC bitcoind service. type BitcoinRPC struct { - client http.Client - rpcURL string - user string - password string - Parser bchain.BlockChainParser - Testnet bool - Network string - Mempool *bchain.UTXOMempool - ParseBlocks bool - mq *bchain.MQ - Subversion string + client http.Client + rpcURL string + user string + password string + Parser bchain.BlockChainParser + Testnet bool + Network string + Mempool *bchain.UTXOMempool + ParseBlocks bool + zeroMQBinding string + pushHandler func(bchain.NotificationType) + mq *bchain.MQ + Subversion string } type configuration struct { @@ -57,28 +59,45 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT } s := &BitcoinRPC{ - client: http.Client{Timeout: time.Duration(c.RPCTimeout) * time.Second, Transport: transport}, - rpcURL: c.RPCURL, - user: c.RPCUser, - password: c.RPCPass, - ParseBlocks: c.Parse, - Subversion: c.Subversion, + client: http.Client{Timeout: time.Duration(c.RPCTimeout) * time.Second, Transport: transport}, + rpcURL: c.RPCURL, + user: c.RPCUser, + password: c.RPCPass, + ParseBlocks: c.Parse, + Subversion: c.Subversion, + zeroMQBinding: c.ZeroMQBinding, + pushHandler: pushHandler, } - mq, err := bchain.NewMQ(c.ZeroMQBinding, pushHandler) - if err != nil { - glog.Error("mq: ", err) - return nil, err - } - s.mq = mq - return s, nil } -func (b *BitcoinRPC) Initialize() error { +// GetChainInfoAndInitializeMempool is called by Initialize and reused by other coins +// it contacts the blockchain rpc interface for the first time +// and if successful it connects to ZeroMQ and creates mempool handler +func (b *BitcoinRPC) GetChainInfoAndInitializeMempool() (string, error) { + // try to connect to block chain and get some info + chainName, err := b.GetBlockChainInfo() + if err != nil { + return "", err + } + + mq, err := bchain.NewMQ(b.zeroMQBinding, b.pushHandler) + if err != nil { + glog.Error("mq: ", err) + return "", err + } + b.mq = mq + b.Mempool = bchain.NewUTXOMempool(b) - chainName, err := b.GetBlockChainInfo() + return chainName, nil +} + +// Initialize initializes BitcoinRPC instance. +func (b *BitcoinRPC) Initialize() error { + + chainName, err := b.GetChainInfoAndInitializeMempool() if err != nil { return err } diff --git a/bchain/coins/zec/zcashrpc.go b/bchain/coins/zec/zcashrpc.go index 7d4fcc7f..3d3010f1 100644 --- a/bchain/coins/zec/zcashrpc.go +++ b/bchain/coins/zec/zcashrpc.go @@ -24,8 +24,13 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp return z, nil } +// Initialize initializes ZCashRPC instance. func (z *ZCashRPC) Initialize() error { - z.Mempool = bchain.NewUTXOMempool(z) + _, err := z.GetChainInfoAndInitializeMempool() + if err != nil { + return err + } + z.Parser = &ZCashParser{} z.Testnet = false z.Network = "livenet" diff --git a/blockbook.go b/blockbook.go index 1de5c3cc..38eef9c2 100644 --- a/blockbook.go +++ b/blockbook.go @@ -86,6 +86,29 @@ func init() { glog.CopyStandardLogTo("INFO") } +func getBlockChainWithRetry(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics, seconds int) (bchain.BlockChain, error) { + var chain bchain.BlockChain + var err error + timer := time.NewTimer(time.Second) + for i := 0; ; i++ { + if chain, err = coins.NewBlockChain(coin, configfile, pushHandler, metrics); err != nil { + if i < seconds { + glog.Error("rpc: ", err, " Retrying...") + select { + case <-chanOsSignal: + return nil, errors.New("Interrupted") + case <-timer.C: + timer.Reset(time.Second) + continue + } + } else { + return nil, err + } + } + return chain, nil + } +} + func main() { flag.Parse() @@ -116,7 +139,7 @@ func main() { glog.Fatal("Missing blockchaincfg configuration parameter") } - if chain, err = coins.NewBlockChain(*coin, *blockchain, pushSynchronizationHandler, metrics); err != nil { + if chain, err = getBlockChainWithRetry(*coin, *blockchain, pushSynchronizationHandler, metrics, 60); err != nil { glog.Fatal("rpc: ", err) }