zcashrpc/zcash_client.go

160 lines
5.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package zcashrpc
import (
"bytes"
"encoding/base64"
"encoding/json"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"io/ioutil"
"net"
"net/http"
"strconv"
)
// ZcashClient defines an interface for any zcash client to present.
type ZcashClient interface {
GetTotalBalance(minConfirmations int) (float64, error)
GetTransaction(string) (Transaction, error)
ListAddresses() ([]string, error)
ListReceivedTransactionsByAddress(string) ([]ZcashTransaction, error)
GetBlock(int) (Block, error)
SendOne(string, string, string, float64) ([]byte, error)
ValidateAddress(address string) (ZValidateAddressResponse, error)
}
type zcashClient struct {
client http.Client
address string
auth string
}
// NewLocalClient creates a new Zcash rpc client over a local address
func NewLocalClient(username, password string) ZcashClient {
zc := new(zcashClient)
zc.address = "127.0.0.1:8232"
zc.client = http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
conn, err := net.Dial("tcp", zc.address)
return conn, err
},
},
}
zc.auth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return zc
}
// NewOnionClient creates a new Zcash rpc client over an onion address
func NewOnionClient(onion string, username, password string, acn connectivity.ACN) ZcashClient {
zc := new(zcashClient)
zc.address = onion + ".onion:9878"
zc.client = http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
conn, _, err := acn.Open(onion)
return conn, err
},
},
}
zc.auth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return zc
}
// Return the total value of funds stored in the nodes wallet. Set the minimum number of confirmations a private or transparent transaction must have in order to be included in the balance. Use 0 to count unconfirmed transactions.
func (zc *zcashClient) GetTotalBalance(minConfirmations int) (float64, error) {
body, err := zc.sendRequest(NewZGetTotalBalance(minConfirmations))
var totalBalance ZGetTotalBalanceResponse
if err == nil {
result := &ZcashResult{Result: &totalBalance}
err = json.Unmarshal(body, &result)
}
return strconv.ParseFloat(totalBalance.Private, 64)
}
// GetTransaction returns a specific transaction given an id
func (zc *zcashClient) GetBlock(id int) (Block, error) {
body, err := zc.sendRequest(NewGetBlock(id))
block := Block{}
if err == nil {
result := &ZcashResult{Result: &block}
err = json.Unmarshal(body, &result)
}
return block, err
}
// GetTransaction returns a specific transaction given an id
func (zc *zcashClient) GetTransaction(id string) (Transaction, error) {
body, err := zc.sendRequest(NewGetTransaction(id))
transaction := Transaction{}
if err == nil {
result := &ZcashResult{Result: &transaction}
err = json.Unmarshal(body, &result)
}
return transaction, err
}
// Returns a list of all the zaddrs in this nodes wallet for which you have a spending key.
func (zc *zcashClient) ListAddresses() ([]string, error) {
body, err := zc.sendRequest(NewZListAddresses())
var addresses []string
if err == nil {
result := &ZcashResult{Result: &addresses}
err = json.Unmarshal(body, &result)
}
return addresses, err
}
// ListReceivedTransactionsByAddress returns all the transactions received by a given zcash address
func (zc *zcashClient) ListReceivedTransactionsByAddress(address string) ([]ZcashTransaction, error) {
body, err := zc.sendRequest(NewZListReceivedByAddress(address))
var transactions []ZcashTransaction
if err == nil {
result := &ZcashResult{Result: &transactions}
err = json.Unmarshal(body, &result)
}
for i := range transactions {
transactions[i].Address = address
}
return transactions, err
}
// SendOne uses z_sendmany to send a single payment to the given address from the given fromAddress
func (zc *zcashClient) SendOne(fromAddress string, toaddress string, memo string, amount float64) ([]byte, error) {
jsonStr := NewZSendMany(fromAddress, []ZcashAmount{NewZcashAmount(toaddress, memo, amount)})
log.Debugf("Zcash SendMany %s", jsonStr)
return zc.sendRequest(jsonStr)
}
// ValidateAddress returns the result of a z_validateaddress call
func (zc *zcashClient) ValidateAddress(address string) (ZValidateAddressResponse, error) {
body, err := zc.sendRequest(NewZValidateAddress(address))
var validation ZValidateAddressResponse
if err == nil {
result := &ZcashResult{Result: &validation}
log.Debugf("Result: %s", body)
err = json.Unmarshal(body, &result)
}
return validation, err
}
func (zc *zcashClient) sendRequest(jsonStr []byte) ([]byte, error) {
req, err := http.NewRequest("POST", "http://"+zc.address, bytes.NewBuffer(jsonStr))
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Basic "+zc.auth)
log.Debugf("Sending request to zcash server %v", req)
resp, err := zc.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
log.Debugf("Got response from zcash server %s", body)
return body, nil
}