2018-09-01 01:50:22 +02:00
|
|
|
package wallet
|
2018-09-01 01:50:09 +02:00
|
|
|
|
2019-12-28 19:32:41 +01:00
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/hex"
|
|
|
|
|
|
|
|
"github.com/lbryio/chainquery/lbrycrd"
|
2020-09-01 20:15:34 +02:00
|
|
|
"github.com/lbryio/lbry.go/v2/extras/errors"
|
|
|
|
"github.com/lbryio/lbry.go/v2/schema/claim"
|
2019-12-28 19:32:41 +01:00
|
|
|
types "github.com/lbryio/types/v2/go"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcutil"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/spf13/cast"
|
|
|
|
)
|
|
|
|
|
2020-03-30 21:57:53 +02:00
|
|
|
// Raw makes a raw wallet server request
|
|
|
|
func (n *Node) Raw(method string, params []string, v interface{}) error {
|
|
|
|
return n.request(method, params, v)
|
|
|
|
}
|
|
|
|
|
2018-09-01 01:50:09 +02:00
|
|
|
// ServerVersion returns the server's version.
|
|
|
|
// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-version
|
|
|
|
func (n *Node) ServerVersion() (string, error) {
|
|
|
|
resp := &struct {
|
|
|
|
Result []string `json:"result"`
|
|
|
|
}{}
|
|
|
|
err := n.request("server.version", []string{"reflector.go", ProtocolVersion}, resp)
|
|
|
|
|
|
|
|
var v string
|
|
|
|
if len(resp.Result) >= 2 {
|
|
|
|
v = resp.Result[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return v, err
|
|
|
|
}
|
|
|
|
|
2019-12-28 19:32:41 +01:00
|
|
|
func (n *Node) Resolve(url string) (*types.Output, error) {
|
|
|
|
outputs := &types.Outputs{}
|
|
|
|
resp := &struct {
|
|
|
|
Result string `json:"result"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
err := n.request("blockchain.claimtrie.resolve", []string{url}, resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := base64.StdEncoding.DecodeString(resp.Result)
|
|
|
|
if err != nil {
|
2020-02-26 16:02:53 +01:00
|
|
|
return nil, errors.Err(err)
|
2019-12-28 19:32:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
err = proto.Unmarshal(b, outputs)
|
|
|
|
if err != nil {
|
2020-02-26 16:02:53 +01:00
|
|
|
return nil, errors.Err(err)
|
2019-12-28 19:32:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(outputs.GetTxos()) != 1 {
|
|
|
|
return nil, errors.Err("expected 1 output, got " + cast.ToString(len(outputs.GetTxos())))
|
|
|
|
}
|
|
|
|
|
|
|
|
if e := outputs.GetTxos()[0].GetError(); e != nil {
|
|
|
|
return nil, errors.Err("%s: %s", e.GetCode(), e.GetText())
|
|
|
|
}
|
|
|
|
|
|
|
|
return outputs.GetTxos()[0], nil
|
|
|
|
}
|
|
|
|
|
2018-09-01 01:50:09 +02:00
|
|
|
type GetClaimsInTxResp struct {
|
|
|
|
Jsonrpc string `json:"jsonrpc"`
|
|
|
|
ID int `json:"id"`
|
|
|
|
Result []struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
ClaimID string `json:"claim_id"`
|
|
|
|
Txid string `json:"txid"`
|
|
|
|
Nout int `json:"nout"`
|
|
|
|
Amount int `json:"amount"`
|
|
|
|
Depth int `json:"depth"`
|
|
|
|
Height int `json:"height"`
|
|
|
|
Value string `json:"value"`
|
|
|
|
ClaimSequence int `json:"claim_sequence"`
|
|
|
|
Address string `json:"address"`
|
|
|
|
Supports []interface{} `json:"supports"` // TODO: finish me
|
|
|
|
EffectiveAmount int `json:"effective_amount"`
|
|
|
|
ValidAtHeight int `json:"valid_at_height"`
|
|
|
|
} `json:"result"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) GetClaimsInTx(txid string) (*GetClaimsInTxResp, error) {
|
|
|
|
var resp GetClaimsInTxResp
|
|
|
|
err := n.request("blockchain.claimtrie.getclaimsintx", []string{txid}, &resp)
|
|
|
|
return &resp, err
|
|
|
|
}
|
2019-12-28 19:32:41 +01:00
|
|
|
|
|
|
|
func (n *Node) GetTx(txid string) (string, error) {
|
|
|
|
resp := &struct {
|
|
|
|
Result string `json:"result"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
err := n.request("blockchain.transaction.get", []string{txid}, resp)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp.Result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) GetClaimInTx(txid string, nout int) (*types.Claim, error) {
|
|
|
|
hexTx, err := n.GetTx(txid)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Err(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
rawTx, err := hex.DecodeString(hexTx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Err(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := btcutil.NewTxFromBytes(rawTx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Err(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tx.MsgTx().TxOut) <= nout {
|
|
|
|
return nil, errors.Err("nout not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
script := tx.MsgTx().TxOut[nout].PkScript
|
|
|
|
|
|
|
|
var value []byte
|
|
|
|
if lbrycrd.IsClaimNameScript(script) {
|
|
|
|
_, value, _, err = lbrycrd.ParseClaimNameScript(script)
|
|
|
|
} else if lbrycrd.IsClaimUpdateScript(script) {
|
|
|
|
_, _, value, _, err = lbrycrd.ParseClaimUpdateScript(script)
|
|
|
|
} else {
|
|
|
|
err = errors.Err("no claim found in output")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Err(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ch, err := claim.DecodeClaimBytes(value, "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Err(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ch.Claim, nil
|
|
|
|
}
|