Extract mempool interface from blockchain
parent
68575b2786
commit
ce3c7c5e66
|
@ -23,17 +23,19 @@ type Worker struct {
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
chainType bchain.ChainType
|
chainType bchain.ChainType
|
||||||
|
mempool bchain.Mempool
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWorker creates new api worker
|
// NewWorker creates new api worker
|
||||||
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*Worker, error) {
|
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, is *common.InternalState) (*Worker, error) {
|
||||||
w := &Worker{
|
w := &Worker{
|
||||||
db: db,
|
db: db,
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
chainType: chain.GetChainParser().GetChainType(),
|
chainType: chain.GetChainParser().GetChainType(),
|
||||||
|
mempool: mempool,
|
||||||
is: is,
|
is: is,
|
||||||
}
|
}
|
||||||
return w, nil
|
return w, nil
|
||||||
|
@ -348,7 +350,7 @@ func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool
|
||||||
}
|
}
|
||||||
if mempool {
|
if mempool {
|
||||||
uniqueTxs := make(map[string]struct{})
|
uniqueTxs := make(map[string]struct{})
|
||||||
o, err := w.chain.GetMempoolTransactionsForAddrDesc(addrDesc)
|
o, err := w.mempool.GetAddrDescTransactions(addrDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (w *Worker) xpubGetAddressTxids(addrDesc bchain.AddressDescriptor, mempool
|
||||||
}
|
}
|
||||||
if mempool {
|
if mempool {
|
||||||
uniqueTxs := make(map[string]int)
|
uniqueTxs := make(map[string]int)
|
||||||
o, err := w.chain.GetMempoolTransactionsForAddrDesc(addrDesc)
|
o, err := w.mempool.GetAddrDescTransactions(addrDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ func (b *BaseChain) GetNetworkName() string {
|
||||||
return b.Network
|
return b.Network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMempoolEntry is not supported by default
|
||||||
|
func (b *BaseChain) GetMempoolEntry(txid string) (*MempoolEntry, error) {
|
||||||
|
return nil, errors.New("GetMempoolEntry: not supported")
|
||||||
|
}
|
||||||
|
|
||||||
// EthereumTypeGetBalance is not supported
|
// EthereumTypeGetBalance is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("Not supported")
|
||||||
|
|
|
@ -33,10 +33,11 @@ func NewBCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
|
||||||
|
|
||||||
// Initialize initializes BCashRPC instance.
|
// Initialize initializes BCashRPC instance.
|
||||||
func (b *BCashRPC) Initialize() error {
|
func (b *BCashRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewBellcoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes BellcoinRPC instance.
|
// Initialize initializes BellcoinRPC instance.
|
||||||
func (b *BellcoinRPC) Initialize() error {
|
func (b *BellcoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -99,30 +99,34 @@ func GetCoinNameFromConfig(configfile string) (string, string, string, error) {
|
||||||
return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
|
return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockChain creates bchain.BlockChain of type defined by parameter coin
|
// NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
|
||||||
func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, error) {
|
func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, bchain.Mempool, error) {
|
||||||
data, err := ioutil.ReadFile(configfile)
|
data, err := ioutil.ReadFile(configfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "Error reading file %v", configfile)
|
return nil, nil, errors.Annotatef(err, "Error reading file %v", configfile)
|
||||||
}
|
}
|
||||||
var config json.RawMessage
|
var config json.RawMessage
|
||||||
err = json.Unmarshal(data, &config)
|
err = json.Unmarshal(data, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "Error parsing file %v", configfile)
|
return nil, nil, errors.Annotatef(err, "Error parsing file %v", configfile)
|
||||||
}
|
}
|
||||||
bcf, ok := BlockChainFactories[coin]
|
bcf, ok := BlockChainFactories[coin]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprint("Unsupported coin '", coin, "'. Must be one of ", reflect.ValueOf(BlockChainFactories).MapKeys()))
|
return nil, nil, errors.New(fmt.Sprint("Unsupported coin '", coin, "'. Must be one of ", reflect.ValueOf(BlockChainFactories).MapKeys()))
|
||||||
}
|
}
|
||||||
bc, err := bcf(config, pushHandler)
|
bc, err := bcf(config, pushHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
err = bc.Initialize()
|
err = bc.Initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return &blockChainWithMetrics{b: bc, m: metrics}, nil
|
mempool, err := bc.CreateMempool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return &blockChainWithMetrics{b: bc, m: metrics}, &mempoolWithMetrics{mempool: mempool, m: metrics}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type blockChainWithMetrics struct {
|
type blockChainWithMetrics struct {
|
||||||
|
@ -142,6 +146,14 @@ func (c *blockChainWithMetrics) Initialize() error {
|
||||||
return c.b.Initialize()
|
return c.b.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) CreateMempool() (bchain.Mempool, error) {
|
||||||
|
return c.b.CreateMempool()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) InitializeMempool() error {
|
||||||
|
return c.b.InitializeMempool()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {
|
func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {
|
||||||
return c.b.Shutdown(ctx)
|
return c.b.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
@ -197,9 +209,9 @@ func (c *blockChainWithMetrics) GetBlockInfo(hash string) (v *bchain.BlockInfo,
|
||||||
return c.b.GetBlockInfo(hash)
|
return c.b.GetBlockInfo(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetMempool() (v []string, err error) {
|
func (c *blockChainWithMetrics) GetMempoolTransactions() (v []string, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetMempool", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactions", s, err) }(time.Now())
|
||||||
return c.b.GetMempool()
|
return c.b.GetMempoolTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetTransaction(txid string) (v *bchain.Tx, err error) {
|
func (c *blockChainWithMetrics) GetTransaction(txid string) (v *bchain.Tx, err error) {
|
||||||
|
@ -232,25 +244,6 @@ func (c *blockChainWithMetrics) SendRawTransaction(tx string) (v string, err err
|
||||||
return c.b.SendRawTransaction(tx)
|
return c.b.SendRawTransaction(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (count int, err error) {
|
|
||||||
defer func(s time.Time) { c.observeRPCLatency("ResyncMempool", s, err) }(time.Now())
|
|
||||||
count, err = c.b.ResyncMempool(onNewTxAddr)
|
|
||||||
if err == nil {
|
|
||||||
c.m.MempoolSize.Set(float64(count))
|
|
||||||
}
|
|
||||||
return count, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetMempoolTransactions(address string) (v []bchain.Outpoint, err error) {
|
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactions", s, err) }(time.Now())
|
|
||||||
return c.b.GetMempoolTransactions(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetMempoolTransactionsForAddrDesc(addrDesc bchain.AddressDescriptor) (v []bchain.Outpoint, err error) {
|
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactionsForAddrDesc", s, err) }(time.Now())
|
|
||||||
return c.b.GetMempoolTransactionsForAddrDesc(addrDesc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) GetMempoolEntry(txid string) (v *bchain.MempoolEntry, err error) {
|
func (c *blockChainWithMetrics) GetMempoolEntry(txid string) (v *bchain.MempoolEntry, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetMempoolEntry", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetMempoolEntry", s, err) }(time.Now())
|
||||||
return c.b.GetMempoolEntry(txid)
|
return c.b.GetMempoolEntry(txid)
|
||||||
|
@ -284,3 +277,35 @@ func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, co
|
||||||
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
|
||||||
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mempoolWithMetrics struct {
|
||||||
|
mempool bchain.Mempool
|
||||||
|
m *common.Metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mempoolWithMetrics) observeRPCLatency(method string, start time.Time, err error) {
|
||||||
|
var e string
|
||||||
|
if err != nil {
|
||||||
|
e = err.Error()
|
||||||
|
}
|
||||||
|
c.m.RPCLatency.With(common.Labels{"method": method, "error": e}).Observe(float64(time.Since(start)) / 1e6) // in milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mempoolWithMetrics) Resync(onNewTxAddr bchain.OnNewTxAddrFunc) (count int, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("ResyncMempool", s, err) }(time.Now())
|
||||||
|
count, err = c.mempool.Resync(onNewTxAddr)
|
||||||
|
if err == nil {
|
||||||
|
c.m.MempoolSize.Set(float64(count))
|
||||||
|
}
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mempoolWithMetrics) GetTransactions(address string) (v []bchain.Outpoint, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactions", s, err) }(time.Now())
|
||||||
|
return c.mempool.GetTransactions(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mempoolWithMetrics) GetAddrDescTransactions(addrDesc bchain.AddressDescriptor) (v []bchain.Outpoint, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactionsForAddrDesc", s, err) }(time.Now())
|
||||||
|
return c.mempool.GetAddrDescTransactions(addrDesc)
|
||||||
|
}
|
||||||
|
|
|
@ -101,37 +101,15 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(bc bchain.BlockChain) (string, error) {
|
|
||||||
// try to connect to block chain and get some info
|
|
||||||
ci, err := bc.GetChainInfo()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
chainName := ci.Chain
|
|
||||||
|
|
||||||
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error("mq: ", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
b.mq = mq
|
|
||||||
|
|
||||||
b.Mempool = bchain.NewMempoolBitcoinType(bc, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers)
|
|
||||||
|
|
||||||
return chainName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize initializes BitcoinRPC instance.
|
// Initialize initializes BitcoinRPC instance.
|
||||||
func (b *BitcoinRPC) Initialize() error {
|
func (b *BitcoinRPC) Initialize() error {
|
||||||
b.ChainConfig.SupportsEstimateFee = false
|
b.ChainConfig.SupportsEstimateFee = false
|
||||||
|
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
@ -152,6 +130,28 @@ func (b *BitcoinRPC) Initialize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateMempool creates mempool if not already created, however does not initialize it
|
||||||
|
func (b *BitcoinRPC) CreateMempool() (bchain.Mempool, error) {
|
||||||
|
if b.Mempool == nil {
|
||||||
|
b.Mempool = bchain.NewMempoolBitcoinType(b, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers)
|
||||||
|
}
|
||||||
|
return b.Mempool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeMempool creates ZeroMQ subscription
|
||||||
|
func (b *BitcoinRPC) InitializeMempool() error {
|
||||||
|
if b.mq == nil {
|
||||||
|
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("mq: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.mq = mq
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown ZeroMQ and other resources
|
||||||
func (b *BitcoinRPC) Shutdown(ctx context.Context) error {
|
func (b *BitcoinRPC) Shutdown(ctx context.Context) error {
|
||||||
if b.mq != nil {
|
if b.mq != nil {
|
||||||
if err := b.mq.Shutdown(ctx); err != nil {
|
if err := b.mq.Shutdown(ctx); err != nil {
|
||||||
|
@ -162,10 +162,12 @@ func (b *BitcoinRPC) Shutdown(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoinName returns the coin name
|
||||||
func (b *BitcoinRPC) GetCoinName() string {
|
func (b *BitcoinRPC) GetCoinName() string {
|
||||||
return b.ChainConfig.CoinName
|
return b.ChainConfig.CoinName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSubversion returns the backend subversion
|
||||||
func (b *BitcoinRPC) GetSubversion() string {
|
func (b *BitcoinRPC) GetSubversion() string {
|
||||||
return b.ChainConfig.Subversion
|
return b.ChainConfig.Subversion
|
||||||
}
|
}
|
||||||
|
@ -458,6 +460,7 @@ func (b *BitcoinRPC) GetChainInfo() (*bchain.ChainInfo, error) {
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsErrBlockNotFound returns true if error means block was not found
|
||||||
func IsErrBlockNotFound(err *bchain.RPCError) bool {
|
func IsErrBlockNotFound(err *bchain.RPCError) bool {
|
||||||
return err.Message == "Block not found" ||
|
return err.Message == "Block not found" ||
|
||||||
err.Message == "Block height out of range"
|
err.Message == "Block height out of range"
|
||||||
|
@ -634,8 +637,8 @@ func (b *BitcoinRPC) GetBlockFull(hash string) (*bchain.Block, error) {
|
||||||
return &res.Result, nil
|
return &res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempool returns transactions in mempool
|
// GetMempoolTransactions returns transactions in mempool
|
||||||
func (b *BitcoinRPC) GetMempool() ([]string, error) {
|
func (b *BitcoinRPC) GetMempoolTransactions() ([]string, error) {
|
||||||
glog.V(1).Info("rpc: getrawmempool")
|
glog.V(1).Info("rpc: getrawmempool")
|
||||||
|
|
||||||
res := ResGetMempool{}
|
res := ResGetMempool{}
|
||||||
|
@ -651,6 +654,7 @@ func (b *BitcoinRPC) GetMempool() ([]string, error) {
|
||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsMissingTx return true if error means missing tx
|
||||||
func IsMissingTx(err *bchain.RPCError) bool {
|
func IsMissingTx(err *bchain.RPCError) bool {
|
||||||
if err.Code == -5 { // "No such mempool or blockchain transaction"
|
if err.Code == -5 { // "No such mempool or blockchain transaction"
|
||||||
return true
|
return true
|
||||||
|
@ -732,23 +736,6 @@ func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResyncMempool gets mempool transactions and maps output scripts to transactions.
|
|
||||||
// ResyncMempool is not reentrant, it should be called from a single thread.
|
|
||||||
// Return value is number of transactions in mempool
|
|
||||||
func (b *BitcoinRPC) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (int, error) {
|
|
||||||
return b.Mempool.Resync(onNewTxAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolTransactions returns slice of mempool transactions for given address
|
|
||||||
func (b *BitcoinRPC) GetMempoolTransactions(address string) ([]bchain.Outpoint, error) {
|
|
||||||
return b.Mempool.GetTransactions(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolTransactionsForAddrDesc returns slice of mempool transactions for given address descriptor
|
|
||||||
func (b *BitcoinRPC) GetMempoolTransactionsForAddrDesc(addrDesc bchain.AddressDescriptor) ([]bchain.Outpoint, error) {
|
|
||||||
return b.Mempool.GetAddrDescTransactions(addrDesc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EstimateSmartFee returns fee estimation
|
// EstimateSmartFee returns fee estimation
|
||||||
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
||||||
// use EstimateFee if EstimateSmartFee is not supported
|
// use EstimateFee if EstimateSmartFee is not supported
|
||||||
|
@ -810,7 +797,7 @@ func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendRawTransaction sends raw transaction.
|
// SendRawTransaction sends raw transaction
|
||||||
func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
||||||
glog.V(1).Info("rpc: sendrawtransaction")
|
glog.V(1).Info("rpc: sendrawtransaction")
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,11 @@ func NewBGoldRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
|
||||||
|
|
||||||
// Initialize initializes BGoldRPC instance.
|
// Initialize initializes BGoldRPC instance.
|
||||||
func (b *BGoldRPC) Initialize() error {
|
func (b *BGoldRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,11 @@ func NewDashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType
|
||||||
|
|
||||||
// Initialize initializes DashRPC instance.
|
// Initialize initializes DashRPC instance.
|
||||||
func (b *DashRPC) Initialize() error {
|
func (b *DashRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewDigiByteRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes DigiByteRPC instance.
|
// Initialize initializes DigiByteRPC instance.
|
||||||
func (b *DigiByteRPC) Initialize() error {
|
func (b *DigiByteRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewDogecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes DogecoinRPC instance.
|
// Initialize initializes DogecoinRPC instance.
|
||||||
func (b *DogecoinRPC) Initialize() error {
|
func (b *DogecoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -160,11 +160,24 @@ func (b *EthereumRPC) Initialize() error {
|
||||||
}
|
}
|
||||||
glog.Info("rpc: block chain ", b.Network)
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMempool creates mempool if not already created, however does not initialize it
|
||||||
|
func (b *EthereumRPC) CreateMempool() (bchain.Mempool, error) {
|
||||||
|
if b.Mempool == nil {
|
||||||
|
b.Mempool = bchain.NewMempoolEthereumType(b)
|
||||||
|
}
|
||||||
|
return b.Mempool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeMempool creates subscriptions to newHeads and newPendingTransactions
|
||||||
|
func (b *EthereumRPC) InitializeMempool() error {
|
||||||
if b.isETC {
|
if b.isETC {
|
||||||
glog.Info(b.ChainConfig.CoinName, " does not support subscription to newHeads")
|
glog.Info(b.ChainConfig.CoinName, " does not support subscription to newHeads")
|
||||||
} else {
|
} else {
|
||||||
// subscriptions
|
// subscriptions
|
||||||
if err = b.subscribe(func() (*rpc.ClientSubscription, error) {
|
if err := b.subscribe(func() (*rpc.ClientSubscription, error) {
|
||||||
// invalidate the previous subscription - it is either the first one or there was an error
|
// invalidate the previous subscription - it is either the first one or there was an error
|
||||||
b.newBlockSubscription = nil
|
b.newBlockSubscription = nil
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
|
@ -180,7 +193,8 @@ func (b *EthereumRPC) Initialize() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = b.subscribe(func() (*rpc.ClientSubscription, error) {
|
|
||||||
|
if err := b.subscribe(func() (*rpc.ClientSubscription, error) {
|
||||||
// invalidate the previous subscription - it is either the first one or there was an error
|
// invalidate the previous subscription - it is either the first one or there was an error
|
||||||
b.newTxSubscription = nil
|
b.newTxSubscription = nil
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
|
@ -195,10 +209,6 @@ func (b *EthereumRPC) Initialize() error {
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create mempool
|
|
||||||
b.Mempool = bchain.NewMempoolEthereumType(b)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,8 +638,8 @@ func (b *EthereumRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, er
|
||||||
return json.RawMessage(m), err
|
return json.RawMessage(m), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempool returns transactions in mempool
|
// GetMempoolTransactions returns transactions in mempool
|
||||||
func (b *EthereumRPC) GetMempool() ([]string, error) {
|
func (b *EthereumRPC) GetMempoolTransactions() ([]string, error) {
|
||||||
raw, err := b.getBlockRaw("pending", 0, false)
|
raw, err := b.getBlockRaw("pending", 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -737,28 +747,6 @@ func (b *EthereumRPC) EthereumTypeGetNonce(addrDesc bchain.AddressDescriptor) (u
|
||||||
return b.client.NonceAt(ctx, ethcommon.BytesToAddress(addrDesc), nil)
|
return b.client.NonceAt(ctx, ethcommon.BytesToAddress(addrDesc), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResyncMempool gets mempool transactions and maps output scripts to transactions.
|
|
||||||
// ResyncMempool is not reentrant, it should be called from a single thread.
|
|
||||||
// Return value is number of transactions in mempool
|
|
||||||
func (b *EthereumRPC) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (int, error) {
|
|
||||||
return b.Mempool.Resync(onNewTxAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolTransactions returns slice of mempool transactions for given address
|
|
||||||
func (b *EthereumRPC) GetMempoolTransactions(address string) ([]bchain.Outpoint, error) {
|
|
||||||
return b.Mempool.GetTransactions(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolTransactionsForAddrDesc returns slice of mempool transactions for given address descriptor
|
|
||||||
func (b *EthereumRPC) GetMempoolTransactionsForAddrDesc(addrDesc bchain.AddressDescriptor) ([]bchain.Outpoint, error) {
|
|
||||||
return b.Mempool.GetAddrDescTransactions(addrDesc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolEntry is not supported by etherem
|
|
||||||
func (b *EthereumRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
|
|
||||||
return nil, errors.New("GetMempoolEntry: not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChainParser returns ethereum BlockChainParser
|
// GetChainParser returns ethereum BlockChainParser
|
||||||
func (b *EthereumRPC) GetChainParser() bchain.BlockChainParser {
|
func (b *EthereumRPC) GetChainParser() bchain.BlockChainParser {
|
||||||
return b.Parser
|
return b.Parser
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/btc"
|
"blockbook/bchain/coins/btc"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
@ -32,10 +33,11 @@ func NewFloRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)
|
||||||
|
|
||||||
// Initialize initializes FloRPC instance.
|
// Initialize initializes FloRPC instance.
|
||||||
func (f *FloRPC) Initialize() error {
|
func (f *FloRPC) Initialize() error {
|
||||||
chainName, err := f.GetChainInfoAndInitializeMempool(f)
|
ci, err := f.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewFujicoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes FujicoinRPC instance.
|
// Initialize initializes FujicoinRPC instance.
|
||||||
func (b *FujicoinRPC) Initialize() error {
|
func (b *FujicoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewGameCreditsRPC(config json.RawMessage, pushHandler func(bchain.Notificat
|
||||||
|
|
||||||
// Initialize initializes GameCreditsRPC instance.
|
// Initialize initializes GameCreditsRPC instance.
|
||||||
func (b *GameCreditsRPC) Initialize() error {
|
func (b *GameCreditsRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -27,10 +27,11 @@ func NewGroestlcoinRPC(config json.RawMessage, pushHandler func(bchain.Notificat
|
||||||
|
|
||||||
// Initialize initializes GroestlcoinRPC instance.
|
// Initialize initializes GroestlcoinRPC instance.
|
||||||
func (g *GroestlcoinRPC) Initialize() error {
|
func (g *GroestlcoinRPC) Initialize() error {
|
||||||
chainName, err := g.GetChainInfoAndInitializeMempool(g)
|
ci, err := g.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,11 @@ func NewKotoRPC(config json.RawMessage, pushHandler func(bchain.NotificationType
|
||||||
|
|
||||||
// Initialize initializes KotoRPC instance.
|
// Initialize initializes KotoRPC instance.
|
||||||
func (z *KotoRPC) Initialize() error {
|
func (z *KotoRPC) Initialize() error {
|
||||||
chainName, err := z.GetChainInfoAndInitializeMempool(z)
|
ci, err := z.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewLiquidRPC(config json.RawMessage, pushHandler func(bchain.NotificationTy
|
||||||
|
|
||||||
// Initialize initializes GameCreditsRPC instance.
|
// Initialize initializes GameCreditsRPC instance.
|
||||||
func (b *LiquidRPC) Initialize() error {
|
func (b *LiquidRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewLitecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes LitecoinRPC instance.
|
// Initialize initializes LitecoinRPC instance.
|
||||||
func (b *LitecoinRPC) Initialize() error {
|
func (b *LitecoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewMonacoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes MonacoinRPC instance.
|
// Initialize initializes MonacoinRPC instance.
|
||||||
func (b *MonacoinRPC) Initialize() error {
|
func (b *MonacoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewMyriadRPC(config json.RawMessage, pushHandler func(bchain.NotificationTy
|
||||||
|
|
||||||
// Initialize initializes MyriadRPC instance.
|
// Initialize initializes MyriadRPC instance.
|
||||||
func (b *MyriadRPC) Initialize() error {
|
func (b *MyriadRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewNamecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes NamecoinRPC instance.
|
// Initialize initializes NamecoinRPC instance.
|
||||||
func (b *NamecoinRPC) Initialize() error {
|
func (b *NamecoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -32,10 +32,11 @@ func NewPivXRPC(config json.RawMessage, pushHandler func(bchain.NotificationType
|
||||||
|
|
||||||
// Initialize initializes PivXRPC instance.
|
// Initialize initializes PivXRPC instance.
|
||||||
func (b *PivXRPC) Initialize() error {
|
func (b *PivXRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/btc"
|
"blockbook/bchain/coins/btc"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,10 +31,11 @@ func NewQtumRPC(config json.RawMessage, pushHandler func(bchain.NotificationType
|
||||||
|
|
||||||
// Initialize initializes QtumRPC instance.
|
// Initialize initializes QtumRPC instance.
|
||||||
func (b *QtumRPC) Initialize() error {
|
func (b *QtumRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewVertcoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||||
|
|
||||||
// Initialize initializes VertcoinRPC instance.
|
// Initialize initializes VertcoinRPC instance.
|
||||||
func (b *VertcoinRPC) Initialize() error {
|
func (b *VertcoinRPC) Initialize() error {
|
||||||
chainName, err := b.GetChainInfoAndInitializeMempool(b)
|
ci, err := b.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
glog.Info("Chain name ", chainName)
|
glog.Info("Chain name ", chainName)
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
|
@ -36,10 +36,11 @@ func NewZcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) Initialize() error {
|
func (zc *ZcoinRPC) Initialize() error {
|
||||||
chainName, err := zc.GetChainInfoAndInitializeMempool(zc)
|
ci, err := zc.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,11 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
|
||||||
|
|
||||||
// Initialize initializes ZCashRPC instance
|
// Initialize initializes ZCashRPC instance
|
||||||
func (z *ZCashRPC) Initialize() error {
|
func (z *ZCashRPC) Initialize() error {
|
||||||
chainName, err := z.GetChainInfoAndInitializeMempool(z)
|
ci, err := z.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
chainName := ci.Chain
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ func (m *MempoolBitcoinType) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
glog.V(1).Info("mempool: resync")
|
glog.V(1).Info("mempool: resync")
|
||||||
m.onNewTxAddr = onNewTxAddr
|
m.onNewTxAddr = onNewTxAddr
|
||||||
txs, err := m.chain.GetMempool()
|
txs, err := m.chain.GetMempoolTransactions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ func appendAddress(io []addrIndex, i int32, a string, parser BlockChainParser) [
|
||||||
func (m *MempoolEthereumType) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
|
func (m *MempoolEthereumType) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
glog.V(1).Info("Mempool: resync")
|
glog.V(1).Info("Mempool: resync")
|
||||||
txs, err := m.chain.GetMempool()
|
txs, err := m.chain.GetMempoolTransactions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,13 @@ type OnNewTxAddrFunc func(tx *Tx, desc AddressDescriptor)
|
||||||
// BlockChain defines common interface to block chain daemon
|
// BlockChain defines common interface to block chain daemon
|
||||||
type BlockChain interface {
|
type BlockChain interface {
|
||||||
// life-cycle methods
|
// life-cycle methods
|
||||||
|
// intialize the block chain connector
|
||||||
Initialize() error
|
Initialize() error
|
||||||
|
// create mempool but do not initialize it
|
||||||
|
CreateMempool() (Mempool, error)
|
||||||
|
// initialize mempool, create ZeroMQ (or other) subscription
|
||||||
|
InitializeMempool() error
|
||||||
|
// shutdown mempool, ZeroMQ and block chain connections
|
||||||
Shutdown(ctx context.Context) error
|
Shutdown(ctx context.Context) error
|
||||||
// chain info
|
// chain info
|
||||||
IsTestnet() bool
|
IsTestnet() bool
|
||||||
|
@ -209,17 +215,13 @@ type BlockChain interface {
|
||||||
GetBlockHeader(hash string) (*BlockHeader, error)
|
GetBlockHeader(hash string) (*BlockHeader, error)
|
||||||
GetBlock(hash string, height uint32) (*Block, error)
|
GetBlock(hash string, height uint32) (*Block, error)
|
||||||
GetBlockInfo(hash string) (*BlockInfo, error)
|
GetBlockInfo(hash string) (*BlockInfo, error)
|
||||||
GetMempool() ([]string, error)
|
GetMempoolTransactions() ([]string, error)
|
||||||
GetTransaction(txid string) (*Tx, error)
|
GetTransaction(txid string) (*Tx, error)
|
||||||
GetTransactionForMempool(txid string) (*Tx, error)
|
GetTransactionForMempool(txid string) (*Tx, error)
|
||||||
GetTransactionSpecific(tx *Tx) (json.RawMessage, error)
|
GetTransactionSpecific(tx *Tx) (json.RawMessage, error)
|
||||||
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
||||||
EstimateFee(blocks int) (big.Int, error)
|
EstimateFee(blocks int) (big.Int, error)
|
||||||
SendRawTransaction(tx string) (string, error)
|
SendRawTransaction(tx string) (string, error)
|
||||||
// mempool
|
|
||||||
ResyncMempool(onNewTxAddr OnNewTxAddrFunc) (int, error)
|
|
||||||
GetMempoolTransactions(address string) ([]Outpoint, error)
|
|
||||||
GetMempoolTransactionsForAddrDesc(addrDesc AddressDescriptor) ([]Outpoint, error)
|
|
||||||
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
||||||
// parser
|
// parser
|
||||||
GetChainParser() BlockChainParser
|
GetChainParser() BlockChainParser
|
||||||
|
@ -270,3 +272,10 @@ type BlockChainParser interface {
|
||||||
// EthereumType specific
|
// EthereumType specific
|
||||||
EthereumTypeGetErc20FromTx(tx *Tx) ([]Erc20Transfer, error)
|
EthereumTypeGetErc20FromTx(tx *Tx) ([]Erc20Transfer, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mempool defines common interface to mempool
|
||||||
|
type Mempool interface {
|
||||||
|
Resync(onNewTxAddr OnNewTxAddrFunc) (int, error)
|
||||||
|
GetTransactions(address string) ([]Outpoint, error)
|
||||||
|
GetAddrDescTransactions(addrDesc AddressDescriptor) ([]Outpoint, error)
|
||||||
|
}
|
||||||
|
|
80
blockbook.go
80
blockbook.go
|
@ -82,6 +82,7 @@ var (
|
||||||
chanSyncMempoolDone = make(chan struct{})
|
chanSyncMempoolDone = make(chan struct{})
|
||||||
chanStoreInternalStateDone = make(chan struct{})
|
chanStoreInternalStateDone = make(chan struct{})
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
|
mempool bchain.Mempool
|
||||||
index *db.RocksDB
|
index *db.RocksDB
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
|
@ -98,26 +99,27 @@ func init() {
|
||||||
glog.CopyStandardLogTo("INFO")
|
glog.CopyStandardLogTo("INFO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockChainWithRetry(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics, seconds int) (bchain.BlockChain, error) {
|
func getBlockChainWithRetry(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics, seconds int) (bchain.BlockChain, bchain.Mempool, error) {
|
||||||
var chain bchain.BlockChain
|
var chain bchain.BlockChain
|
||||||
|
var mempool bchain.Mempool
|
||||||
var err error
|
var err error
|
||||||
timer := time.NewTimer(time.Second)
|
timer := time.NewTimer(time.Second)
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
if chain, err = coins.NewBlockChain(coin, configfile, pushHandler, metrics); err != nil {
|
if chain, mempool, err = coins.NewBlockChain(coin, configfile, pushHandler, metrics); err != nil {
|
||||||
if i < seconds {
|
if i < seconds {
|
||||||
glog.Error("rpc: ", err, " Retrying...")
|
glog.Error("rpc: ", err, " Retrying...")
|
||||||
select {
|
select {
|
||||||
case <-chanOsSignal:
|
case <-chanOsSignal:
|
||||||
return nil, errors.New("Interrupted")
|
return nil, nil, errors.New("Interrupted")
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
timer.Reset(time.Second)
|
timer.Reset(time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return chain, nil
|
return chain, mempool, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +164,7 @@ func main() {
|
||||||
glog.Fatal("metrics: ", err)
|
glog.Fatal("metrics: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if chain, err = getBlockChainWithRetry(coin, *blockchain, pushSynchronizationHandler, metrics, 60); err != nil {
|
if chain, mempool, err = getBlockChainWithRetry(coin, *blockchain, pushSynchronizationHandler, metrics, 60); err != nil {
|
||||||
glog.Fatal("rpc: ", err)
|
glog.Fatal("rpc: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,29 +211,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *rollbackHeight >= 0 {
|
if *rollbackHeight >= 0 {
|
||||||
bestHeight, bestHash, err := index.GetBestBlock()
|
performRollback()
|
||||||
if err != nil {
|
|
||||||
glog.Error("rollbackHeight: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if uint32(*rollbackHeight) > bestHeight {
|
|
||||||
glog.Infof("nothing to rollback, rollbackHeight %d, bestHeight: %d", *rollbackHeight, bestHeight)
|
|
||||||
} else {
|
|
||||||
hashes := []string{bestHash}
|
|
||||||
for height := bestHeight - 1; height >= uint32(*rollbackHeight); height-- {
|
|
||||||
hash, err := index.GetBlockHash(height)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error("rollbackHeight: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
hashes = append(hashes, hash)
|
|
||||||
}
|
|
||||||
err = syncWorker.DisconnectBlocks(uint32(*rollbackHeight), bestHeight, hashes)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error("rollbackHeight: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +227,7 @@ func main() {
|
||||||
|
|
||||||
var internalServer *server.InternalServer
|
var internalServer *server.InternalServer
|
||||||
if *internalBinding != "" {
|
if *internalBinding != "" {
|
||||||
internalServer, err = server.NewInternalServer(*internalBinding, *certFiles, index, chain, txCache, internalState)
|
internalServer, err = server.NewInternalServer(*internalBinding, *certFiles, index, chain, mempool, txCache, internalState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("https: ", err)
|
glog.Error("https: ", err)
|
||||||
return
|
return
|
||||||
|
@ -268,7 +248,7 @@ func main() {
|
||||||
var publicServer *server.PublicServer
|
var publicServer *server.PublicServer
|
||||||
if *publicBinding != "" {
|
if *publicBinding != "" {
|
||||||
// start public server in limited functionality, extend it after sync is finished by calling ConnectFullPublicInterface
|
// start public server in limited functionality, extend it after sync is finished by calling ConnectFullPublicInterface
|
||||||
publicServer, err = server.NewPublicServer(*publicBinding, *certFiles, index, chain, txCache, *explorerURL, metrics, internalState, *debugMode)
|
publicServer, err = server.NewPublicServer(*publicBinding, *certFiles, index, chain, mempool, txCache, *explorerURL, metrics, internalState, *debugMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("socketio: ", err)
|
glog.Error("socketio: ", err)
|
||||||
return
|
return
|
||||||
|
@ -295,8 +275,14 @@ func main() {
|
||||||
glog.Error("resyncIndex ", err)
|
glog.Error("resyncIndex ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// initialize mempool after the initial sync is complete
|
||||||
|
err = chain.InitializeMempool()
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("initializeMempool ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
var mempoolCount int
|
var mempoolCount int
|
||||||
if mempoolCount, err = chain.ResyncMempool(nil); err != nil {
|
if mempoolCount, err = mempool.Resync(nil); err != nil {
|
||||||
glog.Error("resyncMempool ", err)
|
glog.Error("resyncMempool ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -341,8 +327,34 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func performRollback() {
|
||||||
|
bestHeight, bestHash, err := index.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("rollbackHeight: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if uint32(*rollbackHeight) > bestHeight {
|
||||||
|
glog.Infof("nothing to rollback, rollbackHeight %d, bestHeight: %d", *rollbackHeight, bestHeight)
|
||||||
|
} else {
|
||||||
|
hashes := []string{bestHash}
|
||||||
|
for height := bestHeight - 1; height >= uint32(*rollbackHeight); height-- {
|
||||||
|
hash, err := index.GetBlockHash(height)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("rollbackHeight: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hashes = append(hashes, hash)
|
||||||
|
}
|
||||||
|
err = syncWorker.DisconnectBlocks(uint32(*rollbackHeight), bestHeight, hashes)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("rollbackHeight: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
||||||
api, err := api.NewWorker(db, chain, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -442,7 +454,7 @@ func syncMempoolLoop() {
|
||||||
// resync mempool about every minute if there are no chanSyncMempool requests, with debounce 1 second
|
// resync mempool about every minute if there are no chanSyncMempool requests, with debounce 1 second
|
||||||
tickAndDebounce(time.Duration(*resyncMempoolPeriodMs)*time.Millisecond, debounceResyncMempoolMs*time.Millisecond, chanSyncMempool, func() {
|
tickAndDebounce(time.Duration(*resyncMempoolPeriodMs)*time.Millisecond, debounceResyncMempoolMs*time.Millisecond, chanSyncMempool, func() {
|
||||||
internalState.StartedMempoolSync()
|
internalState.StartedMempoolSync()
|
||||||
if count, err := chain.ResyncMempool(onNewTxAddr); err != nil {
|
if count, err := mempool.Resync(onNewTxAddr); err != nil {
|
||||||
glog.Error("syncMempoolLoop ", errors.ErrorStack(err))
|
glog.Error("syncMempoolLoop ", errors.ErrorStack(err))
|
||||||
} else {
|
} else {
|
||||||
internalState.FinishedMempoolSync(count)
|
internalState.FinishedMempoolSync(count)
|
||||||
|
|
|
@ -23,13 +23,14 @@ type InternalServer struct {
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
mempool bchain.Mempool
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
api *api.Worker
|
api *api.Worker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInternalServer creates new internal http interface to blockbook and returns its handle
|
// NewInternalServer creates new internal http interface to blockbook and returns its handle
|
||||||
func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) {
|
func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -47,6 +48,7 @@ func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.B
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
mempool: mempool,
|
||||||
is: is,
|
is: is,
|
||||||
api: api,
|
api: api,
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ type PublicServer struct {
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
mempool bchain.Mempool
|
||||||
api *api.Worker
|
api *api.Worker
|
||||||
explorerURL string
|
explorerURL string
|
||||||
internalExplorer bool
|
internalExplorer bool
|
||||||
|
@ -56,19 +57,19 @@ type PublicServer struct {
|
||||||
|
|
||||||
// NewPublicServer creates new public server http interface to blockbook and returns its handle
|
// NewPublicServer creates new public server http interface to blockbook and returns its handle
|
||||||
// only basic functionality is mapped, to map all functions, call
|
// only basic functionality is mapped, to map all functions, call
|
||||||
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool) (*PublicServer, error) {
|
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool) (*PublicServer, error) {
|
||||||
|
|
||||||
api, err := api.NewWorker(db, chain, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
socketio, err := NewSocketIoServer(db, chain, txCache, metrics, is)
|
socketio, err := NewSocketIoServer(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
websocket, err := NewWebsocketServer(db, chain, txCache, metrics, is)
|
websocket, err := NewWebsocketServer(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -91,6 +92,7 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
mempool: mempool,
|
||||||
explorerURL: explorerURL,
|
explorerURL: explorerURL,
|
||||||
internalExplorer: explorerURL == "",
|
internalExplorer: explorerURL == "",
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
|
|
|
@ -85,6 +85,11 @@ func setupPublicHTTPServer(t *testing.T) (*PublicServer, string) {
|
||||||
glog.Fatal("fakechain: ", err)
|
glog.Fatal("fakechain: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mempool, err := chain.CreateMempool()
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal("mempool: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
// caching is switched off because test transactions do not have hex data
|
// caching is switched off because test transactions do not have hex data
|
||||||
txCache, err := db.NewTxCache(d, chain, metrics, is, false)
|
txCache, err := db.NewTxCache(d, chain, metrics, is, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,7 +97,7 @@ func setupPublicHTTPServer(t *testing.T) (*PublicServer, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// s.Run is never called, binding can be to any port
|
// s.Run is never called, binding can be to any port
|
||||||
s, err := NewPublicServer("localhost:12345", "", d, chain, txCache, "", metrics, is, false)
|
s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,15 @@ type SocketIoServer struct {
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
mempool bchain.Mempool
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
api *api.Worker
|
api *api.Worker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle
|
// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle
|
||||||
func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*SocketIoServer, error) {
|
func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*SocketIoServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -64,6 +65,7 @@ func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCa
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
mempool: mempool,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
is: is,
|
is: is,
|
||||||
api: api,
|
api: api,
|
||||||
|
@ -224,7 +226,7 @@ func (s *SocketIoServer) getAddressTxids(addr []string, opts *addrOpts) (res res
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
o, err := s.chain.GetMempoolTransactions(address)
|
o, err := s.mempool.GetTransactions(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ type WebsocketServer struct {
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
mempool bchain.Mempool
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
api *api.Worker
|
api *api.Worker
|
||||||
|
@ -70,8 +71,8 @@ type WebsocketServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebsocketServer creates new websocket interface to blockbook and returns its handle
|
// NewWebsocketServer creates new websocket interface to blockbook and returns its handle
|
||||||
func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*WebsocketServer, error) {
|
func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*WebsocketServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -89,6 +90,7 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxC
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
mempool: mempool,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
is: is,
|
is: is,
|
||||||
api: api,
|
api: api,
|
||||||
|
|
|
@ -17,10 +17,18 @@ func NewFakeBlockChain(parser bchain.BlockChainParser) (bchain.BlockChain, error
|
||||||
return &fakeBlockChain{&bchain.BaseChain{Parser: parser}}, nil
|
return &fakeBlockChain{&bchain.BaseChain{Parser: parser}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *fakeBlockChain) CreateMempool() (bchain.Mempool, error) {
|
||||||
|
return bchain.NewMempoolBitcoinType(b, 1, 1), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) Initialize() error {
|
func (c *fakeBlockChain) Initialize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *fakeBlockChain) InitializeMempool() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) Shutdown(ctx context.Context) error {
|
func (c *fakeBlockChain) Shutdown(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -118,10 +126,6 @@ func (c *fakeBlockChain) GetBlockInfo(hash string) (v *bchain.BlockInfo, err err
|
||||||
return nil, bchain.ErrBlockNotFound
|
return nil, bchain.ErrBlockNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetMempool() (v []string, err error) {
|
|
||||||
return nil, errors.New("Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTxInBlock(b *bchain.Block, txid string) *bchain.Tx {
|
func getTxInBlock(b *bchain.Block, txid string) *bchain.Tx {
|
||||||
for _, tx := range b.Txs {
|
for _, tx := range b.Txs {
|
||||||
if tx.Txid == txid {
|
if tx.Txid == txid {
|
||||||
|
@ -179,22 +183,12 @@ func (c *fakeBlockChain) SendRawTransaction(tx string) (v string, err error) {
|
||||||
return "", errors.New("Invalid data")
|
return "", errors.New("Invalid data")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (count int, err error) {
|
// GetChainParser returns parser for the blockchain
|
||||||
return 0, errors.New("Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetMempoolTransactions(address string) (v []bchain.Outpoint, err error) {
|
|
||||||
return nil, errors.New("Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetMempoolTransactionsForAddrDesc(addrDesc bchain.AddressDescriptor) (v []bchain.Outpoint, err error) {
|
|
||||||
return []bchain.Outpoint{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetMempoolEntry(txid string) (v *bchain.MempoolEntry, err error) {
|
|
||||||
return nil, errors.New("Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetChainParser() bchain.BlockChainParser {
|
func (c *fakeBlockChain) GetChainParser() bchain.BlockChainParser {
|
||||||
return c.Parser
|
return c.Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMempoolTransactions returns transactions in mempool
|
||||||
|
func (b *fakeBlockChain) GetMempoolTransactions() ([]string, error) {
|
||||||
|
return nil, errors.New("Not implemented")
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ package tests
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins"
|
"blockbook/bchain/coins"
|
||||||
"blockbook/build/tools"
|
build "blockbook/build/tools"
|
||||||
"blockbook/tests/rpc"
|
"blockbook/tests/rpc"
|
||||||
"blockbook/tests/sync"
|
"blockbook/tests/sync"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestFunc func(t *testing.T, coin string, chain bchain.BlockChain, testConfig json.RawMessage)
|
type TestFunc func(t *testing.T, coin string, chain bchain.BlockChain, mempool bchain.Mempool, testConfig json.RawMessage)
|
||||||
|
|
||||||
var integrationTests = map[string]TestFunc{
|
var integrationTests = map[string]TestFunc{
|
||||||
"rpc": rpc.IntegrationTest,
|
"rpc": rpc.IntegrationTest,
|
||||||
|
@ -76,7 +76,7 @@ func runTests(t *testing.T, coin string, cfg map[string]json.RawMessage) {
|
||||||
}
|
}
|
||||||
defer chaincfg.ResetParams()
|
defer chaincfg.ResetParams()
|
||||||
|
|
||||||
bc, err := makeBlockChain(coin)
|
bc, m, err := makeBlockChain(coin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == notConnectedError {
|
if err == notConnectedError {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -86,44 +86,44 @@ func runTests(t *testing.T, coin string, cfg map[string]json.RawMessage) {
|
||||||
|
|
||||||
for test, c := range cfg {
|
for test, c := range cfg {
|
||||||
if fn, found := integrationTests[test]; found {
|
if fn, found := integrationTests[test]; found {
|
||||||
t.Run(test, func(t *testing.T) { fn(t, coin, bc, c) })
|
t.Run(test, func(t *testing.T) { fn(t, coin, bc, m, c) })
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("Test not found: %s", test)
|
t.Errorf("Test not found: %s", test)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBlockChain(coin string) (bchain.BlockChain, error) {
|
func makeBlockChain(coin string) (bchain.BlockChain, bchain.Mempool, error) {
|
||||||
c, err := build.LoadConfig("../configs", coin)
|
c, err := build.LoadConfig("../configs", coin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
outputDir, err := ioutil.TempDir("", "integration_test")
|
outputDir, err := ioutil.TempDir("", "integration_test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(outputDir)
|
defer os.RemoveAll(outputDir)
|
||||||
|
|
||||||
err = build.GeneratePackageDefinitions(c, "../build/templates", outputDir)
|
err = build.GeneratePackageDefinitions(c, "../build/templates", outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(filepath.Join(outputDir, "blockbook", "blockchaincfg.json"))
|
b, err := ioutil.ReadFile(filepath.Join(outputDir, "blockbook", "blockchaincfg.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg json.RawMessage
|
var cfg json.RawMessage
|
||||||
err = json.Unmarshal(b, &cfg)
|
err = json.Unmarshal(b, &cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
coinName, err := getName(cfg)
|
coinName, err := getName(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return initBlockChain(coinName, cfg)
|
return initBlockChain(coinName, cfg)
|
||||||
|
@ -147,29 +147,39 @@ func getName(raw json.RawMessage) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockChain(coinName string, cfg json.RawMessage) (bchain.BlockChain, error) {
|
func initBlockChain(coinName string, cfg json.RawMessage) (bchain.BlockChain, bchain.Mempool, error) {
|
||||||
factory, found := coins.BlockChainFactories[coinName]
|
factory, found := coins.BlockChainFactories[coinName]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("Factory function not found")
|
return nil, nil, fmt.Errorf("Factory function not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
cli, err := factory(cfg, func(_ bchain.NotificationType) {})
|
cli, err := factory(cfg, func(_ bchain.NotificationType) {})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isNetError(err) {
|
if isNetError(err) {
|
||||||
return nil, notConnectedError
|
return nil, nil, notConnectedError
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Factory function failed: %s", err)
|
return nil, nil, fmt.Errorf("Factory function failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cli.Initialize()
|
err = cli.Initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isNetError(err) {
|
if isNetError(err) {
|
||||||
return nil, notConnectedError
|
return nil, nil, notConnectedError
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("BlockChain initialization failed: %s", err)
|
return nil, nil, fmt.Errorf("BlockChain initialization failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cli, nil
|
mempool, err := cli.CreateMempool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Mempool creation failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cli.InitializeMempool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Mempool initialization failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cli, mempool, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNetError(err error) bool {
|
func isNetError(err error) bool {
|
||||||
|
|
|
@ -30,6 +30,7 @@ var testMap = map[string]func(t *testing.T, th *TestHandler){
|
||||||
|
|
||||||
type TestHandler struct {
|
type TestHandler struct {
|
||||||
Chain bchain.BlockChain
|
Chain bchain.BlockChain
|
||||||
|
Mempool bchain.Mempool
|
||||||
TestData *TestData
|
TestData *TestData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ type TestData struct {
|
||||||
TxDetails map[string]*bchain.Tx `json:"txDetails"`
|
TxDetails map[string]*bchain.Tx `json:"txDetails"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, testConfig json.RawMessage) {
|
func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, mempool bchain.Mempool, testConfig json.RawMessage) {
|
||||||
tests, err := getTests(testConfig)
|
tests, err := getTests(testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed loading of test list: %s", err)
|
t.Fatalf("Failed loading of test list: %s", err)
|
||||||
|
@ -54,7 +55,11 @@ func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, testCon
|
||||||
t.Fatalf("Failed loading of test data: %s", err)
|
t.Fatalf("Failed loading of test data: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
h := TestHandler{Chain: chain, TestData: td}
|
h := TestHandler{
|
||||||
|
Chain: chain,
|
||||||
|
Mempool: mempool,
|
||||||
|
TestData: td,
|
||||||
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
if f, found := testMap[test]; found {
|
if f, found := testMap[test]; found {
|
||||||
|
@ -195,7 +200,7 @@ func testMempoolSync(t *testing.T, h *TestHandler) {
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
txs := getMempool(t, h)
|
txs := getMempool(t, h)
|
||||||
|
|
||||||
n, err := h.Chain.ResyncMempool(nil)
|
n, err := h.Mempool.Resync(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -217,7 +222,7 @@ func testMempoolSync(t *testing.T, h *TestHandler) {
|
||||||
|
|
||||||
for txid, addrs := range txid2addrs {
|
for txid, addrs := range txid2addrs {
|
||||||
for _, a := range addrs {
|
for _, a := range addrs {
|
||||||
got, err := h.Chain.GetMempoolTransactions(a)
|
got, err := h.Mempool.GetTransactions(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("address %q: %s", a, err)
|
t.Fatalf("address %q: %s", a, err)
|
||||||
}
|
}
|
||||||
|
@ -337,7 +342,7 @@ func testGetBlockHeader(t *testing.T, h *TestHandler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMempool(t *testing.T, h *TestHandler) []string {
|
func getMempool(t *testing.T, h *TestHandler) []string {
|
||||||
txs, err := h.Chain.GetMempool()
|
txs, err := h.Chain.GetMempoolTransactions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ type BlockInfo struct {
|
||||||
TxDetails []*bchain.Tx `json:"txDetails"`
|
TxDetails []*bchain.Tx `json:"txDetails"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, testConfig json.RawMessage) {
|
func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, mempool bchain.Mempool, testConfig json.RawMessage) {
|
||||||
tests, err := getTests(testConfig)
|
tests, err := getTests(testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed loading of test list: %s", err)
|
t.Fatalf("Failed loading of test list: %s", err)
|
||||||
|
|
Loading…
Reference in New Issue