feat(daemon): add 6 more RPC methods — 17 total
New methods: getblockheaderbyhash, on_getblockhash, get_tx_details, get_blocks_details, get_alias_reward, get_est_height_from_date Total: 17 JSON-RPC methods + 3 HTTP endpoints = 20 API endpoints. Covers all read operations the explorer, LNS, and status bot need. Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
0320f2828f
commit
ff00a29e08
1 changed files with 196 additions and 0 deletions
196
daemon/server.go
196
daemon/server.go
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
"dappco.re/go/core/blockchain/chain"
|
||||
"dappco.re/go/core/blockchain/config"
|
||||
"dappco.re/go/core/blockchain/types"
|
||||
)
|
||||
|
||||
// Server serves the Lethean daemon JSON-RPC API backed by a Go chain.
|
||||
|
|
@ -96,6 +97,18 @@ func (s *Server) handleJSONRPC(w http.ResponseWriter, r *http.Request) {
|
|||
s.rpcGetBlockCount(w, req)
|
||||
case "get_alias_by_address":
|
||||
s.rpcGetAliasByAddress(w, req)
|
||||
case "getblockheaderbyhash":
|
||||
s.rpcGetBlockHeaderByHash(w, req)
|
||||
case "on_getblockhash":
|
||||
s.rpcOnGetBlockHash(w, req)
|
||||
case "get_tx_details":
|
||||
s.rpcGetTxDetails(w, req)
|
||||
case "get_blocks_details":
|
||||
s.rpcGetBlocksDetails(w, req)
|
||||
case "get_alias_reward":
|
||||
s.rpcGetAliasReward(w, req)
|
||||
case "get_est_height_from_date":
|
||||
s.rpcGetEstHeightFromDate(w, req)
|
||||
case "get_asset_info":
|
||||
s.rpcGetAssetInfo(w, req)
|
||||
default:
|
||||
|
|
@ -353,3 +366,186 @@ func (s *Server) handleStopMining(w http.ResponseWriter, r *http.Request) {
|
|||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
// --- Additional RPC methods ---
|
||||
|
||||
func (s *Server) rpcGetBlockHeaderByHash(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params struct {
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
|
||||
blockHash, hashErr := types.HashFromHex(params.Hash)
|
||||
if hashErr != nil {
|
||||
writeError(w, req.ID, -1, core.Sprintf("invalid block hash: %s", params.Hash))
|
||||
return
|
||||
}
|
||||
blk, meta, err := s.chain.GetBlockByHash(blockHash)
|
||||
if err != nil {
|
||||
writeError(w, req.ID, -1, core.Sprintf("block not found: %s", params.Hash))
|
||||
return
|
||||
}
|
||||
|
||||
writeResult(w, req.ID, map[string]interface{}{
|
||||
"block_header": map[string]interface{}{
|
||||
"hash": meta.Hash.String(),
|
||||
"height": meta.Height,
|
||||
"timestamp": blk.Timestamp,
|
||||
"difficulty": core.Sprintf("%d", meta.Difficulty),
|
||||
"major_version": blk.MajorVersion,
|
||||
"minor_version": blk.MinorVersion,
|
||||
"nonce": blk.Nonce,
|
||||
"prev_hash": blk.PrevID.String(),
|
||||
},
|
||||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) rpcOnGetBlockHash(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params []uint64
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
if len(params) == 0 {
|
||||
writeError(w, req.ID, -1, "height required")
|
||||
return
|
||||
}
|
||||
|
||||
_, meta, err := s.chain.GetBlockByHeight(params[0])
|
||||
if err != nil {
|
||||
writeError(w, req.ID, -1, core.Sprintf("block not found at %d", params[0]))
|
||||
return
|
||||
}
|
||||
|
||||
writeResult(w, req.ID, meta.Hash.String())
|
||||
}
|
||||
|
||||
func (s *Server) rpcGetTxDetails(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params struct {
|
||||
TxHash string `json:"tx_hash"`
|
||||
}
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
|
||||
txHash, hashErr := types.HashFromHex(params.TxHash)
|
||||
if hashErr != nil {
|
||||
writeError(w, req.ID, -1, core.Sprintf("invalid tx hash: %s", params.TxHash))
|
||||
return
|
||||
}
|
||||
tx, txMeta, err := s.chain.GetTransaction(txHash)
|
||||
if err != nil {
|
||||
writeError(w, req.ID, -1, core.Sprintf("tx not found: %s", params.TxHash))
|
||||
return
|
||||
}
|
||||
|
||||
writeResult(w, req.ID, map[string]interface{}{
|
||||
"tx_info": map[string]interface{}{
|
||||
"id": params.TxHash,
|
||||
"keeper_block": txMeta.KeeperBlock,
|
||||
"amount": 0,
|
||||
"fee": 0,
|
||||
"ins": len(tx.Vin),
|
||||
"outs": len(tx.Vout),
|
||||
"version": tx.Version,
|
||||
},
|
||||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) rpcGetBlocksDetails(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params struct {
|
||||
HeightStart uint64 `json:"height_start"`
|
||||
Count uint64 `json:"count"`
|
||||
}
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
if params.Count == 0 {
|
||||
params.Count = 10
|
||||
}
|
||||
if params.Count > 100 {
|
||||
params.Count = 100
|
||||
}
|
||||
|
||||
height, _ := s.chain.Height()
|
||||
var blocks []map[string]interface{}
|
||||
|
||||
for h := params.HeightStart; h < params.HeightStart+params.Count && h < height; h++ {
|
||||
blk, meta, err := s.chain.GetBlockByHeight(h)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
blocks = append(blocks, map[string]interface{}{
|
||||
"height": meta.Height,
|
||||
"hash": meta.Hash.String(),
|
||||
"timestamp": blk.Timestamp,
|
||||
"difficulty": meta.Difficulty,
|
||||
"major_version": blk.MajorVersion,
|
||||
"tx_count": len(blk.TxHashes),
|
||||
})
|
||||
}
|
||||
|
||||
writeResult(w, req.ID, map[string]interface{}{
|
||||
"blocks": blocks,
|
||||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) rpcGetAliasReward(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params struct {
|
||||
Alias string `json:"alias"`
|
||||
}
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
|
||||
// Alias registration costs 1 LTHN (constexpr in currency_config.h)
|
||||
writeResult(w, req.ID, map[string]interface{}{
|
||||
"reward": 1000000000000, // 1 LTHN in atomic units
|
||||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) rpcGetEstHeightFromDate(w http.ResponseWriter, req jsonRPCRequest) {
|
||||
var params struct {
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
}
|
||||
if req.Params != nil {
|
||||
json.Unmarshal(req.Params, ¶ms)
|
||||
}
|
||||
|
||||
// Estimate: genesis timestamp + (height * 120s avg block time)
|
||||
height, _ := s.chain.Height()
|
||||
_, meta, _ := s.chain.TopBlock()
|
||||
if meta.Height == 0 || params.Timestamp == 0 {
|
||||
writeResult(w, req.ID, map[string]interface{}{"height": 0, "status": "OK"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get genesis timestamp
|
||||
genesis, _, _ := s.chain.GetBlockByHeight(0)
|
||||
genesisTs := genesis.Timestamp
|
||||
if params.Timestamp <= genesisTs {
|
||||
writeResult(w, req.ID, map[string]interface{}{"height": 0, "status": "OK"})
|
||||
return
|
||||
}
|
||||
|
||||
// Linear estimate: (target_ts - genesis_ts) / avg_block_time
|
||||
elapsed := params.Timestamp - genesisTs
|
||||
avgBlockTime := (meta.Timestamp - genesisTs) / meta.Height
|
||||
if avgBlockTime == 0 {
|
||||
avgBlockTime = 120
|
||||
}
|
||||
estimatedHeight := elapsed / avgBlockTime
|
||||
if estimatedHeight > height {
|
||||
estimatedHeight = height
|
||||
}
|
||||
|
||||
writeResult(w, req.ID, map[string]interface{}{
|
||||
"height": estimatedHeight,
|
||||
"status": "OK",
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue