2019-12-01 21:24:59 +00:00
package zcashrpc
2019-08-23 20:51:21 +00:00
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"
2019-12-21 23:00:54 +00:00
"strconv"
2019-08-23 20:51:21 +00:00
)
2019-12-01 21:24:59 +00:00
// ZcashClient defines an interface for any zcash client to present.
2019-08-23 20:51:21 +00:00
type ZcashClient interface {
2019-12-21 23:00:54 +00:00
GetTotalBalance ( minConfirmations int ) ( float64 , error )
2019-09-14 01:13:29 +00:00
GetTransaction ( string ) ( Transaction , error )
2019-12-20 22:10:18 +00:00
ListAddresses ( ) ( [ ] string , error )
ListReceivedTransactionsByAddress ( string ) ( [ ] ZcashTransaction , error )
2020-03-13 21:35:08 +00:00
GetBlock ( int ) ( Block , error )
2019-12-01 21:24:59 +00:00
SendOne ( string , string , string , float64 ) ( [ ] byte , error )
ValidateAddress ( address string ) ( ZValidateAddressResponse , error )
}
type zcashClient struct {
client http . Client
address string
auth string
2019-08-23 20:51:21 +00:00
}
2019-12-01 21:24:59 +00:00
// 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
2019-08-23 20:51:21 +00:00
}
2019-12-01 21:24:59 +00:00
// 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"
2019-08-23 20:51:21 +00:00
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
}
2019-12-21 23:00:54 +00:00
// 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 )
}
2020-03-13 21:35:08 +00:00
// 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
}
2019-12-01 21:24:59 +00:00
// 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 )
2019-09-14 01:13:29 +00:00
}
2019-12-01 21:24:59 +00:00
return transaction , err
}
2019-12-20 22:10:18 +00:00
// 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
}
2019-12-01 21:24:59 +00:00
// 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 )
2019-09-14 01:13:29 +00:00
}
2019-12-21 23:00:54 +00:00
for i := range transactions {
transactions [ i ] . Address = address
}
2019-12-01 21:24:59 +00:00
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 )
2019-09-14 01:13:29 +00:00
}
2019-12-01 21:24:59 +00:00
return validation , err
2019-09-14 01:13:29 +00:00
}
2019-12-01 21:24:59 +00:00
func ( zc * zcashClient ) sendRequest ( jsonStr [ ] byte ) ( [ ] byte , error ) {
req , err := http . NewRequest ( "POST" , "http://" + zc . address , bytes . NewBuffer ( jsonStr ) )
2019-08-23 20:51:21 +00:00
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 )
2019-12-01 21:24:59 +00:00
return body , nil
2019-08-23 20:51:21 +00:00
}