Fix api.GetTransaction for EthereumType blockchain
parent
38ba033654
commit
fac728bc51
|
@ -20,6 +20,7 @@ type Worker struct {
|
||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
chainType bchain.ChainType
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
chainType: chain.GetChainParser().GetChainType(),
|
||||||
is: is,
|
is: is,
|
||||||
}
|
}
|
||||||
return w, nil
|
return w, nil
|
||||||
|
@ -102,9 +104,12 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewAPIError(fmt.Sprintf("Tx not found, %v", err), true)
|
return nil, NewAPIError(fmt.Sprintf("Tx not found, %v", err), true)
|
||||||
}
|
}
|
||||||
ta, err := w.db.GetTxAddresses(txid)
|
var ta *db.TxAddresses
|
||||||
if err != nil {
|
if w.chainType == bchain.ChainBitcoinType {
|
||||||
return nil, errors.Annotatef(err, "GetTxAddresses %v", txid)
|
ta, err = w.db.GetTxAddresses(txid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "GetTxAddresses %v", txid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var blockhash string
|
var blockhash string
|
||||||
if bchainTx.Confirmations > 0 {
|
if bchainTx.Confirmations > 0 {
|
||||||
|
@ -123,45 +128,56 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool) (*Tx, error) {
|
||||||
vin.Vout = bchainVin.Vout
|
vin.Vout = bchainVin.Vout
|
||||||
vin.Sequence = int64(bchainVin.Sequence)
|
vin.Sequence = int64(bchainVin.Sequence)
|
||||||
vin.ScriptSig.Hex = bchainVin.ScriptSig.Hex
|
vin.ScriptSig.Hex = bchainVin.ScriptSig.Hex
|
||||||
// bchainVin.Txid=="" is coinbase transaction
|
if w.chainType == bchain.ChainBitcoinType {
|
||||||
if bchainVin.Txid != "" {
|
// bchainVin.Txid=="" is coinbase transaction
|
||||||
// load spending addresses from TxAddresses
|
if bchainVin.Txid != "" {
|
||||||
tas, err := w.db.GetTxAddresses(bchainVin.Txid)
|
// load spending addresses from TxAddresses
|
||||||
if err != nil {
|
tas, err := w.db.GetTxAddresses(bchainVin.Txid)
|
||||||
return nil, errors.Annotatef(err, "GetTxAddresses %v", bchainVin.Txid)
|
|
||||||
}
|
|
||||||
if tas == nil {
|
|
||||||
// mempool transactions are not in TxAddresses but confirmed should be there, log a problem
|
|
||||||
if bchainTx.Confirmations > 0 {
|
|
||||||
glog.Warning("DB inconsistency: tx ", bchainVin.Txid, ": not found in txAddresses")
|
|
||||||
}
|
|
||||||
// try to load from backend
|
|
||||||
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", bchainVin.Txid)
|
return nil, errors.Annotatef(err, "GetTxAddresses %v", bchainVin.Txid)
|
||||||
}
|
}
|
||||||
if len(otx.Vout) > int(vin.Vout) {
|
if tas == nil {
|
||||||
vout := &otx.Vout[vin.Vout]
|
// mempool transactions are not in TxAddresses but confirmed should be there, log a problem
|
||||||
vin.ValueSat = vout.ValueSat
|
if bchainTx.Confirmations > 0 {
|
||||||
vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
|
glog.Warning("DB inconsistency: tx ", bchainVin.Txid, ": not found in txAddresses")
|
||||||
|
}
|
||||||
|
// try to load from backend
|
||||||
|
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
|
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", bchainVin.Txid)
|
||||||
}
|
}
|
||||||
}
|
if len(otx.Vout) > int(vin.Vout) {
|
||||||
} else {
|
vout := &otx.Vout[vin.Vout]
|
||||||
if len(tas.Outputs) > int(vin.Vout) {
|
vin.ValueSat = vout.ValueSat
|
||||||
output := &tas.Outputs[vin.Vout]
|
vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
|
||||||
vin.ValueSat = output.ValueSat
|
if err != nil {
|
||||||
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
|
||||||
vin.AddrDesc = output.AddrDesc
|
}
|
||||||
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
|
}
|
||||||
if err != nil {
|
} else {
|
||||||
glog.Errorf("output.Addresses error %v, tx %v, output %v", err, bchainVin.Txid, i)
|
if len(tas.Outputs) > int(vin.Vout) {
|
||||||
|
output := &tas.Outputs[vin.Vout]
|
||||||
|
vin.ValueSat = output.ValueSat
|
||||||
|
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
||||||
|
vin.AddrDesc = output.AddrDesc
|
||||||
|
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("output.Addresses error %v, tx %v, output %v", err, bchainVin.Txid, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
||||||
|
valInSat.Add(&valInSat, &vin.ValueSat)
|
||||||
|
}
|
||||||
|
} else if w.chainType == bchain.ChainEthereumType {
|
||||||
|
if len(bchainVin.Addresses) > 0 {
|
||||||
|
vin.AddrDesc, err = w.chainParser.GetAddrDescFromAddress(bchainVin.Addresses[0])
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("GetAddrDescFromAddress error %v, tx %v, bchainVin %v", err, bchainTx.Txid, bchainVin)
|
||||||
|
}
|
||||||
|
vin.Addresses = bchainVin.Addresses
|
||||||
|
vin.Searchable = true
|
||||||
}
|
}
|
||||||
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
|
||||||
valInSat.Add(&valInSat, &vin.ValueSat)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vouts := make([]Vout, len(bchainTx.Vout))
|
vouts := make([]Vout, len(bchainTx.Vout))
|
||||||
|
|
|
@ -291,7 +291,26 @@ func (p *EthereumParser) UnpackBlockHash(buf []byte) (string, error) {
|
||||||
return hexutil.Encode(buf), nil
|
return hexutil.Encode(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainType returns TypeEthereum
|
// GetChainType returns EthereumType
|
||||||
func (p *EthereumParser) GetChainType() bchain.ChainType {
|
func (p *EthereumParser) GetChainType() bchain.ChainType {
|
||||||
return bchain.ChainEthereumType
|
return bchain.ChainEthereumType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHeightFromTx returns ethereum specific data from bchain.Tx
|
||||||
|
func GetHeightFromTx(tx *bchain.Tx) (uint32, error) {
|
||||||
|
// TODO - temporary implementation - will use bchain.Tx.SpecificData field
|
||||||
|
b, err := hex.DecodeString(tx.Hex)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var r rpcTransaction
|
||||||
|
var n uint64
|
||||||
|
err = json.Unmarshal(b, &r)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if n, err = hexutil.DecodeUint64(r.BlockNumber); err != nil {
|
||||||
|
return 0, errors.Annotatef(err, "BlockNumber %v", r.BlockNumber)
|
||||||
|
}
|
||||||
|
return uint32(n), nil
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ type ChainType int
|
||||||
const (
|
const (
|
||||||
// ChainBitcoinType is blockchain derived from bitcoin
|
// ChainBitcoinType is blockchain derived from bitcoin
|
||||||
ChainBitcoinType = ChainType(iota)
|
ChainBitcoinType = ChainType(iota)
|
||||||
// TypeEthereum is blockchain derived from ethereum
|
// ChainEthereumType is blockchain derived from ethereum
|
||||||
ChainEthereumType
|
ChainEthereumType
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -301,9 +301,11 @@ func (d *RocksDB) writeBlock(block *bchain.Block, op int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if chainType == bchain.ChainEthereumType {
|
} else if chainType == bchain.ChainEthereumType {
|
||||||
if err := d.writeAddressesTypeEthereum(wb, block, op); err != nil {
|
if err := d.writeAddressesEthereumType(wb, block, op); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New("Unknown chain type")
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.db.Write(d.wo, wb)
|
return d.db.Write(d.wo, wb)
|
||||||
|
@ -861,7 +863,7 @@ func (d *RocksDB) addAddrDescToRecords(op int, wb *gorocksdb.WriteBatch, records
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *RocksDB) writeAddressesTypeEthereum(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
|
func (d *RocksDB) writeAddressesEthereumType(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
|
||||||
addresses := make(map[string][]outpoint)
|
addresses := make(map[string][]outpoint)
|
||||||
for _, tx := range block.Txs {
|
for _, tx := range block.Txs {
|
||||||
btxID, err := d.chainParser.PackTxid(tx.Txid)
|
btxID, err := d.chainParser.PackTxid(tx.Txid)
|
||||||
|
|
|
@ -2,18 +2,21 @@ package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
|
"blockbook/bchain/coins/eth"
|
||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TxCache is handle to TxCacheServer
|
// TxCache is handle to TxCacheServer
|
||||||
type TxCache struct {
|
type TxCache struct {
|
||||||
db *RocksDB
|
db *RocksDB
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
enabled bool
|
enabled bool
|
||||||
|
chainType bchain.ChainType
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTxCache creates new TxCache interface and returns its handle
|
// NewTxCache creates new TxCache interface and returns its handle
|
||||||
|
@ -22,11 +25,12 @@ func NewTxCache(db *RocksDB, chain bchain.BlockChain, metrics *common.Metrics, i
|
||||||
glog.Info("txcache: disabled")
|
glog.Info("txcache: disabled")
|
||||||
}
|
}
|
||||||
return &TxCache{
|
return &TxCache{
|
||||||
db: db,
|
db: db,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
is: is,
|
is: is,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
|
chainType: chain.GetChainParser().GetChainType(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,18 +60,27 @@ func (c *TxCache) GetTransaction(txid string) (*bchain.Tx, uint32, error) {
|
||||||
c.metrics.TxCacheEfficiency.With(common.Labels{"status": "miss"}).Inc()
|
c.metrics.TxCacheEfficiency.With(common.Labels{"status": "miss"}).Inc()
|
||||||
// cache only confirmed transactions
|
// cache only confirmed transactions
|
||||||
if tx.Confirmations > 0 {
|
if tx.Confirmations > 0 {
|
||||||
ta, err := c.db.GetTxAddresses(txid)
|
if c.chainType == bchain.ChainBitcoinType {
|
||||||
if err != nil {
|
ta, err := c.db.GetTxAddresses(txid)
|
||||||
return nil, 0, err
|
if err != nil {
|
||||||
}
|
return nil, 0, err
|
||||||
// the transaction may me not yet indexed, in that case get the height from the backend
|
}
|
||||||
if ta == nil {
|
// the transaction may me not yet indexed, in that case get the height from the backend
|
||||||
h, err = c.chain.GetBestBlockHeight()
|
if ta == nil {
|
||||||
|
h, err = c.chain.GetBestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h = ta.Height
|
||||||
|
}
|
||||||
|
} else if c.chainType == bchain.ChainEthereumType {
|
||||||
|
h, err = eth.GetHeightFromTx(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
h = ta.Height
|
return nil, 0, errors.New("Unknown chain type")
|
||||||
}
|
}
|
||||||
if c.enabled {
|
if c.enabled {
|
||||||
err = c.db.PutTx(tx, h, tx.Blocktime)
|
err = c.db.PutTx(tx, h, tx.Blocktime)
|
||||||
|
|
Loading…
Reference in New Issue