Merge branch 'indexv3' into explorer

This commit is contained in:
Martin Boehm 2018-08-19 23:20:43 +02:00
commit 6bfc7240a9
48 changed files with 2022 additions and 990 deletions

View File

@ -1,5 +1,7 @@
package api
import "math/big"
type ScriptSig struct {
Hex string `json:"hex"`
Asm string `json:"asm,omitempty"`
@ -12,8 +14,8 @@ type Vin struct {
N int `json:"n"`
ScriptSig ScriptSig `json:"scriptSig"`
Addr string `json:"addr"`
ValueSat int64 `json:"valueSat"`
Value float64 `json:"value"`
Value string `json:"value"`
ValueSat big.Int `json:"-"`
}
type ScriptPubKey struct {
@ -23,7 +25,8 @@ type ScriptPubKey struct {
Type string `json:"type,omitempty"`
}
type Vout struct {
Value float64 `json:"value"`
Value string `json:"value"`
ValueSat big.Int `json:"-"`
N int `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
SpentTxID string `json:"spentTxId,omitempty"`
@ -32,34 +35,30 @@ type Vout struct {
}
type Tx struct {
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
Locktime uint32 `json:"locktime,omitempty"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
Blockhash string `json:"blockhash,omitempty"`
Blockheight int `json:"blockheight"`
Confirmations uint32 `json:"confirmations"`
Time int64 `json:"time,omitempty"`
Blocktime int64 `json:"blocktime"`
ValueOut float64 `json:"valueOut"`
Size int `json:"size,omitempty"`
ValueIn float64 `json:"valueIn"`
Fees float64 `json:"fees"`
WithSpends bool `json:"withSpends,omitempty"`
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
Locktime uint32 `json:"locktime,omitempty"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
Blockhash string `json:"blockhash,omitempty"`
Blockheight int `json:"blockheight"`
Confirmations uint32 `json:"confirmations"`
Time int64 `json:"time,omitempty"`
Blocktime int64 `json:"blocktime"`
ValueOut string `json:"valueOut"`
Size int `json:"size,omitempty"`
ValueIn string `json:"valueIn"`
Fees string `json:"fees"`
WithSpends bool `json:"withSpends,omitempty"`
}
type Address struct {
AddrStr string `json:"addrStr"`
Balance float64 `json:"balance"`
BalanceSat int64 `json:"balanceSat"`
TotalReceived float64 `json:"totalReceived"`
TotalReceivedSat int64 `json:"totalReceivedSat"`
TotalSent float64 `json:"totalSent"`
TotalSentSat int64 `json:"totalSentSat"`
UnconfirmedBalance float64 `json:"unconfirmedBalance"`
UnconfirmedBalanceSat int64 `json:"unconfirmedBalanceSat"`
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"transactions"`
AddrStr string `json:"addrStr"`
Balance string `json:"balance"`
TotalReceived string `json:"totalReceived"`
TotalSent string `json:"totalSent"`
UnconfirmedBalance string `json:"unconfirmedBalance"`
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"transactions"`
}

View File

@ -4,6 +4,7 @@ import (
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
"math/big"
"github.com/golang/glog"
)
@ -44,7 +45,7 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
return nil, err
}
}
var valIn, valOut, fees float64
var valInSat, valOutSat, feesSat big.Int
vins := make([]Vin, len(bchainTx.Vin))
for i := range bchainTx.Vin {
bchainVin := &bchainTx.Vin[i]
@ -61,9 +62,9 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
}
if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout]
vin.Value = vout.Value
valIn += vout.Value
vin.ValueSat = int64(vout.Value*1E8 + 0.5)
vin.ValueSat = vout.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vout.ValueSat)
valInSat.Add(&valInSat, &vout.ValueSat)
if vout.Address != nil {
a := vout.Address.String()
vin.Addr = a
@ -76,8 +77,9 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
bchainVout := &bchainTx.Vout[i]
vout := &vouts[i]
vout.N = i
vout.Value = bchainVout.Value
valOut += bchainVout.Value
vout.ValueSat = bchainVout.ValueSat
vout.Value = w.chainParser.AmountToDecimalString(&bchainVout.ValueSat)
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
vout.ScriptPubKey.Addresses = bchainVout.ScriptPubKey.Addresses
if spendingTx {
@ -85,9 +87,9 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
}
}
// for coinbase transactions valIn is 0
fees = valIn - valOut
if fees < 0 {
fees = 0
feesSat.Sub(&valInSat, &valOutSat)
if feesSat.Sign() == -1 {
feesSat.SetUint64(0)
}
// for now do not return size, we would have to compute vsize of segwit transactions
// size:=len(bchainTx.Hex) / 2
@ -96,13 +98,13 @@ func (w *Worker) GetTransaction(txid string, bestheight uint32, spendingTx bool)
Blockheight: int(height),
Blocktime: bchainTx.Blocktime,
Confirmations: bchainTx.Confirmations,
Fees: fees,
Fees: w.chainParser.AmountToDecimalString(&feesSat),
Locktime: bchainTx.LockTime,
WithSpends: spendingTx,
Time: bchainTx.Time,
Txid: bchainTx.Txid,
ValueIn: valIn,
ValueOut: valOut,
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
Version: bchainTx.Version,
Vin: vins,
Vout: vouts,
@ -131,26 +133,26 @@ func (s *Worker) getAddressTxids(address string, mempool bool) ([]string, error)
return txids, nil
}
func (t *Tx) getAddrVoutValue(addrID string) float64 {
var val float64
func (t *Tx) getAddrVoutValue(addrID string) *big.Int {
var val big.Int
for _, vout := range t.Vout {
for _, a := range vout.ScriptPubKey.Addresses {
if a == addrID {
val += vout.Value
val.Add(&val, &vout.ValueSat)
}
}
}
return val
return &val
}
func (t *Tx) getAddrVinValue(addrID string) float64 {
var val float64
func (t *Tx) getAddrVinValue(addrID string) *big.Int {
var val big.Int
for _, vin := range t.Vin {
if vin.Addr == addrID {
val += vin.Value
val.Add(&val, &vin.ValueSat)
}
}
return val
return &val
}
// UniqueTxidsInReverse reverts the order of transactions (so that newest are first) and removes duplicate transactions
@ -181,6 +183,7 @@ func (w *Worker) GetAddress(addrID string, page int) (*Address, error) {
if err != nil {
return nil, err
}
txm = UniqueTxidsInReverse(txm)
bestheight, _, err := w.db.GetBestBlock()
if err != nil {
return nil, err
@ -191,14 +194,14 @@ func (w *Worker) GetAddress(addrID string, page int) (*Address, error) {
}
txs := make([]*Tx, len(txm)+lc)
txi := 0
var uBal, bal, totRecv, totSent float64
var uBalSat, balSat, totRecvSat, totSentSat big.Int
for _, tx := range txm {
tx, err := w.GetTransaction(tx, bestheight, false)
// mempool transaction may fail
if err != nil {
glog.Error("GetTransaction ", tx, ": ", err)
} else {
uBal = tx.getAddrVoutValue(addrID) - tx.getAddrVinValue(addrID)
uBalSat.Sub(tx.getAddrVoutValue(addrID), tx.getAddrVinValue(addrID))
txs[txi] = tx
txi++
}
@ -216,26 +219,23 @@ func (w *Worker) GetAddress(addrID string, page int) (*Address, error) {
if err != nil {
return nil, err
} else {
totRecv += tx.getAddrVoutValue(addrID)
totSent += tx.getAddrVinValue(addrID)
totRecvSat.Add(&totRecvSat, tx.getAddrVoutValue(addrID))
totSentSat.Add(&totSentSat, tx.getAddrVinValue(addrID))
if i >= from && i < to {
txs[txi] = tx
txi++
}
}
}
bal = totRecv - totSent
balSat.Sub(&totRecvSat, &totSentSat)
r := &Address{
AddrStr: addrID,
Balance: bal,
BalanceSat: int64(bal*1E8 + 0.5),
TotalReceived: totRecv,
TotalReceivedSat: int64(totRecv*1E8 + 0.5),
TotalSent: totSent,
TotalSentSat: int64(totSent*1E8 + 0.5),
Balance: w.chainParser.AmountToDecimalString(&balSat),
TotalReceived: w.chainParser.AmountToDecimalString(&totRecvSat),
TotalSent: w.chainParser.AmountToDecimalString(&totSentSat),
Transactions: txs[:txi],
TxApperances: len(txc),
UnconfirmedBalance: uBal,
UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat),
UnconfirmedTxApperances: len(txm),
}
glog.Info(addrID, " finished")

View File

@ -3,6 +3,8 @@ package bchain
import (
"encoding/hex"
"encoding/json"
"math/big"
"strings"
"github.com/gogo/protobuf/proto"
"github.com/juju/errors"
@ -14,6 +16,7 @@ type AddressFactoryFunc func(string) (Address, error)
type BaseParser struct {
AddressFactory AddressFactoryFunc
BlockAddressesToKeep int
AmountDecimalPoint int
}
// AddressToOutputScript converts address to ScriptPubKey - currently not implemented
@ -36,7 +39,52 @@ func (p *BaseParser) ParseTx(b []byte) (*Tx, error) {
return nil, errors.New("ParseTx: not implemented")
}
// ParseTxFromJson parses JSON message containing transaction and returs Tx struct
const zeros = "0000000000000000000000000000000000000000"
// AmountToBigInt converts amount in json.Number (string) to big.Int
// it uses string operations to avoid problems with rounding
func (p *BaseParser) AmountToBigInt(n json.Number) (big.Int, error) {
var r big.Int
s := string(n)
i := strings.IndexByte(s, '.')
if i == -1 {
s = s + zeros[:p.AmountDecimalPoint]
} else {
z := p.AmountDecimalPoint - len(s) + i + 1
if z > 0 {
s = s[:i] + s[i+1:] + zeros[:z]
} else {
s = s[:i] + s[i+1:len(s)+z]
}
}
if _, ok := r.SetString(s, 10); !ok {
return r, errors.New("AmountToBigInt: failed to convert")
}
return r, nil
}
// AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
func (p *BaseParser) AmountToDecimalString(a *big.Int) string {
n := a.String()
var s string
if n[0] == '-' {
n = n[1:]
s = "-"
}
if len(n) <= p.AmountDecimalPoint {
n = zeros[:p.AmountDecimalPoint-len(n)+1] + n
}
i := len(n) - p.AmountDecimalPoint
ad := strings.TrimRight(n[i:], "0")
if len(ad) > 0 {
n = n[:i] + "." + ad
} else {
n = n[:i]
}
return s + n
}
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
func (p *BaseParser) ParseTxFromJson(msg json.RawMessage) (*Tx, error) {
var tx Tx
err := json.Unmarshal(msg, &tx)
@ -44,13 +92,20 @@ func (p *BaseParser) ParseTxFromJson(msg json.RawMessage) (*Tx, error) {
return nil, err
}
for i, vout := range tx.Vout {
for i := range tx.Vout {
vout := &tx.Vout[i]
// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
if err != nil {
return nil, err
}
vout.JsonValue = ""
if len(vout.ScriptPubKey.Addresses) == 1 {
a, err := p.AddressFactory(vout.ScriptPubKey.Addresses[0])
if err != nil {
return nil, err
}
tx.Vout[i].Address = a
vout.Address = a
}
}
@ -127,7 +182,7 @@ func (p *BaseParser) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, err
Addresses: vo.ScriptPubKey.Addresses,
N: vo.N,
ScriptPubKeyHex: hex,
Value: vo.Value,
ValueSat: vo.ValueSat.Bytes(),
}
}
pt := &ProtoTransaction{
@ -176,13 +231,15 @@ func (p *BaseParser) UnpackTx(buf []byte) (*Tx, uint32, error) {
}
vout := make([]Vout, len(pt.Vout))
for i, pto := range pt.Vout {
var vs big.Int
vs.SetBytes(pto.ValueSat)
vout[i] = Vout{
N: pto.N,
ScriptPubKey: ScriptPubKey{
Addresses: pto.Addresses,
Hex: hex.EncodeToString(pto.ScriptPubKeyHex),
},
Value: pto.Value,
ValueSat: vs,
}
if len(pto.Addresses) == 1 {
a, err := p.AddressFactory(pto.Addresses[0])

56
bchain/baseparser_test.go Normal file
View File

@ -0,0 +1,56 @@
package bchain
import (
"encoding/json"
"math/big"
"testing"
)
func NewBaseParser(adp int) *BaseParser {
return &BaseParser{
AmountDecimalPoint: adp,
}
}
var amounts = []struct {
a *big.Int
s string
adp int
alternative string
}{
{big.NewInt(123456789), "1.23456789", 8, "!"},
{big.NewInt(2), "0.00000002", 8, "!"},
{big.NewInt(300000000), "3", 8, "!"},
{big.NewInt(498700000), "4.987", 8, "!"},
{big.NewInt(567890), "0.00000000000056789", 18, "!"},
{big.NewInt(-100000000), "-1", 8, "!"},
{big.NewInt(-8), "-0.00000008", 8, "!"},
{big.NewInt(-89012345678), "-890.12345678", 8, "!"},
{big.NewInt(-12345), "-0.00012345", 8, "!"},
{big.NewInt(12345678), "0.123456789012", 8, "0.12345678"}, // test of truncation of too many decimal places
}
func TestBaseParser_AmountToDecimalString(t *testing.T) {
for _, tt := range amounts {
t.Run(tt.s, func(t *testing.T) {
if got := NewBaseParser(tt.adp).AmountToDecimalString(tt.a); got != tt.s && got != tt.alternative {
t.Errorf("BaseParser.AmountToDecimalString() = %v, want %v", got, tt.s)
}
})
}
}
func TestBaseParser_AmountToBigInt(t *testing.T) {
for _, tt := range amounts {
t.Run(tt.s, func(t *testing.T) {
got, err := NewBaseParser(tt.adp).AmountToBigInt(json.Number(tt.s))
if err != nil {
t.Errorf("BaseParser.AmountToBigInt() error = %v", err)
return
}
if got.Cmp(tt.a) != 0 {
t.Errorf("BaseParser.AmountToBigInt() = %v, want %v", got, tt.a)
}
})
}
}

View File

@ -49,6 +49,7 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) (*BCashParser
BaseParser: &bchain.BaseParser{
AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, format) },
BlockAddressesToKeep: c.BlockAddressesToKeep,
AmountDecimalPoint: 8,
},
Params: params,
OutputScriptToAddressesFunc: outputScriptToAddresses,

View File

@ -7,6 +7,7 @@ import (
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -159,8 +160,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 0.00038812,
N: 0,
ValueSat: *big.NewInt(38812),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
Addresses: []string{
@ -190,8 +191,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: .1,
N: 0,
ValueSat: *big.NewInt(10000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
Addresses: []string{
@ -201,8 +202,8 @@ func init() {
Address: addr2,
},
{
Value: 9.20081157,
N: 1,
ValueSat: *big.NewInt(920081157),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
Addresses: []string{

View File

@ -5,6 +5,7 @@ import (
"blockbook/bchain/coins/btc"
"encoding/hex"
"encoding/json"
"math/big"
"github.com/cpacia/bchutil"
"github.com/golang/glog"
@ -132,7 +133,7 @@ func (b *BCashRPC) GetBlockFull(hash string) (*bchain.Block, error) {
}
// EstimateSmartFee returns fee estimation.
func (b *BCashRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
func (b *BCashRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
glog.V(1).Info("rpc: estimatesmartfee ", blocks)
res := btc.ResEstimateSmartFee{}
@ -141,13 +142,18 @@ func (b *BCashRPC) EstimateSmartFee(blocks int, conservative bool) (float64, err
// conservative param is omitted
err := b.Call(&req, &res)
var r big.Int
if err != nil {
return 0, err
return r, err
}
if res.Error != nil {
return 0, res.Error
return r, res.Error
}
return res.Result.Feerate, nil
r, err = b.Parser.AmountToBigInt(res.Result.Feerate)
if err != nil {
return r, err
}
return r, nil
}
func isErrBlockNotFound(err *bchain.RPCError) bool {

View File

@ -18,6 +18,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"reflect"
"time"
@ -175,12 +176,12 @@ func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain
return c.b.GetTransactionForMempool(txid)
}
func (c *blockChainWithMetrics) EstimateSmartFee(blocks int, conservative bool) (v float64, err error) {
func (c *blockChainWithMetrics) EstimateSmartFee(blocks int, conservative bool) (v big.Int, err error) {
defer func(s time.Time) { c.observeRPCLatency("EstimateSmartFee", s, err) }(time.Now())
return c.b.EstimateSmartFee(blocks, conservative)
}
func (c *blockChainWithMetrics) EstimateFee(blocks int) (v float64, err error) {
func (c *blockChainWithMetrics) EstimateFee(blocks int) (v big.Int, err error) {
defer func(s time.Time) { c.observeRPCLatency("EstimateFee", s, err) }(time.Now())
return c.b.EstimateFee(blocks)
}

View File

@ -5,6 +5,7 @@ import (
"bytes"
"encoding/binary"
"encoding/hex"
"math/big"
vlq "github.com/bsm/go-vlq"
"github.com/btcsuite/btcd/blockchain"
@ -30,6 +31,7 @@ func NewBitcoinParser(params *chaincfg.Params, c *Configuration) *BitcoinParser
&bchain.BaseParser{
AddressFactory: bchain.NewBaseAddress,
BlockAddressesToKeep: c.BlockAddressesToKeep,
AmountDecimalPoint: 8,
},
params,
outputScriptToAddresses,
@ -123,8 +125,10 @@ func (p *BitcoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.T
// missing: Asm,
// missing: Type,
}
var vs big.Int
vs.SetInt64(out.Value)
vout[i] = bchain.Vout{
Value: float64(out.Value) / 1E8,
ValueSat: vs,
N: uint32(i),
ScriptPubKey: s,
}

View File

@ -5,6 +5,7 @@ package btc
import (
"blockbook/bchain"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -152,8 +153,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 0.00038812,
N: 0,
ValueSat: *big.NewInt(38812),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
Addresses: []string{
@ -183,8 +184,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: .1,
N: 0,
ValueSat: *big.NewInt(10000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
Addresses: []string{
@ -194,8 +195,8 @@ func init() {
Address: addr2,
},
{
Value: 9.20081157,
N: 1,
ValueSat: *big.NewInt(920081157),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
Addresses: []string{

View File

@ -8,6 +8,7 @@ import (
"encoding/json"
"io"
"io/ioutil"
"math/big"
"net"
"net/http"
"time"
@ -36,19 +37,21 @@ type BitcoinRPC struct {
}
type Configuration struct {
CoinName string `json:"coin_name"`
CoinShortcut string `json:"coin_shortcut"`
RPCURL string `json:"rpc_url"`
RPCUser string `json:"rpc_user"`
RPCPass string `json:"rpc_pass"`
RPCTimeout int `json:"rpc_timeout"`
Parse bool `json:"parse"`
MessageQueueBinding string `json:"message_queue_binding"`
Subversion string `json:"subversion"`
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
MempoolWorkers int `json:"mempool_workers"`
MempoolSubWorkers int `json:"mempool_sub_workers"`
AddressFormat string `json:"address_format"`
CoinName string `json:"coin_name"`
CoinShortcut string `json:"coin_shortcut"`
RPCURL string `json:"rpc_url"`
RPCUser string `json:"rpc_user"`
RPCPass string `json:"rpc_pass"`
RPCTimeout int `json:"rpc_timeout"`
Parse bool `json:"parse"`
MessageQueueBinding string `json:"message_queue_binding"`
Subversion string `json:"subversion"`
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
MempoolWorkers int `json:"mempool_workers"`
MempoolSubWorkers int `json:"mempool_sub_workers"`
AddressFormat string `json:"address_format"`
SupportsEstimateFee bool `json:"supports_estimate_fee"`
SupportsEstimateSmartFee bool `json:"supports_estimate_smart_fee"`
}
// NewBitcoinRPC returns new BitcoinRPC instance.
@ -70,6 +73,9 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
if c.MempoolSubWorkers < 1 {
c.MempoolSubWorkers = 1
}
// btc supports both calls, other coins overriding BitcoinRPC can change this
c.SupportsEstimateFee = true
c.SupportsEstimateSmartFee = true
transport := &http.Transport{
Dial: (&net.Dialer{KeepAlive: 600 * time.Second}).Dial,
@ -302,8 +308,8 @@ type CmdEstimateSmartFee struct {
type ResEstimateSmartFee struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Feerate float64 `json:"feerate"`
Blocks int `json:"blocks"`
Feerate json.Number `json:"feerate"`
Blocks int `json:"blocks"`
} `json:"result"`
}
@ -318,7 +324,7 @@ type CmdEstimateFee struct {
type ResEstimateFee struct {
Error *bchain.RPCError `json:"error"`
Result float64 `json:"result"`
Result json.Number `json:"result"`
}
// sendrawtransaction
@ -617,7 +623,12 @@ func (b *BitcoinRPC) GetMempoolTransactions(address string) ([]string, error) {
}
// EstimateSmartFee returns fee estimation.
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
// use EstimateFee if EstimateSmartFee is not supported
if !b.ChainConfig.SupportsEstimateSmartFee && b.ChainConfig.SupportsEstimateFee {
return b.EstimateFee(blocks)
}
glog.V(1).Info("rpc: estimatesmartfee ", blocks)
res := ResEstimateSmartFee{}
@ -630,17 +641,27 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, e
}
err := b.Call(&req, &res)
var r big.Int
if err != nil {
return 0, err
return r, err
}
if res.Error != nil {
return 0, res.Error
return r, res.Error
}
return res.Result.Feerate, nil
r, err = b.Parser.AmountToBigInt(res.Result.Feerate)
if err != nil {
return r, err
}
return r, nil
}
// EstimateFee returns fee estimation.
func (b *BitcoinRPC) EstimateFee(blocks int) (float64, error) {
func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
// use EstimateSmartFee if EstimateFee is not supported
if !b.ChainConfig.SupportsEstimateFee && b.ChainConfig.SupportsEstimateSmartFee {
return b.EstimateSmartFee(blocks, true)
}
glog.V(1).Info("rpc: estimatefee ", blocks)
res := ResEstimateFee{}
@ -648,13 +669,18 @@ func (b *BitcoinRPC) EstimateFee(blocks int) (float64, error) {
req.Params.Blocks = blocks
err := b.Call(&req, &res)
var r big.Int
if err != nil {
return 0, err
return r, err
}
if res.Error != nil {
return 0, res.Error
return r, res.Error
}
return res.Result, nil
r, err = b.Parser.AmountToBigInt(res.Result)
if err != nil {
return r, err
}
return r, nil
}
// SendRawTransaction sends raw transaction.
@ -685,13 +711,20 @@ func (b *BitcoinRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error)
Params: []string{txid},
}
err := b.Call(&req, &res)
if err != nil {
return nil, err
}
if res.Error != nil {
return nil, res.Error
}
res.Result.FeeSat, err = b.Parser.AmountToBigInt(res.Result.Fee)
if err != nil {
return nil, err
}
res.Result.ModifiedFeeSat, err = b.Parser.AmountToBigInt(res.Result.ModifiedFee)
if err != nil {
return nil, err
}
return res.Result, nil
}

View File

@ -24,6 +24,7 @@ func NewDashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV1{}
s.ChainConfig.SupportsEstimateSmartFee = false
return s, nil
}
@ -53,8 +54,3 @@ func (b *DashRPC) Initialize() error {
return nil
}
// EstimateSmartFee returns fee estimation.
func (b *DashRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
return b.EstimateFee(blocks)
}

View File

@ -9,6 +9,7 @@ import (
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
"path/filepath"
"reflect"
"testing"
@ -111,8 +112,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 27478.75452951,
N: 0,
ValueSat: *big.NewInt(2747875452951),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914eef21768a546590993e313c7f3dfadf6a6efa1e888ac",
Addresses: []string{
@ -122,8 +123,8 @@ func init() {
Address: addr1,
},
{
Value: 74.20567469,
N: 1,
ValueSat: *big.NewInt(7420567469),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914e0fee2ea29dd9c6c759d8341bd0da4c4f738cced88ac",
Addresses: []string{
@ -153,8 +154,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 59890867.89818935,
N: 0,
ValueSat: *big.NewInt(5989086789818935),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9149355c01ed20057eac9fe0bbf8b07d87e62fe712d88ac",
Addresses: []string{
@ -164,8 +165,8 @@ func init() {
Address: addr3,
},
{
Value: 9999998.90000000,
N: 1,
ValueSat: *big.NewInt(999999890000000),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9145b4f2511c94e4fcaa8f8835b2458f8cb6542ca7688ac",
Addresses: []string{

View File

@ -24,6 +24,7 @@ func NewDogecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV1{}
s.ChainConfig.SupportsEstimateSmartFee = false
return s, nil
}
@ -69,8 +70,3 @@ func (b *DogecoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
}
return b.GetBlockWithoutHeader(hash, height)
}
// EstimateSmartFee returns fee estimation.
func (b *DogecoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
return b.EstimateFee(blocks)
}

View File

@ -22,7 +22,11 @@ type EthereumParser struct {
// NewEthereumParser returns new EthereumParser instance
func NewEthereumParser() *EthereumParser {
return &EthereumParser{&bchain.BaseParser{AddressFactory: bchain.NewBaseAddress}}
return &EthereumParser{&bchain.BaseParser{
AddressFactory: bchain.NewBaseAddress,
BlockAddressesToKeep: 0,
AmountDecimalPoint: 18,
}}
}
type rpcTransaction struct {
@ -86,6 +90,10 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, blocktime int64, confirma
}
tx.BlockHash = bh
h := hex.EncodeToString(b)
vs, err := hexutil.DecodeBig(tx.Value)
if err != nil {
return nil, err
}
return &bchain.Tx{
Blocktime: blocktime,
Confirmations: confirmations,
@ -105,8 +113,8 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, blocktime int64, confirma
},
Vout: []bchain.Vout{
{
N: 0, // there is always up to one To address
// Value - cannot be set, it does not fit precisely to float64
N: 0, // there is always up to one To address
ValueSat: *vs,
ScriptPubKey: bchain.ScriptPubKey{
// Hex
Addresses: ta,
@ -286,9 +294,3 @@ func (p *EthereumParser) UnpackBlockHash(buf []byte) (string, error) {
func (p *EthereumParser) IsUTXOChain() bool {
return false
}
// KeepBlockAddresses returns number of blocks which are to be kept in blockaddresses column
// do not use the blockaddresses for eth
func (p *EthereumParser) KeepBlockAddresses() int {
return 0
}

View File

@ -5,6 +5,7 @@ package eth
import (
"blockbook/bchain"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -63,6 +64,68 @@ func TestEthParser_GetAddrIDFromAddress(t *testing.T) {
}
}
var (
testTx1, testTx2 bchain.Tx
testTxPacked1 = "08aebf0a1205012a05f20018a0f73622081234567890abcdef2a24f025caaf00000000000000000000000000000000000000000000000000000000000002253220e6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d38f095af014092f4c1d5054a14682b7903a11098cf770c7aef4aa02a85b3f3601a5214dacc9c61754a0c4616fc5323dc946e89eb272302580162011b6a201bd40a31122c03918df6d166d740a6a3a22f08a25934ceb1688c62977661c80c7220607fbc15c1f7995a4258f5a9bccc63b040362d1991d5efe1361c56222e4ca89f"
testTxPacked2 = "08ece40212050430e234001888a4012201213220cd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b38889eaf0140fa83c3d5054a14555ee11fbddc0e49a9bab358a8941ad95ffdb48f52143e3a3d69dc66ba10737f531ed088954a9ec89d97580a6201296a20f7161c170d43573ad9c8d701cdaf714ff2a548a562b0dc639230d17889fcd40572203c4977fc90385a27efa0032e17b49fd575b2826cb56e3d1ecf21524f2a94f915"
)
func init() {
var (
addr1, addr2 bchain.Address
err error
)
addr1, err = bchain.NewBaseAddress("0x682b7903a11098cf770c7aef4aa02a85b3f3601a")
if err == nil {
addr2, err = bchain.NewBaseAddress("0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f")
}
if err != nil {
panic(err)
}
testTx1 = bchain.Tx{
Blocktime: 1521515026,
Hex: "7b226e6f6e6365223a2230783239666165222c226761735072696365223a223078313261303566323030222c22676173223a2230786462626130222c22746f223a22307836383262373930336131313039386366373730633761656634616130326138356233663336303161222c2276616c7565223a22307831323334353637383930616263646566222c22696e707574223a223078663032356361616630303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030323235222c2268617368223a22307865366231363864366262336438656437386530336462663832386236626664316662363133663665313239636261363234393634393834353533373234633564222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307864616363396336313735346130633436313666633533323364633934366538396562323732333032222c227472616e73616374696f6e496e646578223a22307831222c2276223a2230783162222c2272223a22307831626434306133313132326330333931386466366431363664373430613661336132326630386132353933346365623136383863363239373736363163383063222c2273223a22307836303766626331356331663739393561343235386635613962636363363362303430333632643139393164356566653133363163353632323265346361383966227d",
Time: 1521515026,
Txid: "0xe6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d",
Vin: []bchain.Vin{
{
Addresses: []string{"0xdacc9c61754a0c4616fc5323dc946e89eb272302"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1311768467294899695),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x682b7903a11098cf770c7aef4aa02a85b3f3601a"},
},
Address: addr1,
},
},
}
testTx2 = bchain.Tx{
Blocktime: 1521533434,
Hex: "7b226e6f6e6365223a22307862323663222c226761735072696365223a223078343330653233343030222c22676173223a22307835323038222c22746f223a22307835353565653131666264646330653439613962616233353861383934316164393566666462343866222c2276616c7565223a2230783231222c22696e707574223a223078222c2268617368223a22307863643634373135313535326235313332623261656637633962653030646336663733616663353930316464653135376161623133313333356261616138353362222c22626c6f636b4e756d626572223a223078326263663038222c2266726f6d223a22307833653361336436396463363662613130373337663533316564303838393534613965633839643937222c227472616e73616374696f6e496e646578223a22307861222c2276223a2230783239222c2272223a22307866373136316331373064343335373361643963386437303163646166373134666632613534386135363262306463363339323330643137383839666364343035222c2273223a22307833633439373766633930333835613237656661303033326531376234396664353735623238323663623536653364316563663231353234663261393466393135227d",
Time: 1521533434,
Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"0x3e3a3d69dc66ba10737f531ed088954a9ec89d97"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(33),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f"},
},
Address: addr2,
},
},
}
}
func TestEthereumParser_PackTx(t *testing.T) {
type args struct {
tx *bchain.Tx
@ -77,61 +140,27 @@ func TestEthereumParser_PackTx(t *testing.T) {
wantErr bool
}{
{
name: "with 0x prefix",
name: "1",
args: args{
tx: &bchain.Tx{
Blocktime: 1521515026,
Hex: "7b226e6f6e6365223a2230783239666165222c226761735072696365223a223078313261303566323030222c22676173223a2230786462626130222c22746f223a22307836383262373930336131313039386366373730633761656634616130326138356233663336303161222c2276616c7565223a22307830222c22696e707574223a223078663032356361616630303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030323235222c2268617368223a22307865366231363864366262336438656437386530336462663832386236626664316662363133663665313239636261363234393634393834353533373234633564222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307864616363396336313735346130633436313666633533323364633934366538396562323732333032222c227472616e73616374696f6e496e646578223a22307831222c2276223a2230783162222c2272223a22307831626434306133313132326330333931386466366431363664373430613661336132326630386132353933346365623136383863363239373736363163383063222c2273223a22307836303766626331356331663739393561343235386635613962636363363362303430333632643139393164356566653133363163353632323265346361383966227d",
Time: 1521515026,
Txid: "0xe6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d",
Vin: []bchain.Vin{
{
Addresses: []string{"0xdacc9c61754a0c4616fc5323dc946e89eb272302"},
},
},
Vout: []bchain.Vout{
{
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x682b7903a11098cf770c7aef4aa02a85b3f3601a"},
},
},
},
},
tx: &testTx1,
height: 2870000,
blockTime: 1521515026,
},
want: "08aebf0a1205012a05f20018a0f7362a24f025caaf00000000000000000000000000000000000000000000000000000000000002253220e6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d38f095af014092f4c1d5054a14682b7903a11098cf770c7aef4aa02a85b3f3601a5214dacc9c61754a0c4616fc5323dc946e89eb272302580162011b6a201bd40a31122c03918df6d166d740a6a3a22f08a25934ceb1688c62977661c80c7220607fbc15c1f7995a4258f5a9bccc63b040362d1991d5efe1361c56222e4ca89f",
want: testTxPacked1,
},
{
name: "without 0x prefix",
name: "2",
args: args{
tx: &bchain.Tx{
Blocktime: 1521533434,
Hex: "7b226e6f6e6365223a22307862323663222c226761735072696365223a223078343330653233343030222c22676173223a22307835323038222c22746f223a22307835353565653131666264646330653439613962616233353861383934316164393566666462343866222c2276616c7565223a22307831626330313539643533306536303030222c22696e707574223a223078222c2268617368223a22307863643634373135313535326235313332623261656637633962653030646336663733616663353930316464653135376161623133313333356261616138353362222c22626c6f636b4e756d626572223a223078326263663038222c2266726f6d223a22307833653361336436396463363662613130373337663533316564303838393534613965633839643937222c227472616e73616374696f6e496e646578223a22307861222c2276223a2230783239222c2272223a22307866373136316331373064343335373361643963386437303163646166373134666632613534386135363262306463363339323330643137383839666364343035222c2273223a22307833633439373766633930333835613237656661303033326531376234396664353735623238323663623536653364316563663231353234663261393466393135227d",
Time: 1521533434,
Txid: "cd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"3e3a3d69dc66ba10737f531ed088954a9ec89d97"},
},
},
Vout: []bchain.Vout{
{
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"555ee11fbddc0e49a9bab358a8941ad95ffdb48f"},
},
},
},
},
tx: &testTx2,
height: 2871048,
blockTime: 1521533434,
},
want: "08ece40212050430e234001888a40122081bc0159d530e60003220cd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b38889eaf0140fa83c3d5054a14555ee11fbddc0e49a9bab358a8941ad95ffdb48f52143e3a3d69dc66ba10737f531ed088954a9ec89d97580a6201296a20f7161c170d43573ad9c8d701cdaf714ff2a548a562b0dc639230d17889fcd40572203c4977fc90385a27efa0032e17b49fd575b2826cb56e3d1ecf21524f2a94f915",
want: testTxPacked2,
},
}
p := NewEthereumParser()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := NewEthereumParser()
got, err := p.PackTx(tt.args.tx, tt.args.height, tt.args.blockTime)
if (err != nil) != tt.wantErr {
t.Errorf("EthereumParser.PackTx() error = %v, wantErr %v", err, tt.wantErr)
@ -146,18 +175,6 @@ func TestEthereumParser_PackTx(t *testing.T) {
}
func TestEthereumParser_UnpackTx(t *testing.T) {
var (
addr1, addr2 bchain.Address
err error
)
addr1, err = bchain.NewBaseAddress("0x682b7903a11098cf770c7aef4aa02a85b3f3601a")
if err == nil {
addr2, err = bchain.NewBaseAddress("0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f")
}
if err != nil {
panic(err)
}
type args struct {
hex string
}
@ -170,57 +187,21 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
wantErr bool
}{
{
name: "1",
args: args{hex: "08aebf0a1205012a05f20018a0f7362a24f025caaf00000000000000000000000000000000000000000000000000000000000002253220e6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d38f095af014092f4c1d5054a14682b7903a11098cf770c7aef4aa02a85b3f3601a5214dacc9c61754a0c4616fc5323dc946e89eb272302580162011b6a201bd40a31122c03918df6d166d740a6a3a22f08a25934ceb1688c62977661c80c7220607fbc15c1f7995a4258f5a9bccc63b040362d1991d5efe1361c56222e4ca89f"},
want: &bchain.Tx{
Blocktime: 1521515026,
Hex: "7b226e6f6e6365223a2230783239666165222c226761735072696365223a223078313261303566323030222c22676173223a2230786462626130222c22746f223a22307836383262373930336131313039386366373730633761656634616130326138356233663336303161222c2276616c7565223a22307830222c22696e707574223a223078663032356361616630303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030323235222c2268617368223a22307865366231363864366262336438656437386530336462663832386236626664316662363133663665313239636261363234393634393834353533373234633564222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307864616363396336313735346130633436313666633533323364633934366538396562323732333032222c227472616e73616374696f6e496e646578223a22307831222c2276223a2230783162222c2272223a22307831626434306133313132326330333931386466366431363664373430613661336132326630386132353933346365623136383863363239373736363163383063222c2273223a22307836303766626331356331663739393561343235386635613962636363363362303430333632643139393164356566653133363163353632323265346361383966227d",
Time: 1521515026,
Txid: "0xe6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d",
Vin: []bchain.Vin{
{
Addresses: []string{"0xdacc9c61754a0c4616fc5323dc946e89eb272302"},
},
},
Vout: []bchain.Vout{
{
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x682b7903a11098cf770c7aef4aa02a85b3f3601a"},
},
Address: addr1,
},
},
},
name: "1",
args: args{hex: testTxPacked1},
want: &testTx1,
want1: 2870000,
},
{
name: "1",
args: args{hex: "08ece40212050430e234001888a40122081bc0159d530e60003220cd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b38889eaf0140fa83c3d5054a14555ee11fbddc0e49a9bab358a8941ad95ffdb48f52143e3a3d69dc66ba10737f531ed088954a9ec89d97580a6201296a20f7161c170d43573ad9c8d701cdaf714ff2a548a562b0dc639230d17889fcd40572203c4977fc90385a27efa0032e17b49fd575b2826cb56e3d1ecf21524f2a94f915"},
want: &bchain.Tx{
Blocktime: 1521533434,
Hex: "7b226e6f6e6365223a22307862323663222c226761735072696365223a223078343330653233343030222c22676173223a22307835323038222c22746f223a22307835353565653131666264646330653439613962616233353861383934316164393566666462343866222c2276616c7565223a22307831626330313539643533306536303030222c22696e707574223a223078222c2268617368223a22307863643634373135313535326235313332623261656637633962653030646336663733616663353930316464653135376161623133313333356261616138353362222c22626c6f636b4e756d626572223a223078326263663038222c2266726f6d223a22307833653361336436396463363662613130373337663533316564303838393534613965633839643937222c227472616e73616374696f6e496e646578223a22307861222c2276223a2230783239222c2272223a22307866373136316331373064343335373361643963386437303163646166373134666632613534386135363262306463363339323330643137383839666364343035222c2273223a22307833633439373766633930333835613237656661303033326531376234396664353735623238323663623536653364316563663231353234663261393466393135227d",
Time: 1521533434,
Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"0x3e3a3d69dc66ba10737f531ed088954a9ec89d97"},
},
},
Vout: []bchain.Vout{
{
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f"},
},
Address: addr2,
},
},
},
name: "2",
args: args{hex: testTxPacked2},
want: &testTx2,
want1: 2871048,
},
}
p := NewEthereumParser()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := NewEthereumParser()
b, err := hex.DecodeString(tt.args.hex)
if err != nil {
panic(err)

View File

@ -479,12 +479,12 @@ func (b *EthereumRPC) GetMempool() ([]string, error) {
}
// EstimateFee returns fee estimation.
func (b *EthereumRPC) EstimateFee(blocks int) (float64, error) {
func (b *EthereumRPC) EstimateFee(blocks int) (big.Int, error) {
return b.EstimateSmartFee(blocks, true)
}
// EstimateSmartFee returns fee estimation.
func (b *EthereumRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
func (b *EthereumRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
// TODO - what parameters of msg to use to get better estimate, maybe more data from the wallet are needed
@ -493,10 +493,12 @@ func (b *EthereumRPC) EstimateSmartFee(blocks int, conservative bool) (float64,
To: &a,
}
g, err := b.client.EstimateGas(ctx, msg)
var r big.Int
if err != nil {
return 0, err
return r, err
}
return float64(g), nil
r.SetUint64(g)
return r, nil
}
// SendRawTransaction sends raw transaction.

View File

@ -6,6 +6,7 @@ import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -173,8 +174,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 12.52000000,
N: 0,
ValueSat: *big.NewInt(1252000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9141ae882e788091732da6910595314447c9e38bd8d88ac",
Addresses: []string{
@ -184,8 +185,8 @@ func init() {
Address: addr1,
},
{
Value: 0.01000487,
N: 1,
ValueSat: *big.NewInt(1000487),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9146b474cbf0f6004329b630bdd4798f2c23d1751b688ac",
Addresses: []string{

View File

@ -24,6 +24,7 @@ func NewLitecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV2{}
s.ChainConfig.SupportsEstimateFee = false
return s, nil
}
@ -54,8 +55,3 @@ func (b *LitecoinRPC) Initialize() error {
return nil
}
// EstimateFee returns fee estimation.
func (b *LitecoinRPC) EstimateFee(blocks int) (float64, error) {
return b.EstimateSmartFee(blocks, true)
}

View File

@ -24,6 +24,7 @@ func NewNamecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV1{}
s.ChainConfig.SupportsEstimateSmartFee = false
return s, nil
}
@ -69,8 +70,3 @@ func (b *NamecoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
}
return b.GetBlockWithoutHeader(hash, height)
}
// EstimateSmartFee returns fee estimation.
func (b *NamecoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
return b.EstimateFee(blocks)
}

View File

@ -6,6 +6,7 @@ import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -105,8 +106,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 0.10781192,
N: 0,
ValueSat: *big.NewInt(10781192),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a91499b16da88a7e29b913b6131df2644d6d06cb331b88ac",
Addresses: []string{
@ -116,8 +117,8 @@ func init() {
Address: addr1,
},
{
Value: 0.5000000,
N: 1,
ValueSat: *big.NewInt(50000000),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a91446eb90e002f137f05385896c882fe000cc2e967f87",
Addresses: []string{

View File

@ -24,6 +24,7 @@ func NewVertcoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV2{}
s.ChainConfig.SupportsEstimateFee = false
return s, nil
}
@ -54,8 +55,3 @@ func (b *VertcoinRPC) Initialize() error {
return nil
}
// EstimateFee returns fee estimation.
func (b *VertcoinRPC) EstimateFee(blocks int) (float64, error) {
return b.EstimateSmartFee(blocks, true)
}

View File

@ -20,12 +20,13 @@ type ZCashParser struct {
*bchain.BaseParser
}
// NewZCAshParser returns new ZCAshParser instance
// NewZCashParser returns new ZCashParser instance
func NewZCashParser(c *btc.Configuration) *ZCashParser {
return &ZCashParser{
&bchain.BaseParser{
AddressFactory: bchain.NewBaseAddress,
BlockAddressesToKeep: c.BlockAddressesToKeep,
AmountDecimalPoint: 8,
},
}
}

View File

@ -6,6 +6,7 @@ import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"reflect"
"testing"
)
@ -13,8 +14,8 @@ import (
var (
testTx1, testTx2 bchain.Tx
testTxPacked1 = "0a20e64aac0c211ad210c90934f06b1cc932327329e41a9f70c6eb76f79ef798b7b812ab1002000000019c012650c99d0ef761e863dbb966babf2cb7a7a2b5d90b1461c09521c473d23d000000006b483045022100f220f48c5267ef92a1e7a4d3b44fe9d97cce76eeba2785d45a0e2620b70e8d7302205640bc39e197ce19d95a98a3239af0f208ca289c067f80c97d8e411e61da5dee0121021721e83315fb5282f1d9d2a11892322df589bccd9cef45517b5fb3cfd3055c83ffffffff018eec1a3c040000001976a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac000000000162b4fc6b0000000000000000000000006ffa88c89b74f0f82e24744296845a0d0113b132ff5dfc2af34e6418eb15206af53078c4dd475cf143cd9a427983f5993622464b53e3a37d2519a946492c3977e30f0866550b9097222993a439a39260ac5e7d36aef38c7fdd1df3035a2d5817a9c20526e38f52f822d4db9d2f0156c4119d786d6e3a060ca871df7fae9a5c3a9c921b38ddc6414b13d16aa807389c68016e54bd6a9eb3b23a6bc7bf152e6dba15e9ec36f95dab15ad8f4a92a9d0309bbd930ef24bb7247bf534065c1e2f5b42e2c80eb59f48b4da6ec522319e065f8c4e463f95cc7fcad8d7ee91608e3c0ffcaa44129ba2d2da45d9a413919eca41af29faaf806a3eeb823e5a6c51afb1ec709505d812c0306bd76061a0a62d207355ad44d1ffce2b9e1dfd0818f79bd0f8e4031116b71fee2488484f17818b80532865773166cd389929e8409bb94e3948bd2e0215ef96d4e29d094590fda0de50715c11ff47c03380bb1d31b14e5b4ad8a372ca0b03364ef85f086b8a8eb5c56c3b1aee33e2cfbf1b2be1a3fb41b14b2c432b5d04d54c058fa87a96ae1d65d61b79360d09acc1e25a883fd7ae9a2a734a03362903021401c243173e1050b5cdb459b9ffc07c95e920f026618952d3a800b2e47e03b902084aed7ee8466a65d34abdbbd292781564dcd9b7440029d48c2640ebc196d4b40217f2872c1d0c1c9c2abf1147d6a5a9501895bc92960bfa182ceeb76a658224f1022bc53c4c1cd6888d72a152dc1aec5ba8a1d750fb7e498bee844d3481e4b4cd210227f94f775744185c9f24571b7df0c1c694cb2d3e4e9b955ed0b1caad2b02b5702139c4fbba03f0e422b2f3e4fc822b4f58baf32e7cd217cdbdec8540cb13d6496f271959b72a05e130eeffbe5b9a7fcd2793347cd9c0ea695265669844c363190f690c52a600cf413c3f00bdc5e9d1539e0cc63f4ec2945e0d86e6304a6deb5651e73eac21add5a641dfc95ab56200ed40d81f76755aee4659334c17ed3841ca5a5ab22f923956be1d264be2b485a0de55404510ece5c73d6626798be688f9dc18b69846acfe897a357cc4afe31f57fea32896717f124290e68f36f849fa6ecf76e02087f8c19dbc566135d7fa2daca2d843b9cc5bc3897d35f1de7d174f6407658f4a3706c12cea53d880b4d8c4d45b3f0d210214f815be49a664021a4a44b4a63e06a41d76b46f9aa6bad248e8d1a974ae7bbae5ea8ac269447db91637a19346729083cad5aebd5ff43ea13d04783068e9136da321b1152c666d2995d0ca06b26541deac62f4ef91f0e4af445b18a5c2a17c96eada0b27f85bb26dfb8f16515114c6b9f88037e2b85b3b84b65822eb99c992d99d12dcf9c71e5b46a586016faf5758483a716566db95b42187c101df68ca0554824e1c23cf0302bea03ad0a146af57e91794a268b8c82d78211718c8b5fea286f5de72fc7dfffecddcc02413525c472cb26022641d4bec2b8b7e71a7beb9ee18b82632799498eeee9a351cb9431a8d1906d5164acdf351bd538c3e9d1da8a211fe1cd18c44e72d8cdf16ce3fc9551552c05d52846ea7ef619232102588395cc2bcce509a4e7f150262a76c15475496c923dfce6bfc05871467ee7c213b39ea365c010083e0b1ba8926d3a9e586d8b11c9bab2a47d888bc7cb1a226c0086a1530e295d0047547006f4c8f1c24cdd8e16bb3845749895dec95f03fcda97d3224f6875b1b7b1c819d2fd35dd30968a3c82bc480d10082caf9d9dda8f9ec649c136c7fa07978099d97eaf4abfdc9854c266979d3cfc868f60689b6e3098b6c52a21796fe7c259d9a0dadf1b6efa59297d4c8c902febe7acf826eed30d40d2ac5119be91b51f4839d94599872c9a93c3e2691294914034001d3a278cb4a84d4ae048c0201a97e4cf1341ee663a162f5b586355018b9e5e30624ccdbeacf7d0382afacaf45f08e84d30c50bcd4e55c3138377261deb4e8c2931cd3c51cee94a048ae4839517b6e6537a5c0148d3830a33fea719ef9b4fa437e4d5fecdb646397c19ee56a0973c362a81803895cdc67246352dc566689cb203f9ebda900a5537bbb75aa25ddf3d4ab87b88737a58d760e1d271f08265daae1fe056e71971a8b826e5b215a05b71f99315b167dd2ec78874189657acafac2b5eeb9a901913f55f7ab69e1f9b203504448d414e71098b932a2309db57257eb3fef9de2f2a5a69aa46747d7b827df838345d38b95772bdab8c178c45777b92e8773864964b8e12ae29dbc1b21bf6527589f6bec71ff1cbb9928477409811c2e8150c79c3f21027ee954863b716875d3e9adfc6fdb18cd57a49bb395ca5c42da56f3beb78aad3a7a487de34a870bca61f3cdec422061328c83c910ab32ea7403c354915b7ebee29e1fea5a75158197e4a68e103f017fd7de5a70148ee7ce59356b1a74f83492e14faaa6cd4870bcc004e6eb0114d3429b74ea98fe2851b4553467a7660074e69b040aa31220d0e405d9166dbaf15e3ae2d8ec3b049ed99d17e0743bb6a1a7c3890bbdb7117f7374ad7a59aa1ab47d10445b28f4bc033794a71f88a8bf024189e9d27f9dc5859a4296437585b215656f807aca9dad35747494a43b8a1cf38be2b18a13de32a262ab29f9ba271c4fbce1a470a8243ebf9e7fd37b09262314afbb9a7e180218a0f1c9d505200028b0eb113299010a0012203dd273c42195c061140bd9b5a2a7b72cbfba66b9db63e861f70e9dc95026019c1800226b483045022100f220f48c5267ef92a1e7a4d3b44fe9d97cce76eeba2785d45a0e2620b70e8d7302205640bc39e197ce19d95a98a3239af0f208ca289c067f80c97d8e411e61da5dee0121021721e83315fb5282f1d9d2a11892322df589bccd9cef45517b5fb3cfd3055c8328ffffffff0f3a4b091e6c90cd3ebc664010001a1976a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac222374315934794c31344143486141626a656d6b647057376e594e48576e76317951624441"
testTxPacked2 = "0a20bb47a9dd926de63e9d4f8dac58c3f63f4a079569ed3b80e932274a80f60e58b512e20101000000019cafb5c287980e6e5afb47339f6c1c81136d8255f5bd5226b36b01288494c46f000000006b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea22880feffffff0223a7a784010000001976a914826f87806ddd4643730be99b41c98acc379e83db88ac80969800000000001976a914e395634b7684289285926d4c64db395b783720ec88ac6e75040018e4b1c9d50520eeea1128f9ea113299010a0012206fc4948428016bb32652bdf555826d13811c6c9f3347fb5a6e0e9887c2b5af9c1800226b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea2288028feffffff0f3a4b09257b2170264d504010001a1976a914826f87806ddd4643730be99b41c98acc379e83db88ac22237431566d4854547770457477766f6a786f644e32435351714c596931687a59336341713a4b099a9999999999b93f10011a1976a914e395634b7684289285926d4c64db395b783720ec88ac222374316563784d587070685554525158474c586e56684a367563714433445a6970646467"
testTxPacked1 = "0a20e64aac0c211ad210c90934f06b1cc932327329e41a9f70c6eb76f79ef798b7b812ab1002000000019c012650c99d0ef761e863dbb966babf2cb7a7a2b5d90b1461c09521c473d23d000000006b483045022100f220f48c5267ef92a1e7a4d3b44fe9d97cce76eeba2785d45a0e2620b70e8d7302205640bc39e197ce19d95a98a3239af0f208ca289c067f80c97d8e411e61da5dee0121021721e83315fb5282f1d9d2a11892322df589bccd9cef45517b5fb3cfd3055c83ffffffff018eec1a3c040000001976a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac000000000162b4fc6b0000000000000000000000006ffa88c89b74f0f82e24744296845a0d0113b132ff5dfc2af34e6418eb15206af53078c4dd475cf143cd9a427983f5993622464b53e3a37d2519a946492c3977e30f0866550b9097222993a439a39260ac5e7d36aef38c7fdd1df3035a2d5817a9c20526e38f52f822d4db9d2f0156c4119d786d6e3a060ca871df7fae9a5c3a9c921b38ddc6414b13d16aa807389c68016e54bd6a9eb3b23a6bc7bf152e6dba15e9ec36f95dab15ad8f4a92a9d0309bbd930ef24bb7247bf534065c1e2f5b42e2c80eb59f48b4da6ec522319e065f8c4e463f95cc7fcad8d7ee91608e3c0ffcaa44129ba2d2da45d9a413919eca41af29faaf806a3eeb823e5a6c51afb1ec709505d812c0306bd76061a0a62d207355ad44d1ffce2b9e1dfd0818f79bd0f8e4031116b71fee2488484f17818b80532865773166cd389929e8409bb94e3948bd2e0215ef96d4e29d094590fda0de50715c11ff47c03380bb1d31b14e5b4ad8a372ca0b03364ef85f086b8a8eb5c56c3b1aee33e2cfbf1b2be1a3fb41b14b2c432b5d04d54c058fa87a96ae1d65d61b79360d09acc1e25a883fd7ae9a2a734a03362903021401c243173e1050b5cdb459b9ffc07c95e920f026618952d3a800b2e47e03b902084aed7ee8466a65d34abdbbd292781564dcd9b7440029d48c2640ebc196d4b40217f2872c1d0c1c9c2abf1147d6a5a9501895bc92960bfa182ceeb76a658224f1022bc53c4c1cd6888d72a152dc1aec5ba8a1d750fb7e498bee844d3481e4b4cd210227f94f775744185c9f24571b7df0c1c694cb2d3e4e9b955ed0b1caad2b02b5702139c4fbba03f0e422b2f3e4fc822b4f58baf32e7cd217cdbdec8540cb13d6496f271959b72a05e130eeffbe5b9a7fcd2793347cd9c0ea695265669844c363190f690c52a600cf413c3f00bdc5e9d1539e0cc63f4ec2945e0d86e6304a6deb5651e73eac21add5a641dfc95ab56200ed40d81f76755aee4659334c17ed3841ca5a5ab22f923956be1d264be2b485a0de55404510ece5c73d6626798be688f9dc18b69846acfe897a357cc4afe31f57fea32896717f124290e68f36f849fa6ecf76e02087f8c19dbc566135d7fa2daca2d843b9cc5bc3897d35f1de7d174f6407658f4a3706c12cea53d880b4d8c4d45b3f0d210214f815be49a664021a4a44b4a63e06a41d76b46f9aa6bad248e8d1a974ae7bbae5ea8ac269447db91637a19346729083cad5aebd5ff43ea13d04783068e9136da321b1152c666d2995d0ca06b26541deac62f4ef91f0e4af445b18a5c2a17c96eada0b27f85bb26dfb8f16515114c6b9f88037e2b85b3b84b65822eb99c992d99d12dcf9c71e5b46a586016faf5758483a716566db95b42187c101df68ca0554824e1c23cf0302bea03ad0a146af57e91794a268b8c82d78211718c8b5fea286f5de72fc7dfffecddcc02413525c472cb26022641d4bec2b8b7e71a7beb9ee18b82632799498eeee9a351cb9431a8d1906d5164acdf351bd538c3e9d1da8a211fe1cd18c44e72d8cdf16ce3fc9551552c05d52846ea7ef619232102588395cc2bcce509a4e7f150262a76c15475496c923dfce6bfc05871467ee7c213b39ea365c010083e0b1ba8926d3a9e586d8b11c9bab2a47d888bc7cb1a226c0086a1530e295d0047547006f4c8f1c24cdd8e16bb3845749895dec95f03fcda97d3224f6875b1b7b1c819d2fd35dd30968a3c82bc480d10082caf9d9dda8f9ec649c136c7fa07978099d97eaf4abfdc9854c266979d3cfc868f60689b6e3098b6c52a21796fe7c259d9a0dadf1b6efa59297d4c8c902febe7acf826eed30d40d2ac5119be91b51f4839d94599872c9a93c3e2691294914034001d3a278cb4a84d4ae048c0201a97e4cf1341ee663a162f5b586355018b9e5e30624ccdbeacf7d0382afacaf45f08e84d30c50bcd4e55c3138377261deb4e8c2931cd3c51cee94a048ae4839517b6e6537a5c0148d3830a33fea719ef9b4fa437e4d5fecdb646397c19ee56a0973c362a81803895cdc67246352dc566689cb203f9ebda900a5537bbb75aa25ddf3d4ab87b88737a58d760e1d271f08265daae1fe056e71971a8b826e5b215a05b71f99315b167dd2ec78874189657acafac2b5eeb9a901913f55f7ab69e1f9b203504448d414e71098b932a2309db57257eb3fef9de2f2a5a69aa46747d7b827df838345d38b95772bdab8c178c45777b92e8773864964b8e12ae29dbc1b21bf6527589f6bec71ff1cbb9928477409811c2e8150c79c3f21027ee954863b716875d3e9adfc6fdb18cd57a49bb395ca5c42da56f3beb78aad3a7a487de34a870bca61f3cdec422061328c83c910ab32ea7403c354915b7ebee29e1fea5a75158197e4a68e103f017fd7de5a70148ee7ce59356b1a74f83492e14faaa6cd4870bcc004e6eb0114d3429b74ea98fe2851b4553467a7660074e69b040aa31220d0e405d9166dbaf15e3ae2d8ec3b049ed99d17e0743bb6a1a7c3890bbdb7117f7374ad7a59aa1ab47d10445b28f4bc033794a71f88a8bf024189e9d27f9dc5859a4296437585b215656f807aca9dad35747494a43b8a1cf38be2b18a13de32a262ab29f9ba271c4fbce1a470a8243ebf9e7fd37b09262314afbb9a7e180218a0f1c9d505200028b0eb113299010a0012203dd273c42195c061140bd9b5a2a7b72cbfba66b9db63e861f70e9dc95026019c1800226b483045022100f220f48c5267ef92a1e7a4d3b44fe9d97cce76eeba2785d45a0e2620b70e8d7302205640bc39e197ce19d95a98a3239af0f208ca289c067f80c97d8e411e61da5dee0121021721e83315fb5282f1d9d2a11892322df589bccd9cef45517b5fb3cfd3055c8328ffffffff0f3a490a05043c1aec8e10001a1976a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac222374315934794c31344143486141626a656d6b647057376e594e48576e76317951624441"
testTxPacked2 = "0a20bb47a9dd926de63e9d4f8dac58c3f63f4a079569ed3b80e932274a80f60e58b512e20101000000019cafb5c287980e6e5afb47339f6c1c81136d8255f5bd5226b36b01288494c46f000000006b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea22880feffffff0223a7a784010000001976a914826f87806ddd4643730be99b41c98acc379e83db88ac80969800000000001976a914e395634b7684289285926d4c64db395b783720ec88ac6e75040018e4b1c9d50520eeea1128f9ea113299010a0012206fc4948428016bb32652bdf555826d13811c6c9f3347fb5a6e0e9887c2b5af9c1800226b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea2288028feffffff0f3a490a050184a7a72310001a1976a914826f87806ddd4643730be99b41c98acc379e83db88ac22237431566d4854547770457477766f6a786f644e32435351714c596931687a59336341713a470a0398968010011a1976a914e395634b7684289285926d4c64db395b783720ec88ac222374316563784d587070685554525158474c586e56684a367563714433445a6970646467"
)
func init() {
@ -51,8 +52,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 181.88266638,
N: 0,
ValueSat: *big.NewInt(18188266638),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac",
Addresses: []string{
@ -82,8 +83,8 @@ func init() {
},
Vout: []bchain.Vout{
{
Value: 65.20547107,
N: 0,
ValueSat: *big.NewInt(6520547107),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914826f87806ddd4643730be99b41c98acc379e83db88ac",
Addresses: []string{
@ -93,8 +94,8 @@ func init() {
Address: addr2,
},
{
Value: .1,
N: 1,
ValueSat: *big.NewInt(10000000),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914e395634b7684289285926d4c64db395b783720ec88ac",
Addresses: []string{

View File

@ -22,6 +22,7 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
BitcoinRPC: b.(*btc.BitcoinRPC),
}
z.RPCMarshaler = btc.JSONMarshalerV1{}
z.ChainConfig.SupportsEstimateSmartFee = false
return z, nil
}
@ -114,14 +115,6 @@ func (z *ZCashRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
return z.GetTransaction(txid)
}
// EstimateSmartFee returns fee estimation.
func (z *ZCashRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
glog.V(1).Info("rpc: estimatesmartfee")
// return z.estimateFee(blocks)
return z.EstimateFee(blocks)
}
// GetMempoolEntry returns mempool data for given transaction
func (z *ZCashRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
return nil, errors.New("GetMempoolEntry: not implemented")

View File

@ -1,8 +1,7 @@
// +build integration
package rpc
import (
"blockbook/bchain"
"encoding/json"
"errors"
"fmt"
@ -83,7 +82,7 @@ func LoadRPCConfig(coin string) (json.RawMessage, error) {
return json.RawMessage(fmt.Sprintf(t, coin, c.URL, c.User, c.Pass)), nil
}
func LoadTestData(coin string) (*TestData, error) {
func LoadTestData(coin string, parser bchain.BlockChainParser) (*TestData, error) {
b, err := readDataFile(".", "bchain/tests/rpc/testdata", coin+".json")
if err != nil {
return nil, err
@ -93,5 +92,16 @@ func LoadTestData(coin string) (*TestData, error) {
if err != nil {
return nil, err
}
// convert amounts in test json to bit.Int and clear the temporary JsonValue
for _, tx := range v.TxDetails {
for i := range tx.Vout {
vout := &tx.Vout[i]
vout.ValueSat, err = parser.AmountToBigInt(vout.JsonValue)
if err != nil {
return nil, err
}
vout.JsonValue = ""
}
}
return &v, nil
}

View File

@ -1,5 +1,3 @@
// +build integration
package rpc
import (
@ -9,6 +7,7 @@ import (
"net"
"reflect"
"testing"
"time"
"github.com/deckarep/golang-set"
)
@ -56,7 +55,7 @@ func NewTest(coin string, factory TestChainFactoryFunc) (*Test, error) {
return nil, err
}
} else {
td, err = LoadTestData(coin)
td, err = LoadTestData(coin, cli.GetChainParser())
if err != nil {
return nil, err
}
@ -162,7 +161,7 @@ func (rt *Test) TestGetTransaction(t *testing.T) {
got.Confirmations = 0
if !reflect.DeepEqual(got, want) {
t.Errorf("GetTransaction() got %v, want %v", got, want)
t.Errorf("GetTransaction() got %+v, want %+v", got, want)
}
}
}
@ -181,7 +180,7 @@ func (rt *Test) TestGetTransactionForMempool(t *testing.T) {
// transactions parsed from JSON may contain additional data
got.Confirmations, got.Blocktime, got.Time = 0, 0, 0
if !reflect.DeepEqual(got, want) {
t.Errorf("GetTransactionForMempool() got %v, want %v", got, want)
t.Errorf("GetTransactionForMempool() got %+v, want %+v", got, want)
}
}
}
@ -329,8 +328,8 @@ func (rt *Test) TestGetMempoolEntry(t *testing.T) {
if e.Size <= 0 {
t.Errorf("GetMempoolEntry() got zero or negative size %d", e.Size)
}
if e.Fee <= 0 {
t.Errorf("GetMempoolEntry() got zero or negative fee %f", e.Fee)
if e.FeeSat.Sign() != 1 {
t.Errorf("GetMempoolEntry() got zero or negative fee %v", e.FeeSat.String())
}
// done
@ -347,8 +346,11 @@ func (rt *Test) TestEstimateSmartFee(t *testing.T) {
if err != nil {
t.Error(err)
}
if fee != -1 && fee < 0 {
t.Errorf("EstimateSmartFee() returned unexpected fee rate: %f", fee)
if fee.Sign() == -1 {
sf := rt.Client.GetChainParser().AmountToDecimalString(&fee)
if sf != "-1" {
t.Errorf("EstimateSmartFee() returned unexpected fee rate: %v", sf)
}
}
}
}
@ -361,8 +363,11 @@ func (rt *Test) TestEstimateFee(t *testing.T) {
if err != nil {
t.Error(err)
}
if fee != -1 && fee < 0 {
t.Errorf("EstimateFee() returned unexpected fee rate: %f", fee)
if fee.Sign() == -1 {
sf := rt.Client.GetChainParser().AmountToDecimalString(&fee)
if sf != "-1" {
t.Errorf("EstimateFee() returned unexpected fee rate: %v", sf)
}
}
}
}
@ -385,6 +390,7 @@ func (rt *Test) TestGetBestBlockHash(t *testing.T) {
t.Fatal(err)
}
if hash != hh {
time.Sleep(time.Millisecond * 100)
continue
}

View File

@ -70,6 +70,7 @@
"blocktime":1531135480,
"time":1531135480,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "fe496933e0a3582ef020bd35c38fe8244a80fa7c63e7607f6f9ccb0806f419e4",
@ -175,6 +176,7 @@
"blocktime":1531135480,
"time":1531135480,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "52f37874fd5a2497c5d84619ab415ca17ebb1d49d559f0d468869f70537354b9",

View File

@ -12,6 +12,7 @@
"blocktime":1529571678,
"time":1529571678,
"locktime": 0,
"version": 1,
"vin": [
{
"coinbase": "03fbf212055374617368",
@ -34,6 +35,7 @@
"blocktime":1529571678,
"time":1529571678,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "58ff2450a71b3c228d17d04ec8edcaae452bc97d5ccc4591e2741fd8b031d221",

View File

@ -120,6 +120,7 @@
"blocktime": 1529915213,
"time": 1529915213,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "83eff5bcc738d52e04528984cd5cf601b69e7df65b2b10ed2475c0072cdde14c",
@ -153,6 +154,7 @@
"blocktime": 1529915213,
"time": 1529915213,
"locktime": 529149,
"version": 2,
"vin": [
{
"txid": "413988d546516707f3b20ca9876e026a9472bd814662e42f37f4e57a15713da7",

View File

@ -43,6 +43,7 @@
"blocktime": 1528788394,
"time": 1528788394,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "4097f5265397047bffe219a1bca65ea5726402c3d9aeecd577fa1c274fc1b8a4",
@ -84,6 +85,7 @@
"blocktime": 1528788394,
"time": 1528788394,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "80437ba4e81bde8b584258f5adad0d08dea60f1e38026344442ad59a4ef797c9",

View File

@ -27,6 +27,7 @@
"blocktime": 1530189699,
"time": 1530189699,
"locktime": 0,
"version": 1,
"vin": [
{
"txid": "a78824a88c089ea1344fe2a33c454024e6501e76cca2590515b390d85082bd23",

View File

@ -31,6 +31,7 @@
"blocktime": 1528713762,
"time": 1528713762,
"locktime": 139520,
"version": 2,
"vin": [
{
"txid": "a41616c7585c98aeda98d6ff6766b15455e327c9472582b80289dab7597ad309",
@ -64,6 +65,7 @@
"blocktime": 1528713762,
"time": 1528713762,
"locktime": 139520,
"version": 2,
"vin": [
{
"txid": "187ae015e41dff766f5a18ae705f59db950a6729a06fa5fd04630c362a9aee27",

View File

@ -16,38 +16,21 @@
"0x7f0d140329941f120b5b3fc751e30adeb87b2aebbfce5adcd0216604a34b6cc0"
],
"txDetails": {
"0xe6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d": {
"hex": "7b226e6f6e6365223a2230783239666165222c226761735072696365223a223078313261303566323030222c22676173223a2230786462626130222c22746f223a22307836383262373930336131313039386366373730633761656634616130326138356233663336303161222c2276616c7565223a22307830222c22696e707574223a223078663032356361616630303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030323235222c2268617368223a22307865366231363864366262336438656437386530336462663832386236626664316662363133663665313239636261363234393634393834353533373234633564222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307864616363396336313735346130633436313666633533323364633934366538396562323732333032222c227472616e73616374696f6e496e646578223a22307831222c2276223a2230783162222c2272223a22307831626434306133313132326330333931386466366431363664373430613661336132326630386132353933346365623136383863363239373736363163383063222c2273223a22307836303766626331356331663739393561343235386635613962636363363362303430333632643139393164356566653133363163353632323265346361383966227d",
"txid": "0xe6b168d6bb3d8ed78e03dbf828b6bfd1fb613f6e129cba624964984553724c5d",
"0x7f0d140329941f120b5b3fc751e30adeb87b2aebbfce5adcd0216604a34b6cc0": {
"hex": "7b226e6f6e6365223a223078333632306136222c226761735072696365223a223078313261303566323030222c22676173223a22307835323038222c22746f223a22307831623137626331326166623635643563346238316139666632613037366234326131396661616136222c2276616c7565223a223078646530623662336137363430303030222c22696e707574223a223078222c2268617368223a22307837663064313430333239393431663132306235623366633735316533306164656238376232616562626663653561646364303231363630346133346236636330222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307838316237653038663635626466353634383630366338393939386139636338313634333937363437222c227472616e73616374696f6e496e646578223a22307862222c2276223a2230783162222c2272223a22307862666662323864633865373939383833366639356664616139396433626435666635346365663562313839636462383537333537666161326431616231393136222c2273223a22307833616462316365313264396664306538616662373064386639346534636538356137666639346465333966623636333139363638363435663464643138646432227d",
"txid": "0x7f0d140329941f120b5b3fc751e30adeb87b2aebbfce5adcd0216604a34b6cc0",
"blocktime": 1521515026,
"time": 1521515026,
"vin": [
{
"addresses": ["0xdacc9c61754a0c4616fc5323dc946e89eb272302"]
"addresses": ["0x81b7e08f65bdf5648606c89998a9cc8164397647"]
}
],
"vout": [
{
"value": 1,
"scriptPubKey": {
"addresses": ["0x682b7903a11098cf770c7aef4aa02a85b3f3601a"]
}
}
]
},
"0x17ee235fc0359155b25419e0e4c65d9c500df6e71e8288d6ef020d04cc2f2cb3": {
"hex": "7b226e6f6e6365223a223078346566222c226761735072696365223a223078626134336237343030222c22676173223a2230783936653838222c22746f223a22307864303534323939633438326164356362333961336661383734373235663965326132306433343963222c2276616c7565223a22307830222c22696e707574223a2230783165626366613630303030303030303030303030303030303030303030303030633034383732383566313736663532306635636434363732306236383662366534366165636430373030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030313430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030633461303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303530303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030353831303030303030303030303030303030303030303030303030633365313631343261306432366336616530623163656238643961373236653734653164613664663666656562653137653437306464626434656261663364623938333136386235316337623136363732613131623966306662383864623438323962653237346230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303034363336663665363230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303437323666373336313030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030222c2268617368223a22307831376565323335666330333539313535623235343139653065346336356439633530306466366537316538323838643665663032306430346363326632636233222c22626c6f636b4e756d626572223a223078326263616630222c2266726f6d223a22307838623461353365353739303739343466633261653539623837373066393331623639326232373062222c227472616e73616374696f6e496e646578223a22307830222c2276223a2230783163222c2272223a22307866633739633836353638323039313030323134616339353662373930653066383935656130343135313438643233613239353632356564393761633936333534222c2273223a223078373232303833616331643764663662626162393939383537616163323561336665646265386130633561326266376364653835393738363266373862313937227d",
"txid": "0x17ee235fc0359155b25419e0e4c65d9c500df6e71e8288d6ef020d04cc2f2cb3",
"blocktime": 1521515026,
"time": 1521515026,
"vin": [
{
"addresses": ["0x8b4a53e57907944fc2ae59b8770f931b692b270b"]
}
],
"vout": [
{
"scriptPubKey": {
"addresses": ["0xd054299c482ad5cb39a3fa874725f9e2a20d349c"]
"addresses": ["0x1b17bc12afb65d5c4b81a9ff2a076b42a19faaa6"]
}
}
]

View File

@ -39,6 +39,7 @@
"blocktime": 1530003649,
"time": 1530003649,
"locktime": 404678,
"version": 1,
"vin": [
{
"txid": "223a4ff7a613173ffbc67f9efffe1b0c3fd5ba2471935a44cc81814038272901",

View File

@ -14,6 +14,7 @@
"blocktime": 1529932850,
"time": 1529932850,
"locktime": 952232,
"version": 2,
"vin": [
{
"txid": "8ec70404bdd16559c589736863ee9d9f69431ba4e6b2ab3b1641b3f9f3821624",
@ -47,6 +48,7 @@
"blocktime": 1529932850,
"time": 1529932850,
"locktime": 952233,
"version": 1,
"vin": [
{
"txid": "5765db7dd62cddada154b2c95505e298818a308cc1ce1e28d6e8565301cb8d74",

View File

@ -22,6 +22,7 @@
"blocktime": 1530264033,
"time": 1530264033,
"locktime": 349399,
"version": 3,
"vin": [
{
"txid": "9c9faac29b0fa1b0e683727f2973bfcb87e4baadd07e9c997b431a31713cb30c",
@ -57,6 +58,7 @@
"blocktime": 1530264033,
"time": 1530264033,
"locktime": 0,
"version": 3,
"vin": [
{
"txid": "4440c8e9d5b57da7ca0fb3f62ec13f392267aeb797c123bb01e850adf8573dd0",

View File

@ -13,6 +13,7 @@
"blocktime": 1528781777,
"time": 1528781777,
"locktime": 251028,
"version": 3,
"vin": [
{
"txid": "19a1d013b898239e9a2943faa07f8716b9be168bc8e001daf3625f535fde1a60",
@ -48,6 +49,7 @@
"blocktime": 1528781777,
"time": 1528781777,
"locktime": 251090,
"version": 3,
"vin": [
{
"txid": "9acab5f13cf94074e75f5686b59fccd938f54b5f20ddddfcb6077c679a13c0ea",

View File

@ -148,7 +148,7 @@ func (m *ProtoTransaction_VinType) GetAddresses() []string {
}
type ProtoTransaction_VoutType struct {
Value float64 `protobuf:"fixed64,1,opt,name=Value" json:"Value,omitempty"`
ValueSat []byte `protobuf:"bytes,1,opt,name=ValueSat,proto3" json:"ValueSat,omitempty"`
N uint32 `protobuf:"varint,2,opt,name=N" json:"N,omitempty"`
ScriptPubKeyHex []byte `protobuf:"bytes,3,opt,name=ScriptPubKeyHex,proto3" json:"ScriptPubKeyHex,omitempty"`
Addresses []string `protobuf:"bytes,4,rep,name=Addresses" json:"Addresses,omitempty"`
@ -159,11 +159,11 @@ func (m *ProtoTransaction_VoutType) String() string { return proto.Co
func (*ProtoTransaction_VoutType) ProtoMessage() {}
func (*ProtoTransaction_VoutType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 1} }
func (m *ProtoTransaction_VoutType) GetValue() float64 {
func (m *ProtoTransaction_VoutType) GetValueSat() []byte {
if m != nil {
return m.Value
return m.ValueSat
}
return 0
return nil
}
func (m *ProtoTransaction_VoutType) GetN() uint32 {
@ -196,26 +196,26 @@ func init() {
func init() { proto.RegisterFile("tx.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 330 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x4e, 0xc2, 0x40,
0x10, 0x86, 0xb3, 0xb4, 0x14, 0x18, 0x21, 0x92, 0x89, 0x31, 0x0d, 0xf1, 0x50, 0x39, 0xf5, 0xd4,
0x03, 0xc6, 0x07, 0x50, 0x2f, 0x24, 0x1a, 0x42, 0x16, 0xd2, 0x7b, 0x5b, 0x36, 0xb0, 0x11, 0x77,
0xb1, 0xdd, 0x1a, 0x78, 0x16, 0x1f, 0xc1, 0x97, 0x34, 0x3b, 0x2d, 0x45, 0x48, 0xbc, 0xed, 0xff,
0xef, 0x4c, 0xff, 0x6f, 0xff, 0x14, 0xba, 0x66, 0x1f, 0xed, 0x72, 0x6d, 0x34, 0x7a, 0x69, 0xb6,
0x49, 0xa4, 0x1a, 0x7f, 0xbb, 0x30, 0x9c, 0x5b, 0x67, 0x99, 0x27, 0xaa, 0x48, 0x32, 0x23, 0xb5,
0x42, 0x04, 0x77, 0xb9, 0x97, 0x2b, 0x9f, 0x05, 0x2c, 0xec, 0x73, 0x3a, 0xe3, 0x10, 0x9c, 0xa9,
0xd8, 0xfb, 0x2d, 0xb2, 0xec, 0x11, 0xef, 0xa0, 0xf7, 0xbc, 0xd5, 0xd9, 0xbb, 0x91, 0x1f, 0xc2,
0x77, 0x02, 0x16, 0xba, 0xfc, 0x64, 0xe0, 0x08, 0xba, 0x6f, 0xc7, 0x4b, 0x37, 0x60, 0xe1, 0x80,
0x37, 0x1a, 0x6f, 0xc1, 0x9b, 0x0a, 0xb9, 0xde, 0x18, 0xbf, 0x4d, 0x37, 0xb5, 0xc2, 0x09, 0x38,
0xb1, 0x54, 0xbe, 0x17, 0x38, 0xe1, 0xd5, 0x24, 0x88, 0x2a, 0xc4, 0xe8, 0x12, 0x2f, 0x8a, 0xa5,
0x5a, 0x1e, 0x76, 0x82, 0xdb, 0x61, 0x7c, 0x04, 0x37, 0xd6, 0xa5, 0xf1, 0x3b, 0xb4, 0x74, 0xff,
0xff, 0x92, 0x2e, 0x0d, 0x6d, 0xd1, 0xf8, 0xe8, 0x87, 0x41, 0xa7, 0xfe, 0x8e, 0x45, 0x7d, 0xd1,
0x52, 0xa5, 0x49, 0x21, 0xe8, 0xc9, 0x3d, 0xde, 0xe8, 0xa6, 0x8a, 0xd6, 0x9f, 0x2a, 0xb0, 0x8e,
0x74, 0x08, 0x9e, 0xce, 0x38, 0x86, 0xfe, 0x22, 0xcb, 0xe5, 0xce, 0x2c, 0xe4, 0xda, 0xf6, 0xe4,
0xd2, 0xfc, 0x99, 0x67, 0x73, 0x16, 0xe2, 0xb3, 0x14, 0x2a, 0x13, 0xf5, 0xc3, 0x1b, 0x6d, 0xcb,
0x7c, 0x5a, 0xad, 0x72, 0x51, 0x14, 0xa2, 0xa0, 0x02, 0x7a, 0xfc, 0x64, 0x8c, 0xbe, 0xa0, 0x7b,
0xe4, 0xc7, 0x1b, 0x68, 0xc7, 0xc9, 0xb6, 0xac, 0x50, 0x19, 0xaf, 0x04, 0xf6, 0x81, 0xcd, 0x08,
0x72, 0xc0, 0xd9, 0x0c, 0x43, 0xb8, 0xae, 0x92, 0xe7, 0x65, 0xfa, 0x2a, 0x0e, 0x16, 0xc8, 0x21,
0xa0, 0x4b, 0xfb, 0x3c, 0xd7, 0xbd, 0xc8, 0x4d, 0x3d, 0xfa, 0x59, 0x1e, 0x7e, 0x03, 0x00, 0x00,
0xff, 0xff, 0x64, 0x1d, 0x38, 0xac, 0x38, 0x02, 0x00, 0x00,
// 331 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xc1, 0x6e, 0xea, 0x30,
0x10, 0x94, 0x89, 0x5f, 0x80, 0x7d, 0xa0, 0x87, 0xf6, 0xf0, 0x14, 0xa1, 0x1e, 0x52, 0x4e, 0x39,
0xe5, 0x40, 0xd5, 0x0f, 0x68, 0x7b, 0x41, 0x6a, 0x85, 0x90, 0x83, 0x72, 0x4f, 0x82, 0x05, 0x56,
0xa9, 0x4d, 0x13, 0x47, 0x02, 0xa9, 0x3f, 0xd3, 0x73, 0x7f, 0xb2, 0xf2, 0x12, 0x42, 0x41, 0xea,
0x6d, 0x67, 0xbc, 0xe3, 0x19, 0x4f, 0x02, 0x3d, 0xbb, 0x8f, 0x77, 0xa5, 0xb1, 0x06, 0xfd, 0xbc,
0xd8, 0x64, 0x4a, 0x4f, 0x3e, 0x39, 0x8c, 0x16, 0x8e, 0x59, 0x96, 0x99, 0xae, 0xb2, 0xc2, 0x2a,
0xa3, 0x11, 0x81, 0x2f, 0xf7, 0x6a, 0x15, 0xb0, 0x90, 0x45, 0x03, 0x41, 0x33, 0x8e, 0xc0, 0x9b,
0xc9, 0x7d, 0xd0, 0x21, 0xca, 0x8d, 0x78, 0x03, 0xfd, 0xc7, 0xad, 0x29, 0x5e, 0xad, 0x7a, 0x93,
0x81, 0x17, 0xb2, 0x88, 0x8b, 0x33, 0x81, 0x63, 0xe8, 0xbd, 0x9c, 0x0e, 0x79, 0xc8, 0xa2, 0xa1,
0x68, 0x31, 0xfe, 0x07, 0x7f, 0x26, 0xd5, 0x7a, 0x63, 0x83, 0x3f, 0x74, 0xd2, 0x20, 0x9c, 0x82,
0x97, 0x2a, 0x1d, 0xf8, 0xa1, 0x17, 0xfd, 0x9d, 0x86, 0xf1, 0x31, 0x62, 0x7c, 0x1d, 0x2f, 0x4e,
0x95, 0x5e, 0x1e, 0x76, 0x52, 0xb8, 0x65, 0xbc, 0x07, 0x9e, 0x9a, 0xda, 0x06, 0x5d, 0x12, 0xdd,
0xfe, 0x2e, 0x32, 0xb5, 0x25, 0x15, 0xad, 0x8f, 0xbf, 0x18, 0x74, 0x9b, 0x7b, 0x5c, 0xd4, 0x27,
0xa3, 0x74, 0x9e, 0x55, 0x92, 0x9e, 0xdc, 0x17, 0x2d, 0x6e, 0xab, 0xe8, 0xfc, 0xa8, 0x02, 0x1b,
0x4b, 0x8f, 0xc2, 0xd3, 0x8c, 0x13, 0x18, 0x24, 0x45, 0xa9, 0x76, 0x36, 0x51, 0x6b, 0xd7, 0x13,
0xa7, 0xfd, 0x0b, 0xce, 0xf9, 0x24, 0xf2, 0xbd, 0x96, 0xba, 0x90, 0xcd, 0xc3, 0x5b, 0xec, 0xca,
0x7c, 0x58, 0xad, 0x4a, 0x59, 0x55, 0xb2, 0xa2, 0x02, 0xfa, 0xe2, 0x4c, 0x8c, 0x3f, 0xa0, 0x77,
0xca, 0xef, 0x6e, 0x49, 0xb3, 0x6d, 0x2d, 0x93, 0xcc, 0x36, 0x1f, 0xa8, 0xc5, 0x38, 0x00, 0x36,
0xa7, 0xa8, 0x43, 0xc1, 0xe6, 0x18, 0xc1, 0xbf, 0xa3, 0xff, 0xa2, 0xce, 0x9f, 0xe5, 0xc1, 0xc5,
0xf2, 0x48, 0x70, 0x4d, 0x5f, 0xba, 0xf3, 0x2b, 0xf7, 0xdc, 0xa7, 0x5f, 0xe6, 0xee, 0x3b, 0x00,
0x00, 0xff, 0xff, 0x95, 0x9e, 0x00, 0x7a, 0x3e, 0x02, 0x00, 0x00,
}

View File

@ -11,7 +11,7 @@ syntax = "proto3";
repeated string Addresses = 6;
}
message VoutType {
double Value = 1;
bytes ValueSat = 1;
uint32 N = 2;
bytes ScriptPubKeyHex = 3;
repeated string Addresses = 4;

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math/big"
)
// errors with specific meaning returned by blockchain rpc
@ -49,7 +50,8 @@ type Address interface {
}
type Vout struct {
Value float64 `json:"value"`
ValueSat big.Int
JsonValue json.Number `json:"value"`
N uint32 `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
Address Address
@ -89,18 +91,20 @@ type BlockHeader struct {
}
type MempoolEntry struct {
Size uint32 `json:"size"`
Fee float64 `json:"fee"`
ModifiedFee float64 `json:"modifiedfee"`
Time float64 `json:"time"`
Height uint32 `json:"height"`
DescendantCount uint32 `json:"descendantcount"`
DescendantSize uint32 `json:"descendantsize"`
DescendantFees uint32 `json:"descendantfees"`
AncestorCount uint32 `json:"ancestorcount"`
AncestorSize uint32 `json:"ancestorsize"`
AncestorFees uint32 `json:"ancestorfees"`
Depends []string `json:"depends"`
Size uint32 `json:"size"`
FeeSat big.Int
Fee json.Number `json:"fee"`
ModifiedFeeSat big.Int
ModifiedFee json.Number `json:"modifiedfee"`
Time uint64 `json:"time"`
Height uint32 `json:"height"`
DescendantCount uint32 `json:"descendantcount"`
DescendantSize uint32 `json:"descendantsize"`
DescendantFees uint32 `json:"descendantfees"`
AncestorCount uint32 `json:"ancestorcount"`
AncestorSize uint32 `json:"ancestorsize"`
AncestorFees uint32 `json:"ancestorfees"`
Depends []string `json:"depends"`
}
type RPCError struct {
@ -132,8 +136,8 @@ type BlockChain interface {
GetMempool() ([]string, error)
GetTransaction(txid string) (*Tx, error)
GetTransactionForMempool(txid string) (*Tx, error)
EstimateSmartFee(blocks int, conservative bool) (float64, error)
EstimateFee(blocks int) (float64, error)
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
EstimateFee(blocks int) (big.Int, error)
SendRawTransaction(tx string) (string, error)
// mempool
ResyncMempool(onNewTxAddr func(txid string, addr string)) (int, error)
@ -145,7 +149,7 @@ type BlockChain interface {
// BlockChainParser defines common interface to parsing and conversions of block chain data
type BlockChainParser interface {
// self description
// chain configuration description
// UTXO chains need "inputs" column in db, that map transactions to transactions that spend them
// non UTXO chains have mapping of address to input and output transactions directly in "outputs" column in db
IsUTXOChain() bool
@ -153,6 +157,11 @@ type BlockChainParser interface {
// and used in case of fork
// if 0 the blockaddresses column is not used at all (usually non UTXO chains)
KeepBlockAddresses() int
// AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
AmountToDecimalString(a *big.Int) string
// AmountToBigInt converts amount in json.Number (string) to big.Int
// it uses string operations to avoid problems with rounding
AmountToBigInt(n json.Number) (big.Int, error)
// address id conversions
GetAddrIDFromVout(output *Vout) ([]byte, error)
GetAddrIDFromAddress(address string) ([]byte, error)

View File

@ -175,7 +175,11 @@ func main() {
}
index.SetInternalState(internalState)
if internalState.DbState != common.DbStateClosed {
glog.Warning("internalState: database in not closed state ", internalState.DbState, ", possibly previous ungraceful shutdown")
if internalState.DbState == common.DbStateInconsistent {
glog.Error("internalState: database is in inconsistent state and cannot be used")
return
}
glog.Warning("internalState: database was left in open state, possibly previous ungraceful shutdown")
}
if *computeColumnStats {

View File

@ -11,6 +11,8 @@ const (
DbStateClosed = uint32(iota)
// DbStateOpen means db is open or application died without closing the db
DbStateOpen
// DbStateInconsistent means db is in inconsistent state and cannot be used
DbStateInconsistent
)
// InternalStateColumn contains the data of a db column

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -213,17 +213,26 @@ func (w *SyncWorker) ConnectBlocksParallel(lower, higher uint32) error {
writeBlockDone := make(chan struct{})
writeBlockWorker := func() {
defer close(writeBlockDone)
bc, err := w.db.InitBulkConnect()
if err != nil {
glog.Error("sync: InitBulkConnect error ", err)
}
lastBlock := lower - 1
keep := uint32(w.chain.GetChainParser().KeepBlockAddresses())
for b := range bch {
if lastBlock+1 != b.Height {
glog.Error("writeBlockWorker skipped block, last connected block", lastBlock, ", new block ", b.Height)
}
err := w.db.ConnectBlock(b)
err := bc.ConnectBlock(b, b.Height+keep > higher)
if err != nil {
glog.Error("writeBlockWorker ", b.Height, " ", b.Hash, " error ", err)
}
lastBlock = b.Height
}
err = bc.Close()
if err != nil {
glog.Error("sync: bulkconnect.Close error ", err)
}
glog.Info("WriteBlock exiting...")
}
getBlockWorker := func(i int) {
@ -276,6 +285,7 @@ func (w *SyncWorker) ConnectBlocksParallel(lower, higher uint32) error {
}
go writeBlockWorker()
var hash string
start := time.Now()
ConnectLoop:
for h := lower; h <= higher; {
select {
@ -292,7 +302,8 @@ ConnectLoop:
}
hch <- hashHeight{hash, h}
if h > 0 && h%1000 == 0 {
glog.Info("connecting block ", h, " ", hash)
glog.Info("connecting block ", h, " ", hash, ", elapsed ", time.Since(start))
start = time.Now()
}
h++
}
@ -346,25 +357,23 @@ func (w *SyncWorker) getBlockChain(out chan blockResult, done chan struct{}) {
}
// DisconnectBlocks removes all data belonging to blocks in range lower-higher,
// using block data from blockchain, if they are available,
// otherwise doing full scan
func (w *SyncWorker) DisconnectBlocks(lower uint32, higher uint32, hashes []string) error {
glog.Infof("sync: disconnecting blocks %d-%d", lower, higher)
// if the chain uses Block to Addresses mapping, always use DisconnectBlockRange
if w.chain.GetChainParser().KeepBlockAddresses() > 0 {
return w.db.DisconnectBlockRange(lower, higher)
// if the chain is UTXO, always use DisconnectBlockRange
if w.chain.GetChainParser().IsUTXOChain() {
return w.db.DisconnectBlockRangeUTXO(lower, higher)
}
blocks := make([]*bchain.Block, len(hashes))
var err error
// get all blocks first to see if we can avoid full scan
// try to get all blocks first to see if we can avoid full scan
for i, hash := range hashes {
blocks[i], err = w.chain.GetBlock(hash, 0)
if err != nil {
// cannot get a block, we must do full range scan
return w.db.DisconnectBlockRange(lower, higher)
return w.db.DisconnectBlockRangeNonUTXO(lower, higher)
}
}
// then disconnect one after another
// got all blocks to be disconnected, disconnect them one after another
for i, block := range blocks {
glog.Info("Disconnecting block ", (int(higher) - i), " ", block.Hash)
if err = w.db.DisconnectBlock(block); err != nil {

View File

@ -113,8 +113,10 @@ func formatUnixTime(ut int64) string {
return time.Unix(ut, 0).Format(time.RFC1123)
}
func formatAmount(a float64) string {
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%0.8f", a), "0"), ".")
// for now return the string as it is
// in future could be used to do coin specific formatting
func formatAmount(a string) string {
return a
}
// Run starts the server

View File

@ -7,6 +7,7 @@ import (
"blockbook/db"
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
@ -236,11 +237,11 @@ type txInputs struct {
// ScriptAsm *string `json:"scriptAsm"`
Sequence int64 `json:"sequence"`
Address *string `json:"address"`
Satoshis int64 `json:"satoshis"`
Satoshis string `json:"satoshis"`
}
type txOutputs struct {
Satoshis int64 `json:"satoshis"`
Satoshis string `json:"satoshis"`
Script *string `json:"script"`
// ScriptAsm *string `json:"scriptAsm"`
SpentTxID *string `json:"spentTxId,omitempty"`
@ -267,7 +268,7 @@ type resTx struct {
type addressHistoryItem struct {
Addresses map[string]addressHistoryIndexes `json:"addresses"`
Satoshis int64 `json:"satoshis"`
Satoshis string `json:"satoshis"`
Confirmations int `json:"confirmations"`
Tx resTx `json:"tx"`
}
@ -329,7 +330,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
for _, vout := range tx.Vout {
aoh := vout.ScriptPubKey.Hex
ao := txOutputs{
Satoshis: int64(vout.Value*1E8 + 0.5),
Satoshis: vout.ValueSat.String(),
Script: &aoh,
}
if vout.Address != nil {
@ -452,6 +453,7 @@ func unmarshalEstimateSmartFee(params []byte) (blocks int, conservative bool, er
}
type resultEstimateSmartFee struct {
// for compatibility reasons use float64
Result float64 `json:"result"`
}
@ -460,7 +462,7 @@ func (s *SocketIoServer) estimateSmartFee(blocks int, conservative bool) (res re
if err != nil {
return
}
res.Result = fee
res.Result, err = strconv.ParseFloat(s.chainParser.AmountToDecimalString(&fee), 64)
return
}
@ -479,6 +481,7 @@ func unmarshalEstimateFee(params []byte) (blocks int, err error) {
}
type resultEstimateFee struct {
// for compatibility reasons use float64
Result float64 `json:"result"`
}
@ -487,7 +490,7 @@ func (s *SocketIoServer) estimateFee(blocks int) (res resultEstimateFee, err err
if err != nil {
return
}
res.Result = fee
res.Result, err = strconv.ParseFloat(s.chainParser.AmountToDecimalString(&fee), 64)
return
}
@ -588,7 +591,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
a := vout.Address.String()
ai.Address = &a
}
ai.Satoshis = int64(vout.Value*1E8 + 0.5)
ai.Satoshis = vout.ValueSat.String()
}
}
hi = append(hi, ai)
@ -596,7 +599,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
for _, vout := range tx.Vout {
aos := vout.ScriptPubKey.Hex
ao := txOutputs{
Satoshis: int64(vout.Value*1E8 + 0.5),
Satoshis: vout.ValueSat.String(),
Script: &aos,
}
if vout.Address != nil {