Add some blockchain RPC handlers and DB fetching routines #55

Merged
moodyjon merged 15 commits from blockchain_rpc1 into master 2022-09-14 17:23:35 +02:00
2 changed files with 179 additions and 96 deletions
Showing only changes of commit d0d6145f9d - Show all commits

View file

@ -9,7 +9,10 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"net/http"
"strings"
"github.com/lbryio/herald.go/db"
"github.com/lbryio/herald.go/internal" "github.com/lbryio/herald.go/internal"
"github.com/lbryio/lbcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
@ -19,12 +22,69 @@ import (
"golang.org/x/exp/constraints" "golang.org/x/exp/constraints"
) )
type RpcReq interface { // TODO: import this from gorilla/rpc
// Codec creates a CodecRequest to process each request.
type Codec interface {
NewRequest(*http.Request) CodecRequest
} }
type RpcResp interface {
// TODO: import this from gorilla/rpc
// CodecRequest decodes a request and encodes a response using a specific
// serialization scheme.
type CodecRequest interface {
// Reads request and returns the RPC method name.
Method() (string, error)
// Reads request filling the RPC method args.
ReadRequest(interface{}) error
// Writes response using the RPC method reply. The error parameter is
// the error returned by the method call, if any.
WriteResponse(http.ResponseWriter, interface{}, error) error
} }
type RpcHandler interface {
Handle() (RpcResp, error) type BlockchainCodec struct {
Codec
}
func (c *BlockchainCodec) NewRequest(r *http.Request) CodecRequest {
return &BlockchainCodecRequest{c.Codec.NewRequest(r)}
}
type BlockchainCodecRequest struct {
CodecRequest
}
func (cr *BlockchainCodecRequest) Method() (string, error) {
rawMethod, err := cr.CodecRequest.Method()
if err != nil {
return rawMethod, err
}
parts := strings.Split(rawMethod, ".")
if len(parts) < 2 {
return rawMethod, fmt.Errorf("blockchain rpc: service/method ill-formed: %q", rawMethod)
}
service := strings.Join(parts[0:len(parts)-1], "_")
method := parts[len(parts)-1]
if len(method) < 1 {
return rawMethod, fmt.Errorf("blockchain rpc: method ill-formed: %q", method)
}
method = strings.ToUpper(string(method[0])) + string(method[1:])
return service + "." + method, err
}
// BlockchainService methods handle "blockchain.block.*" RPCs
type BlockchainService struct {
DB *db.ReadOnlyDBColumnFamily
Chain *chaincfg.Params
}
// BlockchainAddressService methods handle "blockchain.address.*" RPCs
type BlockchainAddressService struct {
BlockchainService
}
// BlockchainScripthashService methods handle "blockchain.scripthash.*" RPCs
type BlockchainScripthashService struct {
BlockchainService
} }
const CHUNK_SIZE = 96 const CHUNK_SIZE = 96
@ -39,26 +99,27 @@ func min[Ord constraints.Ordered](x, y Ord) Ord {
return y return y
} }
type blockGetChunkReq uint32 type BlockGetChunkReq uint32
type blockGetChunkResp string type blockGetChunkResp string
// 'blockchain.block.get_chunk' // 'blockchain.block.get_chunk'
func (req *blockGetChunkReq) Handle(s *Server) (*blockGetChunkResp, error) { func (s *BlockchainService) Get_chunk(r *http.Request, req *BlockGetChunkReq, resp **blockGetChunkResp) error {
index := uint32(*req) index := uint32(*req)
db_headers, err := s.DB.GetHeaders(index*CHUNK_SIZE, CHUNK_SIZE) db_headers, err := s.DB.GetHeaders(index*CHUNK_SIZE, CHUNK_SIZE)
if err != nil { if err != nil {
return nil, err return err
} }
raw := make([]byte, 0, HEADER_SIZE*len(db_headers)) raw := make([]byte, 0, HEADER_SIZE*len(db_headers))
for _, h := range db_headers { for _, h := range db_headers {
raw = append(raw, h[:]...) raw = append(raw, h[:]...)
} }
headers := blockGetChunkResp(hex.EncodeToString(raw)) headers := blockGetChunkResp(hex.EncodeToString(raw))
return &headers, err *resp = &headers
return err
} }
type blockGetHeaderReq uint32 type BlockGetHeaderReq uint32
type blockGetHeaderResp struct { type BlockGetHeaderResp struct {
Version uint32 `json:"version"` Version uint32 `json:"version"`
PrevBlockHash string `json:"prev_block_hash"` PrevBlockHash string `json:"prev_block_hash"`
MerkleRoot string `json:"merkle_root"` MerkleRoot string `json:"merkle_root"`
@ -70,21 +131,21 @@ type blockGetHeaderResp struct {
} }
// 'blockchain.block.get_header' // 'blockchain.block.get_header'
func (req *blockGetHeaderReq) Handle(s *Server) (*blockGetHeaderResp, error) { func (s *BlockchainService) Get_header(r *http.Request, req *BlockGetHeaderReq, resp **BlockGetHeaderResp) error {
height := uint32(*req) height := uint32(*req)
headers, err := s.DB.GetHeaders(height, 1) headers, err := s.DB.GetHeaders(height, 1)
if err != nil { if err != nil {
return nil, err return err
} }
if len(headers) < 1 { if len(headers) < 1 {
return nil, errors.New("not found") return errors.New("not found")
} }
decode := func(header *[HEADER_SIZE]byte, height uint32) *blockGetHeaderResp { decode := func(header *[HEADER_SIZE]byte, height uint32) *BlockGetHeaderResp {
var h1, h2, h3 chainhash.Hash var h1, h2, h3 chainhash.Hash
h1.SetBytes(header[4:36]) h1.SetBytes(header[4:36])
h2.SetBytes(header[36:68]) h2.SetBytes(header[36:68])
h3.SetBytes(header[68:100]) h3.SetBytes(header[68:100])
return &blockGetHeaderResp{ return &BlockGetHeaderResp{
Version: binary.LittleEndian.Uint32(header[0:]), Version: binary.LittleEndian.Uint32(header[0:]),
PrevBlockHash: h1.String(), PrevBlockHash: h1.String(),
MerkleRoot: h2.String(), MerkleRoot: h2.String(),
@ -95,17 +156,18 @@ func (req *blockGetHeaderReq) Handle(s *Server) (*blockGetHeaderResp, error) {
BlockHeight: height, BlockHeight: height,
} }
} }
return decode(&headers[0], height), nil *resp = decode(&headers[0], height)
return err
} }
type blockHeadersReq struct { type BlockHeadersReq struct {
StartHeight uint32 `json:"start_height"` StartHeight uint32 `json:"start_height"`
Count uint32 `json:"count"` Count uint32 `json:"count"`
CpHeight uint32 `json:"cp_height"` CpHeight uint32 `json:"cp_height"`
B64 bool `json:"b64"` B64 bool `json:"b64"`
} }
type blockHeadersResp struct { type BlockHeadersResp struct {
Base64 string `json:"base64,omitempty"` Base64 string `json:"base64,omitempty"`
Hex string `json:"hex,omitempty"` Hex string `json:"hex,omitempty"`
Count uint32 `json:"count"` Count uint32 `json:"count"`
@ -115,18 +177,18 @@ type blockHeadersResp struct {
} }
// 'blockchain.block.headers' // 'blockchain.block.headers'
func (req *blockHeadersReq) Handle(s *Server) (*blockHeadersResp, error) { func (s *BlockchainService) Headers(r *http.Request, req *BlockHeadersReq, resp **BlockHeadersResp) error {
count := min(req.Count, MAX_CHUNK_SIZE) count := min(req.Count, MAX_CHUNK_SIZE)
db_headers, err := s.DB.GetHeaders(req.StartHeight, count) db_headers, err := s.DB.GetHeaders(req.StartHeight, count)
if err != nil { if err != nil {
return nil, err return err
} }
count = uint32(len(db_headers)) count = uint32(len(db_headers))
raw := make([]byte, 0, HEADER_SIZE*count) raw := make([]byte, 0, HEADER_SIZE*count)
for _, h := range db_headers { for _, h := range db_headers {
raw = append(raw, h[:]...) raw = append(raw, h[:]...)
} }
result := &blockHeadersResp{ result := &BlockHeadersResp{
Count: count, Count: count,
Max: MAX_CHUNK_SIZE, Max: MAX_CHUNK_SIZE,
} }
@ -143,7 +205,8 @@ func (req *blockHeadersReq) Handle(s *Server) (*blockHeadersResp, error) {
// TODO // TODO
//last_height := height + count - 1 //last_height := height + count - 1
} }
return result, err *resp = result
return err
} }
func decodeScriptHash(scripthash string) ([]byte, error) { func decodeScriptHash(scripthash string) ([]byte, error) {
@ -157,6 +220,7 @@ func decodeScriptHash(scripthash string) ([]byte, error) {
internal.ReverseBytesInPlace(sh) internal.ReverseBytesInPlace(sh)
return sh, nil return sh, nil
} }
func hashX(scripthash []byte) []byte { func hashX(scripthash []byte) []byte {
return scripthash[:HASHX_LEN] return scripthash[:HASHX_LEN]
} }
@ -176,55 +240,57 @@ func hashXScript(script []byte, coin *chaincfg.Params) []byte {
return sum[:HASHX_LEN] return sum[:HASHX_LEN]
} }
type addressGetBalanceReq struct { type AddressGetBalanceReq struct {
Address string `json:"address"` Address string `json:"address"`
} }
type addressGetBalanceResp struct { type AddressGetBalanceResp struct {
Confirmed uint64 `json:"confirmed"` Confirmed uint64 `json:"confirmed"`
Unconfirmed uint64 `json:"unconfirmed"` Unconfirmed uint64 `json:"unconfirmed"`
} }
// 'blockchain.address.get_balance' // 'blockchain.address.get_balance'
func (req *addressGetBalanceReq) Handle(s *Server) (*addressGetBalanceResp, error) { func (s *BlockchainAddressService) Get_balance(r *http.Request, req *AddressGetBalanceReq, resp **AddressGetBalanceResp) error {
address, err := lbcutil.DecodeAddress(req.Address, s.Chain) address, err := lbcutil.DecodeAddress(req.Address, s.Chain)
if err != nil { if err != nil {
return nil, err return err
} }
script, err := txscript.PayToAddrScript(address) script, err := txscript.PayToAddrScript(address)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashXScript(script, s.Chain) hashX := hashXScript(script, s.Chain)
confirmed, unconfirmed, err := s.DB.GetBalance(hashX) confirmed, unconfirmed, err := s.DB.GetBalance(hashX)
if err != nil { if err != nil {
return nil, err return err
} }
return &addressGetBalanceResp{confirmed, unconfirmed}, err *resp = &AddressGetBalanceResp{confirmed, unconfirmed}
return err
} }
type scripthashGetBalanceReq struct { type scripthashGetBalanceReq struct {
ScriptHash string `json:"scripthash"` ScriptHash string `json:"scripthash"`
} }
type scripthashGetBalanceResp struct { type ScripthashGetBalanceResp struct {
Confirmed uint64 `json:"confirmed"` Confirmed uint64 `json:"confirmed"`
Unconfirmed uint64 `json:"unconfirmed"` Unconfirmed uint64 `json:"unconfirmed"`
} }
// 'blockchain.scripthash.get_balance' // 'blockchain.scripthash.get_balance'
func (req *scripthashGetBalanceReq) Handle(s *Server) (*scripthashGetBalanceResp, error) { func (s *BlockchainScripthashService) Get_balance(r *http.Request, req *scripthashGetBalanceReq, resp **ScripthashGetBalanceResp) error {
scripthash, err := decodeScriptHash(req.ScriptHash) scripthash, err := decodeScriptHash(req.ScriptHash)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashX(scripthash) hashX := hashX(scripthash)
confirmed, unconfirmed, err := s.DB.GetBalance(hashX) confirmed, unconfirmed, err := s.DB.GetBalance(hashX)
if err != nil { if err != nil {
return nil, err return err
} }
return &scripthashGetBalanceResp{confirmed, unconfirmed}, err *resp = &ScripthashGetBalanceResp{confirmed, unconfirmed}
return err
} }
type addressGetHistoryReq struct { type AddressGetHistoryReq struct {
Address string `json:"address"` Address string `json:"address"`
} }
type TxInfo struct { type TxInfo struct {
@ -235,25 +301,25 @@ type TxInfoFee struct {
TxInfo TxInfo
Fee uint64 `json:"fee"` Fee uint64 `json:"fee"`
} }
type addressGetHistoryResp struct { type AddressGetHistoryResp struct {
Confirmed []TxInfo `json:"confirmed"` Confirmed []TxInfo `json:"confirmed"`
Unconfirmed []TxInfoFee `json:"unconfirmed"` Unconfirmed []TxInfoFee `json:"unconfirmed"`
} }
// 'blockchain.address.get_history' // 'blockchain.address.get_history'
func (req *addressGetHistoryReq) Handle(s *Server) (*addressGetHistoryResp, error) { func (s *BlockchainAddressService) Get_history(r *http.Request, req *AddressGetHistoryReq, resp **AddressGetHistoryResp) error {
address, err := lbcutil.DecodeAddress(req.Address, s.Chain) address, err := lbcutil.DecodeAddress(req.Address, s.Chain)
if err != nil { if err != nil {
return nil, err return err
} }
script, err := txscript.PayToAddrScript(address) script, err := txscript.PayToAddrScript(address)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashXScript(script, s.Chain) hashX := hashXScript(script, s.Chain)
dbTXs, err := s.DB.GetHistory(hashX) dbTXs, err := s.DB.GetHistory(hashX)
if err != nil { if err != nil {
return nil, err return err
} }
confirmed := make([]TxInfo, 0, len(dbTXs)) confirmed := make([]TxInfo, 0, len(dbTXs))
for _, tx := range dbTXs { for _, tx := range dbTXs {
@ -263,31 +329,32 @@ func (req *addressGetHistoryReq) Handle(s *Server) (*addressGetHistoryResp, erro
Height: tx.Height, Height: tx.Height,
}) })
} }
result := &addressGetHistoryResp{ result := &AddressGetHistoryResp{
Confirmed: confirmed, Confirmed: confirmed,
Unconfirmed: []TxInfoFee{}, // TODO Unconfirmed: []TxInfoFee{}, // TODO
} }
return result, nil *resp = result
return err
} }
type scripthashGetHistoryReq struct { type ScripthashGetHistoryReq struct {
ScriptHash string `json:"scripthash"` ScriptHash string `json:"scripthash"`
} }
type scripthashGetHistoryResp struct { type ScripthashGetHistoryResp struct {
Confirmed []TxInfo `json:"confirmed"` Confirmed []TxInfo `json:"confirmed"`
Unconfirmed []TxInfoFee `json:"unconfirmed"` Unconfirmed []TxInfoFee `json:"unconfirmed"`
} }
// 'blockchain.scripthash.get_history' // 'blockchain.scripthash.get_history'
func (req *scripthashGetHistoryReq) Handle(s *Server) (*scripthashGetHistoryResp, error) { func (s *BlockchainScripthashService) Get_history(r *http.Request, req *ScripthashGetHistoryReq, resp **ScripthashGetHistoryResp) error {
scripthash, err := decodeScriptHash(req.ScriptHash) scripthash, err := decodeScriptHash(req.ScriptHash)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashX(scripthash) hashX := hashX(scripthash)
dbTXs, err := s.DB.GetHistory(hashX) dbTXs, err := s.DB.GetHistory(hashX)
if err != nil { if err != nil {
return nil, err return err
} }
confirmed := make([]TxInfo, 0, len(dbTXs)) confirmed := make([]TxInfo, 0, len(dbTXs))
for _, tx := range dbTXs { for _, tx := range dbTXs {
@ -297,56 +364,59 @@ func (req *scripthashGetHistoryReq) Handle(s *Server) (*scripthashGetHistoryResp
Height: tx.Height, Height: tx.Height,
}) })
} }
result := &scripthashGetHistoryResp{ result := &ScripthashGetHistoryResp{
Confirmed: confirmed, Confirmed: confirmed,
Unconfirmed: []TxInfoFee{}, // TODO Unconfirmed: []TxInfoFee{}, // TODO
} }
return result, nil *resp = result
return err
} }
type addressGetMempoolReq struct { type AddressGetMempoolReq struct {
Address string `json:"address"` Address string `json:"address"`
} }
type addressGetMempoolResp []TxInfoFee type AddressGetMempoolResp []TxInfoFee
// 'blockchain.address.get_mempool' // 'blockchain.address.get_mempool'
func (req *addressGetMempoolReq) Handle(s *Server) (*addressGetMempoolResp, error) { func (s *BlockchainAddressService) Get_mempool(r *http.Request, req *AddressGetMempoolReq, resp **AddressGetMempoolResp) error {
address, err := lbcutil.DecodeAddress(req.Address, s.Chain) address, err := lbcutil.DecodeAddress(req.Address, s.Chain)
if err != nil { if err != nil {
return nil, err return err
} }
script, err := txscript.PayToAddrScript(address) script, err := txscript.PayToAddrScript(address)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashXScript(script, s.Chain) hashX := hashXScript(script, s.Chain)
// TODO... // TODO...
internal.ReverseBytesInPlace(hashX) internal.ReverseBytesInPlace(hashX)
unconfirmed := make([]TxInfoFee, 0, 100) unconfirmed := make([]TxInfoFee, 0, 100)
result := addressGetMempoolResp(unconfirmed) result := AddressGetMempoolResp(unconfirmed)
return &result, nil *resp = &result
return err
} }
type scripthashGetMempoolReq struct { type ScripthashGetMempoolReq struct {
ScriptHash string `json:"scripthash"` ScriptHash string `json:"scripthash"`
} }
type scripthashGetMempoolResp []TxInfoFee type ScripthashGetMempoolResp []TxInfoFee
// 'blockchain.scripthash.get_mempool' // 'blockchain.scripthash.get_mempool'
func (req *scripthashGetMempoolReq) Handle(s *Server) (*scripthashGetMempoolResp, error) { func (s *BlockchainScripthashService) Get_mempool(r *http.Request, req *ScripthashGetMempoolReq, resp **ScripthashGetMempoolResp) error {
scripthash, err := decodeScriptHash(req.ScriptHash) scripthash, err := decodeScriptHash(req.ScriptHash)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashX(scripthash) hashX := hashX(scripthash)
// TODO... // TODO...
internal.ReverseBytesInPlace(hashX) internal.ReverseBytesInPlace(hashX)
unconfirmed := make([]TxInfoFee, 0, 100) unconfirmed := make([]TxInfoFee, 0, 100)
result := scripthashGetMempoolResp(unconfirmed) result := ScripthashGetMempoolResp(unconfirmed)
return &result, nil *resp = &result
return err
} }
type addressListUnspentReq struct { type AddressListUnspentReq struct {
Address string `json:"address"` Address string `json:"address"`
} }
type TXOInfo struct { type TXOInfo struct {
@ -355,17 +425,17 @@ type TXOInfo struct {
Height uint32 `json:"height"` Height uint32 `json:"height"`
Value uint64 `json:"value"` Value uint64 `json:"value"`
} }
type addressListUnspentResp []TXOInfo type AddressListUnspentResp []TXOInfo
// 'blockchain.address.listunspent' // 'blockchain.address.listunspent'
func (req *addressListUnspentReq) Handle(s *Server) (*addressListUnspentResp, error) { func (s *BlockchainAddressService) Listunspent(r *http.Request, req *AddressListUnspentReq, resp **AddressListUnspentResp) error {
address, err := lbcutil.DecodeAddress(req.Address, s.Chain) address, err := lbcutil.DecodeAddress(req.Address, s.Chain)
if err != nil { if err != nil {
return nil, err return err
} }
script, err := txscript.PayToAddrScript(address) script, err := txscript.PayToAddrScript(address)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashXScript(script, s.Chain) hashX := hashXScript(script, s.Chain)
dbTXOs, err := s.DB.GetUnspent(hashX) dbTXOs, err := s.DB.GetUnspent(hashX)
@ -379,20 +449,21 @@ func (req *addressListUnspentReq) Handle(s *Server) (*addressListUnspentResp, er
Value: txo.Value, Value: txo.Value,
}) })
} }
result := addressListUnspentResp(unspent) result := AddressListUnspentResp(unspent)
return &result, nil *resp = &result
return err
} }
type scripthashListUnspentReq struct { type ScripthashListUnspentReq struct {
ScriptHash string `json:"scripthash"` ScriptHash string `json:"scripthash"`
} }
type scripthashListUnspentResp []TXOInfo type ScripthashListUnspentResp []TXOInfo
// 'blockchain.scripthash.listunspent' // 'blockchain.scripthash.listunspent'
func (req *scripthashListUnspentReq) Handle(s *Server) (*scripthashListUnspentResp, error) { func (s *BlockchainScripthashService) Listunspent(r *http.Request, req *ScripthashListUnspentReq, resp **ScripthashListUnspentResp) error {
scripthash, err := decodeScriptHash(req.ScriptHash) scripthash, err := decodeScriptHash(req.ScriptHash)
if err != nil { if err != nil {
return nil, err return err
} }
hashX := hashX(scripthash) hashX := hashX(scripthash)
dbTXOs, err := s.DB.GetUnspent(hashX) dbTXOs, err := s.DB.GetUnspent(hashX)
@ -406,6 +477,7 @@ func (req *scripthashListUnspentReq) Handle(s *Server) (*scripthashListUnspentRe
Value: txo.Value, Value: txo.Value,
}) })
} }
result := scripthashListUnspentResp(unspent) result := ScripthashListUnspentResp(unspent)
return &result, nil *resp = &result
return err
} }

View file

@ -20,14 +20,15 @@ func TestGetChunk(t *testing.T) {
return return
} }
s := &Server{ s := &BlockchainService{
DB: db, DB: db,
Chain: &chaincfg.MainNetParams, Chain: &chaincfg.MainNetParams,
} }
for index := 0; index < 10; index++ { for index := 0; index < 10; index++ {
req := blockGetChunkReq(index) req := BlockGetChunkReq(index)
resp, err := (&req).Handle(s) var resp *blockGetChunkResp
err := s.Get_chunk(nil, &req, &resp)
if err != nil { if err != nil {
t.Errorf("index: %v handler err: %v", index, err) t.Errorf("index: %v handler err: %v", index, err)
} }
@ -54,14 +55,15 @@ func TestGetHeader(t *testing.T) {
return return
} }
s := &Server{ s := &BlockchainService{
DB: db, DB: db,
Chain: &chaincfg.MainNetParams, Chain: &chaincfg.MainNetParams,
} }
for height := 1000; height < 1010; height++ { for height := 1000; height < 1010; height++ {
req := blockGetHeaderReq(height) req := BlockGetHeaderReq(height)
resp, err := (&req).Handle(s) var resp *BlockGetHeaderResp
err := s.Get_header(nil, &req, &resp)
if err != nil { if err != nil {
t.Errorf("height: %v handler err: %v", height, err) t.Errorf("height: %v handler err: %v", height, err)
} }
@ -85,9 +87,11 @@ func TestGetBalance(t *testing.T) {
return return
} }
s := &Server{ s := &BlockchainAddressService{
BlockchainService{
DB: db, DB: db,
Chain: &chaincfg.MainNetParams, Chain: &chaincfg.MainNetParams,
},
} }
addrs := []string{ addrs := []string{
@ -96,8 +100,9 @@ func TestGetBalance(t *testing.T) {
} }
for _, addr := range addrs { for _, addr := range addrs {
req := addressGetBalanceReq{addr} req := AddressGetBalanceReq{addr}
resp, err := (&req).Handle(s) var resp *AddressGetBalanceResp
err := s.Get_balance(nil, &req, &resp)
if err != nil { if err != nil {
t.Errorf("address: %v handler err: %v", addr, err) t.Errorf("address: %v handler err: %v", addr, err)
} }
@ -121,9 +126,11 @@ func TestGetHistory(t *testing.T) {
return return
} }
s := &Server{ s := &BlockchainAddressService{
BlockchainService{
DB: db, DB: db,
Chain: &chaincfg.MainNetParams, Chain: &chaincfg.MainNetParams,
},
} }
addrs := []string{ addrs := []string{
@ -132,8 +139,9 @@ func TestGetHistory(t *testing.T) {
} }
for _, addr := range addrs { for _, addr := range addrs {
req := addressGetHistoryReq{addr} req := AddressGetHistoryReq{addr}
resp, err := (&req).Handle(s) var resp *AddressGetHistoryResp
err := s.Get_history(nil, &req, &resp)
if err != nil { if err != nil {
t.Errorf("address: %v handler err: %v", addr, err) t.Errorf("address: %v handler err: %v", addr, err)
} }
@ -157,9 +165,11 @@ func TestListUnspent(t *testing.T) {
return return
} }
s := &Server{ s := &BlockchainAddressService{
BlockchainService{
DB: db, DB: db,
Chain: &chaincfg.MainNetParams, Chain: &chaincfg.MainNetParams,
},
} }
addrs := []string{ addrs := []string{
@ -168,8 +178,9 @@ func TestListUnspent(t *testing.T) {
} }
for _, addr := range addrs { for _, addr := range addrs {
req := addressListUnspentReq{addr} req := AddressListUnspentReq{addr}
resp, err := (&req).Handle(s) var resp *AddressListUnspentResp
err := s.Listunspent(nil, &req, &resp)
if err != nil { if err != nil {
t.Errorf("address: %v handler err: %v", addr, err) t.Errorf("address: %v handler err: %v", addr, err)
} }