Started moving out of main

This commit is contained in:
Ben Wilson 2020-09-23 15:14:51 -04:00
parent 21e172d5e4
commit 8d67edc421
6 changed files with 55 additions and 417 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.env
zfaucet
eccfaucet
a_main-packr.go

7
go.mod
View File

@ -6,15 +6,16 @@ require (
github.com/doubtingben/zfaucet v0.0.0-20200722134018-70e63e333601 // indirect
github.com/gobuffalo/packr v1.30.1
github.com/gobuffalo/packr/v2 v2.8.0 // indirect
github.com/karrick/godirwalk v1.15.6 // indirect
github.com/karrick/godirwalk v1.16.1 // indirect
github.com/kelseyhightower/envconfig v1.4.0
github.com/lib/pq v1.7.1
github.com/muesli/cache2go v0.0.0-20200423001931-a100c5aac93f
github.com/rogpeppe/go-internal v1.6.2 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/spf13/cobra v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/ybbus/jsonrpc v2.1.2+incompatible
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 // indirect
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
)

16
go.sum
View File

@ -17,6 +17,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@ -81,6 +82,8 @@ github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0L
github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/karrick/godirwalk v1.15.6 h1:Yf2mmR8TJy+8Fa0SuQVto5SYap6IF7lNVX4Jdl8G1qA=
github.com/karrick/godirwalk v1.15.6/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@ -114,9 +117,11 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
@ -135,6 +140,8 @@ github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.0 h1:IZRgg4sfrDH7nsAD1Y/Nwj+GzIfEwpJSLjCaNC3SbsI=
github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -164,6 +171,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@ -185,6 +193,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -197,6 +207,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -225,6 +236,9 @@ golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3ox
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 h1:X9xIZ1YU8bLZA3l6gqDUHSFiD0GFI9S548h6C8nDtOY=
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -235,6 +249,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -257,5 +272,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

366
main.go
View File

@ -5,43 +5,33 @@ import (
"crypto/tls"
"encoding/base64"
"encoding/gob"
"encoding/json"
"errors"
"flag"
"fmt"
"html/template"
"log"
"net/http"
"os"
"strconv"
"time"
"github.com/gobuffalo/packr"
"github.com/kelseyhightower/envconfig"
_ "github.com/lib/pq"
"github.com/muesli/cache2go"
"github.com/ybbus/jsonrpc"
"github.com/zcash-hackworks/eccfaucet/pkg/eccfaucet"
"github.com/zcash-hackworks/eccfaucet/pkg/rpc"
)
const tapAmount = 1.0
const tapWaitMinutes = 2
const opStatusWaitSeconds = 120
type TapRequest struct {
NetworkAddress string
WalletAddress string
RequestedAt time.Time
}
type ECCfaucetConfig struct {
ListenPort string
ListenAddress string
RPCUser string
RPCPassword string
RPCHost string
RPCPort string
FundingAddress string
TLSCertFile string
TLSKeyFile string
ListenPort string
ListenAddress string
RPCUser string
RPCPassword string
RPCHost string
RPCPort string
FundingAddress string
TLSCertFile string
TLSKeyFile string
TapAmount float64
TapWaitMinutes float64
OpStatusWaitSeconds int
}
func (c *ECCfaucetConfig) checkConfig() error {
@ -64,172 +54,20 @@ func (c *ECCfaucetConfig) checkConfig() error {
(c.TLSCertFile != "" && c.TLSKeyFile == "") {
return fmt.Errorf("ECCFAUCET_TLSCERTFILE and ECCFAUCET_TLSKEYFILE are both required")
}
c.TapAmount = 1.0
c.TapWaitMinutes = 2
c.OpStatusWaitSeconds = 120
return nil
}
// ECCFaucet holds a zfaucet configuration
type ECCFaucet struct {
RPCConnetion jsonrpc.RPCClient
CurrentHeight int
UpdatedChainInfo time.Time
UpdatedWallet time.Time
Operations map[string]OperationStatus
ZcashdVersion string
ZcashNetwork string
FundingAddress string
TapRequests []*TapRequest
TapCache *cache2go.CacheTable
HomeHTML string
}
type SendAmount struct {
Address string `json:"address"`
Amount float32 `json:"amount"`
}
// TODO tag facet transactions, zaddr targets only
type SendAmountMemo struct {
SendAmount
Memo string
}
func (z *ECCFaucet) ClearCache() {
for {
now := time.Now()
fmt.Printf("Clearing cache: %d\n", len(z.TapRequests))
for _, t := range z.TapRequests {
fmt.Printf("Checking RemoteAddress: '%#v' - '%#v'\n", t.NetworkAddress, t.RequestedAt)
diff := now.Sub(t.RequestedAt)
if diff.Minutes() > tapWaitMinutes {
fmt.Printf("Old entry! : %#v\n", t)
}
}
time.Sleep(time.Second * 60 * tapWaitMinutes)
}
}
func (z *ECCFaucet) UpdateZcashInfo() {
for {
z.UpdatedChainInfo = time.Now()
var blockChainInfo *GetBlockchainInfo
if err := z.RPCConnetion.CallFor(&blockChainInfo, "getblockchaininfo"); err != nil {
fmt.Printf("Failed to get blockchaininfo: %s\n", err)
} else {
z.CurrentHeight = blockChainInfo.Blocks
z.ZcashNetwork = blockChainInfo.Chain
}
var info *GetBlockInfo
if err := z.RPCConnetion.CallFor(&info, "getinfo"); err != nil {
fmt.Printf("Failed to get getinfo: %s\n", err)
} else {
z.ZcashdVersion = strconv.Itoa(info.Version)
}
fmt.Println("Updated Zcashd Info")
time.Sleep(time.Second * 30)
}
}
func (z *ECCFaucet) WaitForOperation(opid string) (os OperationStatus, err error) {
var opStatus []struct {
CreationTime int `json:"creation_time"`
ID string `json:"id"`
Method string `json:"method"`
Result struct {
TxID string `json:"txid"`
}
Status string `json:"status"`
}
var parentList [][]string
var opList []string
opList = append(opList, opid)
parentList = append(parentList, opList)
fmt.Printf("opList: %s\n", opList)
fmt.Printf("parentList: %s\n", parentList)
// Wait for a few seconds for the operational status to become available
for i := 0; i < opStatusWaitSeconds; i++ {
if err := z.RPCConnetion.CallFor(
&opStatus,
"z_getoperationresult",
parentList,
); err != nil {
return os, fmt.Errorf("failed to call z_getoperationresult: %s", err)
} else {
fmt.Printf("op: %s, i: %d, status: %#v\n", opid, i, opStatus)
if len(opStatus) > 0 {
fmt.Printf("opStatus: %#v\n", opStatus[0])
//z.Operations[opid] = OperationStatus{
os = OperationStatus{
UpdatedAt: time.Now(),
TxID: opStatus[0].Result.TxID,
Status: opStatus[0].Status,
}
z.Operations[opid] = os
return os, nil
}
}
time.Sleep(time.Second * 1)
}
return os, errors.New("Timeout waiting for operations status")
}
func (z *ECCFaucet) ValidateFundingAddress() (bool, error) {
if z.FundingAddress == "" {
return false, errors.New("FundingAddressis required")
}
return true, nil
}
func (z *ECCFaucet) ZSendManyFaucet(remoteAddr string, remoteWallet string) (opStatus OperationStatus, err error) {
var op *string
amountEntry := SendAmount{
Address: remoteWallet,
Amount: tapAmount,
}
fmt.Printf("ZSendManyFaucet sending: %#v\n", amountEntry)
fmt.Printf("ZSendManyFaucet from funding address: %s\n", z.FundingAddress)
// if err != nil {
// return opStatus, err
// }
// Call z_sendmany with a single entry entry list
if err := z.RPCConnetion.CallFor(
&op,
"z_sendmany",
z.FundingAddress,
[]SendAmount{amountEntry},
); err != nil {
return opStatus, err
}
fmt.Printf("ZSendManyFaucet sent to %s: Address: %s %s\n", remoteWallet, remoteAddr, *op)
opStatus, err = z.WaitForOperation(*op)
if err != nil {
return opStatus, err
}
if opStatus.Status != "success" {
return opStatus, fmt.Errorf("Failed to send funds: %s", err)
}
tapRequest := &TapRequest{
NetworkAddress: remoteAddr,
WalletAddress: remoteWallet,
RequestedAt: time.Now(),
}
z.TapCache.Add(remoteAddr, tapWaitMinutes*60*time.Second, tapRequest)
z.TapRequests = append(z.TapRequests, tapRequest)
return opStatus, err
}
type GetBlockInfo struct {
Version int
}
func getBlockchainInfo(rpcClient jsonrpc.RPCClient) (blockChainInfo *GetBlockchainInfo, err error) {
func getBlockchainInfo(rpcClient jsonrpc.RPCClient) (blockChainInfo *rpc.GetBlockchainInfo, err error) {
if err := rpcClient.CallFor(&blockChainInfo, "getblockchaininfo"); err != nil {
return nil, err
}
return
}
func getInfo(rpcClient jsonrpc.RPCClient) (info *GetBlockInfo, err error) {
func getInfo(rpcClient jsonrpc.RPCClient) (info *rpc.GetBlockInfo, err error) {
if err := rpcClient.CallFor(&info, "getinfo"); err != nil {
return nil, err
}
@ -256,10 +94,13 @@ func main() {
fmt.Printf("zfaucet: %#v\n", zConfig)
basicAuth := base64.StdEncoding.EncodeToString([]byte(zConfig.RPCUser + ":" + zConfig.RPCPassword))
var z ECCFaucet
var z eccfaucet.ECCFaucet
z.TapCache = cache2go.Cache("tapRequests")
z.FundingAddress = zConfig.FundingAddress
z.Operations = make(map[string]OperationStatus)
z.TapAmount = zConfig.TapAmount
z.TapWaitMinutes = zConfig.TapWaitMinutes
z.OpStatusWaitSeconds = zConfig.OpStatusWaitSeconds
z.Operations = make(map[string]eccfaucet.OperationStatus)
z.RPCConnetion = jsonrpc.NewClientWithOpts("http://"+zConfig.RPCHost+":"+zConfig.RPCPort,
&jsonrpc.RPCClientOpts{
CustomHeaders: map[string]string{
@ -274,10 +115,10 @@ func main() {
if err != nil {
log.Fatal(err)
}
homeHandler := http.HandlerFunc(z.home)
balanceHandler := http.HandlerFunc(z.balance)
opsStatusHandler := http.HandlerFunc(z.opsStatus)
addressHandler := http.HandlerFunc(z.addresses)
homeHandler := http.HandlerFunc(z.Home)
balanceHandler := http.HandlerFunc(z.Balance)
opsStatusHandler := http.HandlerFunc(z.OpsStatus)
addressHandler := http.HandlerFunc(z.Addresses)
mux := http.NewServeMux()
mux.Handle("/", homeHandler)
mux.Handle("/balance", z.OKMiddleware(balanceHandler))
@ -311,157 +152,6 @@ func main() {
log.Fatal(err)
}
// OperationStatus describes an rpc response
type OperationStatus struct {
UpdatedAt time.Time
Status string
TxID string
result interface{}
}
// home is the default request handler
func (z *ECCFaucet) home(w http.ResponseWriter, r *http.Request) {
// tData is the html template data
tData := struct {
Z *ECCFaucet
Msg string
}{
z,
"",
}
switch r.Method {
case http.MethodPost:
res, err := z.TapCache.Value(r.RemoteAddr)
if err == nil {
fmt.Println("Found value in cache:", res.Data().(*TapRequest).NetworkAddress)
tData.Msg = fmt.Sprintf("You may only tap the faucet every %d minutes\nPlease try again later\n", tapWaitMinutes)
break
} else {
fmt.Println("Error retrieving value from cache:", err)
}
if err := checkFaucetAddress(r.FormValue("address")); err != nil {
tData.Msg = fmt.Sprintf("Invalid address: %s", err)
break
}
opStatus, err := z.ZSendManyFaucet(r.RemoteAddr, r.FormValue("address"))
if err != nil {
tData.Msg = fmt.Sprintf("Failed to send funds: %s", err)
break
}
tData.Msg = fmt.Sprintf("Successfully submitted operation, transaction: %s", opStatus.TxID)
}
w.Header().Set("Content-Type", "text/html")
tmpl, err := template.New("name").Parse(z.HomeHTML)
if err != nil {
http.Error(w, err.Error(), 500)
}
tmpl.Execute(w, tData)
}
// OKMiddleware determines if a request is allowed before execution
func (z *ECCFaucet) OKMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here...
next.ServeHTTP(w, r)
})
}
// Balance
func (z *ECCFaucet) balance(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var totalBalance *z_gettotalbalance
if err := z.RPCConnetion.CallFor(&totalBalance, "z_gettotalbalance"); err != nil {
http.Error(w, err.Error(), 500)
return
}
out, err := json.Marshal(totalBalance)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
fmt.Fprintf(w, string(out))
}
// opsStatus
func (z *ECCFaucet) opsStatus(w http.ResponseWriter, r *http.Request) {
// tData is the html template data
tData := struct {
Z *ECCFaucet
Ops *[]string
Type string
}{
z,
nil,
"opsStatus",
}
if err := z.RPCConnetion.CallFor(&tData.Ops, "z_listoperationids"); err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Set("Content-Type", "text/html")
tmpl, err := template.New("name").Parse(z.HomeHTML)
if err != nil {
http.Error(w, err.Error(), 500)
}
tmpl.Execute(w, tData)
}
// addresses
func (z *ECCFaucet) addresses(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var addresses []WalletAddress
var zlist *[]string
var taddrs []interface{}
// Z addresses
if err := z.RPCConnetion.CallFor(&zlist, "z_listaddresses"); err != nil {
http.Error(w, err.Error(), 500)
return
}
for _, zaddr := range *zlist {
entry := WalletAddress{
Address: zaddr,
}
entry.Notes = append(entry.Notes, "z address")
addresses = append(addresses, entry)
}
// T addresses
if err := z.RPCConnetion.CallFor(&taddrs, "listaddressgroupings"); err != nil {
http.Error(w, fmt.Sprintf("Problem calling listaddressgroupings: %s", err.Error()), 500)
return
}
fmt.Printf("T addresses:\n%#v\n", taddrs)
// TODO: fix this mess
for _, a := range taddrs {
switch aResult := a.(type) {
case []interface{}:
for _, b := range aResult {
switch bResult := b.(type) {
case []interface{}:
for _, x := range bResult {
switch x.(type) {
case string:
taddr := fmt.Sprintf("%v", x)
fmt.Printf("Adding T Address: %s\n", taddr)
entry := WalletAddress{
Address: taddr,
}
entry.Notes = append(entry.Notes, "t address")
addresses = append(addresses, entry)
}
}
}
}
}
}
out, err := json.Marshal(addresses)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
fmt.Fprintf(w, string(out))
}
// GetBytes returns a byte slice from an interface
func GetBytes(key interface{}) ([]byte, error) {
var buf bytes.Buffer

View File

@ -1,7 +1,10 @@
package main
package rpc
// GetBlockInfo is the important getblockinfo response data
type GetBlockInfo struct {
Version int
}
// GetBlockchainInfo return the zcashd rpc `getblockchaininfo` status
// https://zcash-rpc.github.io/getblockchaininfo.html
type GetBlockchainInfo struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
@ -17,14 +20,3 @@ type SoftFork struct {
ID string `json:"id"`
Version int `json:"version"`
}
type z_gettotalbalance struct {
Transparent string
Private string
Total string
}
type WalletAddress struct {
Address string
Notes []string
}

View File

@ -1,62 +0,0 @@
package main
import (
"errors"
"fmt"
"net/http"
"regexp"
)
func zSendManyHTTPPost(r *http.Request) (opid string, err error) {
fmt.Printf("zSendManyHTTPPost address: %s\n", r.FormValue("address"))
switch {
case r.FormValue("address") == "":
fmt.Println("address blank case")
return "", errors.New("Form field value required: address")
case isTestnetTransparent(r.FormValue("address")):
fmt.Println("Address is a transparent testnet address")
return r.FormValue("address"), nil
default:
fmt.Println("address default case")
return "", errors.New("A valid address is required")
}
}
func isTestnetTransparent(addr string) bool {
//TODO Check length and encoding
matched, _ := regexp.MatchString(`^tm`, addr)
return matched
}
func isTestnetSaplingZaddr(addr string) bool {
//TODO Check length and encoding
matched, _ := regexp.MatchString(`^ztestsapling`, addr)
return matched
}
func checkSourceAddress(rAddress string) error {
return nil
}
func checkFaucetAddress(checkAddr string) error {
switch {
case checkAddr == "":
fmt.Println("address blank case")
return errors.New("Form field value required: address")
case isTestnetTransparent(checkAddr):
fmt.Println("Address is a testnet transparent address")
return nil
case isTestnetSaplingZaddr(checkAddr):
fmt.Println("Address is a testnet sapling address")
return nil
default:
fmt.Println("address default case")
return errors.New("A valid address is required")
}
}
func zSendManyFaucet(addr string) (opid string, err error) {
return "000-test-opid-string-000", nil
}