diff --git a/faucet/go.mod b/faucet/go.mod index eee30d5..02997da 100644 --- a/faucet/go.mod +++ b/faucet/go.mod @@ -3,7 +3,7 @@ module github.com/gnolang/gnochess-faucet go 1.20 require ( - github.com/gnolang/faucet v0.0.0-20230916181707-934303e1b40d + github.com/gnolang/faucet v0.0.0-20230926204217-cdf94c5e2bb3 github.com/gnolang/gno v0.0.0-20230914214026-ef6a55bf9db2 github.com/peterbourgon/ff/v3 v3.4.0 github.com/redis/go-redis/v9 v9.2.0 @@ -16,6 +16,8 @@ require ( github.com/btcsuite/btcd/btcutil v1.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/apd v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v3 v3.2103.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -45,5 +47,6 @@ require ( golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect + golang.org/x/tools v0.6.0 // indirect google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/faucet/go.sum b/faucet/go.sum index 641a4e7..d66abe0 100644 --- a/faucet/go.sum +++ b/faucet/go.sum @@ -25,6 +25,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -49,8 +51,8 @@ github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpm github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gnolang/faucet v0.0.0-20230916181707-934303e1b40d h1:BNpijDc+VMZrw9DYbtwC94TBKEyMW/Dn3fv/h0gsfPA= -github.com/gnolang/faucet v0.0.0-20230916181707-934303e1b40d/go.mod h1:LEZJ9cCyK7PCb63RB543pTU/lbchePJPmz74MymilO0= +github.com/gnolang/faucet v0.0.0-20230926204217-cdf94c5e2bb3 h1:sKQK4srz3XfyuJeSm2VN/ofM88TjlkLuu6ijhw6FG9A= +github.com/gnolang/faucet v0.0.0-20230926204217-cdf94c5e2bb3/go.mod h1:avrJFGcj3BuetjcIzI3i7dIElUq1JygGA5Os1NvqgsU= github.com/gnolang/gno v0.0.0-20230914214026-ef6a55bf9db2 h1:/j3GhCiNnE04Yc+zF+ouY7sZuopGwYx6R9NPipSVVLE= github.com/gnolang/gno v0.0.0-20230914214026-ef6a55bf9db2/go.mod h1:dtwSoPiPCcGxACg4y2iJVWZ/vuU133n4kwF28mx6Krg= github.com/gnolang/goleveldb v0.0.9 h1:Q7rGko9oXMKtQA+Apeeed5a3sjba/mcDhzJGoTVLCKE= @@ -99,6 +101,7 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/linxGnu/grocksdb v1.8.4 h1:ZMsBpPpJNtRLHiKKp0mI7gW+NT4s7UgfD5xHxx1jVRo= @@ -209,6 +212,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/faucet/main.go b/faucet/main.go index 7df63d5..d1b6574 100644 --- a/faucet/main.go +++ b/faucet/main.go @@ -15,12 +15,15 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/gnolang/faucet" "github.com/gnolang/faucet/client" tm2Client "github.com/gnolang/faucet/client/http" "github.com/gnolang/faucet/config" "github.com/gnolang/faucet/estimate/static" + "github.com/gnolang/gno/gno.land/pkg/sdk/vm" + "github.com/gnolang/gno/tm2/pkg/sdk/bank" "github.com/peterbourgon/ff/v3" "github.com/peterbourgon/ff/v3/fftoml" "github.com/redis/go-redis/v9" @@ -61,6 +64,9 @@ type rootCfg struct { redisURL string + tokenFundMethod string + tokenFundRealm string + allowedTokens stringArr // TODO temporary } @@ -180,6 +186,20 @@ func registerFlags(fs *flag.FlagSet, c *rootCfg) { "redis connection string", ) + fs.StringVar( + &c.tokenFundRealm, + "token-fund-realm", + "", + "the path to the Realm that can fund the player", + ) + + fs.StringVar( + &c.tokenFundMethod, + "token-fund-method", + "", + "the Realm method that can fund the player", + ) + // TODO temporary fs.Var( &c.allowedTokens, @@ -221,12 +241,24 @@ func execMain(cfg *rootCfg) error { // Create the client (HTTP) cli := tm2Client.NewClient(cfg.remote) - // Prepare the middlewares - var middlewares []faucet.Middleware + // Prepare the faucet values + var ( + middlewares []faucet.Middleware + prepareTxFn faucet.PrepareTxMessageFn + ) if len(cfg.allowedTokens) != 0 { - // TODO temporary for testing purpose without redis + // TODO temporary for testing purposes without redis middlewares = append(middlewares, prepareTokenListMiddleware(cfg.allowedTokens)) + + // By default, for testing purposes, the transaction is a MsgSend + prepareTxFn = func(cfg faucet.PrepareCfg) std.Msg { + return bank.MsgSend{ + FromAddress: cfg.FromAddress, + ToAddress: cfg.ToAddress, + Amount: cfg.SendAmount, + } + } } else { redisOpts, err := redis.ParseURL(cfg.redisURL) if err != nil { @@ -234,7 +266,24 @@ func execMain(cfg *rootCfg) error { } redisClient := redis.NewClient(redisOpts) + // Prepare the middlewares middlewares = append(middlewares, prepareTokenMiddleware(redisClient)) + + // Validate the realm values + if cfg.tokenFundMethod == "" { + return errors.New("invalid token Realm method supplied") + } + + if cfg.tokenFundRealm == "" { + return errors.New("invalid token Realm path supplied") + } + + // Prepare the tx message creation + prepareTxFn = prepareTxMessage( + redisClient, + cfg.tokenFundRealm, + cfg.tokenFundMethod, + ) } // Call prepareFundMiddleware last to avoid funding users with invalid tokens middlewares = append(middlewares, prepareFundMiddleware(cli, fundLimit)) @@ -247,6 +296,7 @@ func execMain(cfg *rootCfg) error { faucet.WithLogger(newCommandLogger(logger)), faucet.WithConfig(cfg.generateFaucetConfig()), faucet.WithMiddlewares(middlewares), + faucet.WithPrepareTxMessageFn(prepareTxFn), ) if err != nil { return fmt.Errorf("unable to create faucet, %w", err) @@ -262,6 +312,39 @@ func execMain(cfg *rootCfg) error { return w.wait() } +// prepareTxMessage returns the Realm fund call message creator. +// NOTE: This prepare method assumes the token was previously saved +// in the redis storage, through a middleware +func prepareTxMessage(redisClient *redis.Client, fundRealm, fundMethod string) faucet.PrepareTxMessageFn { + return func(cfg faucet.PrepareCfg) std.Msg { + var ( + token string + err error + + ctx, cancelFn = context.WithTimeout(context.Background(), time.Second*10) + ) + + defer cancelFn() + + // Fetch the token from Redis + token, err = redisClient.HGet(ctx, "GNO:"+cfg.ToAddress.String(), "token").Result() + if err != nil { + // Invalid token request, pass it + // to the Realm as an empty value + token = "" + } + + // Prepare the method call + return vm.MsgCall{ + Caller: cfg.FromAddress, + PkgPath: fundRealm, + Func: fundMethod, + Args: []string{cfg.ToAddress.String(), token}, + Send: cfg.SendAmount, + } + } +} + type cmdLogger struct { logger *zap.Logger } @@ -499,7 +582,7 @@ func prepareTokenMiddleware(redisClient *redis.Client) faucet.Middleware { http.Error(w, "Unable to read token email", http.StatusInternalServerError) return } - // Store gno adress, email and token, so they are retrievable via the + // Store gno address, email and token, so they are retrievable via the // getEmail middleware. err = redisClient.HSet(r.Context(), "GNO:"+request.To, "email", email, "token", token).Err() if err != nil {