Implement Bitcore socket.io method estimateSmartFee

pull/1/head
Martin Boehm 2018-02-07 19:59:09 +01:00
parent 8c9dfc3ef4
commit bcc8de4763
3 changed files with 141 additions and 13 deletions

View File

@ -132,6 +132,24 @@ type resGetRawTransactionVerbose struct {
Result Tx `json:"result"`
}
// estimatesmartfee
type cmdEstimateSmartFee struct {
Method string `json:"method"`
Params struct {
ConfTarget int `json:"conf_target"`
EstimateMode string `json:"estimate_mode"`
} `json:"params"`
}
type resEstimateSmartFee struct {
Error *RPCError `json:"error"`
Result struct {
Feerate float64 `json:"feerate"`
Blocks int `json:"blocks"`
} `json:"result"`
}
type BlockParser interface {
ParseBlock(b []byte) (*Block, error)
}
@ -355,6 +373,29 @@ func (b *BitcoinRPC) GetTransaction(txid string) (*Tx, error) {
return &res.Result, nil
}
// EstimateSmartFee returns fee estimation.
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
glog.V(1).Info("rpc: estimatesmartfee ", blocks)
res := resEstimateSmartFee{}
req := cmdEstimateSmartFee{Method: "estimatesmartfee"}
req.Params.ConfTarget = blocks
if conservative {
req.Params.EstimateMode = "CONSERVATIVE"
} else {
req.Params.EstimateMode = "ECONOMICAL"
}
err := b.call(&req, &res)
if err != nil {
return 0, err
}
if res.Error != nil {
return 0, res.Error
}
return res.Result.Feerate, nil
}
func (b *BitcoinRPC) call(req interface{}, res interface{}) error {
httpData, err := json.Marshal(req)
if err != nil {

View File

@ -103,21 +103,38 @@ type reqRange struct {
To int `json:"to"`
}
var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (interface{}, error){
"\"getAddressTxids\"": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
addr, rr, err := unmarshalGetAddressTxids(params)
if err == nil {
rv, err = s.getAddressTxids(addr, &rr)
}
return
},
"\"getBlockHeader\"": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
height, hash, err := unmarshalGetBlockHeader(params)
if err == nil {
rv, err = s.getBlockHeader(height, hash)
}
return
},
"\"estimateSmartFee\"": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
blocks, conservative, err := unmarshalEstimateSmartFee(params)
if err == nil {
rv, err = s.estimateSmartFee(blocks, conservative)
}
return
},
}
func (s *SocketIoServer) onMessage(c *gosocketio.Channel, req map[string]json.RawMessage) interface{} {
var err error
var rv interface{}
method := string(req["method"])
params := req["params"]
if method == "\"getAddressTxids\"" {
addr, rr, err := unmarshalGetAddressTxids(params)
if err == nil {
rv, err = s.getAddressTxids(addr, &rr)
}
} else if method == "\"getBlockHeader\"" {
height, hash, err := unmarshalGetBlockHeader(params)
if err == nil {
rv, err = s.getBlockHeader(height, hash)
}
f, ok := onMessageHandlers[method]
if ok {
rv, err = f(s, params)
} else {
err = errors.New("unknown method")
}
@ -184,16 +201,23 @@ func (s *SocketIoServer) getAddressTxids(addr []string, rr *reqRange) ([]string,
return txids, nil
}
func unmarshalGetBlockHeader(params []byte) (height uint32, hash string, err error) {
var p []interface{}
func unmarshalArray(params []byte, np int) (p []interface{}, err error) {
err = json.Unmarshal(params, &p)
if err != nil {
return
}
if len(p) != 1 {
if len(p) != np {
err = errors.New("incorrect number of parameters")
return
}
return
}
func unmarshalGetBlockHeader(params []byte) (height uint32, hash string, err error) {
p, err := unmarshalArray(params, 1)
if err != nil {
return
}
fheight, ok := p[0].(float64)
if ok {
return uint32(fheight), "", nil
@ -248,6 +272,38 @@ func (s *SocketIoServer) getBlockHeader(height uint32, hash string) (res resultG
return
}
func unmarshalEstimateSmartFee(params []byte) (blocks int, conservative bool, err error) {
p, err := unmarshalArray(params, 2)
if err != nil {
return
}
fblocks, ok := p[0].(float64)
if !ok {
err = errors.New("Invalid parameter blocks")
return
}
blocks = int(fblocks)
conservative, ok = p[1].(bool)
if !ok {
err = errors.New("Invalid parameter conservative")
return
}
return
}
type resultEstimateSmartFee struct {
Result float64 `json:"result"`
}
func (s *SocketIoServer) estimateSmartFee(blocks int, conservative bool) (res resultEstimateSmartFee, err error) {
fee, err := s.chain.EstimateSmartFee(blocks, conservative)
if err != nil {
return
}
res.Result = fee
return
}
func (s *SocketIoServer) onSubscribe(c *gosocketio.Channel, req map[string]json.RawMessage) interface{} {
glog.Info(c.Id(), " onSubscribe ", req)
return nil

View File

@ -66,6 +66,21 @@
return socket.send({ method, params }, f);
}
function estimateSmartFee() {
var blocks = document.getElementById('estimateSmartFeeBlocks').value;
var conservative = document.getElementById("estimateSmartFeeConservative").checked;
estimateSmartTxFee(parseInt(blocks), conservative, function (result) {
console.log('estimateSmartFee sent successfully');
console.log(result);
document.getElementById('estimateSmartFeeResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
});
}
function estimateSmartTxFee(blocks, conservative, f) {
const method = 'estimateSmartFee';
const params = [blocks, conservative];
return socket.send({ method, params }, f);
}
</script>
</head>
@ -115,6 +130,22 @@
<div class="col" id="getBlockHeaderResult">
</div>
</div>
<div class="row">
<div class="col">
<input class="btn btn-secondary" type="button" value="estimateSmartFee" onclick="estimateSmartFee()">
</div>
<div class="col-8">
<input type="text" class="form-control" id="estimateSmartFeeBlocks" value="20">
</div>
<div class="col form-inline">
<input type="checkbox" id="estimateSmartFeeConservative" checked>&nbsp;
<label>conservative</label>
</div>
</div>
<div class="row">
<div class="col" id="estimateSmartFeeResult">
</div>
</div>
</div>
</div>
</body>