diff --git a/cmd/faucet/README.md b/cmd/faucet/README.md
index 364689a78277..c29d097ea933 100644
--- a/cmd/faucet/README.md
+++ b/cmd/faucet/README.md
@@ -1,31 +1,27 @@
# Faucet
-The `faucet` is a simplistic web application with the goal of distributing small amounts of Ether in private and test networks.
+The `faucet` is a simplistic web application with the goal of distributing small amounts of W3Q in private and test networks.
-Users need to post their Ethereum addresses to fund in a Twitter status update or public Facebook post and share the link to the faucet. The faucet will in turn deduplicate user requests and send the Ether. After a funding round, the faucet prevents the same user requesting again for a pre-configured amount of time, proportional to the amount of Ether requested.
+Users need to post their Web3Q addresses to fund in a Twitter status update or public Facebook post and share the link to the faucet. The faucet will in turn deduplicate user requests and send the W3Q. After a funding round, the faucet prevents the same user requesting again for a pre-configured amount of time, proportional to the amount of W3Q requested.
## Operation
The `faucet` is a single binary app (everything included) with all configurations set via command line flags and a few files.
-First thing's first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set:
+First thing's first, the `faucet` needs to connect to an Web3Q network, for which it needs the wsrpc to connect network. Each of the following flags must be set:
-- `--genesis` is a path to a file containin the network `genesis.json`
-- `--network` is the devp2p network id used during connection
-- `--bootnodes` is a list of `enode://` ids to join the network through
-
-The `faucet` will use the `les` protocol to join the configured Ethereum network and will store its data in `$HOME/.faucet` (currently not configurable).
+- `--wsrpc` is a websocket rpc URL for ethclient to get data and submit tx from network
## Funding
-To be able to distribute funds, the `faucet` needs access to an already funded Ethereum account. This can be configured via:
+To be able to distribute funds, the `faucet` needs access to an already funded Web3Q account. This can be configured via:
-- `--account.json` is a path to the Ethereum account's JSON key file
+- `--account.json` is a path to the Web3Q account's JSON key file
- `--account.pass` is a path to a text file with the decryption passphrase
-The faucet is able to distribute various amounts of Ether in exchange for various timeouts. These can be configured via:
+The faucet is able to distribute various amounts of W3Q in exchange for various timeouts. These can be configured via:
-- `--faucet.amount` is the number of Ethers to send by default
+- `--faucet.amount` is the number of W3Qs to send by default
- `--faucet.minutes` is the time to wait before allowing a rerequest
- `--faucet.tiers` is the funding tiers to support (x3 time, x2.5 funds)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 2d9d7a1e99f2..db410a92105c 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -43,31 +43,16 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
- "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethclient"
- "github.com/ethereum/go-ethereum/ethstats"
- "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/nat"
- "github.com/ethereum/go-ethereum/params"
"github.com/gorilla/websocket"
)
var (
- genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with")
- apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection")
- ethPortFlag = flag.Int("ethport", 30303, "Listener port for the devp2p connection")
- bootFlag = flag.String("bootnodes", "", "Comma separated bootnode enode URLs to seed with")
- netFlag = flag.Uint64("network", 0, "Network ID to use for the Ethereum protocol")
- statsFlag = flag.String("ethstats", "", "Ethstats network monitoring auth string")
+ wsRpcFlag = flag.String("wsrpc", "", "websocket rpc URL for ethclient to get data and submit tx")
+ apiPortFlag = flag.Int("apiport", 81, "Listener port for the HTTP API connection")
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")
@@ -85,20 +70,12 @@ var (
twitterTokenFlag = flag.String("twitter.token", "", "Bearer token to authenticate with the v2 Twitter API")
twitterTokenV1Flag = flag.String("twitter.token.v1", "", "Bearer token to authenticate with the v1.1 Twitter API")
-
- goerliFlag = flag.Bool("goerli", false, "Initializes the faucet with Görli network config")
- rinkebyFlag = flag.Bool("rinkeby", false, "Initializes the faucet with Rinkeby network config")
)
var (
ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
)
-var (
- gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
- gitDate = "" // Git commit date YYYYMMDD of the release (set via linker flags)
-)
-
func main() {
// Parse the flags and set up the logger to print everything requested
flag.Parse()
@@ -110,7 +87,7 @@ func main() {
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))
+ amounts[i] = fmt.Sprintf("%s W3Qs", strconv.FormatFloat(amount, 'f', -1, 64))
if amount == 1 {
amounts[i] = strings.TrimSuffix(amounts[i], "s")
}
@@ -146,20 +123,7 @@ func main() {
if err != nil {
log.Crit("Failed to render the faucet template", "err", err)
}
- // Load and parse the genesis block requested by the user
- genesis, err := getGenesis(genesisFlag, *goerliFlag, *rinkebyFlag)
- if err != nil {
- log.Crit("Failed to parse genesis config", "err", err)
- }
- // Convert the bootnodes to internal enode representations
- var enodes []*enode.Node
- for _, boot := range strings.Split(*bootFlag, ",") {
- if url, err := enode.Parse(enode.ValidSchemes, boot); err == nil {
- enodes = append(enodes, url)
- } else {
- log.Error("Failed to parse bootnode URL", "url", boot, "err", err)
- }
- }
+
// Load up the account key and decrypt its password
blob, err := ioutil.ReadFile(*accPassFlag)
if err != nil {
@@ -179,11 +143,10 @@ func main() {
log.Crit("Failed to unlock faucet signer account", "err", err)
}
// Assemble and start the faucet light service
- faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes())
+ faucet, err := newFaucet(*wsRpcFlag, ks, website.Bytes())
if err != nil {
log.Crit("Failed to start faucet", "err", err)
}
- defer faucet.close()
if err := faucet.listenAndServe(*apiPortFlag); err != nil {
log.Crit("Failed to launch faucet API", "err", err)
@@ -200,16 +163,15 @@ type request struct {
// faucet represents a crypto faucet backed by an Ethereum light client.
type faucet struct {
- config *params.ChainConfig // Chain configurations for signing
- stack *node.Node // Ethereum protocol stack
- client *ethclient.Client // Client connection to the Ethereum chain
- index []byte // Index page to serve up on the web
+ client *ethclient.Client // Client connection to the Ethereum chain
+ index []byte // Index page to serve up on the web
keystore *keystore.KeyStore // Keystore containing the single signer
account accounts.Account // Account funding user faucet requests
head *types.Header // Current head header of the faucet
balance *big.Int // Current balance of the faucet
nonce uint64 // Current pending nonce of the faucet
+ chainId *big.Int // Current chainId use to generate faucet tx
price *big.Int // Current gas price to issue funds with
conns []*wsConn // Currently live websocket connections
@@ -227,78 +189,27 @@ type wsConn struct {
wlock sync.Mutex
}
-func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
- // Assemble the raw devp2p protocol stack
- stack, err := node.New(&node.Config{
- Name: "geth",
- Version: params.VersionWithCommit(gitCommit, gitDate),
- DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"),
- P2P: p2p.Config{
- NAT: nat.Any(),
- NoDiscovery: true,
- DiscoveryV5: true,
- ListenAddr: fmt.Sprintf(":%d", port),
- MaxPeers: 25,
- BootstrapNodesV5: enodes,
- },
- })
- if err != nil {
- return nil, err
- }
-
- // Assemble the Ethereum light client protocol
- cfg := ethconfig.Defaults
- cfg.SyncMode = downloader.LightSync
- cfg.NetworkId = network
- cfg.Genesis = genesis
- utils.SetDNSDiscoveryDefaults(&cfg, genesis.ToBlock(nil).Hash())
-
- lesBackend, err := les.New(stack, &cfg)
+func newFaucet(rpcFlag string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
+ client, err := ethclient.Dial(rpcFlag)
if err != nil {
- return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
- }
-
- // Assemble the ethstats monitoring and reporting service'
- if stats != "" {
- if err := ethstats.New(stack, lesBackend.ApiBackend, lesBackend.Engine(), stats); err != nil {
- return nil, err
- }
- }
- // Boot up the client and ensure it connects to bootnodes
- if err := stack.Start(); err != nil {
return nil, err
}
- for _, boot := range enodes {
- old, err := enode.Parse(enode.ValidSchemes, boot.String())
- if err == nil {
- stack.Server().AddPeer(old)
- }
- }
- // Attach to the client and retrieve and interesting metadatas
- api, err := stack.Attach()
+ chainId, err := client.ChainID(context.Background())
if err != nil {
- stack.Close()
return nil, err
}
- client := ethclient.NewClient(api)
return &faucet{
- config: genesis.Config,
- stack: stack,
client: client,
index: index,
keystore: ks,
+ chainId: chainId,
account: ks.Accounts()[0],
timeouts: make(map[string]time.Time),
update: make(chan struct{}, 1),
}, nil
}
-// close terminates the Ethereum connection and tears down the faucet.
-func (f *faucet) close() error {
- return f.stack.Close()
-}
-
// listenAndServe registers the HTTP handlers for the faucet and boots it up
// for service user funding requests.
func (f *faucet) listenAndServe(port int) error {
@@ -317,7 +228,11 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
// apiHandler handles requests for Ether grants and transaction statuses.
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
- upgrader := websocket.Upgrader{}
+ upgrader := websocket.Upgrader{
+ CheckOrigin: func(r *http.Request) bool {
+ return true
+ },
+ }
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
@@ -376,7 +291,6 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
if err = send(wsconn, map[string]interface{}{
"funds": new(big.Int).Div(balance, ether),
"funded": nonce,
- "peers": f.stack.Server().PeerCount(),
"requests": reqs,
}, 3*time.Second); err != nil {
log.Warn("Failed to send initial stats to client", "err", err)
@@ -493,7 +407,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
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, 21000, f.price, nil)
- signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
+ signed, err := f.keystore.SignTx(f.account, tx, f.chainId)
if err != nil {
f.lock.Unlock()
if err = sendError(wsconn, err); err != nil {
@@ -616,13 +530,11 @@ func (f *faucet) loop() {
log.Info("Updated faucet state", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp), "balance", f.balance, "nonce", f.nonce, "price", f.price)
balance := new(big.Int).Div(f.balance, ether)
- peers := f.stack.Server().PeerCount()
for _, conn := range f.conns {
if err := send(conn, map[string]interface{}{
"funds": balance,
"funded": f.nonce,
- "peers": peers,
"requests": f.reqs,
}, time.Second); err != nil {
log.Warn("Failed to send stats to client", "err", err)
@@ -738,10 +650,10 @@ func authTwitter(url string, tokenV1, tokenV2 string) (string, string, string, c
address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body)))
if address == (common.Address{}) {
//lint:ignore ST1005 This error is to be displayed in the browser
- return "", "", "", common.Address{}, errors.New("No Ethereum address found to fund")
+ return "", "", "", common.Address{}, errors.New("No Web3Q Chain address found to fund")
}
var avatar string
- if parts = regexp.MustCompile(`src="([^"]+twimg\.com/profile_images[^"]+)"`).FindStringSubmatch(string(body)); len(parts) == 2 {
+ if parts = regexp.MustCompile("src=\"([^\"]+twimg.com/profile_images[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 {
avatar = parts[1]
}
return username + "@twitter", username, avatar, address, nil
@@ -864,10 +776,10 @@ func authFacebook(url string) (string, string, common.Address, error) {
address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body)))
if address == (common.Address{}) {
//lint:ignore ST1005 This error is to be displayed in the browser
- return "", "", common.Address{}, errors.New("No Ethereum address found to fund")
+ return "", "", common.Address{}, errors.New("No Web3Q Chain address found to fund")
}
var avatar string
- if parts = regexp.MustCompile(`src="([^"]+fbcdn\.net[^"]+)"`).FindStringSubmatch(string(body)); len(parts) == 2 {
+ if parts = regexp.MustCompile("src=\"([^\"]+fbcdn.net[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 {
avatar = parts[1]
}
return username + "@facebook", avatar, address, nil
@@ -880,23 +792,7 @@ func authNoAuth(url string) (string, string, common.Address, error) {
address := common.HexToAddress(regexp.MustCompile("0x[0-9a-fA-F]{40}").FindString(url))
if address == (common.Address{}) {
//lint:ignore ST1005 This error is to be displayed in the browser
- return "", "", common.Address{}, errors.New("No Ethereum address found to fund")
+ return "", "", common.Address{}, errors.New("No Web3Q Chain address found to fund")
}
return address.Hex() + "@noauth", "", address, nil
}
-
-// getGenesis returns a genesis based on input args
-func getGenesis(genesisFlag *string, goerliFlag bool, rinkebyFlag bool) (*core.Genesis, error) {
- switch {
- case genesisFlag != nil:
- var genesis core.Genesis
- err := common.LoadJSON(*genesisFlag, &genesis)
- return &genesis, err
- case goerliFlag:
- return core.DefaultGoerliGenesisBlock(), nil
- case rinkebyFlag:
- return core.DefaultRinkebyGenesisBlock(), nil
- default:
- return nil, fmt.Errorf("no genesis flag provided")
- }
-}
diff --git a/cmd/faucet/faucet.html b/cmd/faucet/faucet.html
index dad5ad84f210..20eeecd98fa1 100644
--- a/cmd/faucet/faucet.html
+++ b/cmd/faucet/faucet.html
@@ -5,7 +5,7 @@
-
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 common 3rd party social network accounts. Anyone having a Twitter or Facebook account may request funds within the permitted limits.
-
-
-
To request funds via Twitter, make a tweet with your Ethereum address pasted into the contents (surrounding text doesn't matter). Copy-paste the tweets URL into the above input box and fire away!
-
-
-
To request funds via Facebook, publish a new public post with your Ethereum address embedded into the content (surrounding text doesn't matter). Copy-paste the posts URL into the above input box and fire away!
-
- {{if .NoAuth}}
-
-
To request funds without authentication, simply copy-paste your Ethereum address into the above input box (surrounding text doesn't matter) and fire away. This mode is susceptible to Byzantine attacks. Only use for debugging or private networks!
- {{end}}
-
-
You can track the current pending requests below the input field to see how much you have to wait until your turn comes.
- {{if .Recaptcha}}The faucet is running invisible reCaptcha protection against bots.{{end}}
-