Merge branch 'master' into ethereum
This commit is contained in:
commit
73486e851f
@ -119,6 +119,11 @@ func (c *blockChainWithMetrics) EstimateSmartFee(blocks int, conservative bool)
|
|||||||
return c.b.EstimateSmartFee(blocks, conservative)
|
return c.b.EstimateSmartFee(blocks, conservative)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EstimateFee(blocks int) (v float64, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("EstimateFee", s, err) }(time.Now())
|
||||||
|
return c.b.EstimateFee(blocks)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) SendRawTransaction(tx string) (v string, err error) {
|
func (c *blockChainWithMetrics) SendRawTransaction(tx string) (v string, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("SendRawTransaction", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("SendRawTransaction", s, err) }(time.Now())
|
||||||
return c.b.SendRawTransaction(tx)
|
return c.b.SendRawTransaction(tx)
|
||||||
|
|||||||
@ -33,10 +33,12 @@ func GetChainParams(chain string) *chaincfg.Params {
|
|||||||
return &chaincfg.MainNetParams
|
return &chaincfg.MainNetParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAddrIDFromAddress returns internal address representation of given transaction output
|
||||||
func (p *BitcoinBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
|
func (p *BitcoinBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
|
||||||
return hex.DecodeString(output.ScriptPubKey.Hex)
|
return hex.DecodeString(output.ScriptPubKey.Hex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAddrIDFromAddress returns internal address representation of given address
|
||||||
func (p *BitcoinBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
|
func (p *BitcoinBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
|
||||||
return p.AddressToOutputScript(address)
|
return p.AddressToOutputScript(address)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -255,6 +255,20 @@ type resEstimateSmartFee struct {
|
|||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// estimatefee
|
||||||
|
|
||||||
|
type cmdEstimateFee struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params struct {
|
||||||
|
Blocks int `json:"nblocks"`
|
||||||
|
} `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type resEstimateFee struct {
|
||||||
|
Error *bchain.RPCError `json:"error"`
|
||||||
|
Result float64 `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
// sendrawtransaction
|
// sendrawtransaction
|
||||||
|
|
||||||
type cmdSendRawTransaction struct {
|
type cmdSendRawTransaction struct {
|
||||||
@ -582,6 +596,24 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, e
|
|||||||
return res.Result.Feerate, nil
|
return res.Result.Feerate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateFee returns fee estimation.
|
||||||
|
func (b *BitcoinRPC) EstimateFee(blocks int) (float64, error) {
|
||||||
|
glog.V(1).Info("rpc: estimatefee ", blocks)
|
||||||
|
|
||||||
|
res := resEstimateFee{}
|
||||||
|
req := cmdEstimateFee{Method: "estimatefee"}
|
||||||
|
req.Params.Blocks = blocks
|
||||||
|
err := b.Call(&req, &res)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0, res.Error
|
||||||
|
}
|
||||||
|
return res.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendRawTransaction sends raw transaction.
|
// SendRawTransaction sends raw transaction.
|
||||||
func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
||||||
glog.V(1).Info("rpc: sendrawtransaction")
|
glog.V(1).Info("rpc: sendrawtransaction")
|
||||||
@ -600,6 +632,7 @@ func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
|||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMempoolEntry returns mempool data for given transaction
|
||||||
func (b *BitcoinRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
|
func (b *BitcoinRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
|
||||||
glog.V(1).Info("rpc: getmempoolentry")
|
glog.V(1).Info("rpc: getmempoolentry")
|
||||||
|
|
||||||
|
|||||||
41
bchain/coins/zec/address.go
Normal file
41
bchain/coins/zec/address.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package zec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"github.com/btcsuite/btcutil/base58"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrChecksumMismatch describes an error where decoding failed due
|
||||||
|
// to a bad checksum.
|
||||||
|
ErrChecksumMismatch = errors.New("checksum mismatch")
|
||||||
|
|
||||||
|
// ErrInvalidFormat describes an error where decoding failed due to invalid version
|
||||||
|
ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing")
|
||||||
|
)
|
||||||
|
|
||||||
|
// checksum: first four bytes of sha256^2
|
||||||
|
func checksum(input []byte) (cksum [4]byte) {
|
||||||
|
h := sha256.Sum256(input)
|
||||||
|
h2 := sha256.Sum256(h[:])
|
||||||
|
copy(cksum[:], h2[:4])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
|
||||||
|
func CheckDecode(input string) (result []byte, version []byte, err error) {
|
||||||
|
decoded := base58.Decode(input)
|
||||||
|
if len(decoded) < 5 {
|
||||||
|
return nil, nil, ErrInvalidFormat
|
||||||
|
}
|
||||||
|
version = append(version, decoded[0:2]...)
|
||||||
|
var cksum [4]byte
|
||||||
|
copy(cksum[:], decoded[len(decoded)-4:])
|
||||||
|
if checksum(decoded[:len(decoded)-4]) != cksum {
|
||||||
|
return nil, nil, ErrChecksumMismatch
|
||||||
|
}
|
||||||
|
payload := decoded[2 : len(decoded)-4]
|
||||||
|
result = append(result, payload...)
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -2,37 +2,83 @@ package zec
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/btc"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"encoding/gob"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// bitcoinwire parsing
|
type ZCashBlockParser struct{}
|
||||||
|
|
||||||
type ZCashBlockParser struct {
|
|
||||||
btc.BitcoinBlockParser
|
|
||||||
}
|
|
||||||
|
|
||||||
// getChainParams contains network parameters for the main Bitcoin network,
|
|
||||||
// the regression test Bitcoin network, the test Bitcoin network and
|
|
||||||
// the simulation test Bitcoin network, in this order
|
|
||||||
func GetChainParams(chain string) *chaincfg.Params {
|
|
||||||
switch chain {
|
|
||||||
case "test":
|
|
||||||
return &chaincfg.TestNet3Params
|
|
||||||
case "regtest":
|
|
||||||
return &chaincfg.RegressionNetParams
|
|
||||||
}
|
|
||||||
return &chaincfg.MainNetParams
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// GetAddrIDFromAddress returns internal address representation of given transaction output
|
||||||
func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
|
func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
|
||||||
if len(output.ScriptPubKey.Addresses) != 1 {
|
if len(output.ScriptPubKey.Addresses) != 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return []byte(output.ScriptPubKey.Addresses[0]), nil
|
hash, _, err := CheckDecode(output.ScriptPubKey.Addresses[0])
|
||||||
|
return hash, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAddrIDFromAddress returns internal address representation of given address
|
||||||
func (p *ZCashBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
|
func (p *ZCashBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
|
||||||
return []byte(address), nil
|
hash, _, err := CheckDecode(address)
|
||||||
|
return hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PackTx packs transaction to byte array
|
||||||
|
func (p *ZCashBlockParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(buf, height)
|
||||||
|
buf, err := encodeTx(buf, tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeTx(b []byte, tx *bchain.Tx) ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(tx)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpackTx unpacks transaction from byte array
|
||||||
|
func (p *ZCashBlockParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||||
|
height := binary.BigEndian.Uint32(buf)
|
||||||
|
tx, err := decodeTx(buf[4:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return tx, height, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTx(buf []byte) (*bchain.Tx, error) {
|
||||||
|
tx := new(bchain.Tx)
|
||||||
|
dec := gob.NewDecoder(bytes.NewBuffer(buf))
|
||||||
|
err := dec.Decode(tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ZCashBlockParser) AddressToOutputScript(address string) ([]byte, error) {
|
||||||
|
return nil, errors.New("AddressToOutputScript: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ZCashBlockParser) OutputScriptToAddresses(script []byte) ([]string, error) {
|
||||||
|
return nil, errors.New("OutputScriptToAddresses: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ZCashBlockParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
|
return nil, errors.New("ParseBlock: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ZCashBlockParser) ParseTx(b []byte) (*bchain.Tx, error) {
|
||||||
|
return nil, errors.New("ParseTx: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ZCashBlockParser) IsUTXOChain() bool {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
185
bchain/coins/zec/zcashparser_test.go
Normal file
185
bchain/coins/zec/zcashparser_test.go
Normal file
File diff suppressed because one or more lines are too long
@ -5,8 +5,6 @@ import (
|
|||||||
"blockbook/bchain/coins/btc"
|
"blockbook/bchain/coins/btc"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
@ -28,31 +26,11 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(*bchain.MQMessage)) (b
|
|||||||
|
|
||||||
func (z *ZCashRPC) Initialize() error {
|
func (z *ZCashRPC) Initialize() error {
|
||||||
z.Mempool = bchain.NewMempool(z)
|
z.Mempool = bchain.NewMempool(z)
|
||||||
|
z.Parser = &ZCashBlockParser{}
|
||||||
|
z.Testnet = false
|
||||||
|
z.Network = "livenet"
|
||||||
|
|
||||||
chainName, err := z.GetBlockChainInfo()
|
glog.Info("rpc: block chain mainnet")
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
params := GetChainParams(chainName)
|
|
||||||
|
|
||||||
// always create parser
|
|
||||||
z.Parser = &ZCashBlockParser{
|
|
||||||
btc.BitcoinBlockParser{
|
|
||||||
Params: params,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameters for getInfo request
|
|
||||||
if params.Net == wire.MainNet {
|
|
||||||
z.Testnet = false
|
|
||||||
z.Network = "livenet"
|
|
||||||
} else {
|
|
||||||
z.Testnet = true
|
|
||||||
z.Network = "testnet"
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Info("rpc: block chain ", params.Name)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -90,15 +68,30 @@ type resGetBlockHeader struct {
|
|||||||
Result bchain.BlockHeader `json:"result"`
|
Result bchain.BlockHeader `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// estimatefee
|
||||||
|
|
||||||
|
type resEstimateFee struct {
|
||||||
|
Error *bchain.RPCError `json:"error"`
|
||||||
|
Result float64 `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlock returns block with given hash.
|
// GetBlock returns block with given hash.
|
||||||
func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
||||||
|
var err error
|
||||||
|
if hash == "" && height > 0 {
|
||||||
|
hash, err = z.GetBlockHash(height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glog.V(1).Info("rpc: getblock (verbosity=1) ", hash)
|
glog.V(1).Info("rpc: getblock (verbosity=1) ", hash)
|
||||||
|
|
||||||
res := resGetBlockThin{}
|
res := resGetBlockThin{}
|
||||||
req := untypedArrayParams{Method: "getblock"}
|
req := untypedArrayParams{Method: "getblock"}
|
||||||
req.Params = append(req.Params, hash)
|
req.Params = append(req.Params, hash)
|
||||||
req.Params = append(req.Params, true)
|
req.Params = append(req.Params, true)
|
||||||
err := z.Call(&req, &res)
|
err = z.Call(&req, &res)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
@ -111,6 +104,10 @@ func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
|||||||
for i, txid := range res.Result.Txids {
|
for i, txid := range res.Result.Txids {
|
||||||
tx, err := z.GetTransaction(txid)
|
tx, err := z.GetTransaction(txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isInvalidTx(err) {
|
||||||
|
glog.Errorf("rpc: getblock: skipping transanction in block %s due error: %s", hash, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
txs[i] = *tx
|
txs[i] = *tx
|
||||||
@ -122,6 +119,20 @@ func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
|||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isInvalidTx(err error) bool {
|
||||||
|
switch e1 := err.(type) {
|
||||||
|
case *errors.Err:
|
||||||
|
switch e2 := e1.Cause().(type) {
|
||||||
|
case *bchain.RPCError:
|
||||||
|
if e2.Code == -5 { // "No information available about transaction"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// GetTransaction returns a transaction by the transaction ID.
|
// GetTransaction returns a transaction by the transaction ID.
|
||||||
func (z *ZCashRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
func (z *ZCashRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
||||||
@ -154,6 +165,9 @@ func (z *ZCashRPC) GetBlockHash(height uint32) (string, error) {
|
|||||||
return "", errors.Annotatef(err, "height %v", height)
|
return "", errors.Annotatef(err, "height %v", height)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return "", bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return "", errors.Annotatef(res.Error, "height %v", height)
|
return "", errors.Annotatef(res.Error, "height %v", height)
|
||||||
}
|
}
|
||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
@ -173,7 +187,49 @@ func (z *ZCashRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
|
|||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||||
}
|
}
|
||||||
return &res.Result, nil
|
return &res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateSmartFee returns fee estimation.
|
||||||
|
func (z *ZCashRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
|
||||||
|
glog.V(1).Info("rpc: estimatesmartfee")
|
||||||
|
|
||||||
|
return z.estimateFee(blocks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateFee returns fee estimation.
|
||||||
|
func (z *ZCashRPC) EstimateFee(blocks int) (float64, error) {
|
||||||
|
glog.V(1).Info("rpc: estimatefee ", blocks)
|
||||||
|
|
||||||
|
return z.estimateFee(blocks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZCashRPC) estimateFee(blocks int) (float64, error) {
|
||||||
|
res := resEstimateFee{}
|
||||||
|
req := untypedArrayParams{Method: "estimatefee"}
|
||||||
|
req.Params = append(req.Params, blocks)
|
||||||
|
err := z.Call(&req, &res)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0, res.Error
|
||||||
|
}
|
||||||
|
return res.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMempoolEntry returns mempool data for given transaction
|
||||||
|
func (z *ZCashRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
|
||||||
|
return nil, errors.New("GetMempoolEntry: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isErrBlockNotFound(err *bchain.RPCError) bool {
|
||||||
|
return err.Message == "Block not found" ||
|
||||||
|
err.Message == "Block height out of range"
|
||||||
|
}
|
||||||
|
|||||||
@ -113,6 +113,7 @@ type BlockChain interface {
|
|||||||
GetMempool() ([]string, error)
|
GetMempool() ([]string, error)
|
||||||
GetTransaction(txid string) (*Tx, error)
|
GetTransaction(txid string) (*Tx, error)
|
||||||
EstimateSmartFee(blocks int, conservative bool) (float64, error)
|
EstimateSmartFee(blocks int, conservative bool) (float64, error)
|
||||||
|
EstimateFee(blocks int) (float64, error)
|
||||||
SendRawTransaction(tx string) (string, error)
|
SendRawTransaction(tx string) (string, error)
|
||||||
// mempool
|
// mempool
|
||||||
ResyncMempool(onNewTxAddr func(txid string, addr string)) error
|
ResyncMempool(onNewTxAddr func(txid string, addr string)) error
|
||||||
|
|||||||
@ -162,6 +162,13 @@ var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (inter
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
|
"estimateFee": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
|
||||||
|
blocks, err := unmarshalEstimateFee(params)
|
||||||
|
if err == nil {
|
||||||
|
rv, err = s.estimateFee(blocks)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
"getInfo": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
|
"getInfo": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
|
||||||
return s.getInfo()
|
return s.getInfo()
|
||||||
},
|
},
|
||||||
@ -527,6 +534,33 @@ func (s *SocketIoServer) estimateSmartFee(blocks int, conservative bool) (res re
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmarshalEstimateFee(params []byte) (blocks int, err error) {
|
||||||
|
p, err := unmarshalArray(params, 1)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fblocks, ok := p[0].(float64)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("Invalid parameter nblocks")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
blocks = int(fblocks)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type resultEstimateFee struct {
|
||||||
|
Result float64 `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocketIoServer) estimateFee(blocks int) (res resultEstimateFee, err error) {
|
||||||
|
fee, err := s.chain.EstimateFee(blocks)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Result = fee
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type resultGetInfo struct {
|
type resultGetInfo struct {
|
||||||
Result struct {
|
Result struct {
|
||||||
Version int `json:"version,omitempty"`
|
Version int `json:"version,omitempty"`
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
function getAddressTxids() {
|
function getAddressTxids() {
|
||||||
var addresses = document.getElementById('getAddressTxidsAddresses').value.split(",");
|
var addresses = document.getElementById('getAddressTxidsAddresses').value.split(",");
|
||||||
|
addresses = addresses.map(s => s.trim());
|
||||||
var mempool = document.getElementById("getAddressTxidsMempool").checked;
|
var mempool = document.getElementById("getAddressTxidsMempool").checked;
|
||||||
lookupTransactionsIdsMempool(addresses, mempool, 2000000, 0, function (result) {
|
lookupTransactionsIdsMempool(addresses, mempool, 2000000, 0, function (result) {
|
||||||
console.log('getAddressTxids sent successfully');
|
console.log('getAddressTxids sent successfully');
|
||||||
@ -53,6 +54,7 @@
|
|||||||
|
|
||||||
function getAddressHistory() {
|
function getAddressHistory() {
|
||||||
var addresses = document.getElementById('getAddressHistoryAddresses').value.split(",");
|
var addresses = document.getElementById('getAddressHistoryAddresses').value.split(",");
|
||||||
|
addresses = addresses.map(s => s.trim());
|
||||||
var mempool = document.getElementById("getAddressHistoryMempool").checked;
|
var mempool = document.getElementById("getAddressHistoryMempool").checked;
|
||||||
lookupAddressHistories(addresses, 0, 5, mempool, 2000000, 0, function (result) {
|
lookupAddressHistories(addresses, 0, 5, mempool, 2000000, 0, function (result) {
|
||||||
console.log('getAddressHistory sent successfully');
|
console.log('getAddressHistory sent successfully');
|
||||||
@ -102,22 +104,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBlockHeader() {
|
function getBlockHeader() {
|
||||||
var height = document.getElementById('getBlockHeaderHeight').value;
|
var param = document.getElementById('getBlockHeaderParam').value.trim();
|
||||||
lookupBlockHash(parseInt(height), function (result) {
|
lookupBlockHash(isHash(param) ? param : parseInt(param), function (result) {
|
||||||
console.log('getBlockHeader sent successfully');
|
console.log('getBlockHeader sent successfully');
|
||||||
console.log(result);
|
console.log(result);
|
||||||
document.getElementById('getBlockHeaderResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
|
document.getElementById('getBlockHeaderResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function lookupBlockHash(height, f) {
|
function isHash(str) {
|
||||||
|
var re = /[0-9A-Fa-f]{64}/g;
|
||||||
|
return re.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lookupBlockHash(heightOrHash, f) {
|
||||||
const method = 'getBlockHeader';
|
const method = 'getBlockHeader';
|
||||||
const params = [height];
|
const params = [heightOrHash];
|
||||||
return socket.send({ method, params }, f);
|
return socket.send({ method, params }, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
function estimateSmartFee() {
|
function estimateSmartFee() {
|
||||||
var blocks = document.getElementById('estimateSmartFeeBlocks').value;
|
var blocks = document.getElementById('estimateSmartFeeBlocks').value.trim();
|
||||||
var conservative = document.getElementById("estimateSmartFeeConservative").checked;
|
var conservative = document.getElementById("estimateSmartFeeConservative").checked;
|
||||||
estimateSmartTxFee(parseInt(blocks), conservative, function (result) {
|
estimateSmartTxFee(parseInt(blocks), conservative, function (result) {
|
||||||
console.log('estimateSmartFee sent successfully');
|
console.log('estimateSmartFee sent successfully');
|
||||||
@ -147,7 +154,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDetailedTransaction() {
|
function getDetailedTransaction() {
|
||||||
var hash = document.getElementById('getDetailedTransactionHash').value;
|
var hash = document.getElementById('getDetailedTransactionHash').value.trim();
|
||||||
lookupDetailedTransaction(hash, function (result) {
|
lookupDetailedTransaction(hash, function (result) {
|
||||||
console.log('getDetailedTransaction sent successfully');
|
console.log('getDetailedTransaction sent successfully');
|
||||||
console.log(result);
|
console.log(result);
|
||||||
@ -164,7 +171,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendTransaction() {
|
function sendTransaction() {
|
||||||
var tx = document.getElementById('sendTransactionHex').value;
|
var tx = document.getElementById('sendTransactionHex').value.trim();
|
||||||
sendTransactionF(tx, function (result) {
|
sendTransactionF(tx, function (result) {
|
||||||
console.log('sendTransaction sent successfully');
|
console.log('sendTransaction sent successfully');
|
||||||
console.log(result);
|
console.log(result);
|
||||||
@ -194,6 +201,7 @@
|
|||||||
|
|
||||||
function subscribeAddressTxid() {
|
function subscribeAddressTxid() {
|
||||||
var addresses = document.getElementById('subscribeAddressTxidAddresses').value.split(",");
|
var addresses = document.getElementById('subscribeAddressTxidAddresses').value.split(",");
|
||||||
|
addresses = addresses.map(s => s.trim());
|
||||||
socket.emit('subscribe', "bitcoind/addresstxid", addresses, function (result) {
|
socket.emit('subscribe', "bitcoind/addresstxid", addresses, function (result) {
|
||||||
console.log('subscribe bitcoind/addresstxid sent successfully');
|
console.log('subscribe bitcoind/addresstxid sent successfully');
|
||||||
console.log(result);
|
console.log(result);
|
||||||
@ -206,7 +214,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMempoolEntry() {
|
function getMempoolEntry() {
|
||||||
var hash = document.getElementById('getMempoolEntryHash').value;
|
var hash = document.getElementById('getMempoolEntryHash').value.trim();
|
||||||
lookupMempoolEntry(hash, function (result) {
|
lookupMempoolEntry(hash, function (result) {
|
||||||
console.log('getMempoolEntry sent successfully');
|
console.log('getMempoolEntry sent successfully');
|
||||||
console.log(result);
|
console.log(result);
|
||||||
@ -277,7 +285,7 @@
|
|||||||
<input class="btn btn-secondary" type="button" value="getBlockHeader" onclick="getBlockHeader()">
|
<input class="btn btn-secondary" type="button" value="getBlockHeader" onclick="getBlockHeader()">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<input type="text" class="form-control" id="getBlockHeaderHeight" value="0">
|
<input type="text" class="form-control" id="getBlockHeaderParam" value="0">
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user