[lbry] rpc: support claim related methods
This commit is contained in:
parent
0c5f94420a
commit
6834591d52
7 changed files with 553 additions and 3 deletions
|
@ -298,6 +298,8 @@ type GetBlockTemplateResult struct {
|
||||||
// Block proposal from BIP 0023.
|
// Block proposal from BIP 0023.
|
||||||
Capabilities []string `json:"capabilities,omitempty"`
|
Capabilities []string `json:"capabilities,omitempty"`
|
||||||
RejectReasion string `json:"reject-reason,omitempty"`
|
RejectReasion string `json:"reject-reason,omitempty"`
|
||||||
|
|
||||||
|
ClaimTrieHash string `json:"claimtrie"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntryResult models the data returned from the getmempoolentry's
|
// GetMempoolEntryResult models the data returned from the getmempoolentry's
|
||||||
|
@ -430,6 +432,9 @@ type ScriptPubKeyResult struct {
|
||||||
Hex string `json:"hex,omitempty"`
|
Hex string `json:"hex,omitempty"`
|
||||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
SubType string `json:"subtype"`
|
||||||
|
IsClaim bool `json:"isclaim"`
|
||||||
|
IsSupport bool `json:"issupport"`
|
||||||
Addresses []string `json:"addresses,omitempty"`
|
Addresses []string `json:"addresses,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,6 +593,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
||||||
type PrevOut struct {
|
type PrevOut struct {
|
||||||
Addresses []string `json:"addresses,omitempty"`
|
Addresses []string `json:"addresses,omitempty"`
|
||||||
Value float64 `json:"value"`
|
Value float64 `json:"value"`
|
||||||
|
IsClaim bool `json:"isclaim"`
|
||||||
|
IsSupport bool `json:"issupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
||||||
|
|
|
@ -70,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
|
||||||
},
|
},
|
||||||
Sequence: 4294967295,
|
Sequence: 4294967295,
|
||||||
},
|
},
|
||||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
|
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
97
btcjson/claimcmds.go
Normal file
97
btcjson/claimcmds.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package btcjson
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// No special flags for commands in this file.
|
||||||
|
flags := UsageFlag(0)
|
||||||
|
|
||||||
|
MustRegisterCmd("getchangesinblock", (*GetChangesInBlockCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getclaimsforname", (*GetClaimsForNameCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getclaimsfornamebyid", (*GetClaimsForNameByIDCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
|
||||||
|
// optional inputs have to be at the bottom of the struct
|
||||||
|
// optional outputs require ",omitempty"
|
||||||
|
// traditional bitcoin fields are all lowercase
|
||||||
|
|
||||||
|
type GetChangesInBlockCmd struct {
|
||||||
|
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetChangesInBlockResult struct {
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Height int32 `json:"height"`
|
||||||
|
Names []string `json:"names"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetClaimsForNameCmd struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||||
|
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetClaimsForNameByIDCmd struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
PartialClaimIDs []string `json:"partialclaimids"`
|
||||||
|
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||||
|
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetClaimsForNameByBidCmd struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Bids []int32 `json:"bids"`
|
||||||
|
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||||
|
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetClaimsForNameBySeqCmd struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Sequences []int32 `json:"sequences" jsonrpcusage:"[sequence,...]"`
|
||||||
|
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||||
|
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetClaimsForNameResult struct {
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Height int32 `json:"height"`
|
||||||
|
LastTakeoverHeight int32 `json:"lasttakeoverheight"`
|
||||||
|
NormalizedName string `json:"normalizedname"`
|
||||||
|
Claims []ClaimResult `json:"claims"`
|
||||||
|
// UnclaimedSupports []SupportResult `json:"supportswithoutclaim"` how would this work with other constraints?
|
||||||
|
}
|
||||||
|
|
||||||
|
type SupportResult struct {
|
||||||
|
TXID string `json:"txid"`
|
||||||
|
N uint32 `json:"n"`
|
||||||
|
Height int32 `json:"height"`
|
||||||
|
ValidAtHeight int32 `json:"validatheight"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Address string `json:"address,omitempty"`
|
||||||
|
Value string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClaimResult struct {
|
||||||
|
ClaimID string `json:"claimid"`
|
||||||
|
TXID string `json:"txid"`
|
||||||
|
N uint32 `json:"n"`
|
||||||
|
Bid int32 `json:"bid"`
|
||||||
|
Sequence int32 `json:"sequence"`
|
||||||
|
Height int32 `json:"height"`
|
||||||
|
ValidAtHeight int32 `json:"validatheight"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
EffectiveAmount int64 `json:"effectiveamount"`
|
||||||
|
Supports []SupportResult `json:"supports,omitempty"`
|
||||||
|
Address string `json:"address,omitempty"`
|
||||||
|
Value string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetNormalizedCmd struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetNormalizedResult struct {
|
||||||
|
NormalizedName string `json:"normalizedname"`
|
||||||
|
}
|
|
@ -547,6 +547,12 @@ func GenerateHelp(method string, descs map[string]string, resultTypes ...interfa
|
||||||
return desc
|
return desc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(key, "base-") {
|
||||||
|
if desc, ok := descs[strings.ReplaceAll(key, "base-", "-")]; ok {
|
||||||
|
return desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
missingKey = key
|
missingKey = key
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,8 +226,12 @@ func NewResponse(rpcVersion RPCVersion, id interface{}, marshalledResult []byte,
|
||||||
// JSON-RPC client.
|
// JSON-RPC client.
|
||||||
func MarshalResponse(rpcVersion RPCVersion, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) {
|
func MarshalResponse(rpcVersion RPCVersion, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) {
|
||||||
if !rpcVersion.IsValid() {
|
if !rpcVersion.IsValid() {
|
||||||
str := fmt.Sprintf("rpcversion '%s' is invalid", rpcVersion)
|
if rpcVersion == "" {
|
||||||
return nil, makeError(ErrInvalidType, str)
|
rpcVersion = RpcVersion1
|
||||||
|
} else {
|
||||||
|
str := fmt.Sprintf("rpcversion '%s' is unsupported", rpcVersion)
|
||||||
|
return nil, makeError(ErrInvalidType, str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
marshalledResult, err := json.Marshal(result)
|
marshalledResult, err := json.Marshal(result)
|
||||||
|
|
352
rpcclaimtrie.go
Normal file
352
rpcclaimtrie.go
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
|
"github.com/lbryio/lbcd/claimtrie/node"
|
||||||
|
"github.com/lbryio/lbcd/claimtrie/normalization"
|
||||||
|
"github.com/lbryio/lbcd/database"
|
||||||
|
"github.com/lbryio/lbcd/txscript"
|
||||||
|
"github.com/lbryio/lbcd/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var claimtrieHandlers = map[string]commandHandler{
|
||||||
|
"getchangesinblock": handleGetChangesInBlock,
|
||||||
|
"getclaimsforname": handleGetClaimsForName,
|
||||||
|
"getclaimsfornamebyid": handleGetClaimsForNameByID,
|
||||||
|
"getclaimsfornamebybid": handleGetClaimsForNameByBid,
|
||||||
|
"getclaimsfornamebyseq": handleGetClaimsForNameBySeq,
|
||||||
|
"normalize": handleGetNormalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetChangesInBlock(s *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
|
||||||
|
c := cmd.(*btcjson.GetChangesInBlockCmd)
|
||||||
|
hash, height, err := parseHashOrHeight(s, c.HashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
names, err := s.cfg.Chain.GetNamesChangedInBlock(height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCMisc,
|
||||||
|
Message: "Message: " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return btcjson.GetChangesInBlockResult{
|
||||||
|
Hash: hash,
|
||||||
|
Height: height,
|
||||||
|
Names: names,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHashOrHeight(s *rpcServer, hashOrHeight *string) (string, int32, error) {
|
||||||
|
if hashOrHeight == nil || len(*hashOrHeight) == 0 {
|
||||||
|
|
||||||
|
if !s.cfg.Chain.IsCurrent() {
|
||||||
|
return "", 0, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCClientInInitialDownload,
|
||||||
|
Message: "Unable to query the chain tip during initial download",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just give them the latest block if a specific one wasn't requested
|
||||||
|
best := s.cfg.Chain.BestSnapshot()
|
||||||
|
return best.Hash.String(), best.Height, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ht, err := strconv.ParseInt(*hashOrHeight, 10, 32)
|
||||||
|
if err == nil && len(*hashOrHeight) < 32 {
|
||||||
|
hs, err := s.cfg.Chain.BlockHashByHeight(int32(ht))
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCBlockNotFound,
|
||||||
|
Message: "Unable to locate a block at height " + *hashOrHeight + ": " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hs.String(), int32(ht), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hs, err := chainhash.NewHashFromStr(*hashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCInvalidParameter,
|
||||||
|
Message: "Unable to parse a height or hash from " + *hashOrHeight + ": " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h, err := s.cfg.Chain.BlockHeightByHash(hs)
|
||||||
|
if err != nil {
|
||||||
|
return hs.String(), h, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCBlockNotFound,
|
||||||
|
Message: "Unable to find a block with hash " + hs.String() + ": " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hs.String(), h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetClaimsForName(s *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
|
||||||
|
c := cmd.(*btcjson.GetClaimsForNameCmd)
|
||||||
|
hash, height, err := parseHashOrHeight(s, c.HashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, n, err := s.cfg.Chain.GetClaimsForName(height, c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCMisc,
|
||||||
|
Message: "Message: " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []btcjson.ClaimResult
|
||||||
|
for i := range n.Claims {
|
||||||
|
cr, err := toClaimResult(s, int32(i), n, c.IncludeValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results = append(results, cr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return btcjson.GetClaimsForNameResult{
|
||||||
|
Hash: hash,
|
||||||
|
Height: height,
|
||||||
|
LastTakeoverHeight: n.TakenOverAt,
|
||||||
|
NormalizedName: name,
|
||||||
|
Claims: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetClaimsForNameByID(s *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
|
||||||
|
c := cmd.(*btcjson.GetClaimsForNameByIDCmd)
|
||||||
|
hash, height, err := parseHashOrHeight(s, c.HashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, n, err := s.cfg.Chain.GetClaimsForName(height, c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCMisc,
|
||||||
|
Message: "Message: " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []btcjson.ClaimResult
|
||||||
|
for i := 0; i < len(n.Claims); i++ {
|
||||||
|
for _, id := range c.PartialClaimIDs {
|
||||||
|
if strings.HasPrefix(n.Claims[i].ClaimID.String(), id) {
|
||||||
|
cr, err := toClaimResult(s, int32(i), n, c.IncludeValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results = append(results, cr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return btcjson.GetClaimsForNameResult{
|
||||||
|
Hash: hash,
|
||||||
|
Height: height,
|
||||||
|
LastTakeoverHeight: n.TakenOverAt,
|
||||||
|
NormalizedName: name,
|
||||||
|
Claims: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetClaimsForNameByBid(s *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
|
||||||
|
c := cmd.(*btcjson.GetClaimsForNameByBidCmd)
|
||||||
|
hash, height, err := parseHashOrHeight(s, c.HashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, n, err := s.cfg.Chain.GetClaimsForName(height, c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCMisc,
|
||||||
|
Message: "Message: " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []btcjson.ClaimResult
|
||||||
|
for _, b := range c.Bids { // claims are already sorted in bid order
|
||||||
|
if b >= 0 && int(b) < len(n.Claims) {
|
||||||
|
cr, err := toClaimResult(s, b, n, c.IncludeValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results = append(results, cr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return btcjson.GetClaimsForNameResult{
|
||||||
|
Hash: hash,
|
||||||
|
Height: height,
|
||||||
|
LastTakeoverHeight: n.TakenOverAt,
|
||||||
|
NormalizedName: name,
|
||||||
|
Claims: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetClaimsForNameBySeq(s *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
|
||||||
|
c := cmd.(*btcjson.GetClaimsForNameBySeqCmd)
|
||||||
|
hash, height, err := parseHashOrHeight(s, c.HashOrHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, n, err := s.cfg.Chain.GetClaimsForName(height, c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCMisc,
|
||||||
|
Message: "Message: " + err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sm := map[int32]bool{}
|
||||||
|
for _, seq := range c.Sequences {
|
||||||
|
sm[seq] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []btcjson.ClaimResult
|
||||||
|
for i := 0; i < len(n.Claims); i++ {
|
||||||
|
if sm[n.Claims[i].Sequence] {
|
||||||
|
cr, err := toClaimResult(s, int32(i), n, c.IncludeValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results = append(results, cr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return btcjson.GetClaimsForNameResult{
|
||||||
|
Hash: hash,
|
||||||
|
Height: height,
|
||||||
|
LastTakeoverHeight: n.TakenOverAt,
|
||||||
|
NormalizedName: name,
|
||||||
|
Claims: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toClaimResult(s *rpcServer, i int32, n *node.Node, includeValues *bool) (btcjson.ClaimResult, error) {
|
||||||
|
claim := n.Claims[i]
|
||||||
|
address, value, err := lookupValue(s, claim.OutPoint, includeValues)
|
||||||
|
supports, err := toSupportResults(s, i, n, includeValues)
|
||||||
|
effectiveAmount := n.SupportSums[claim.ClaimID.Key()] // should only be active supports
|
||||||
|
if claim.Status == node.Activated {
|
||||||
|
effectiveAmount += claim.Amount
|
||||||
|
}
|
||||||
|
return btcjson.ClaimResult{
|
||||||
|
ClaimID: claim.ClaimID.String(),
|
||||||
|
Height: claim.AcceptedAt,
|
||||||
|
ValidAtHeight: claim.ActiveAt,
|
||||||
|
TXID: claim.OutPoint.Hash.String(),
|
||||||
|
N: claim.OutPoint.Index,
|
||||||
|
Bid: i, // assuming sorted by bid
|
||||||
|
Amount: claim.Amount,
|
||||||
|
EffectiveAmount: effectiveAmount,
|
||||||
|
Sequence: claim.Sequence,
|
||||||
|
Supports: supports,
|
||||||
|
Address: address,
|
||||||
|
Value: value,
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func toSupportResults(s *rpcServer, i int32, n *node.Node, includeValues *bool) ([]btcjson.SupportResult, error) {
|
||||||
|
var results []btcjson.SupportResult
|
||||||
|
c := n.Claims[i]
|
||||||
|
for _, sup := range n.Supports {
|
||||||
|
if sup.Status == node.Activated && c.ClaimID == sup.ClaimID {
|
||||||
|
address, value, err := lookupValue(s, sup.OutPoint, includeValues)
|
||||||
|
if err != nil {
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
results = append(results, btcjson.SupportResult{
|
||||||
|
TXID: sup.OutPoint.Hash.String(),
|
||||||
|
N: sup.OutPoint.Index,
|
||||||
|
Height: sup.AcceptedAt,
|
||||||
|
ValidAtHeight: sup.ActiveAt,
|
||||||
|
Amount: sup.Amount,
|
||||||
|
Value: value,
|
||||||
|
Address: address,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupValue(s *rpcServer, outpoint wire.OutPoint, includeValues *bool) (string, string, error) {
|
||||||
|
if includeValues == nil || !*includeValues {
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
// TODO: maybe use addrIndex if the txIndex is not available
|
||||||
|
|
||||||
|
if s.cfg.TxIndex == nil {
|
||||||
|
return "", "", &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCNoTxInfo,
|
||||||
|
Message: "The transaction index must be " +
|
||||||
|
"enabled to query the blockchain " +
|
||||||
|
"(specify --txindex)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash := &outpoint.Hash
|
||||||
|
blockRegion, err := s.cfg.TxIndex.TxBlockRegion(txHash)
|
||||||
|
if err != nil {
|
||||||
|
context := "Failed to retrieve transaction location"
|
||||||
|
return "", "", internalRPCError(err.Error(), context)
|
||||||
|
}
|
||||||
|
if blockRegion == nil {
|
||||||
|
return "", "", rpcNoTxInfoError(txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the raw transaction bytes from the database.
|
||||||
|
var txBytes []byte
|
||||||
|
err = s.cfg.DB.View(func(dbTx database.Tx) error {
|
||||||
|
var err error
|
||||||
|
txBytes, err = dbTx.FetchBlockRegion(blockRegion)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", "", rpcNoTxInfoError(txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize the transaction
|
||||||
|
var msgTx wire.MsgTx
|
||||||
|
err = msgTx.Deserialize(bytes.NewReader(txBytes))
|
||||||
|
if err != nil {
|
||||||
|
context := "Failed to deserialize transaction"
|
||||||
|
return "", "", internalRPCError(err.Error(), context)
|
||||||
|
}
|
||||||
|
|
||||||
|
txo := msgTx.TxOut[outpoint.Index]
|
||||||
|
cs, err := txscript.ExtractClaimScript(txo.PkScript)
|
||||||
|
if err != nil {
|
||||||
|
context := "Failed to decode the claim script"
|
||||||
|
return "", "", internalRPCError(err.Error(), context)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, addresses, _, _ := txscript.ExtractPkScriptAddrs(txo.PkScript[cs.Size:], s.cfg.ChainParams)
|
||||||
|
return addresses[0].EncodeAddress(), hex.EncodeToString(cs.Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetNormalized(_ *rpcServer, cmd interface{}, _ <-chan struct{}) (interface{}, error) {
|
||||||
|
c := cmd.(*btcjson.GetNormalizedCmd)
|
||||||
|
r := btcjson.GetNormalizedResult{
|
||||||
|
NormalizedName: string(normalization.Normalize([]byte(c.Name))),
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
|
@ -247,6 +247,7 @@ var helpDescsEnUS = map[string]string{
|
||||||
"getblockverboseresult-version": "The block version",
|
"getblockverboseresult-version": "The block version",
|
||||||
"getblockverboseresult-versionHex": "The block version in hexadecimal",
|
"getblockverboseresult-versionHex": "The block version in hexadecimal",
|
||||||
"getblockverboseresult-merkleroot": "Root hash of the merkle tree",
|
"getblockverboseresult-merkleroot": "Root hash of the merkle tree",
|
||||||
|
"getblockverboseresult-nameclaimroot": "Root hash of the claim trie",
|
||||||
"getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)",
|
"getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)",
|
||||||
"getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosity=2)",
|
"getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosity=2)",
|
||||||
"getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT",
|
"getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT",
|
||||||
|
@ -288,6 +289,7 @@ var helpDescsEnUS = map[string]string{
|
||||||
"getblockheaderverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty",
|
"getblockheaderverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty",
|
||||||
"getblockheaderverboseresult-previousblockhash": "The hash of the previous block",
|
"getblockheaderverboseresult-previousblockhash": "The hash of the previous block",
|
||||||
"getblockheaderverboseresult-nextblockhash": "The hash of the next block (only if there is one)",
|
"getblockheaderverboseresult-nextblockhash": "The hash of the next block (only if there is one)",
|
||||||
|
"getblockheaderverboseresult-nameclaimroot": "The hash of the root of the claim trie",
|
||||||
|
|
||||||
// TemplateRequest help.
|
// TemplateRequest help.
|
||||||
"templaterequest-mode": "This is 'template', 'proposal', or omitted",
|
"templaterequest-mode": "This is 'template', 'proposal', or omitted",
|
||||||
|
@ -339,6 +341,8 @@ var helpDescsEnUS = map[string]string{
|
||||||
"getblocktemplateresult-reject-reason": "Reason the proposal was invalid as-is (only applies to proposal responses)",
|
"getblocktemplateresult-reject-reason": "Reason the proposal was invalid as-is (only applies to proposal responses)",
|
||||||
"getblocktemplateresult-default_witness_commitment": "The witness commitment itself. Will be populated if the block has witness data",
|
"getblocktemplateresult-default_witness_commitment": "The witness commitment itself. Will be populated if the block has witness data",
|
||||||
"getblocktemplateresult-weightlimit": "The current limit on the max allowed weight of a block",
|
"getblocktemplateresult-weightlimit": "The current limit on the max allowed weight of a block",
|
||||||
|
"getblocktemplateresult-rules": "Rules that are required to process the output",
|
||||||
|
"getblocktemplateresult-claimtrie": "The hash of the root of the claim trie - a necessary block header",
|
||||||
|
|
||||||
// GetBlockTemplateCmd help.
|
// GetBlockTemplateCmd help.
|
||||||
"getblocktemplate--synopsis": "Returns a JSON object with information necessary to construct a block to mine or accepts a proposal to validate.\n" +
|
"getblocktemplate--synopsis": "Returns a JSON object with information necessary to construct a block to mine or accepts a proposal to validate.\n" +
|
||||||
|
@ -708,6 +712,78 @@ var helpDescsEnUS = map[string]string{
|
||||||
"versionresult-patch": "The patch component of the JSON-RPC API version",
|
"versionresult-patch": "The patch component of the JSON-RPC API version",
|
||||||
"versionresult-prerelease": "Prerelease info about the current build",
|
"versionresult-prerelease": "Prerelease info about the current build",
|
||||||
"versionresult-buildmetadata": "Metadata about the current build",
|
"versionresult-buildmetadata": "Metadata about the current build",
|
||||||
|
|
||||||
|
"getclaimsforname--synopsis": "Look up claims for the given name as they stand at a give block",
|
||||||
|
"getclaimsfornamebyid--synopsis": "Look up claims for the given name as they stand at a give block",
|
||||||
|
"getclaimsfornamebybid--synopsis": "Look up claims for the given name as they stand at a give block",
|
||||||
|
"getclaimsfornamebyseq--synopsis": "Look up claims for the given name as they stand at a give block",
|
||||||
|
|
||||||
|
"getclaimsforname-hashorheight": "Requested block hash or height; default to tip",
|
||||||
|
"getclaimsfornamebyid-hashorheight": "Requested block hash or height; default to tip",
|
||||||
|
"getclaimsfornamebybid-hashorheight": "Requested block hash or height; default to tip",
|
||||||
|
"getclaimsfornamebyseq-hashorheight": "Requested block hash or height; default to tip",
|
||||||
|
|
||||||
|
"getclaimsforname-name": "Requested name for lookup",
|
||||||
|
"getclaimsfornamebyid-name": "Requested name for lookup",
|
||||||
|
"getclaimsfornamebybid-name": "Requested name for lookup",
|
||||||
|
"getclaimsfornamebyseq-name": "Requested name for lookup",
|
||||||
|
|
||||||
|
"getclaimsfornamebyid-partialclaimids": "Limit the returned claims to those with matching (partial) claimIDs in this list",
|
||||||
|
"getclaimsfornamebybid-bids": "Limit the returned claims to those with bids to this list",
|
||||||
|
"getclaimsfornamebyseq-sequences": "Limit the returned claims to those with bids to this list",
|
||||||
|
|
||||||
|
"getclaimsforname-includevalues": "Return the metadata and address",
|
||||||
|
"getclaimsfornamebyseq-includevalues": "Return the metadata and address",
|
||||||
|
"getclaimsfornamebybid-includevalues": "Return the metadata and address",
|
||||||
|
"getclaimsfornamebyid-includevalues": "Return the metadata and address",
|
||||||
|
|
||||||
|
"getclaimsfornameresult-claims": "All the active claims on the given name",
|
||||||
|
"getclaimsfornameresult-normalizedname": "Lower-case version of the passed-in name",
|
||||||
|
"getclaimsfornameresult-height": "Height of the requested block",
|
||||||
|
"getclaimsfornameresult-lasttakeoverheight": "Height of the most recent name takeover",
|
||||||
|
"getclaimsfornameresult-hash": "Hash of the requested block",
|
||||||
|
|
||||||
|
"getchangesinblock--synopsis": "Returns a list of names affected by a given block",
|
||||||
|
"getchangesinblockresult-names": "Names that changed (or were at least checked for change) on the given height",
|
||||||
|
"getchangesinblockresult-height": "Height that was requested",
|
||||||
|
"getchangesinblockresult-hash": "Hash of the block at the height requested",
|
||||||
|
|
||||||
|
"scriptpubkeyresult-subtype": "Claims return Non-standard address types, but they use standard address types internally exposed here",
|
||||||
|
|
||||||
|
"supportresult-value": "This is the metadata given as part of the support",
|
||||||
|
"supportresult-txid": "The hash of the transaction",
|
||||||
|
"supportresult-n": "The output (TXO) index",
|
||||||
|
"supportresult-address": "The destination address for the support",
|
||||||
|
"supportresult-amount": "LBC staked",
|
||||||
|
"supportresult-height": "The height when the stake was created or updated",
|
||||||
|
"supportresult-validatheight": "The height when the stake becomes valid",
|
||||||
|
"claimresult-value": "This is the metadata given as part of the claim",
|
||||||
|
"claimresult-txid": "The hash of the transaction",
|
||||||
|
"claimresult-n": "The output (TXO) index",
|
||||||
|
"claimresult-address": "The destination address for the claim",
|
||||||
|
"claimresult-supports": "The list of supports active on the claim",
|
||||||
|
"claimresult-validatheight": "The height when the stake becomes valid",
|
||||||
|
"claimresult-height": "The height when the stake was created or updated",
|
||||||
|
"claimresult-amount": "The stake amount in sats",
|
||||||
|
"claimresult-effectiveamount": "The stake amount plus the active supports' amounts",
|
||||||
|
"claimresult-sequence": "The order this claim was created compared to other claims on this name",
|
||||||
|
"claimresult-bid": "Bid of 0 means that this claim currently owns the name",
|
||||||
|
"claimresult-claimid": "20-byte hash of TXID:N, often used in indexes for the claims",
|
||||||
|
|
||||||
|
"generatetoaddress--synopsis": "Mine blocks and send their reward to a given address",
|
||||||
|
"generatetoaddress--result0": "The list of generated blocks' hashes",
|
||||||
|
"generatetoaddress-maxtries": "The maximum number of hashes to attempt",
|
||||||
|
"generatetoaddress-address": "The destination -- the place where the LBC will be sent",
|
||||||
|
"generatetoaddress-numblocks": "The number of blocks to mine",
|
||||||
|
"getchangesinblock-hashorheight": "The requested height or block hash whose changes are of interest",
|
||||||
|
|
||||||
|
"normalize--synopsis": "Used to show how lbcd will normalize a string",
|
||||||
|
"normalize--result0": "The normalized name",
|
||||||
|
"normalize-name": "The string to be normalized",
|
||||||
|
|
||||||
|
"getblockverboseresult-getblockverboseresultbase": "",
|
||||||
|
"prevout-issupport": "Previous output created a support",
|
||||||
|
"prevout-isclaim": "Previous output created or updated a claim",
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpcResultTypes specifies the result types that each RPC command can return.
|
// rpcResultTypes specifies the result types that each RPC command can return.
|
||||||
|
@ -776,6 +852,14 @@ var rpcResultTypes = map[string][]interface{}{
|
||||||
"stopnotifyspent": nil,
|
"stopnotifyspent": nil,
|
||||||
"rescan": nil,
|
"rescan": nil,
|
||||||
"rescanblocks": {(*[]btcjson.RescannedBlock)(nil)},
|
"rescanblocks": {(*[]btcjson.RescannedBlock)(nil)},
|
||||||
|
|
||||||
|
// ClaimTrie
|
||||||
|
"getclaimsforname": {(*btcjson.GetClaimsForNameResult)(nil)},
|
||||||
|
"getclaimsfornamebyid": {(*btcjson.GetClaimsForNameResult)(nil)},
|
||||||
|
"getclaimsfornamebybid": {(*btcjson.GetClaimsForNameResult)(nil)},
|
||||||
|
"getclaimsfornamebyseq": {(*btcjson.GetClaimsForNameResult)(nil)},
|
||||||
|
"normalize": {(*string)(nil)},
|
||||||
|
"getchangesinblock": {(*btcjson.GetChangesInBlockResult)(nil)},
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpCacher provides a concurrent safe type that provides help and usage for
|
// helpCacher provides a concurrent safe type that provides help and usage for
|
||||||
|
|
Loading…
Reference in a new issue