aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2017-05-02 18:52:51 +0800
committerPéter Szilágyi <peterke@gmail.com>2017-05-04 16:42:43 +0800
commit8a28408616cab76bf756170a4f39025c821e4d21 (patch)
tree3211df8c26ac55f4743827edf7af461fb233a3e1 /cmd
parente1dc7ece624a2f539b71f1dfb5901047f7a9f214 (diff)
downloadgo-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar.gz
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar.bz2
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar.lz
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar.xz
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.tar.zst
go-tangerine-8a28408616cab76bf756170a4f39025c821e4d21.zip
cmd/faucet, cmd/puppeth: support multi-tiered faucet
Diffstat (limited to 'cmd')
-rw-r--r--cmd/faucet/faucet.go85
-rw-r--r--cmd/faucet/faucet.html11
-rw-r--r--cmd/faucet/website.go2
-rw-r--r--cmd/puppeth/module_faucet.go16
-rw-r--r--cmd/puppeth/wizard_faucet.go8
5 files changed, 92 insertions, 30 deletions
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 1c5c43edc..2a9a74593 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -27,11 +27,13 @@ import (
"fmt"
"html/template"
"io/ioutil"
+ "math"
"math/big"
"net/http"
"net/url"
"os"
"path/filepath"
+ "strconv"
"strings"
"sync"
"time"
@@ -67,6 +69,7 @@ var (
netnameFlag = flag.String("faucet.name", "", "Network name to assign to the faucet")
payoutFlag = flag.Int("faucet.amount", 1, "Number of Ethers to pay out per user request")
minutesFlag = flag.Int("faucet.minutes", 1440, "Number of minutes to wait between funding rounds")
+ tiersFlag = flag.Int("faucet.tiers", 3, "Number of funding tiers to enable (x3 time, x2.5 funds)")
accJSONFlag = flag.String("account.json", "", "Key json file to fund user requests with")
accPassFlag = flag.String("account.pass", "", "Decryption password to access faucet funds")
@@ -89,22 +92,46 @@ func main() {
flag.Parse()
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*logFlag), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
+ // Construct the payout tiers
+ amounts := make([]string, *tiersFlag)
+ periods := make([]string, *tiersFlag)
+ for i := 0; i < *tiersFlag; i++ {
+ // Calculate the amount for the next tier and format it
+ amount := float64(*payoutFlag) * math.Pow(2.5, float64(i))
+ amounts[i] = fmt.Sprintf("%s Ethers", strconv.FormatFloat(amount, 'f', -1, 64))
+ if amount == 1 {
+ amounts[i] = strings.TrimSuffix(amounts[i], "s")
+ }
+ // Calcualte the period for th enext tier and format it
+ period := *minutesFlag * int(math.Pow(3, float64(i)))
+ periods[i] = fmt.Sprintf("%d mins", period)
+ if period%60 == 0 {
+ period /= 60
+ periods[i] = fmt.Sprintf("%d hours", period)
+ }
+ if period%24 == 0 {
+ period /= 24
+ periods[i] = fmt.Sprintf("%d days", period)
+ }
+ if period == 1 {
+ periods[i] = strings.TrimSuffix(periods[i], "s")
+ }
+ }
// Load up and render the faucet website
tmpl, err := Asset("faucet.html")
if err != nil {
log.Crit("Failed to load the faucet template", "err", err)
}
- period := fmt.Sprintf("%d minute(s)", *minutesFlag)
- if *minutesFlag%60 == 0 {
- period = fmt.Sprintf("%d hour(s)", *minutesFlag/60)
- }
website := new(bytes.Buffer)
- template.Must(template.New("").Parse(string(tmpl))).Execute(website, map[string]interface{}{
+ err = template.Must(template.New("").Parse(string(tmpl))).Execute(website, map[string]interface{}{
"Network": *netnameFlag,
- "Amount": *payoutFlag,
- "Period": period,
+ "Amounts": amounts,
+ "Periods": periods,
"Recaptcha": *captchaToken,
})
+ if err != nil {
+ log.Crit("Failed to render the faucet template", "err", err)
+ }
// Load and parse the genesis block requested by the user
blob, err := ioutil.ReadFile(*genesisFlag)
if err != nil {
@@ -171,10 +198,10 @@ type faucet struct {
nonce uint64 // Current pending nonce of the faucet
price *big.Int // Current gas price to issue funds with
- conns []*websocket.Conn // Currently live websocket connections
- history map[string]time.Time // History of users and their funding requests
- reqs []*request // Currently pending funding requests
- update chan struct{} // Channel to signal request updates
+ conns []*websocket.Conn // Currently live websocket connections
+ timeouts map[string]time.Time // History of users and their funding timeouts
+ reqs []*request // Currently pending funding requests
+ update chan struct{} // Channel to signal request updates
lock sync.RWMutex // Lock protecting the faucet's internals
}
@@ -241,7 +268,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
index: index,
keystore: ks,
account: ks.Accounts()[0],
- history: make(map[string]time.Time),
+ timeouts: make(map[string]time.Time),
update: make(chan struct{}, 1),
}, nil
}
@@ -295,14 +322,22 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
"peers": f.stack.Server().PeerCount(),
"requests": f.reqs,
})
- header, _ := f.client.HeaderByNumber(context.Background(), nil)
- websocket.JSON.Send(conn, header)
+ // Send the initial block to the client
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+ header, err := f.client.HeaderByNumber(ctx, nil)
+ cancel()
+ if err != nil {
+ log.Error("Failed to retrieve latest header", "err", err)
+ } else {
+ websocket.JSON.Send(conn, header)
+ }
// Keep reading requests from the websocket until the connection breaks
for {
// Fetch the next funding request and validate against github
var msg struct {
URL string `json:"url"`
+ Tier uint `json:"tier"`
Captcha string `json:"captcha"`
}
if err := websocket.JSON.Receive(conn, &msg); err != nil {
@@ -312,7 +347,11 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
websocket.JSON.Send(conn, map[string]string{"error": "URL doesn't link to GitHub Gists"})
continue
}
- log.Info("Faucet funds requested", "gist", msg.URL)
+ if msg.Tier >= uint(*tiersFlag) {
+ websocket.JSON.Send(conn, map[string]string{"error": "Invalid funding tier requested"})
+ continue
+ }
+ log.Info("Faucet funds requested", "gist", msg.URL, "tier", msg.Tier)
// If captcha verifications are enabled, make sure we're not dealing with a robot
if *captchaToken != "" {
@@ -337,7 +376,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
}
if !result.Success {
log.Warn("Captcha verification failed", "err", string(result.Errors))
- websocket.JSON.Send(conn, map[string]string{"error": "Beep-boop, you're a robot!"})
+ websocket.JSON.Send(conn, map[string]string{"error": "Beep-bop, you're a robot!"})
continue
}
}
@@ -396,11 +435,15 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
f.lock.Lock()
var (
fund bool
- elapsed time.Duration
+ timeout time.Time
)
- if elapsed = time.Since(f.history[gist.Owner.Login]); elapsed > time.Duration(*minutesFlag)*time.Minute {
+ if timeout = f.timeouts[gist.Owner.Login]; time.Now().After(timeout) {
// User wasn't funded recently, create the funding transaction
- tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether), big.NewInt(21000), f.price, nil)
+ amount := new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether)
+ amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil))
+ amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
+
+ tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, big.NewInt(21000), f.price, nil)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainId)
if err != nil {
websocket.JSON.Send(conn, map[string]string{"error": err.Error()})
@@ -419,14 +462,14 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
Time: time.Now(),
Tx: signed,
})
- f.history[gist.Owner.Login] = time.Now()
+ f.timeouts[gist.Owner.Login] = time.Now().Add(time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute)
fund = true
}
f.lock.Unlock()
// Send an error if too frequent funding, othewise a success
if !fund {
- websocket.JSON.Send(conn, map[string]string{"error": fmt.Sprintf("User already funded %s ago", common.PrettyDuration(elapsed))})
+ websocket.JSON.Send(conn, map[string]string{"error": fmt.Sprintf("%s left until next allowance", common.PrettyDuration(timeout.Sub(time.Now())))})
continue
}
websocket.JSON.Send(conn, map[string]string{"success": fmt.Sprintf("Funding request accepted for %s into %s", gist.Owner.Login, address.Hex())})
diff --git a/cmd/faucet/faucet.html b/cmd/faucet/faucet.html
index 9e02134b7..56dd37623 100644
--- a/cmd/faucet/faucet.html
+++ b/cmd/faucet/faucet.html
@@ -51,7 +51,10 @@
<div class="input-group">
<input id="gist" type="text" class="form-control" placeholder="GitHub Gist URL containing your Ethereum address...">
<span class="input-group-btn">
- <button class="btn btn-default" type="button" onclick="{{if .Recaptcha}}grecaptcha.execute(){{else}}submit(){{end}}">Give me Ether!</button>
+ <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Give me Ether <i class="fa fa-caret-down" aria-hidden="true"></i></button>
+ <ul class="dropdown-menu dropdown-menu-right">{{range $idx, $amount := .Amounts}}
+ <li><a style="text-align: center;" onclick="tier={{$idx}}; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submit({{$idx}}){{end}}">{{$amount}} / {{index $.Periods $idx}}</a></li>{{end}}
+ </ul>
</span>
</div>{{if .Recaptcha}}
<div class="g-recaptcha" data-sitekey="{{.Recaptcha}}" data-callback="submit" data-size="invisible"></div>{{end}}
@@ -77,8 +80,9 @@
<div class="row" style="margin-top: 32px;">
<div class="col-lg-12">
<h3>How does this work?</h3>
- <p>This Ether faucet is running on the {{.Network}} network. To prevent malicious actors from exhausting all available funds or accumulating enough Ether to mount long running spam attacks, requests are tied to GitHub accounts. Anyone having a GitHub account may request funds within the permitted limit of <strong>{{.Amount}} Ether(s) / {{.Period}}</strong>.{{if .Recaptcha}} The faucet is running invisible reCaptcha protection against bots.{{end}}</p>
+ <p>This Ether faucet is running on the {{.Network}} network. To prevent malicious actors from exhausting all available funds or accumulating enough Ether to mount long running spam attacks, requests are tied to GitHub accounts. Anyone having a GitHub account may request funds within the permitted limits.</p>
<p>To request funds, simply create a <a href="https://gist.github.com/" target="_about:blank">GitHub Gist</a> with your Ethereum address pasted into the contents (the file name doesn't matter), copy paste the gists URL into the above input box and fire away! You can track the current pending requests below the input field to see how much you have to wait until your turn comes.</p>
+ {{if .Recaptcha}}<em>The faucet is running invisible reCaptcha protection against bots.</em>{{end}}
</div>
</div>
</div>
@@ -88,10 +92,11 @@
// Global variables to hold the current status of the faucet
var attempt = 0;
var server;
+ var tier = 0;
// Define the function that submits a gist url to the server
var submit = function({{if .Recaptcha}}captcha{{end}}) {
- server.send(JSON.stringify({url: $("#gist")[0].value{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
+ server.send(JSON.stringify({url: $("#gist")[0].value, tier: tier{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
grecaptcha.reset();{{end}}
};
// Define a method to reconnect upon server loss
diff --git a/cmd/faucet/website.go b/cmd/faucet/website.go
index 1a5e2e4c5..3151ab584 100644
--- a/cmd/faucet/website.go
+++ b/cmd/faucet/website.go
@@ -68,7 +68,7 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil
}
-var _faucetHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\xef\x72\xdb\x36\x12\xff\xac\x3c\xc5\x86\x77\xad\xa5\xb1\x49\xda\x71\x26\xed\xc8\xa4\x3a\x99\x34\x97\xf6\xe6\xa6\xed\xb4\xe9\xdc\x75\xda\xce\x0d\x48\x2e\x49\xc4\x20\xc0\x02\x4b\xc9\xaa\x47\xef\x7e\x03\x80\xa4\x28\x59\x4e\xd3\x4b\xbf\xc8\x04\xb0\xf8\xed\x62\x77\xb1\x7f\xe0\xe4\xe9\x97\xdf\xbe\x7a\xfb\xd3\x77\xaf\xa1\xa6\x46\xac\x9e\x24\xf6\x0f\x08\x26\xab\x34\x40\x19\xac\x9e\xcc\x92\x1a\x59\xb1\x7a\x32\x9b\x25\x0d\x12\x83\xbc\x66\xda\x20\xa5\x41\x47\x65\xf8\x79\xb0\x5f\xa8\x89\xda\x10\x7f\xeb\xf8\x3a\x0d\xfe\x13\xfe\xf8\x32\x7c\xa5\x9a\x96\x11\xcf\x04\x06\x90\x2b\x49\x28\x29\x0d\xbe\x7e\x9d\x62\x51\xe1\x64\x9f\x64\x0d\xa6\xc1\x9a\xe3\xa6\x55\x9a\x26\xa4\x1b\x5e\x50\x9d\x16\xb8\xe6\x39\x86\x6e\x70\x01\x5c\x72\xe2\x4c\x84\x26\x67\x02\xd3\xab\x60\xf5\xc4\xe2\x10\x27\x81\xab\xfb\xfb\xe8\x1b\xa4\x8d\xd2\xb7\xbb\xdd\x12\xde\x70\xfa\xaa\xcb\xe0\x1f\xac\xcb\x91\x92\xd8\x93\x38\x6a\xc1\xe5\x2d\xd4\x1a\xcb\x34\xb0\x32\x9b\x65\x1c\xe7\x85\x7c\x67\xa2\x5c\xa8\xae\x28\x05\xd3\x18\xe5\xaa\x89\xd9\x3b\x76\x17\x0b\x9e\x99\x98\x36\x9c\x08\x75\x98\x29\x45\x86\x34\x6b\xe3\xeb\xe8\x3a\xfa\x2c\xce\x8d\x89\xc7\xb9\xa8\xe1\x32\xca\x8d\x09\x40\xa3\x48\x03\x43\x5b\x81\xa6\x46\xa4\x00\xe2\xd5\xff\xc7\xb7\x54\x92\x42\xb6\x41\xa3\x1a\x8c\x9f\x47\x9f\x45\x97\x8e\xe5\x74\xfa\xfd\x5c\x2d\x5b\x93\x6b\xde\x12\x18\x9d\x7f\x30\xdf\x77\xbf\x75\xa8\xb7\xf1\x75\x74\x15\x5d\xf5\x03\xc7\xe7\x9d\x09\x56\x49\xec\x01\x57\x1f\x85\x1d\x4a\x45\xdb\xf8\x59\xf4\x3c\xba\x8a\x5b\x96\xdf\xb2\x0a\x8b\x81\x93\x5d\x8a\x86\xc9\xbf\x8c\xef\x63\x36\x7c\x77\x6c\xc2\xbf\x82\x59\xa3\x1a\x94\x14\xbd\x33\xf1\xb3\xe8\xea\xf3\xe8\x72\x98\x78\x88\xef\x18\x58\xa3\x59\x56\xb3\x68\x8d\x9a\x78\xce\x44\x98\xa3\x24\xd4\x70\x6f\x67\x67\x0d\x97\x61\x8d\xbc\xaa\x69\x09\x57\x97\x97\x9f\xdc\x9c\x9a\x5d\xd7\x7e\xba\xe0\xa6\x15\x6c\xbb\x84\x52\xe0\x9d\x9f\x62\x82\x57\x32\xe4\x84\x8d\x59\x82\x47\x76\x0b\x3b\xc7\xb3\xd5\xaa\xd2\x68\x4c\xcf\xac\x55\x86\x13\x57\x72\x69\x3d\x8a\x11\x5f\xe3\x29\x5a\xd3\x32\xf9\x60\x03\xcb\x8c\x12\x1d\xe1\x91\x20\x99\x50\xf9\xad\x9f\x73\xd7\x78\x7a\x88\x5c\x09\xa5\x97\xb0\xa9\x79\xbf\x0d\x1c\x23\x68\x35\xf6\xf0\xd0\xb2\xa2\xe0\xb2\x5a\xc2\x8b\xb6\x3f\x0f\x34\x4c\x57\x5c\x2e\xe1\x72\xbf\x25\x89\x07\x35\x26\xb1\x8f\x58\x4f\x66\x49\xa6\x8a\xad\xb3\x61\xc1\xd7\x90\x0b\x66\x4c\x1a\x1c\xa9\xd8\x45\xa2\x03\x02\x1b\x80\x18\x97\xc3\xd2\xc1\x9a\x56\x9b\x00\x1c\xa3\x34\xf0\x42\x84\x99\x22\x52\xcd\x12\xae\xac\x78\xfd\x96\x23\x3c\x11\x8a\x2a\xbc\x7a\x36\x2c\xce\x92\xfa\x6a\x00\x21\xbc\xa3\xd0\xd9\x67\xb4\x4c\xb0\x4a\xf8\xb0\xb7\x64\x50\xb2\x30\x63\x54\x07\xc0\x34\x67\x61\xcd\x8b\x02\x65\x1a\x90\xee\xd0\xfa\x11\x5f\xc1\x34\xee\x0d\x61\xef\x65\x47\x35\x4a\x7b\x4e\xc2\xa2\x0f\x82\x70\x0c\x5b\x71\xaa\xbb\x2c\x64\x82\x1e\x05\x4f\xe2\xfa\x6a\x38\x52\x5c\xf0\x75\xaf\x91\xc9\xe7\x91\x72\x1e\x3f\xff\xe7\xd0\x7f\xa8\xb2\x34\x48\xe1\x44\x1d\x13\x62\x2e\xdb\x8e\xc2\x4a\xab\xae\x1d\xd7\x67\x89\x9b\x05\x5e\xa4\x41\xc5\x0d\x05\x40\xdb\xb6\xd7\x5d\x30\x1e\x49\xe9\x26\xb4\xa6\xd3\x4a\x04\xd0\x0a\x96\x63\xad\x44\x81\x3a\x0d\x7a\x9d\xbc\xe1\x86\xe0\xc7\xef\xff\x05\xbd\x81\xb9\xac\x60\xab\x3a\x0d\xaf\xa9\x46\x8d\x5d\x03\xac\x28\xac\x73\x47\x51\x34\xe1\xed\x3c\xfd\xa1\x74\x61\x46\x72\x4f\x35\x4b\xb2\x8e\x48\x8d\x84\x19\x49\xc8\x48\x86\x05\x96\xac\x13\xa3\xc4\x9e\x28\x00\x25\x73\xc1\xf3\xdb\x34\xb8\xbf\xe7\x25\x44\xdf\x63\xce\x5a\xca\x6b\xb6\xdb\x55\x7a\xf8\x8e\xf0\x0e\xf3\x8e\x70\xbe\xb8\xbf\x47\x61\x70\xb7\x33\x5d\xd6\x70\x72\x63\x59\xec\x76\xc1\xea\x0d\x5f\x23\x34\xe8\x0f\xf0\x34\x89\x3d\xfc\x5e\xf4\xd8\xca\x3e\x6a\xd9\x19\xed\x01\xc3\x13\x36\xa8\xc2\x51\x88\x00\x0a\x46\x2c\x34\x9c\xf0\x16\xb7\x56\xde\xe9\xde\x7e\x35\x67\x42\x64\xcc\x1e\xc7\x4b\x38\x6e\xfa\x1d\xad\xca\xd6\xdc\xb8\x22\x60\x35\x48\xe0\xa4\xff\x33\x4e\x75\x74\xe3\x48\xb5\x4b\xb8\x7e\x36\xb9\x6e\xa7\xfc\xed\xc5\x91\xbf\x5d\x9f\x24\x6e\x99\x44\x01\xee\x37\x34\x0d\x13\xc3\xf7\x60\xb8\xbd\x32\x8f\x37\x85\x36\xb8\x8c\xa2\x8d\x41\xea\xf2\x06\xd4\x1a\x75\x29\xd4\x66\x09\xac\x23\x75\x03\x0d\xbb\x1b\x03\xf5\xf5\xe5\xe5\x54\x6e\x5b\xbc\xb0\x4c\xa0\xf3\x6d\x8d\xbf\x75\x68\xc8\x8c\x3e\xed\x97\xdc\xaf\x75\xed\x02\xa5\xc1\xe2\x48\x1b\x96\xa3\x55\xad\xa3\x9a\x98\x7e\x54\xe6\x49\xd9\x4b\xa5\xc6\xd8\x37\x15\xa3\x87\x9e\x84\xe9\x60\x95\x90\xde\xd3\xcd\x12\x2a\xfe\x54\xec\xd2\xb6\x36\x79\x2c\x74\xf9\xcb\x65\xcf\xde\x22\x6a\x9f\x18\xad\xcb\x82\x1b\x26\x31\x15\x1f\xc1\xd9\x3a\x61\xc6\x0c\x7e\x08\x7b\x97\xa2\xf6\xec\xdd\xf0\x63\xf9\xd7\xc8\x34\x65\xc8\x1e\x8f\xae\x13\x01\xca\x4e\x16\x93\xf3\xbb\x1b\xfd\xb1\x02\x74\x92\xaf\x51\x1b\x4e\xdb\x0f\x95\x00\x8b\xbd\x08\x7e\x7c\x28\x42\x12\x93\x7e\xbf\xaf\x4d\x07\x7f\xd1\xe5\xfe\xa3\x5c\x7a\xbd\xfa\x4a\x6d\xa0\x50\x68\x80\x6a\x6e\xc0\x66\xc2\x2f\x92\xb8\xbe\x1e\x49\xda\xd5\x5b\xbb\xe0\x94\x0a\xa5\x4f\x86\xdc\x80\xee\xa4\x4b\x02\x4a\x02\xd5\x78\x98\x47\xa5\xff\x8a\xe0\xad\xb2\xb5\xc8\x1a\x25\x41\xc3\x04\xcf\xb9\xea\x0c\xb0\x9c\x94\x36\x50\x6a\xd5\x00\xde\xd5\xac\x33\x64\x81\x6c\xf8\x60\x6b\xc6\x85\xbb\x4b\xce\xa4\xa0\x34\xb0\x3c\xef\x9a\xce\xd6\x52\xb2\x02\x94\xaa\xab\xea\x5e\x16\x52\xd0\xa8\x4e\x12\x08\x25\xab\x51\x1e\xd3\xb2\x06\x18\x11\xcb\x6f\xcd\x05\x0c\x51\x01\x98\x46\x20\x8e\x85\xdd\xd5\xa7\x34\x96\xe7\x76\xbb\x89\xe0\xa5\xdc\x2a\x89\x50\xb3\xb5\x13\xe4\x88\x00\x1a\xb6\x1d\x80\x7a\xb9\x36\x9c\x6a\xee\x0f\xde\xa2\x6e\x6c\x71\x5c\x80\xe0\x0d\x27\x50\x25\x24\x86\xb4\x92\x95\xed\xa9\x5e\x3a\x09\x77\x3b\x2f\xf2\xdc\x2c\x20\xb6\xaa\xfa\x0e\x35\x57\xc5\x6e\x67\xeb\x2e\x47\x1a\x3d\x48\x2d\xf0\xb6\xc6\x13\xea\x1e\x33\x02\x68\x7c\xe5\x69\xa1\xd5\x8a\x30\xb7\x55\x24\xb0\x8a\x71\x69\x08\x32\x45\x26\xea\x93\x45\x12\xb7\x53\x63\xaa\xc3\xb3\x5c\x80\xe1\x4d\x2b\xb6\x90\x6b\x64\x84\xc0\x20\x61\x47\x8d\x96\x2d\x1b\x22\x5f\xef\xb8\x52\x3d\x00\x62\xba\xb2\x6d\xec\x7f\x59\xa6\x3a\x5a\x66\x82\xc9\x5b\x9b\x51\xc7\x52\x21\x89\xd9\xca\x69\xe9\x74\x91\x00\x2d\x33\x56\x65\x5c\x92\x72\x5a\xec\xfb\x56\x03\x73\x3b\x2a\xb9\x40\xd7\xda\x3a\xc7\x94\x67\xd6\x04\xb6\xff\x58\x5c\x40\xae\xda\xad\xdf\xed\xf6\x59\xd1\x8c\xab\x4b\x46\x28\x96\xa9\x35\x82\x2f\x7a\x32\x75\x07\x4c\x16\x50\x72\x8d\xc0\x36\x6c\xfb\x14\x7e\x52\x1d\xe4\x4c\x02\x69\x96\xdf\x7a\xde\x9d\xd6\xd6\x43\x5b\x94\x36\x0b\xed\x7d\x26\x43\xa1\x36\x8e\xc4\xa3\x95\x1c\x85\x73\x20\x83\x08\xb5\xda\x40\xd3\xe5\xee\x80\xd6\x73\xd0\x2e\x6c\x18\x27\xe8\x24\x71\xe1\xcf\x4d\x9d\x96\x90\xab\x06\x4d\xb4\xb7\xc2\xc9\x9b\x3d\x7e\xf5\x1f\xfb\xde\xc9\x2d\xc7\x31\xbc\x11\x2a\x63\x02\xd6\x36\x18\x65\xc2\xde\x57\x05\xb6\x48\x3b\x38\x83\x21\x46\x9d\xb1\x4e\x48\xa3\xfb\xd8\xfd\x6b\xa6\xed\xa5\xc0\xa6\x25\x48\xfb\xca\xdf\xce\x19\xd4\x6b\xdb\xcf\xf4\x3c\xbe\xc4\x92\x4b\xaf\xd9\xb2\x93\xde\xa5\xa8\x66\x04\xbe\x36\x31\xc0\x9c\xc6\xa1\xd3\x02\x7a\x75\x7b\x84\x11\xcf\xd1\x41\x3a\x6e\x9f\x3f\x70\xec\xfe\xa3\x77\xce\x45\xdf\xa8\x78\x98\xc8\xa0\x2c\xe6\xff\xfc\xe1\xdb\x6f\x22\x43\x9a\xcb\x8a\x97\xdb\xf9\x7d\xa7\xc5\x12\xfe\x3e\x0f\xfe\xe6\xea\xd7\xc5\xcf\x97\xbf\x46\x6b\x26\x3a\x7c\x00\x7d\x01\xfd\xe7\x12\x0e\xb9\xec\x16\x8b\x9b\xd3\xc5\xdb\xa4\x64\xd4\x68\x90\xe6\x96\x70\xac\xb1\x76\x37\x87\x8a\x61\xd0\x20\xd5\xca\x39\x81\xc6\x5c\x49\x89\x39\x41\xd7\x2a\xd9\xeb\x01\x84\x32\x66\x50\xc6\x9e\x62\xa2\x8f\xe1\xc0\xbc\x84\xf9\x60\x91\x4f\xe0\x19\xa4\x29\x5c\x0e\x6b\xbd\x36\x20\x05\x89\x1b\xf8\x37\x66\x3f\xa8\xfc\x16\x69\x1e\x6c\x8c\xbd\x8f\x01\x9c\x83\x50\x39\xb3\x78\x51\xad\x0c\xc1\x39\x04\x31\x6b\x79\xb0\xf0\x2d\xde\x0e\x6c\xcd\xfb\xc7\x60\x1f\x84\xe5\x9b\x60\x2f\xe9\xf9\xb9\x77\x95\xc1\x5c\x4a\x36\x68\x0c\xab\x70\x7a\x42\x17\xef\xc7\xa3\x58\x45\x34\xa6\x82\x14\x9c\x59\x5b\xa6\x0d\x7a\x92\xc8\xd6\x18\x3d\x17\xa7\x0e\x47\x96\xa6\x20\x3b\x21\xc6\xfd\x33\x8d\xf6\x16\xf5\x64\xbb\x27\x07\xe4\x91\x0f\xc7\x4f\xd3\x14\x6c\xc2\xb5\x36\x2a\xf6\x3b\xad\xcb\xf8\xd2\x60\x11\xd9\x9c\xbf\xdf\xb1\x18\xe1\x1e\xa0\x61\xf1\x47\x70\x58\x1c\xe3\x61\xf1\x08\xa0\xab\xc4\xde\x87\xe7\x2b\xb7\x09\x9c\x9b\x78\x04\x4d\x76\x4d\x86\xfa\x7d\x70\xbe\x12\xeb\xe1\x9c\xaa\xbf\x96\x34\xd9\x7b\x01\x57\x2f\x16\x8f\xa0\xa3\xd6\xea\x51\x70\xa9\x68\x3b\xbf\x17\x6c\x6b\xc3\x3d\x9c\x91\x6a\x5f\xb9\xc2\xe9\xec\x02\x2c\xaf\x25\x8c\x08\x17\xae\x5b\x5b\xc2\x99\x1b\x9d\xed\x1e\xe1\x66\xba\x3c\xb7\x89\xe0\x63\xf8\xf5\x18\x23\xc7\x7e\xfc\x28\xcf\x31\xb0\x1f\x30\x85\x4f\x3f\x85\x07\xab\x87\x2e\x68\x7d\xb8\xcf\x50\x90\x42\x10\xf4\xf0\xb3\x52\x69\x98\xdb\x45\x9e\x5e\xde\x00\x4f\xa6\x30\x91\x40\x59\x51\x7d\x03\xfc\xfc\x7c\x8f\x34\x1b\x60\xce\x53\x08\x6c\x6f\x90\x50\xb1\x72\x35\x9a\x2f\xe4\x7e\x09\x6c\x2f\x68\x7b\x64\x59\x2c\x6d\x98\x9d\x9f\xed\xb3\xf0\x24\x01\x9f\x1f\x88\xfc\x33\xff\x35\xea\x0c\x6a\x97\x32\xcf\x21\x88\x5a\x59\x7d\xe1\x3a\xc8\x17\xcf\xcf\x16\x37\xb0\xc7\x74\x7d\xe5\x12\x72\xdb\x65\xdd\x80\xef\x54\x5c\xbd\x08\x63\x8f\xe5\x46\x99\xd2\x05\xea\x50\xb3\x82\x77\x66\x09\xcf\xdb\xbb\x9b\x5f\x86\x1e\xd4\x55\xb5\x4e\xee\x56\xe3\xea\x94\x2c\x43\xe1\x74\x0e\x41\x12\x5b\xa2\x61\xcb\x78\xca\xe9\x53\x16\x9c\xa8\xc7\x61\x7c\x68\xea\xe7\x1b\x5e\x14\x02\xad\x10\x8e\xa1\x7f\x11\x2c\x3a\xed\x02\xd7\xdc\x8f\xe7\xc7\x72\x10\x6f\x70\x11\x75\x92\xdf\xcd\x17\x61\x4f\x33\x8c\x2f\xe0\xcc\xd8\xf8\x5c\x98\xb3\x45\x54\x77\x0d\x93\xfc\x77\x9c\xdb\xe2\x7e\xe1\xe5\xb6\x12\xdb\x8a\x7d\xb4\xf6\x6e\x72\xd1\xc6\x6e\x73\x11\xd5\xd4\x88\x79\x90\x90\x7b\x2e\xb3\xc2\x8d\x26\x76\x28\x7e\xfa\xd0\x23\x77\x87\x31\x34\x17\xca\xe0\x51\x8e\x00\x83\xf4\x96\x37\xa8\x3a\x9a\x8f\x79\xe4\xc2\x76\xc0\x97\x8b\x1b\xd8\xed\x5f\x15\xe3\x18\x5e\x1b\xdb\x53\x70\x53\x03\x83\x0d\x66\xc6\xc5\x77\xe8\xf7\xb8\x14\xee\x53\xf5\xcb\xef\xbe\x9e\xa4\xeb\x11\x75\xee\x84\x1b\x5f\x55\x4f\xe5\xc9\x93\xcf\xb8\x9b\xcd\x26\xaa\x94\xaa\x84\x7f\xc0\x1d\x13\xa9\xcd\x1e\xd1\x3b\xdb\xb8\x9a\xad\xcc\xa1\xc0\x12\xf5\x6a\x02\xdf\x67\xd7\x24\xf6\x0f\x8c\x49\xec\xff\x79\xf2\xbf\x00\x00\x00\xff\xff\x82\x9c\x59\xe7\x4d\x19\x00\x00")
+var _faucetHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x6d\x6f\xdc\x36\x12\xfe\xec\xfc\x8a\xa9\x2e\xad\x77\x61\x4b\xb2\xe3\x20\x2d\xd6\xd2\x16\x41\x9a\x4b\x7b\x38\xb4\x45\x9b\xe2\xae\x68\x8b\x03\x25\xcd\x4a\x8c\x29\x52\x25\x87\xbb\xde\x1a\xfb\xdf\x0f\x24\x25\xad\x76\x6d\xa7\xb9\x4b\xf3\x61\x23\x92\x33\xcf\xbc\x51\xf3\x22\x67\x9f\x7c\xf5\xdd\xab\xb7\x3f\x7f\xff\x1a\x1a\x6a\xc5\xf2\x49\xe6\xfe\x03\xc1\x64\x9d\x47\x28\xa3\xe5\x93\x93\xac\x41\x56\x2d\x9f\x9c\x9c\x64\x2d\x12\x83\xb2\x61\xda\x20\xe5\x91\xa5\x55\xfc\x45\xb4\x3f\x68\x88\xba\x18\x7f\xb7\x7c\x9d\x47\xff\x8e\x7f\x7a\x19\xbf\x52\x6d\xc7\x88\x17\x02\x23\x28\x95\x24\x94\x94\x47\xdf\xbc\xce\xb1\xaa\x71\xc2\x27\x59\x8b\x79\xb4\xe6\xb8\xe9\x94\xa6\x09\xe9\x86\x57\xd4\xe4\x15\xae\x79\x89\xb1\x5f\x9c\x03\x97\x9c\x38\x13\xb1\x29\x99\xc0\xfc\x32\x5a\x3e\x71\x38\xc4\x49\xe0\xf2\xee\x2e\xf9\x16\x69\xa3\xf4\xcd\x6e\xb7\x80\x37\x9c\xbe\xb6\x05\xfc\x9d\xd9\x12\x29\x4b\x03\x89\xa7\x16\x5c\xde\x40\xa3\x71\x95\x47\x4e\x67\xb3\x48\xd3\xb2\x92\xef\x4c\x52\x0a\x65\xab\x95\x60\x1a\x93\x52\xb5\x29\x7b\xc7\x6e\x53\xc1\x0b\x93\xd2\x86\x13\xa1\x8e\x0b\xa5\xc8\x90\x66\x5d\x7a\x95\x5c\x25\x9f\xa7\xa5\x31\xe9\xb8\x97\xb4\x5c\x26\xa5\x31\x11\x68\x14\x79\x64\x68\x2b\xd0\x34\x88\x14\x41\xba\xfc\xff\xe4\xae\x94\xa4\x98\x6d\xd0\xa8\x16\xd3\xe7\xc9\xe7\xc9\x85\x17\x39\xdd\x7e\xbf\x54\x27\xd6\x94\x9a\x77\x04\x46\x97\x1f\x2c\xf7\xdd\xef\x16\xf5\x36\xbd\x4a\x2e\x93\xcb\x7e\xe1\xe5\xbc\x33\xd1\x32\x4b\x03\xe0\xf2\xa3\xb0\x63\xa9\x68\x9b\x3e\x4b\x9e\x27\x97\x69\xc7\xca\x1b\x56\x63\x35\x48\x72\x47\xc9\xb0\xf9\x97\xc9\x7d\x2c\x86\xef\x8e\x43\xf8\x57\x08\x6b\x55\x8b\x92\x92\x77\x26\x7d\x96\x5c\x7e\x91\x5c\x0c\x1b\xf7\xf1\xbd\x00\x17\x34\x27\xea\x24\x59\xa3\x26\x5e\x32\x11\x97\x28\x09\x35\xdc\xb9\xdd\x93\x96\xcb\xb8\x41\x5e\x37\xb4\x80\xcb\x8b\x8b\x4f\xaf\x1f\xda\x5d\x37\x61\xbb\xe2\xa6\x13\x6c\xbb\x80\x95\xc0\xdb\xb0\xc5\x04\xaf\x65\xcc\x09\x5b\xb3\x80\x80\xec\x0f\x76\x5e\x66\xa7\x55\xad\xd1\x98\x5e\x58\xa7\x0c\x27\xae\xe4\xc2\xdd\x28\x46\x7c\x8d\x0f\xd1\x9a\x8e\xc9\x7b\x0c\xac\x30\x4a\x58\xc2\x23\x45\x0a\xa1\xca\x9b\xb0\xe7\x5f\xe3\xa9\x11\xa5\x12\x4a\x2f\x60\xd3\xf0\x9e\x0d\xbc\x20\xe8\x34\xf6\xf0\xd0\xb1\xaa\xe2\xb2\x5e\xc0\x8b\xae\xb7\x07\x5a\xa6\x6b\x2e\x17\x70\xb1\x67\xc9\xd2\xc1\x8d\x59\x1a\x32\xd6\x93\x93\xac\x50\xd5\xd6\xc7\xb0\xe2\x6b\x28\x05\x33\x26\x8f\x8e\x5c\xec\x33\xd1\x01\x81\x4b\x40\x8c\xcb\xe1\xe8\xe0\x4c\xab\x4d\x04\x5e\x50\x1e\x05\x25\xe2\x42\x11\xa9\x76\x01\x97\x4e\xbd\x9e\xe5\x08\x4f\xc4\xa2\x8e\x2f\x9f\x0d\x87\x27\x59\x73\x39\x80\x10\xde\x52\xec\xe3\x33\x46\x26\x5a\x66\x7c\xe0\x5d\x31\x58\xb1\xb8\x60\xd4\x44\xc0\x34\x67\x71\xc3\xab\x0a\x65\x1e\x91\xb6\xe8\xee\x11\x5f\xc2\x34\xef\x0d\x69\xef\xa5\xa5\x06\xa5\xb3\x93\xb0\xea\x93\x20\x1c\xc3\xd6\x9c\x1a\x5b\xc4\x4c\xd0\xa3\xe0\x59\xda\x5c\x0e\x26\xa5\x15\x5f\xf7\x1e\x99\x3c\x1e\x39\xe7\x71\xfb\xbf\x80\xfe\x41\xad\x56\x06\x29\x9e\xb8\x63\x42\xcc\x65\x67\x29\xae\xb5\xb2\xdd\x78\x7e\x92\xf9\x5d\xe0\x55\x1e\xd5\xdc\x50\x04\xb4\xed\x7a\xdf\x45\xa3\x49\x4a\xb7\xb1\x0b\x9d\x56\x22\x82\x4e\xb0\x12\x1b\x25\x2a\xd4\x79\xd4\xfb\xe4\x0d\x37\x04\x3f\xfd\xf0\x4f\xe8\x03\xcc\x65\x0d\x5b\x65\x35\xbc\xa6\x06\x35\xda\x16\x58\x55\xb9\xcb\x9d\x24\xc9\x44\xb6\xbf\xe9\xf7\xb5\x8b\x0b\x92\x7b\xaa\x93\xac\xb0\x44\x6a\x24\x2c\x48\x42\x41\x32\xae\x70\xc5\xac\x20\xa8\xb4\xea\x2a\xb5\x91\x31\xa9\xba\x76\x05\x31\x58\x10\x98\x22\xa8\x18\xb1\xfe\x28\x8f\x06\xda\x21\x28\xcc\x74\xaa\xb3\x5d\x1f\x96\xb0\x89\xb7\x1d\x93\x15\x56\x2e\x94\xc2\x60\xb4\x7c\xc3\xd7\x08\x2d\x06\x5b\x4e\x8e\x23\x5d\x32\x8d\x14\x4f\x41\x1f\x88\x74\x50\x26\x98\x04\xfd\xbf\xcc\x8a\x01\x69\x34\xa1\x45\x69\xe1\x60\x15\x6b\x97\x85\xa2\xe5\xdd\x9d\x66\xb2\x46\x78\xca\xab\xdb\x73\x78\xca\x5a\x65\x25\xc1\x22\x87\xe4\xa5\x7f\x34\xbb\xdd\x01\x3a\x40\x26\xf8\x32\x63\xef\x7b\x19\x40\xc9\x52\xf0\xf2\x26\x8f\x88\xa3\xce\xef\xee\x1c\xf8\x6e\x77\x0d\x77\x77\x7c\x05\x4f\x93\x1f\xb0\x64\x1d\x95\x0d\xdb\xed\x6a\x3d\x3c\x27\x78\x8b\xa5\x25\x9c\xcd\xef\xee\x50\x18\xdc\xed\x8c\x2d\x5a\x4e\xb3\x81\xdd\xed\xcb\x6a\xb7\x73\x3a\xf7\x7a\xee\x76\x90\x3a\x50\x59\xe1\x2d\x3c\x4d\xbe\x47\xcd\x55\x65\x20\xd0\x67\x29\x5b\x66\xa9\xe0\xcb\x9e\xef\xd0\x49\xa9\x15\xfb\xfb\x92\xba\x0b\x33\x5e\x6d\xff\xa6\x78\x55\xa7\x9a\x3e\x70\xf1\xeb\x78\xd4\xbe\xbf\x0f\x86\x13\xde\xe0\x36\x8f\xee\xee\xa6\xbc\xfd\x69\xc9\x84\x28\x98\xf3\x4b\x30\x6d\x64\xfa\x03\xdd\x3d\x5d\x73\xe3\x3b\xaf\xe5\xa0\xc1\x5e\xed\x0f\x7c\x93\x8f\xd2\x1c\xa9\x6e\x01\x57\xcf\x26\x39\xee\xa1\x97\xfc\xc5\xd1\x4b\x7e\xf5\x20\x71\xc7\x24\x0a\xf0\xbf\xb1\x69\x99\x18\x9e\xfb\xb7\x65\xf2\xf2\x1d\x33\xc5\x2e\xa3\x8f\xaa\x8d\x95\xe1\xe2\x1a\xd4\x1a\xf5\x4a\xa8\xcd\x02\x98\x25\x75\x0d\x2d\xbb\x1d\xab\xe3\xd5\xc5\xc5\x54\x6f\xd7\x31\xb2\x42\xa0\x4f\x28\x1a\x7f\xb7\x68\xc8\x8c\x89\x24\x1c\xf9\x5f\x97\x4f\x2a\x94\x06\xab\x23\x6f\x38\x89\xce\xb5\x9e\x6a\x12\xfa\xd1\x99\x0f\xea\xbe\x52\x6a\x2c\x38\x53\x35\x7a\xe8\x49\x6d\x8c\x96\x19\xe9\x3d\xdd\x49\x46\xd5\xff\x54\x30\xb4\x6b\x08\x1f\xab\x17\x21\xa3\x39\xdb\x3b\x44\x1d\xba\x11\x77\x65\xc1\x2f\xb3\x94\xaa\x8f\x90\xec\x2e\x61\xc1\x0c\x7e\x88\x78\xdf\x17\xec\xc5\xfb\xe5\xc7\xca\x6f\x90\x69\x2a\x90\x3d\x5e\xd2\x26\x0a\xac\xac\xac\x26\xf6\xfb\xdc\xf9\xb1\x0a\x58\xc9\xd7\xa8\x0d\xa7\xed\x87\x6a\x80\xd5\x5e\x85\xb0\x3e\x54\x21\x4b\x49\xbf\xff\xae\x4d\x17\x7f\xd1\xcb\xfd\x67\x0d\xcc\xd5\xf2\x6b\xb5\x81\x4a\xa1\x01\x6a\xb8\x01\xd7\x7e\x7c\x99\xa5\xcd\xd5\x48\xd2\x2d\xdf\xba\x03\xef\x54\x58\x85\x0e\x84\x1b\xd0\x56\xfa\xca\xab\x24\x50\x83\x87\xcd\x8b\x0c\x4f\x09\xbc\x55\xae\x01\x5c\xa3\x24\x68\x99\xe0\x25\x57\xd6\x00\x2b\x49\x69\x03\x2b\xad\x5a\xc0\xdb\x86\x59\x43\x0e\xc8\xa5\x0f\xb6\x66\x5c\xf8\x77\xc9\x87\x14\x94\x06\x56\x96\xb6\xb5\xae\x81\x95\x35\xa0\x54\xb6\x6e\x7a\x5d\x48\x41\x28\x4c\x42\xc9\x7a\xd4\xc7\x74\xac\x05\x46\xc4\xca\x1b\x73\x0e\x43\x56\x00\xa6\x11\x88\x63\xe5\xb8\xfa\x3e\x82\x95\xa5\x2f\x66\x09\xbc\x94\x5b\x25\x11\x1a\xb6\xf6\x8a\x1c\x11\x40\xcb\xb6\x03\x50\xaf\xd7\x86\x53\xc3\x83\xe1\x1d\xea\xd6\x4d\x24\x15\x08\xde\x72\x32\x49\x96\x76\x53\xdf\xa9\x43\xd6\x73\x30\xbc\xed\xc4\x16\x4a\x8d\x8c\x10\x18\x64\xec\x68\x98\x74\xad\x51\x12\x7a\x3a\x3f\x8e\x44\x40\x4c\xd7\x6e\x54\xff\x0f\x2b\x94\xa5\x45\x21\x98\xbc\x71\xad\xc2\xd8\x0e\xb9\xb2\xe6\x95\x7a\xb8\x11\x82\x8e\x19\xa7\x21\x97\xa4\xbc\xd2\xfd\x6c\x6e\x60\xe6\x56\x2b\x2e\xd0\x8f\xef\xfe\x1e\xc8\x53\x67\xb1\x9b\xb1\xe6\xe7\x50\xaa\x6e\x1b\xb8\x3d\x9f\x53\xcd\xf8\xde\x6b\x84\x62\x85\x5a\x23\x84\xc6\xae\x50\xb7\xc0\x64\x05\x2b\xae\x11\xd8\x86\x6d\x3f\x81\x9f\x95\x85\x92\x49\x20\xcd\xca\x9b\x20\xdb\x6a\xed\x2e\x44\x87\xd2\x25\xfd\x7d\x88\x0a\x14\x6a\xe3\x49\x02\xda\x8a\xa3\xf0\xf1\x32\x88\xd0\xa8\x0d\xb4\xb6\xf4\x06\xba\x40\xa1\x3b\xd8\x30\x4e\x60\x25\x71\x11\xec\x26\xab\x25\x94\xaa\xc5\x83\x28\xdc\xab\xda\x19\xb6\xcb\xb7\xce\xee\x7b\x97\x79\xac\xb7\xa0\xf1\x55\x20\x87\x4e\x2b\xc2\xd2\x0d\x46\xc0\x6a\xc6\xa5\x71\x76\xfa\x38\x63\xfb\x01\xf5\x78\x7c\xea\x1f\xf6\x93\xa8\x3f\x4e\x53\x78\x23\x54\xc1\x04\xac\x5d\x96\x29\x84\x7b\x11\x15\xb8\x96\xf7\xc0\x5b\x86\x18\x59\x03\x6a\xe5\x77\x83\xe6\x8e\x7f\xcd\xb4\xbb\xed\xd8\x76\x04\x79\x3f\x47\xb9\x3d\x83\x7a\xdd\x4f\x87\x6e\xe9\x7a\xae\x70\xde\x0b\xfd\x0a\x57\x5c\x86\xa0\xae\xac\x0c\xe6\x51\xc3\x08\x42\x17\x62\x80\xf9\x60\x83\xd5\x02\xfa\x48\x07\xc8\x51\x80\xa7\x83\x7c\x64\x9f\xdd\xf3\x73\xff\xd0\xfb\x68\xde\xcf\x81\x01\x26\x31\x28\xab\xd9\x3f\x7e\xfc\xee\xdb\xc4\x90\xe6\xb2\xe6\xab\xed\xec\xce\x6a\xb1\x80\xa7\xb3\xe8\x6f\x7e\x3c\x98\xff\x72\xf1\x5b\xb2\x66\xc2\xe2\xb9\x37\x60\xe1\x7f\xef\x89\x39\x87\xfe\x71\x01\x87\x12\x77\xf3\xf9\xf5\xc3\x2d\xdb\xa4\xc3\xd4\x68\x90\x66\x8e\x70\x8c\xe4\xee\xfa\xd0\x49\x0c\x5a\xa4\x46\xf9\xbb\xa8\xb1\x54\x52\x62\x49\x60\x3b\x25\x7b\x9f\x80\x50\xc6\x0c\x8e\xd9\x53\x4c\x7c\x33\x18\xcf\x57\x30\x1b\xc2\xf5\x29\x3c\x83\x3c\x87\x8b\xe1\xac\xf7\x0c\xe4\x20\x71\x03\xff\xc2\xe2\x47\x55\xde\x20\xcd\xa2\x8d\x71\x69\x21\x82\x33\x10\xaa\x64\x0e\x2f\x69\x94\x21\x38\x83\x28\x65\x1d\x8f\xe6\x61\x9a\xde\x81\x6b\x91\xff\x1c\xec\x83\xb0\xc2\xf7\x86\xa0\xe9\xd9\x59\xb8\x36\x43\xe8\x94\x6c\xd1\x18\x56\xe3\xd4\x42\x9f\xe5\x47\x53\x9c\x23\x5a\x53\x43\x0e\x3e\xc4\x1d\xd3\x06\x03\x49\xe2\x3a\x8b\x5e\x8a\x77\x87\x27\xcb\x73\x90\x56\x88\x91\xff\x44\xa3\x7b\x99\x7b\xb2\xdd\x93\x03\xf2\x24\x24\xe1\x4f\xf2\x1c\x5c\x99\x75\x31\xaa\xf6\x9c\xee\xfa\x84\x86\x60\x9e\xb8\x4a\xbf\xe7\x98\x8f\x70\xf7\xd0\xb0\xfa\x33\x38\xac\x8e\xf1\xb0\x7a\x04\xd0\xf7\x5f\xef\xc3\x0b\xfd\xda\x04\xce\x6f\x3c\x82\x26\x6d\x5b\xa0\x7e\x1f\x5c\xe8\xbf\x7a\x38\xef\xea\x6f\x24\x4d\x78\xcf\xe1\xf2\xc5\xfc\x11\x74\xd4\x5a\x3d\x0a\x2e\x15\x6d\x67\x77\x82\x6d\x5d\xd5\x81\x53\x52\xdd\x2b\xdf\x2e\x9d\x9e\x83\x93\xb5\x80\x11\xe1\xdc\x0f\xc2\x0b\x38\xf5\xab\xd3\xdd\x23\xd2\x8c\x2d\x4b\x57\x8f\x3e\x46\x5e\x8f\x31\x4a\xec\xd7\x8f\xca\x1c\xeb\xcb\x81\x50\xf8\xec\x33\xb8\x77\x7a\x78\x05\xdd\x1d\xee\x0b\x25\xe4\x10\x45\x3d\xfc\xc9\x4a\x69\x98\xb9\x43\x9e\x5f\x5c\x03\xcf\xa6\x30\x89\x40\x59\x53\x73\x0d\xfc\xec\x6c\x8f\x74\x32\xc0\x9c\xe5\x10\xb9\x89\x20\xa3\x6a\xe9\x3b\xb3\xd0\xbe\xfd\x1a\xb9\x09\xb0\xd6\xca\xca\x6a\xe1\x52\xee\xec\x74\xdf\x0c\x4c\xfa\x80\xb3\x03\x95\x7f\xe1\xbf\x25\xd6\xa0\xf6\x95\xfb\x0c\xa2\xa4\x93\xf5\x97\x7e\x6e\x7c\xf1\xfc\x74\x7e\x0d\x7b\x4c\x3f\x4d\x2e\xa0\x74\xb3\xd5\x35\x84\xf9\xc4\x77\x89\x30\x4e\x56\x7e\x55\x28\x5d\xa1\x8e\x35\xab\xb8\x35\x0b\x78\xde\xdd\x5e\xff\x3a\x4c\x9e\xbe\x97\xf5\x7a\x77\x1a\x97\x0f\xe9\x32\xb4\x4b\x67\x10\x65\xa9\x23\x1a\x58\x46\x2b\xa7\x5f\x0d\xe1\x81\x2e\x1c\xc6\x6f\x7a\xfd\x7e\xcb\xab\x4a\xa0\x53\xc2\x0b\x0c\x1f\x5f\x2b\xab\x7d\xe2\x9a\x85\xf5\xec\x58\x0f\xe2\x2d\xce\x13\x2b\xf9\xed\x6c\x1e\xf7\x34\xc3\xfa\x1c\x4e\x8d\xcb\xcf\x95\x39\x9d\x27\x8d\x6d\x99\xe4\x7f\xe0\xcc\xb5\xf4\xf3\xa0\xb7\xd3\xd8\xf5\xe9\x63\xb4\x77\x93\x17\x6d\x9c\x31\xe7\x49\x43\xad\x98\x45\x19\xf9\x2f\x93\x4e\xb9\x31\xc4\x1e\x25\x6c\x1f\xde\xc8\xdd\x61\x0e\x2d\x85\x32\x78\x54\x23\xc0\x20\xbd\xe5\x2d\x2a\x4b\xb3\xb1\x8e\x9c\xbb\xb9\xf7\x62\x7e\x0d\xbb\xfd\x07\xdc\x34\x85\xd7\xc6\x4d\x12\xdc\x34\xc0\x60\x83\x85\xf1\xf9\x1d\x7a\x1e\x5f\xce\x43\xd9\x7e\xf9\xfd\x37\x93\xd2\x3d\xa2\xce\xbc\x72\xe3\x07\xec\x87\xea\xe4\x83\x5f\xcc\x37\x9b\x4d\x52\x2b\x55\x8b\xf0\xad\x7c\x2c\xa4\xae\x7a\x24\xef\xdc\xb8\x6a\xb6\xb2\x84\x0a\x57\xa8\x97\x13\xf8\xbe\xba\x66\x69\xf8\x96\x9b\xa5\xe1\xef\x54\xff\x0d\x00\x00\xff\xff\x71\x50\x77\xf3\xb8\x1a\x00\x00")
func faucetHtmlBytes() ([]byte, error) {
return bindataRead(
diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go
index fc957721d..5a5dc6506 100644
--- a/cmd/puppeth/module_faucet.go
+++ b/cmd/puppeth/module_faucet.go
@@ -51,10 +51,10 @@ ADD account.pass /account.pass
EXPOSE 8080
CMD [ \
- "/faucet", "--genesis", "/genesis.json", "--network", "{{.NetworkID}}", "--bootnodes", "{{.Bootnodes}}", "--ethstats", "{{.Ethstats}}", \
- "--ethport", "{{.EthPort}}", "--faucet.name", "{{.FaucetName}}", "--faucet.amount", "{{.FaucetAmount}}", "--faucet.minutes", "{{.FaucetMinutes}}", \
- "--github.user", "{{.GitHubUser}}", "--github.token", "{{.GitHubToken}}", "--account.json", "/account.json", "--account.pass", "/account.pass" \
- {{if .CaptchaToken}}, "--captcha.token", "{{.CaptchaToken}}", "--captcha.secret", "{{.CaptchaSecret}}"{{end}} \
+ "/faucet", "--genesis", "/genesis.json", "--network", "{{.NetworkID}}", "--bootnodes", "{{.Bootnodes}}", "--ethstats", "{{.Ethstats}}", "--ethport", "{{.EthPort}}", \
+ "--faucet.name", "{{.FaucetName}}", "--faucet.amount", "{{.FaucetAmount}}", "--faucet.minutes", "{{.FaucetMinutes}}", "--faucet.tiers", "{{.FaucetTiers}}", \
+ "--github.user", "{{.GitHubUser}}", "--github.token", "{{.GitHubToken}}", "--account.json", "/account.json", "--account.pass", "/account.pass" \
+ {{if .CaptchaToken}}, "--captcha.token", "{{.CaptchaToken}}", "--captcha.secret", "{{.CaptchaSecret}}"{{end}} \
]`
// faucetComposefile is the docker-compose.yml file required to deploy and maintain
@@ -75,6 +75,7 @@ services:
- ETH_NAME={{.EthName}}
- FAUCET_AMOUNT={{.FaucetAmount}}
- FAUCET_MINUTES={{.FaucetMinutes}}
+ - FAUCET_TIERS={{.FaucetTiers}}
- GITHUB_USER={{.GitHubUser}}
- GITHUB_TOKEN={{.GitHubToken}}
- CAPTCHA_TOKEN={{.CaptchaToken}}
@@ -105,6 +106,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
"FaucetName": strings.Title(network),
"FaucetAmount": config.amount,
"FaucetMinutes": config.minutes,
+ "FaucetTiers": config.tiers,
})
files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()
@@ -122,6 +124,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
"CaptchaSecret": config.captchaSecret,
"FaucetAmount": config.amount,
"FaucetMinutes": config.minutes,
+ "FaucetTiers": config.tiers,
})
files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
@@ -147,6 +150,7 @@ type faucetInfos struct {
port int
amount int
minutes int
+ tiers int
githubUser string
githubToken string
captchaToken string
@@ -155,7 +159,7 @@ type faucetInfos struct {
// String implements the stringer interface.
func (info *faucetInfos) String() string {
- return fmt.Sprintf("host=%s, api=%d, eth=%d, amount=%d, minutes=%d, github=%s, captcha=%v, ethstats=%s", info.host, info.port, info.node.portFull, info.amount, info.minutes, info.githubUser, info.captchaToken != "", info.node.ethstats)
+ return fmt.Sprintf("host=%s, api=%d, eth=%d, amount=%d, minutes=%d, tiers=%d, github=%s, captcha=%v, ethstats=%s", info.host, info.port, info.node.portFull, info.amount, info.minutes, info.tiers, info.githubUser, info.captchaToken != "", info.node.ethstats)
}
// checkFaucet does a health-check against an faucet server to verify whether
@@ -186,6 +190,7 @@ func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
}
amount, _ := strconv.Atoi(infos.envvars["FAUCET_AMOUNT"])
minutes, _ := strconv.Atoi(infos.envvars["FAUCET_MINUTES"])
+ tiers, _ := strconv.Atoi(infos.envvars["FAUCET_TIERS"])
// Retrieve the funding account informations
var out []byte
@@ -213,6 +218,7 @@ func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
port: port,
amount: amount,
minutes: minutes,
+ tiers: tiers,
githubUser: infos.envvars["GITHUB_USER"],
githubToken: infos.envvars["GITHUB_TOKEN"],
captchaToken: infos.envvars["CAPTCHA_TOKEN"],
diff --git a/cmd/puppeth/wizard_faucet.go b/cmd/puppeth/wizard_faucet.go
index f3fd7c2a1..66ec98c73 100644
--- a/cmd/puppeth/wizard_faucet.go
+++ b/cmd/puppeth/wizard_faucet.go
@@ -44,6 +44,7 @@ func (w *wizard) deployFaucet() {
host: client.server,
amount: 1,
minutes: 1440,
+ tiers: 3,
}
}
infos.node.genesis, _ = json.MarshalIndent(w.conf.genesis, "", " ")
@@ -68,6 +69,13 @@ func (w *wizard) deployFaucet() {
fmt.Printf("How many minutes to enforce between requests? (default = %d)\n", infos.minutes)
infos.minutes = w.readDefaultInt(infos.minutes)
+ fmt.Println()
+ fmt.Printf("How many funding tiers to feature (x2.5 amounts, x3 timeout)? (default = %d)\n", infos.tiers)
+ infos.tiers = w.readDefaultInt(infos.tiers)
+ if infos.tiers == 0 {
+ log.Error("At least one funding tier must be set")
+ return
+ }
// Accessing GitHub gists requires API authorization, retrieve it
if infos.githubUser != "" {
fmt.Println()