160 lines
5.1 KiB
Go
160 lines
5.1 KiB
Go
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 node’s 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 node’s 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
|
||
}
|