Merge branch 'master' into ethereum

indexv1
Martin Boehm 2018-03-20 17:07:40 +01:00
commit 3c97142dd1
8 changed files with 78 additions and 66 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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
}

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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
}