diff --git a/CHANGELOG.md b/CHANGELOG.md index 34db7f95..eefabf28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,12 +39,13 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (faucet) [\#678](https://github.com/cosmos/ethermint/pull/678) Faucet module has been removed in favor of client libraries such as [`@cosmjs/faucet`](https://github.com/cosmos/cosmjs/tree/master/packages/faucet). * (evm) [\#670](https://github.com/cosmos/ethermint/pull/670) Migrate types to the ones defined by the protobuf messages, which are required for the stargate release. ### Bug Fixes -* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot -* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent +* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent. +* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot. ## [v0.4.0] - 2020-12-15 diff --git a/app/ethermint.go b/app/ethermint.go index b9dfba57..78616432 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -30,7 +30,6 @@ import ( ethermintcodec "github.com/cosmos/ethermint/codec" ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/x/evm" - "github.com/cosmos/ethermint/x/faucet" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -74,7 +73,6 @@ var ( evidence.AppModuleBasic{}, upgrade.AppModuleBasic{}, evm.AppModuleBasic{}, - faucet.AppModuleBasic{}, ) // module account permissions @@ -85,7 +83,6 @@ var ( staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, gov.ModuleName: {supply.Burner}, - faucet.ModuleName: {supply.Minter}, } // module accounts that are allowed to receive tokens @@ -126,7 +123,6 @@ type EthermintApp struct { ParamsKeeper params.Keeper EvidenceKeeper evidence.Keeper EvmKeeper *evm.Keeper - FaucetKeeper faucet.Keeper // the module manager mm *module.Manager @@ -157,7 +153,7 @@ func NewEthermintApp( bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey, - evm.StoreKey, faucet.StoreKey, + evm.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(params.TStoreKey) @@ -215,9 +211,6 @@ func NewEthermintApp( app.EvmKeeper = evm.NewKeeper( app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper, ) - app.FaucetKeeper = faucet.NewKeeper( - app.cdc, keys[faucet.StoreKey], app.SupplyKeeper, - ) // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( @@ -261,7 +254,6 @@ func NewEthermintApp( staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), evidence.NewAppModule(app.EvidenceKeeper), evm.NewAppModule(app.EvmKeeper, app.AccountKeeper), - faucet.NewAppModule(app.FaucetKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -281,7 +273,6 @@ func NewEthermintApp( auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName, - faucet.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) diff --git a/codecov.yml b/codecov.yml index e754fadc..fad64951 100644 --- a/codecov.yml +++ b/codecov.yml @@ -58,7 +58,6 @@ ignore: - "docs" - "*.md" - "cmd" - - "x/faucet" - "**/*.pb.go" - "types/*.pb.go" - "tests/*" diff --git a/docs/guides/join_network.md b/docs/guides/join_network.md index 77c6c1be..12ede037 100644 --- a/docs/guides/join_network.md +++ b/docs/guides/join_network.md @@ -2,67 +2,79 @@ order: 5 --> - # Joining Chainsafe's Public Testnet -This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io). +This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io). -## Steps: -1. Install the Ethermint binaries (ethermintd & ethermint cli): -``` -git clone https://github.com/cosmos/ethermint -cd ethermint -make install -``` +## Steps -2. Create an Ethermint account: -``` -ethermintcli keys add -``` +1. Install the Ethermint binaries (ethermintd & ethermint cli) -3. Copy genesis file: -Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json + ```bash + git clone https://github.com/cosmos/ethermint + cd ethermint + make install + ``` -4. Add peers: -Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following; -``` -"7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656" -``` +2. Create an Ethermint account -5. Validate genesis and start the Ethermint network: -``` -ethermintd validate-genesis -``` -``` -ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace -``` -(we recommend running the command in the background for convenience) + ```bash + ethermintcli keys add + ``` -6. Start the RPC server: -``` -ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace -``` -where `$KEY` is the key name that was used in step 2. -(we recommend running the command in the background for convenience) +3. Copy genesis file -7. Request funds from the faucet: -You will need to know the Ethereum hex address, and it can be found with the following command: + Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json -``` -curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 -``` -Using the output of the above command, you will then send the command with your valid Ethereum address: -``` -curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000 -``` +4. Add peers + + Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following + + ```toml + "7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656" + ``` + +5. Validate genesis and start the Ethermint network + + ```bash + ethermintd validate-genesis + + ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace + ``` + + (we recommend running the command in the background for convenience) + +6. Start the RPC server + + ```bash + ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace + ``` + + where `$KEY` is the key name that was used in step 2. + (we recommend running the command in the background for convenience) + +7. Request funds from the faucet + + You will need to know the Ethereum hex address, and it can be found with the following command: + + ```bash + curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 + ``` + + Using the output of the above command, you will then send the command with your valid Ethereum address + + ```bash + curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000 + ``` ## Public Testnet Node RPC Endpoints -Node0: `54.210.246.165:8545` -Node1: `3.86.104.251:8545` -Node2: `18.204.206.179:8545` +- **Node0**: `54.210.246.165:8545` +- **Node1**: `3.86.104.251:8545` +- **Node2**: `18.204.206.179:8545` example: -``` + +```bash curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -H "Content-Type: application/json" 54.210.246.165:8545 -``` \ No newline at end of file +``` diff --git a/docs/quickstart/run_node.md b/docs/quickstart/run_node.md index 1561ef00..ca928498 100644 --- a/docs/quickstart/run_node.md +++ b/docs/quickstart/run_node.md @@ -12,7 +12,7 @@ Run a local node and start the REST and JSON-RPC clients {synopsis} ## Automated deployment -Run the local node with faucet enabled: +Run the local node ::: warning The script below will remove any pre-existing binaries installed. Use the manual deploy if you want diff --git a/docs/quickstart/testnet.md b/docs/quickstart/testnet.md index 98ca23de..1719e609 100644 --- a/docs/quickstart/testnet.md +++ b/docs/quickstart/testnet.md @@ -311,31 +311,6 @@ For more information on seeds and peers, you can the Tendermint [P2P documentati The final step is to [start the nodes](./run_node.md#start-node). Once enough voting power (+2/3) from the genesis validators is up-and-running, the testnet will start producing blocks. -## Testnet faucet - -Once the ethermint daemon is up and running, you can request tokens to your address using the `faucet` module: - -```bash -# query your initial balance -ethermintcli q bank balances $(ethermintcli keys show -a) - -# send a tx to request tokens to your account address -ethermintcli tx faucet request 100aphoton --from - -# query your balance after the request -ethermintcli q bank balances $(ethermintcli keys show -a) -``` - -You can also check to total amount funded by the faucet and the total supply of the chain via: - -```bash -# total amount funded by the faucet -ethermintcli q faucet funded - -# total supply -ethermintcli q supply total -``` - ## Next {hide} Learn about how to setup a [validator](./validator-setup.md) node on Ethermint {hide} diff --git a/init.sh b/init.sh index 46acda79..65067c73 100755 --- a/init.sh +++ b/init.sh @@ -29,9 +29,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - # increase block time (?) cat $HOME/.ethermintd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="30000"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json @@ -56,11 +53,6 @@ ethermintd gentx --name $KEY --amount=1000000000000000000aphoton --keyring-backe # Collect genesis tx ethermintd collect-gentxs -echo -e '\n\ntestnet faucet enabled' -echo -e 'to transfer tokens to your account address use:' -echo -e "ethermintcli tx faucet request 100aphoton --from $KEY\n" - - # Run this to ensure everything worked and that the genesis file is setup correctly ethermintd validate-genesis diff --git a/scripts/contract-test.sh b/scripts/contract-test.sh index 554fed6a..359bc582 100644 --- a/scripts/contract-test.sh +++ b/scripts/contract-test.sh @@ -31,9 +31,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - # Allocate genesis accounts (cosmos formatted addresses) $PWD/build/ethermintd add-genesis-account "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a)" 100000000000000000000aphoton @@ -51,7 +48,7 @@ $PWD/build/ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:inf sleep 1 -# Start the rest server with unlocked faucet key in background and log to file +# Start the rest server with unlocked key in background and log to file $PWD/build/ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id $CHAINID --trace > ethermintcli.log & solcjs --abi $PWD/tests-solidity/suites/basic/contracts/Counter.sol --bin -o $PWD/tests-solidity/suites/basic/counter diff --git a/tests-solidity/init-test-node.sh b/tests-solidity/init-test-node.sh index 867081ae..fd642d91 100755 --- a/tests-solidity/init-test-node.sh +++ b/tests-solidity/init-test-node.sh @@ -42,14 +42,6 @@ ethermintd gentx --name $VAL_KEY --keyring-backend test # Collect genesis tx ethermintd collect-gentxs -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - -echo -e '\n\ntestnet faucet enabled' -echo -e 'to transfer tokens to your account address use:' -echo -e "ethermintcli tx faucet request 100aphoton --from $VAL_KEY\n" - - # Run this to ensure everything worked and that the genesis file is setup correctly ethermintd validate-genesis diff --git a/x/faucet/alias.go b/x/faucet/alias.go deleted file mode 100644 index f280118e..00000000 --- a/x/faucet/alias.go +++ /dev/null @@ -1,24 +0,0 @@ -package faucet - -import ( - "github.com/cosmos/ethermint/x/faucet/keeper" - "github.com/cosmos/ethermint/x/faucet/types" -) - -const ( - ModuleName = types.ModuleName - RouterKey = types.RouterKey - StoreKey = types.StoreKey - QuerierRoute = types.QuerierRoute -) - -var ( - NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier - ModuleCdc = types.ModuleCdc - RegisterCodec = types.RegisterCodec -) - -type ( - Keeper = keeper.Keeper -) diff --git a/x/faucet/client/cli/query.go b/x/faucet/client/cli/query.go deleted file mode 100644 index 65725ecb..00000000 --- a/x/faucet/client/cli/query.go +++ /dev/null @@ -1,53 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - - "github.com/cosmos/ethermint/x/faucet/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GetQueryCmd defines evm module queries through the cli -func GetQueryCmd(cdc *codec.Codec) *cobra.Command { - faucetQueryCmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - faucetQueryCmd.AddCommand(flags.GetCommands( - GetCmdFunded(cdc), - )...) - return faucetQueryCmd -} - -// GetCmdFunded queries the total amount funded by the faucet. -func GetCmdFunded(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "funded", - Short: "Gets storage for an account at a given key", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := context.NewCLIContext().WithCodec(cdc) - - res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded)) - if err != nil { - return err - } - - var out sdk.Coins - cdc.MustUnmarshalJSON(res, &out) - clientCtx = clientCtx.WithHeight(height) - return clientCtx.PrintOutput(out) - }, - } -} diff --git a/x/faucet/client/cli/tx.go b/x/faucet/client/cli/tx.go deleted file mode 100644 index d3382005..00000000 --- a/x/faucet/client/cli/tx.go +++ /dev/null @@ -1,71 +0,0 @@ -package cli - -import ( - "bufio" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// GetTxCmd return faucet sub-command for tx -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - faucetTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "faucet transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - faucetTxCmd.AddCommand(flags.PostCommands( - GetCmdRequest(cdc), - )...) - - return faucetTxCmd -} - -// GetCmdRequest is the CLI command to fund an address with the requested coins -func GetCmdRequest(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "request [amount] [other-recipient (optional)]", - Short: "request an address with the requested coins", - Args: cobra.RangeArgs(1, 2), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - clientCtx := context.NewCLIContext().WithCodec(cdc) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - - amount, err := sdk.ParseCoins(args[0]) - if err != nil { - return err - } - - var recipient sdk.AccAddress - if len(args) == 1 { - recipient = clientCtx.GetFromAddress() - } else { - recipient, err = sdk.AccAddressFromBech32(args[1]) - } - - if err != nil { - return err - } - - msg := types.NewMsgFund(amount, clientCtx.GetFromAddress(), recipient) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg}) - }, - } -} diff --git a/x/faucet/client/rest/tx.go b/x/faucet/client/rest/tx.go deleted file mode 100644 index dd634694..00000000 --- a/x/faucet/client/rest/tx.go +++ /dev/null @@ -1,83 +0,0 @@ -package rest - -import ( - "fmt" - "net/http" - - "github.com/gorilla/mux" - - "github.com/cosmos/cosmos-sdk/client/context" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/rest" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// RegisterRoutes register REST endpoints for the faucet module -func RegisterRoutes(clientCtx context.CLIContext, r *mux.Router) { - r.HandleFunc(fmt.Sprintf("/%s/request", types.ModuleName), requestHandler(clientCtx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/%s/funded", types.ModuleName), fundedHandlerFn(clientCtx)).Methods("GET") -} - -// PostRequestBody defines fund request's body. -type PostRequestBody struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Amount sdk.Coins `json:"amount" yaml:"amount"` - Recipient string `json:"receipient" yaml:"receipient"` -} - -func requestHandler(clientCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req PostRequestBody - if !rest.ReadRESTReq(w, r, clientCtx.Codec, &req) { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request") - return - } - - baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { - return - } - - sender, err := sdk.AccAddressFromBech32(baseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - var recipient sdk.AccAddress - if req.Recipient == "" { - recipient = sender - } else { - recipient, err = sdk.AccAddressFromBech32(req.Recipient) - } - - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - msg := types.NewMsgFund(req.Amount, sender, recipient) - err = msg.ValidateBasic() - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - authclient.WriteGenerateStdTxResponse(w, clientCtx, baseReq, []sdk.Msg{msg}) - } -} - -func fundedHandlerFn(clientCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, _ *http.Request) { - res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - clientCtx = clientCtx.WithHeight(height) - rest.PostProcessResponse(w, clientCtx, res) - } -} diff --git a/x/faucet/genesis.go b/x/faucet/genesis.go deleted file mode 100644 index 6e3f7888..00000000 --- a/x/faucet/genesis.go +++ /dev/null @@ -1,35 +0,0 @@ -package faucet - -import ( - "fmt" - - "github.com/cosmos/ethermint/x/faucet/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - - abci "github.com/tendermint/tendermint/abci/types" -) - -// InitGenesis initializes genesis state based on exported genesis -func InitGenesis(ctx sdk.Context, k Keeper, data types.GenesisState) []abci.ValidatorUpdate { - if acc := k.GetFaucetAccount(ctx); acc == nil { - panic(fmt.Sprintf("%s module account has not been set", ModuleName)) - } - - k.SetEnabled(ctx, data.EnableFaucet) - k.SetTimout(ctx, data.Timeout) - k.SetCap(ctx, data.FaucetCap) - k.SetMaxPerRequest(ctx, data.MaxAmountPerRequest) - - return []abci.ValidatorUpdate{} -} - -// ExportGenesis exports genesis state -func ExportGenesis(ctx sdk.Context, k Keeper) types.GenesisState { - return types.GenesisState{ - EnableFaucet: k.IsEnabled(ctx), - Timeout: k.GetTimeout(ctx), - FaucetCap: k.GetCap(ctx), - MaxAmountPerRequest: k.GetMaxPerRequest(ctx), - } -} diff --git a/x/faucet/handler.go b/x/faucet/handler.go deleted file mode 100644 index 9124d704..00000000 --- a/x/faucet/handler.go +++ /dev/null @@ -1,43 +0,0 @@ -package faucet - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// NewHandler returns a handler for faucet messages. -func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - switch msg := msg.(type) { - case types.MsgFund: - return handleMsgFund(ctx, keeper, msg) - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) - } - } -} - -// handleMsgFund handles a message to fund an address -func handleMsgFund(ctx sdk.Context, keeper Keeper, msg types.MsgFund) (*sdk.Result, error) { - err := keeper.Fund(ctx, msg.Amount, msg.Recipient) - if err != nil { - return nil, err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), - sdk.NewAttribute(types.AttributeRecipient, msg.Recipient.String()), - ), - ) - - return &sdk.Result{ - Events: ctx.EventManager().Events(), - }, nil -} diff --git a/x/faucet/keeper/keeper.go b/x/faucet/keeper/keeper.go deleted file mode 100644 index 80a4a087..00000000 --- a/x/faucet/keeper/keeper.go +++ /dev/null @@ -1,209 +0,0 @@ -package keeper - -import ( - "errors" - "fmt" - "time" - - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// Keeper defines the faucet Keeper. -type Keeper struct { - cdc *codec.Codec - storeKey sdk.StoreKey - supplyKeeper types.SupplyKeeper - - // History of users and their funding timeouts. They are reset if the app is reinitialized. - timeouts map[string]time.Time -} - -// NewKeeper creates a new faucet Keeper instance. -func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, supplyKeeper types.SupplyKeeper, -) Keeper { - return Keeper{ - cdc: cdc, - storeKey: storeKey, - supplyKeeper: supplyKeeper, - timeouts: make(map[string]time.Time), - } -} - -// Logger returns a module-specific logger. -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) -} - -// GetFaucetAccount returns the faucet ModuleAccount -func (k Keeper) GetFaucetAccount(ctx sdk.Context) supplyexported.ModuleAccountI { - return k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName) -} - -// Fund checks for timeout and max thresholds and then mints coins and transfers -// coins to the recipient. -func (k Keeper) Fund(ctx sdk.Context, amount sdk.Coins, recipient sdk.AccAddress) error { - if !k.IsEnabled(ctx) { - return errors.New("faucet is not enabled. Restart the application and set faucet's 'enable_faucet' genesis field to true") - } - - if err := k.rateLimit(ctx, recipient.String()); err != nil { - return err - } - - totalRequested := sdk.ZeroInt() - for _, coin := range amount { - totalRequested = totalRequested.Add(coin.Amount) - } - - maxPerReq := k.GetMaxPerRequest(ctx) - if totalRequested.GT(maxPerReq) { - return fmt.Errorf("canot fund more than %s per request. requested %s", maxPerReq, totalRequested) - } - - funded := k.GetFunded(ctx) - totalFunded := sdk.ZeroInt() - for _, coin := range funded { - totalFunded = totalFunded.Add(coin.Amount) - } - - cap := k.GetCap(ctx) - - if totalFunded.Add(totalRequested).GT(cap) { - return fmt.Errorf("maximum cap of %s reached. Cannot continue funding", cap) - } - - if err := k.supplyKeeper.MintCoins(ctx, types.ModuleName, amount); err != nil { - return err - } - - if err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, amount); err != nil { - return err - } - - k.SetFunded(ctx, funded.Add(amount...)) - - k.Logger(ctx).Info(fmt.Sprintf("funded %s to %s", amount, recipient)) - return nil -} - -func (k Keeper) GetTimeout(ctx sdk.Context) time.Duration { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.TimeoutKey) - if len(bz) == 0 { - return time.Duration(0) - } - - var timeout time.Duration - k.cdc.MustUnmarshalBinaryBare(bz, &timeout) - - return timeout -} - -func (k Keeper) SetTimout(ctx sdk.Context, timeout time.Duration) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(timeout) - store.Set(types.TimeoutKey, bz) -} - -func (k Keeper) IsEnabled(ctx sdk.Context) bool { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.EnableFaucetKey) - if len(bz) == 0 { - return false - } - - var enabled bool - k.cdc.MustUnmarshalBinaryBare(bz, &enabled) - return enabled -} - -func (k Keeper) SetEnabled(ctx sdk.Context, enabled bool) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(enabled) - store.Set(types.EnableFaucetKey, bz) -} - -func (k Keeper) GetCap(ctx sdk.Context) sdk.Int { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.CapKey) - if len(bz) == 0 { - return sdk.ZeroInt() - } - - var cap sdk.Int - k.cdc.MustUnmarshalBinaryBare(bz, &cap) - - return cap -} - -func (k Keeper) SetCap(ctx sdk.Context, cap sdk.Int) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(cap) - store.Set(types.CapKey, bz) -} - -func (k Keeper) GetMaxPerRequest(ctx sdk.Context) sdk.Int { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.MaxPerRequestKey) - if len(bz) == 0 { - return sdk.ZeroInt() - } - - var maxPerReq sdk.Int - k.cdc.MustUnmarshalBinaryBare(bz, &maxPerReq) - - return maxPerReq -} - -func (k Keeper) SetMaxPerRequest(ctx sdk.Context, maxPerReq sdk.Int) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(maxPerReq) - store.Set(types.MaxPerRequestKey, bz) -} - -func (k Keeper) GetFunded(ctx sdk.Context) sdk.Coins { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.FundedKey) - if len(bz) == 0 { - return nil - } - - var funded sdk.Coins - k.cdc.MustUnmarshalBinaryBare(bz, &funded) - - return funded -} - -func (k Keeper) SetFunded(ctx sdk.Context, funded sdk.Coins) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(funded) - store.Set(types.FundedKey, bz) -} - -func (k Keeper) rateLimit(ctx sdk.Context, address string) error { - // first time requester, can send request - lastRequest, ok := k.timeouts[address] - if !ok { - k.timeouts[address] = time.Now().UTC() - return nil - } - - defaultTimeout := k.GetTimeout(ctx) - sinceLastRequest := time.Since(lastRequest) - - if defaultTimeout > sinceLastRequest { - wait := defaultTimeout - sinceLastRequest - return fmt.Errorf("%s has requested funds within the last %s, wait %s before trying again", address, defaultTimeout.String(), wait.String()) - } - - // user able to send funds since they have waited for period - k.timeouts[address] = time.Now().UTC() - return nil -} diff --git a/x/faucet/keeper/querier.go b/x/faucet/keeper/querier.go deleted file mode 100644 index f63a928c..00000000 --- a/x/faucet/keeper/querier.go +++ /dev/null @@ -1,34 +0,0 @@ -package keeper - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/ethermint/x/faucet/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// NewQuerier is the module level router for state queries -func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) { - switch path[0] { - case types.QueryFunded: - return queryFunded(ctx, req, k) - default: - return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query endpoint") - } - } -} - -func queryFunded(ctx sdk.Context, _ abci.RequestQuery, k Keeper) ([]byte, error) { - funded := k.GetFunded(ctx) - - bz, err := codec.MarshalJSONIndent(k.cdc, funded) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} diff --git a/x/faucet/module.go b/x/faucet/module.go deleted file mode 100644 index a770610a..00000000 --- a/x/faucet/module.go +++ /dev/null @@ -1,137 +0,0 @@ -package faucet - -import ( - "encoding/json" - "fmt" - - "github.com/gorilla/mux" - "github.com/spf13/cobra" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - - "github.com/cosmos/ethermint/x/faucet/client/cli" - "github.com/cosmos/ethermint/x/faucet/client/rest" - "github.com/cosmos/ethermint/x/faucet/types" -) - -// type check to ensure the interface is properly implemented -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} -) - -// AppModuleBasic defines the basic application module used by the faucet module. -type AppModuleBasic struct{} - -// Name returns the faucet module's name. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -// RegisterCodec registers the faucet module's types for the given codec. -func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { - RegisterCodec(cdc) -} - -// DefaultGenesis returns default genesis state as raw bytes for the faucet -// module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState()) -} - -// ValidateGenesis performs genesis state validation for the faucet module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { - var genesisState types.GenesisState - if err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) - } - - return genesisState.Validate() -} - -// RegisterRESTRoutes registers the REST routes for the faucet module. -func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr) -} - -// GetTxCmd returns the root tx command for the faucet module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) -} - -// GetQueryCmd returns no root query command for the faucet module. -func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetQueryCmd(cdc) -} - -type AppModule struct { - AppModuleBasic - keeper Keeper -} - -// NewAppModule creates a new AppModule Object -func NewAppModule(k Keeper) AppModule { - return AppModule{ - AppModuleBasic: AppModuleBasic{}, - keeper: k, - } -} - -// Name returns the faucet module's name. -func (AppModule) Name() string { - return ModuleName -} - -// RegisterInvariants registers the faucet module invariants. -func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// Route returns the message routing key for the faucet module. -func (AppModule) Route() string { - return RouterKey -} - -// NewHandler returns an sdk.Handler for the faucet module. -func (am AppModule) NewHandler() sdk.Handler { - return NewHandler(am.keeper) -} - -// QuerierRoute returns the faucet module's querier route name. -func (AppModule) QuerierRoute() string { - return QuerierRoute -} - -// NewQuerierHandler returns the faucet module sdk.Querier. -func (am AppModule) NewQuerierHandler() sdk.Querier { - return NewQuerier(am.keeper) -} - -// InitGenesis performs genesis initialization for the faucet module. It returns -// no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState types.GenesisState - types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) - return []abci.ValidatorUpdate{} -} - -// ExportGenesis returns the exported genesis state as raw bytes for the faucet -// module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) - return types.ModuleCdc.MustMarshalJSON(gs) -} - -// BeginBlock returns the begin blocker for the faucet module. -func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { -} - -// EndBlock returns the end blocker for the faucet module. It returns no validator -// updates. -func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} diff --git a/x/faucet/types/codec.go b/x/faucet/types/codec.go deleted file mode 100644 index 0378955b..00000000 --- a/x/faucet/types/codec.go +++ /dev/null @@ -1,17 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// ModuleCdc is the codec for the module -var ModuleCdc = codec.New() - -func init() { - RegisterCodec(ModuleCdc) -} - -// RegisterCodec registers concrete types on the Amino codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgFund{}, "ethermint/MsgFund", nil) -} diff --git a/x/faucet/types/errors.go b/x/faucet/types/errors.go deleted file mode 100644 index ec36514a..00000000 --- a/x/faucet/types/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -var ( - // ErrWithdrawTooOften withdraw too often - ErrWithdrawTooOften = sdkerrors.Register(ModuleName, 2, "each address can withdraw only once") -) diff --git a/x/faucet/types/events.go b/x/faucet/types/events.go deleted file mode 100644 index f43e62a5..00000000 --- a/x/faucet/types/events.go +++ /dev/null @@ -1,11 +0,0 @@ -package types - -// Faucet module events -const ( - AttributeRecipient string = "recipient" -) - -// Supported endpoints -const ( - QueryFunded = "funded" -) diff --git a/x/faucet/types/expected_keepers.go b/x/faucet/types/expected_keepers.go deleted file mode 100644 index 17fb5509..00000000 --- a/x/faucet/types/expected_keepers.go +++ /dev/null @@ -1,20 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -// SupplyKeeper is required for mining coin -type SupplyKeeper interface { - MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - SendCoinsFromModuleToAccount( - ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, - ) error - GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI -} - -// StakingKeeper is required for getting Denom -type StakingKeeper interface { - BondDenom(ctx sdk.Context) string -} diff --git a/x/faucet/types/genesis.go b/x/faucet/types/genesis.go deleted file mode 100644 index 6721482e..00000000 --- a/x/faucet/types/genesis.go +++ /dev/null @@ -1,45 +0,0 @@ -package types - -import ( - "fmt" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GenesisState defines the application's genesis state. It contains all the -// information required and accounts to initialize the blockchain. -type GenesisState struct { - // enable faucet funding - EnableFaucet bool `json:"enable_faucet" yaml:"enable_faucet"` - // addresses can send requests every duration - Timeout time.Duration `json:"timeout" yaml:"timeout"` - // max total amount to be funded by the faucet - FaucetCap sdk.Int `json:"faucet_cap" yaml:"faucet_cap"` - // max amount per request (i.e sum of all requested coin amounts). - MaxAmountPerRequest sdk.Int `json:"max_amount_per_request" yaml:"max_amount_per_request"` -} - -// Validate performs a basic validation of the GenesisState fields. -func (gs GenesisState) Validate() error { - if gs.Timeout < 0 { - return fmt.Errorf("timeout cannot be negative: %s", gs.Timeout) - } - if gs.FaucetCap.IsNegative() { - return fmt.Errorf("faucet cap cannot be negative: %d", gs.FaucetCap) - } - if gs.MaxAmountPerRequest.IsNegative() { - return fmt.Errorf("max amount per request cannot be negative: %d", gs.MaxAmountPerRequest) - } - return nil -} - -// DefaultGenesisState sets default evm genesis config -func DefaultGenesisState() GenesisState { - return GenesisState{ - EnableFaucet: false, - Timeout: 20 * time.Minute, - FaucetCap: sdk.NewInt(1000000000), - MaxAmountPerRequest: sdk.NewInt(1000), - } -} diff --git a/x/faucet/types/key.go b/x/faucet/types/key.go deleted file mode 100644 index 6b1adc75..00000000 --- a/x/faucet/types/key.go +++ /dev/null @@ -1,23 +0,0 @@ -package types - -const ( - // ModuleName is the name of the module - ModuleName = "faucet" - - // StoreKey to be used when creating the KVStore - StoreKey = ModuleName - - // RouterKey uses module name for tx routing - RouterKey = ModuleName - - // QuerierRoute uses module name for query routing - QuerierRoute = ModuleName -) - -var ( - EnableFaucetKey = []byte{0x01} - TimeoutKey = []byte{0x02} - CapKey = []byte{0x03} - MaxPerRequestKey = []byte{0x04} - FundedKey = []byte{0x05} -) diff --git a/x/faucet/types/msgs.go b/x/faucet/types/msgs.go deleted file mode 100644 index 04f91415..00000000 --- a/x/faucet/types/msgs.go +++ /dev/null @@ -1,52 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// MsgFund funds a recipient address -type MsgFund struct { - Amount sdk.Coins `json:"amount" yaml:"amount"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Recipient sdk.AccAddress `json:"receipient" yaml:"receipient"` -} - -// NewMsgFund is a constructor function for NewMsgFund -func NewMsgFund(amount sdk.Coins, sender, recipient sdk.AccAddress) MsgFund { - return MsgFund{ - Amount: amount, - Sender: sender, - Recipient: recipient, - } -} - -// Route should return the name of the module -func (msg MsgFund) Route() string { return RouterKey } - -// Type should return the action -func (msg MsgFund) Type() string { return "fund" } - -// ValidateBasic runs stateless checks on the message -func (msg MsgFund) ValidateBasic() error { - if !msg.Amount.IsValid() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) - } - if msg.Sender.Empty() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "sender %s", msg.Sender.String()) - } - if msg.Recipient.Empty() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "recipient %s", msg.Recipient.String()) - } - return nil -} - -// GetSignBytes encodes the message for signing -func (msg MsgFund) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -// GetSigners defines whose signature is required -func (msg MsgFund) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -}