Merge branch 'master' into ethereum
commit
3c97142dd1
|
@ -33,6 +33,22 @@ func GetChainParams(chain string) *chaincfg.Params {
|
|||
return &chaincfg.MainNetParams
|
||||
}
|
||||
|
||||
func (p *BitcoinBlockParser) GetUIDFromVout(output *bchain.Vout) string {
|
||||
return output.ScriptPubKey.Hex
|
||||
}
|
||||
|
||||
func (p *BitcoinBlockParser) GetUIDFromAddress(address string) ([]byte, error) {
|
||||
return p.AddressToOutputScript(address)
|
||||
}
|
||||
|
||||
func (p *BitcoinBlockParser) PackUID(script string) ([]byte, error) {
|
||||
return hex.DecodeString(script)
|
||||
}
|
||||
|
||||
func (p *BitcoinBlockParser) UnpackUID(buf []byte) string {
|
||||
return hex.EncodeToString(buf)
|
||||
}
|
||||
|
||||
// AddressToOutputScript converts bitcoin address to ScriptPubKey
|
||||
func (p *BitcoinBlockParser) AddressToOutputScript(address string) ([]byte, error) {
|
||||
da, err := btcutil.DecodeAddress(address, p.Params)
|
||||
|
|
|
@ -48,7 +48,7 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(*bchain.MQMessage),
|
|||
var c configuration
|
||||
err = json.Unmarshal(config, &c)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "Invalid configuragion file")
|
||||
return nil, errors.Annotatef(err, "Invalid configuration file")
|
||||
}
|
||||
transport := &http.Transport{
|
||||
Dial: (&net.Dialer{KeepAlive: 600 * time.Second}).Dial,
|
||||
|
@ -531,9 +531,9 @@ func (b *BitcoinRPC) ResyncMempool(onNewTxAddr func(txid string, addr string)) e
|
|||
return b.Mempool.Resync(onNewTxAddr)
|
||||
}
|
||||
|
||||
// GetMempoolTransactions returns slice of mempool transactions for given output script.
|
||||
func (b *BitcoinRPC) GetMempoolTransactions(outputScript []byte) ([]string, error) {
|
||||
return b.Mempool.GetTransactions(outputScript)
|
||||
// GetMempoolTransactions returns slice of mempool transactions for given address.
|
||||
func (b *BitcoinRPC) GetMempoolTransactions(address string) ([]string, error) {
|
||||
return b.Mempool.GetTransactions(address)
|
||||
}
|
||||
|
||||
// GetMempoolSpentOutput returns transaction in mempool which spends given outpoint
|
||||
|
|
|
@ -2,13 +2,13 @@ package bchain
|
|||
|
||||
import (
|
||||
"blockbook/common"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// TODO rename
|
||||
type scriptIndex struct {
|
||||
script string
|
||||
n uint32
|
||||
|
@ -20,31 +20,36 @@ type outpoint struct {
|
|||
}
|
||||
|
||||
type inputOutput struct {
|
||||
outputScripts []scriptIndex
|
||||
inputs []outpoint
|
||||
outputs []scriptIndex
|
||||
inputs []outpoint
|
||||
}
|
||||
|
||||
// Mempool is mempool handle.
|
||||
type Mempool struct {
|
||||
chain BlockChain
|
||||
chainParser BlockChainParser
|
||||
mux sync.Mutex
|
||||
txToInputOutput map[string]inputOutput
|
||||
scriptToTx map[string][]outpoint
|
||||
scriptToTx map[string][]outpoint // TODO rename all occurences
|
||||
inputs map[outpoint]string
|
||||
metrics *common.Metrics
|
||||
}
|
||||
|
||||
// NewMempool creates new mempool handler.
|
||||
func NewMempool(chain BlockChain, metrics *common.Metrics) *Mempool {
|
||||
return &Mempool{chain: chain, metrics: metrics}
|
||||
return &Mempool{chain: chain, chainParser: chain.GetChainParser(), metrics: metrics}
|
||||
}
|
||||
|
||||
// GetTransactions returns slice of mempool transactions for given output script.
|
||||
func (m *Mempool) GetTransactions(outputScript []byte) ([]string, error) {
|
||||
func (m *Mempool) GetTransactions(address string) ([]string, error) {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
scriptHex := hex.EncodeToString(outputScript)
|
||||
outpoints := m.scriptToTx[scriptHex]
|
||||
buf, err := m.chainParser.GetUIDFromAddress(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outid := m.chainParser.UnpackUID(buf)
|
||||
outpoints := m.scriptToTx[outid]
|
||||
txs := make([]string, 0, len(outpoints)+len(outpoints)/2)
|
||||
for _, o := range outpoints {
|
||||
txs = append(txs, o.txid)
|
||||
|
@ -93,11 +98,11 @@ func (m *Mempool) Resync(onNewTxAddr func(txid string, addr string)) error {
|
|||
glog.Error("cannot get transaction ", txid, ": ", err)
|
||||
continue
|
||||
}
|
||||
io.outputScripts = make([]scriptIndex, 0, len(tx.Vout))
|
||||
io.outputs = make([]scriptIndex, 0, len(tx.Vout))
|
||||
for _, output := range tx.Vout {
|
||||
outputScript := output.ScriptPubKey.Hex
|
||||
if outputScript != "" {
|
||||
io.outputScripts = append(io.outputScripts, scriptIndex{outputScript, output.N})
|
||||
outid := m.chainParser.GetUIDFromVout(&output)
|
||||
if outid != "" {
|
||||
io.outputs = append(io.outputs, scriptIndex{outid, output.N})
|
||||
}
|
||||
if onNewTxAddr != nil && len(output.ScriptPubKey.Addresses) == 1 {
|
||||
onNewTxAddr(tx.Txid, output.ScriptPubKey.Addresses[0])
|
||||
|
@ -112,7 +117,7 @@ func (m *Mempool) Resync(onNewTxAddr func(txid string, addr string)) error {
|
|||
}
|
||||
}
|
||||
newTxToInputOutput[txid] = io
|
||||
for _, si := range io.outputScripts {
|
||||
for _, si := range io.outputs {
|
||||
newScriptToTx[si.script] = append(newScriptToTx[si.script], outpoint{txid, si.n})
|
||||
}
|
||||
for _, i := range io.inputs {
|
||||
|
|
|
@ -103,7 +103,7 @@ type BlockChain interface {
|
|||
SendRawTransaction(tx string) (string, error)
|
||||
// mempool
|
||||
ResyncMempool(onNewTxAddr func(txid string, addr string)) error
|
||||
GetMempoolTransactions(outputScript []byte) ([]string, error)
|
||||
GetMempoolTransactions(address string) ([]string, error)
|
||||
GetMempoolSpentOutput(outputTxid string, vout uint32) string
|
||||
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
||||
// parser
|
||||
|
@ -111,6 +111,10 @@ type BlockChain interface {
|
|||
}
|
||||
|
||||
type BlockChainParser interface {
|
||||
GetUIDFromVout(output *Vout) string
|
||||
GetUIDFromAddress(address string) ([]byte, error)
|
||||
PackUID(script string) ([]byte, error)
|
||||
UnpackUID(buf []byte) string
|
||||
AddressToOutputScript(address string) ([]byte, error)
|
||||
OutputScriptToAddresses(script []byte) ([]string, error)
|
||||
ParseTx(b []byte) (*Tx, error)
|
||||
|
|
|
@ -229,12 +229,7 @@ func main() {
|
|||
address := *queryAddress
|
||||
|
||||
if address != "" {
|
||||
script, err := chain.GetChainParser().AddressToOutputScript(address)
|
||||
if err != nil {
|
||||
glog.Error("GetTransactions ", err)
|
||||
return
|
||||
}
|
||||
if err = index.GetTransactions(script, height, until, printResult); err != nil {
|
||||
if err = index.GetTransactions(address, height, until, printResult); err != nil {
|
||||
glog.Error("GetTransactions ", err)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -136,18 +136,19 @@ func (d *RocksDB) Reopen() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetTransactions finds all input/output transactions for address specified by outputScript.
|
||||
// GetTransactions finds all input/output transactions for address
|
||||
// Transaction are passed to callback function.
|
||||
func (d *RocksDB) GetTransactions(outputScript []byte, lower uint32, higher uint32, fn func(txid string, vout uint32, isOutput bool) error) (err error) {
|
||||
func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, fn func(txid string, vout uint32, isOutput bool) error) (err error) {
|
||||
if glog.V(1) {
|
||||
glog.Infof("rocksdb: address get %s %d-%d ", unpackOutputScript(outputScript), lower, higher)
|
||||
glog.Infof("rocksdb: address get %s %d-%d ", address, lower, higher)
|
||||
}
|
||||
outid, err := d.chainParser.GetUIDFromAddress(address)
|
||||
|
||||
kstart, err := packOutputKey(outputScript, lower)
|
||||
kstart, err := packOutputKey(outid, lower)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kstop, err := packOutputKey(outputScript, higher)
|
||||
kstop, err := packOutputKey(outid, higher)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -240,12 +241,12 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op
|
|||
|
||||
for _, tx := range block.Txs {
|
||||
for _, output := range tx.Vout {
|
||||
outputScript := output.ScriptPubKey.Hex
|
||||
if outputScript != "" {
|
||||
if len(outputScript) > 1024 {
|
||||
glog.Infof("block %d, skipping outputScript of length %d", block.Height, len(outputScript)/2)
|
||||
outid := d.chainParser.GetUIDFromVout(&output)
|
||||
if outid != "" {
|
||||
if len(outid) > 1024 {
|
||||
glog.Infof("block %d, skipping outid of length %d", block.Height, len(outid)/2)
|
||||
} else {
|
||||
records[outputScript] = append(records[outputScript], outpoint{
|
||||
records[outid] = append(records[outid], outpoint{
|
||||
txid: tx.Txid,
|
||||
vout: output.N,
|
||||
})
|
||||
|
@ -262,15 +263,15 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op
|
|||
}
|
||||
}
|
||||
|
||||
for outputScript, outpoints := range records {
|
||||
bOutputScript, err := packOutputScript(outputScript)
|
||||
for outid, outpoints := range records {
|
||||
bOutid, err := d.chainParser.PackUID(outid)
|
||||
if err != nil {
|
||||
glog.Warningf("rocksdb: packOutputScript: %v - %d %s", err, block.Height, outputScript)
|
||||
glog.Warningf("rocksdb: packOutputID: %v - %d %s", err, block.Height, outid)
|
||||
continue
|
||||
}
|
||||
key, err := packOutputKey(bOutputScript, block.Height)
|
||||
key, err := packOutputKey(bOutid, block.Height)
|
||||
if err != nil {
|
||||
glog.Warningf("rocksdb: packOutputKey: %v - %d %s", err, block.Height, outputScript)
|
||||
glog.Warningf("rocksdb: packOutputKey: %v - %d %s", err, block.Height, outid)
|
||||
continue
|
||||
}
|
||||
val, err := packOutputValue(outpoints)
|
||||
|
@ -663,11 +664,3 @@ func packBlockValue(hash string) ([]byte, error) {
|
|||
func unpackBlockValue(buf []byte) (string, error) {
|
||||
return hex.EncodeToString(buf), nil
|
||||
}
|
||||
|
||||
func packOutputScript(script string) ([]byte, error) {
|
||||
return hex.DecodeString(script)
|
||||
}
|
||||
|
||||
func unpackOutputScript(buf []byte) string {
|
||||
return hex.EncodeToString(buf)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"blockbook/db"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -135,14 +136,16 @@ func (s *HTTPServer) blockHash(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *HTTPServer) getAddress(r *http.Request) (address string, script []byte, err error) {
|
||||
address = mux.Vars(r)["address"]
|
||||
script, err = s.chainParser.AddressToOutputScript(address)
|
||||
func (s *HTTPServer) getAddress(r *http.Request) (address string, err error) {
|
||||
address, ok := mux.Vars(r)["address"]
|
||||
if !ok {
|
||||
err = errors.New("Empty address")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *HTTPServer) getAddressAndHeightRange(r *http.Request) (address string, script []byte, lower, higher uint32, err error) {
|
||||
address, script, err = s.getAddress(r)
|
||||
func (s *HTTPServer) getAddressAndHeightRange(r *http.Request) (address string, lower, higher uint32, err error) {
|
||||
address, err = s.getAddress(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -154,7 +157,7 @@ func (s *HTTPServer) getAddressAndHeightRange(r *http.Request) (address string,
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
return address, script, uint32(lower64), uint32(higher64), err
|
||||
return address, uint32(lower64), uint32(higher64), err
|
||||
}
|
||||
|
||||
type transactionList struct {
|
||||
|
@ -162,11 +165,11 @@ type transactionList struct {
|
|||
}
|
||||
|
||||
func (s *HTTPServer) unconfirmedTransactions(w http.ResponseWriter, r *http.Request) {
|
||||
address, script, err := s.getAddress(r)
|
||||
address, err := s.getAddress(r)
|
||||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("unconfirmedTransactions for address", address))
|
||||
}
|
||||
txs, err := s.chain.GetMempoolTransactions(script)
|
||||
txs, err := s.chain.GetMempoolTransactions(address)
|
||||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("unconfirmedTransactions for address", address))
|
||||
}
|
||||
|
@ -175,12 +178,12 @@ func (s *HTTPServer) unconfirmedTransactions(w http.ResponseWriter, r *http.Requ
|
|||
}
|
||||
|
||||
func (s *HTTPServer) confirmedTransactions(w http.ResponseWriter, r *http.Request) {
|
||||
address, script, lower, higher, err := s.getAddressAndHeightRange(r)
|
||||
address, lower, higher, err := s.getAddressAndHeightRange(r)
|
||||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("confirmedTransactions for address", address))
|
||||
}
|
||||
txList := transactionList{}
|
||||
err = s.db.GetTransactions(script, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
err = s.db.GetTransactions(address, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
txList.Txid = append(txList.Txid, txid)
|
||||
return nil
|
||||
})
|
||||
|
@ -191,12 +194,12 @@ func (s *HTTPServer) confirmedTransactions(w http.ResponseWriter, r *http.Reques
|
|||
}
|
||||
|
||||
func (s *HTTPServer) transactions(w http.ResponseWriter, r *http.Request) {
|
||||
address, script, lower, higher, err := s.getAddressAndHeightRange(r)
|
||||
address, lower, higher, err := s.getAddressAndHeightRange(r)
|
||||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("transactions for address", address))
|
||||
}
|
||||
txList := transactionList{}
|
||||
err = s.db.GetTransactions(script, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
err = s.db.GetTransactions(address, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
txList.Txid = append(txList.Txid, txid)
|
||||
if isOutput {
|
||||
input := s.chain.GetMempoolSpentOutput(txid, vout)
|
||||
|
@ -209,7 +212,7 @@ func (s *HTTPServer) transactions(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("transactions for address", address))
|
||||
}
|
||||
txs, err := s.chain.GetMempoolTransactions(script)
|
||||
txs, err := s.chain.GetMempoolTransactions(address)
|
||||
if err != nil {
|
||||
respondError(w, err, fmt.Sprint("transactions for address", address))
|
||||
}
|
||||
|
|
|
@ -258,12 +258,8 @@ func (s *SocketIoServer) getAddressTxids(addr []string, rr *reqRange) (res resul
|
|||
txids := make([]string, 0)
|
||||
lower, higher := uint32(rr.To), uint32(rr.Start)
|
||||
for _, address := range addr {
|
||||
script, err := s.chainParser.AddressToOutputScript(address)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if !rr.QueryMempoolOnly {
|
||||
err = s.db.GetTransactions(script, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
err = s.db.GetTransactions(address, lower, higher, func(txid string, vout uint32, isOutput bool) error {
|
||||
txids = append(txids, txid)
|
||||
if isOutput && rr.QueryMempol {
|
||||
input := s.chain.GetMempoolSpentOutput(txid, vout)
|
||||
|
@ -278,7 +274,7 @@ func (s *SocketIoServer) getAddressTxids(addr []string, rr *reqRange) (res resul
|
|||
}
|
||||
}
|
||||
if rr.QueryMempoolOnly || rr.QueryMempol {
|
||||
mtxids, err := s.chain.GetMempoolTransactions(script)
|
||||
mtxids, err := s.chain.GetMempoolTransactions(address)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue