Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Miner namespace #377

Merged
merged 39 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7ef52ce
miner namespace
ramacarlucho Jul 26, 2021
dce20db
SetGasPrice call
hanchon Jul 26, 2021
60808e0
Added note plus fixed error logging
hanchon Jul 26, 2021
609677e
Refactor to use the keyring in the miner namespace
hanchon Jul 26, 2021
e22252b
Merge branch 'tharsis:main' into miner_namespace
hanchon Jul 27, 2021
f9d4a01
Changed keyring function return
hanchon Jul 27, 2021
bfc58d8
Added more detailed logs to unsupported functions
hanchon Jul 27, 2021
b479e04
Merge branch 'miner_namespace' of github.com:hanchon/ethermint into m…
hanchon Jul 27, 2021
d7b5f87
Reverted changes on ethapi and just using a refrence to it on miner
hanchon Jul 27, 2021
61742f7
Creating a transaction
hanchon Jul 27, 2021
292ccfc
fix condition
ramacarlucho Jul 27, 2021
0e527ce
Error string not capitalized
hanchon Jul 27, 2021
0af193d
suggested changes to setEtherbase
ramacarlucho Jul 28, 2021
37c1950
change log level
ramacarlucho Jul 28, 2021
6efe47c
minor changes
ramacarlucho Jul 28, 2021
b10cc83
minor changes
ramacarlucho Jul 28, 2021
5fc883e
Merge branch 'tharsis:main' into miner_corrections
hanchon Jul 28, 2021
b6ffa96
Merge branch 'tharsis:main' into miner_namespace
hanchon Jul 28, 2021
78e0a46
Sending tx to test the endpoint
hanchon Jul 28, 2021
66c9aa4
get tx nonce
ramacarlucho Jul 28, 2021
4807d4d
Using aphoton const and changing the logger to debug
hanchon Jul 28, 2021
235a3a6
Merge pull request #1 from hanchon/miner_corrections
hanchon Jul 28, 2021
6179c5b
Using default RPC gas limit constant
hanchon Jul 28, 2021
5e025d6
Apply suggestions from code review
ramacarlucho Jul 29, 2021
e89bc48
pair programming session
fedekunze Jul 30, 2021
f243ad8
get gas
ramacarlucho Jul 30, 2021
ef576c5
Set gas prices note added
hanchon Aug 2, 2021
adb4cf9
Setting fess and max gas
hanchon Aug 2, 2021
0faf64e
delete unnecessary log
ramacarlucho Aug 2, 2021
7757254
Apply suggestions from code review
ramacarlucho Aug 3, 2021
1a09f3f
Suggested changes applied
hanchon Aug 3, 2021
2987a8b
Updated changelog and json_rpc docs
hanchon Aug 3, 2021
6acf94c
Update CHANGELOG.md
ramacarlucho Aug 3, 2021
11c56f9
Update ethereum/rpc/namespaces/miner/api.go
hanchon Aug 4, 2021
106d709
Update ethereum/rpc/namespaces/miner/api.go
hanchon Aug 4, 2021
bbd1567
Update ethereum/rpc/namespaces/miner/api.go
hanchon Aug 4, 2021
a5e5fd3
Update ethereum/rpc/namespaces/miner/api.go
hanchon Aug 4, 2021
41b51f6
Using the same coin denom as the gas price for the fee
hanchon Aug 4, 2021
430bfe2
Merge branch 'tharsis:main' into miner_namespace
hanchon Aug 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (rpc) [tharsis#272](https://github.com/tharsis/ethermint/pull/272) do binary search to estimate gas accurately
* (rpc) [#313](https://github.com/tharsis/ethermint/pull/313) Implement internal debug namespace (Not including logger functions nor traces).
* (rpc) [#349](https://github.com/tharsis/ethermint/pull/349) Implement configurable JSON-RPC APIs to manage enabled namespaces.
* (rpc) [#377](https://github.com/tharsis/ethermint/pull/377) Implement `miner_` namespace. `miner_setEtherbase` and `miner_setGasPrice` are working as intended. All the other calls are not applicable and return `unsupported`.

### Bug Fixes

Expand Down
13 changes: 7 additions & 6 deletions docs/basics/json_rpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,13 @@ ethermintd start --evm-rpc.api eth,txpool,personal,net,debug,web3
| `les_latestCheckpoint` | Les | | |
| `les_getCheckpoint` | Les | | |
| `les_getCheckpointContractAddress` | Les | | |
| `miner_getHashrate` | Miner | | |
| `miner_setExtra` | Miner | | |
| `miner_setGasPrice` | Miner | | |
| `miner_start` | Miner | | |
| `miner_stop` | Miner | | |
| `miner_setEtherbase` | Miner | | |
| `miner_getHashrate` | Miner | N/A | Not relevant to Ethermint |
| `miner_setExtra` | Miner | N/A | Not relevant to Ethermint |
| `miner_setGasPrice` | Miner | ✔ | |
| `miner_start` | Miner | N/A | Not relevant to Ethermint |
| `miner_stop` | Miner | N/A | Not relevant to Ethermint |
| `miner_setGasLimit` | Miner | N/A | Not relevant to Ethermint |
| `miner_setEtherbase` | Miner | ✔ | |
| `txpool_content` | TXPool | ✔ | |
| `txpool_inspect` | TXPool | ✔ | |
| `txpool_status` | TXPool | ✔ | |
Expand Down
11 changes: 11 additions & 0 deletions ethereum/rpc/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth/filters"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/miner"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/net"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/personal"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/txpool"
Expand All @@ -27,6 +28,7 @@ const (
NetNamespace = "net"
TxPoolNamespace = "txpool"
DebugNamespace = "debug"
MinerNamespace = "miner"

apiVersion = "1.0"
)
Expand Down Expand Up @@ -104,6 +106,15 @@ func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpccl
Public: true,
},
)
case MinerNamespace:
apis = append(apis,
rpc.API{
Namespace: MinerNamespace,
Version: apiVersion,
Service: miner.NewMinerAPI(ctx, ethAPI, evmBackend),
Public: true,
},
)
default:
ctx.Logger.Error("invalid namespace value", "namespace", selectedAPIs[index])
}
Expand Down
27 changes: 27 additions & 0 deletions ethereum/rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type Backend interface {
// Used by log filter
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
BloomStatus() (uint64, uint64)

GetCoinbase() (sdk.AccAddress, error)
}

var _ Backend = (*EVMBackend)(nil)
Expand Down Expand Up @@ -417,3 +419,28 @@ func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.
func (e *EVMBackend) BloomStatus() (uint64, uint64) {
return 4096, 0
}

// GetCoinbase is the address that staking rewards will be send to (alias for Etherbase).
func (e *EVMBackend) GetCoinbase() (sdk.AccAddress, error) {
node, err := e.clientCtx.GetNode()
if err != nil {
return nil, err
}

status, err := node.Status(e.ctx)
if err != nil {
return nil, err
}

req := &evmtypes.QueryValidatorAccountRequest{
ConsAddress: sdk.ConsAddress(status.ValidatorInfo.Address).String(),
}

res, err := e.queryClient.ValidatorAccount(e.ctx, req)
if err != nil {
return nil, err
}

address, _ := sdk.AccAddressFromBech32(res.AccountAddress)
return address, nil
}
28 changes: 10 additions & 18 deletions ethereum/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ func (e *PublicAPI) ClientCtx() client.Context {
return e.clientCtx
}

func (e *PublicAPI) QueryClient() *rpctypes.QueryClient {
return e.queryClient
}

func (e *PublicAPI) Ctx() context.Context {
return e.ctx
}

// ProtocolVersion returns the supported Ethereum protocol version.
func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
e.logger.Debug("eth_protocolVersion")
Expand Down Expand Up @@ -137,27 +145,11 @@ func (e *PublicAPI) Syncing() (interface{}, error) {
func (e *PublicAPI) Coinbase() (string, error) {
e.logger.Debug("eth_coinbase")

node, err := e.clientCtx.GetNode()
if err != nil {
return "", err
}

status, err := node.Status(e.ctx)
coinbase, err := e.backend.GetCoinbase()
if err != nil {
return "", err
}

req := &evmtypes.QueryValidatorAccountRequest{
ConsAddress: sdk.ConsAddress(status.ValidatorInfo.Address).String(),
}

res, err := e.queryClient.ValidatorAccount(e.ctx, req)
if err != nil {
return "", err
}

toAddr, _ := sdk.AccAddressFromBech32(res.AccountAddress)
ethAddr := common.BytesToAddress(toAddr.Bytes())
ethAddr := common.BytesToAddress(coinbase.Bytes())
return ethAddr.Hex(), nil
}

Expand Down
191 changes: 191 additions & 0 deletions ethereum/rpc/namespaces/miner/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package miner

import (
"errors"
"math/big"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"

authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"

"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/tharsis/ethermint/ethereum/rpc/backend"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth"
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
)

// API is the miner prefixed set of APIs in the Miner JSON-RPC spec.
type API struct {
ctx *server.Context
logger log.Logger
ethAPI *eth.PublicAPI
backend backend.Backend
}

// NewMinerAPI creates an instance of the Miner API.
func NewMinerAPI(
ctx *server.Context,
ethAPI *eth.PublicAPI,
backend backend.Backend,
) *API {
return &API{
ctx: ctx,
ethAPI: ethAPI,
logger: ctx.Logger.With("api", "miner"),
backend: backend,
}
}

// SetEtherbase sets the etherbase of the miner
func (api *API) SetEtherbase(etherbase common.Address) bool {
api.logger.Debug("miner_setEtherbase")

delAddr, err := api.backend.GetCoinbase()
if err != nil {
api.logger.Debug("failed to get coinbase address", "error", err.Error())
return false
}

withdrawAddr := sdk.AccAddress(etherbase.Bytes())
msg := distributiontypes.NewMsgSetWithdrawAddress(delAddr, withdrawAddr)

if err := msg.ValidateBasic(); err != nil {
api.logger.Debug("tx failed basic validation", "error", err.Error())
return false
}

// Assemble transaction from fields
builder, ok := api.ethAPI.ClientCtx().TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
if !ok {
api.logger.Debug("clientCtx.TxConfig.NewTxBuilder returns unsupported builder", "error", err.Error())
ramacarlucho marked this conversation as resolved.
Show resolved Hide resolved
return false
}

err = builder.SetMsgs(msg)
if err != nil {
api.logger.Error("builder.SetMsgs failed", "error", err.Error())
ramacarlucho marked this conversation as resolved.
Show resolved Hide resolved
return false
}

// Fetch minimun gas price to calculate fees using the configuration.
appConf, err := config.ParseConfig(api.ctx.Viper)
if err != nil {
api.logger.Error("failed to parse file.", "file", api.ctx.Viper.ConfigFileUsed(), "error:", err.Error())
return false
}

minGasPrices := appConf.GetMinGasPrices()
if len(minGasPrices) == 0 || minGasPrices.Empty() {
api.logger.Debug("the minimun fee is not set")
return false
}
minGasPriceValue := minGasPrices[0].Amount
denom := minGasPrices[0].Denom

delCommonAddr := common.BytesToAddress(delAddr.Bytes())
nonce, err := api.ethAPI.GetTransactionCount(delCommonAddr, rpctypes.EthPendingBlockNumber)
if err != nil {
api.logger.Debug("failed to get nonce", "error", err.Error())
return false
}

txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(api.ethAPI.ClientCtx().ChainID).
WithKeybase(api.ethAPI.ClientCtx().Keyring).
WithTxConfig(api.ethAPI.ClientCtx().TxConfig).
WithSequence(uint64(*nonce)).
WithGasAdjustment(1.11)

_, gas, err := tx.CalculateGas(api.ethAPI.ClientCtx(), txFactory, msg)
if err != nil {
api.logger.Debug("failed to calculate gas", "error", err.Error())
return false
}

txFactory = txFactory.WithGas(gas)

value := new(big.Int).SetUint64(gas * minGasPriceValue.Ceil().TruncateInt().Uint64())
fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(value))}
builder.SetFeeAmount(fees)
builder.SetGasLimit(gas)

keyInfo, err := api.ethAPI.ClientCtx().Keyring.KeyByAddress(delAddr)
if err != nil {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
api.logger.Debug("failed to get the wallet address using the keyring", "error", err.Error())
return false
}

if err := tx.Sign(txFactory, keyInfo.GetName(), builder, false); err != nil {
api.logger.Debug("failed to sign tx", "error", err.Error())
return false
}

// Encode transaction by default Tx encoder
txEncoder := api.ethAPI.ClientCtx().TxConfig.TxEncoder()
txBytes, err := txEncoder(builder.GetTx())
if err != nil {
api.logger.Debug("failed to encode eth tx using default encoder", "error", err.Error())
return false
}

tmHash := common.BytesToHash(tmtypes.Tx(txBytes).Hash())

// Broadcast transaction in sync mode (default)
// NOTE: If error is encountered on the node, the broadcast will not return an error
syncCtx := api.ethAPI.ClientCtx().WithBroadcastMode(flags.BroadcastSync)
rsp, err := syncCtx.BroadcastTx(txBytes)
if err != nil || rsp.Code != 0 {
if err == nil {
err = errors.New(rsp.RawLog)
}
api.logger.Debug("failed to broadcast tx", "error", err.Error())
return false
}

api.logger.Debug("broadcasted tx to set miner withdraw address (etherbase)", "hash", tmHash.String())
return true
}

// SetGasPrice sets the minimum accepted gas price for the miner.
// NOTE: this function accepts only integers to have the same interface than go-eth
// to use float values, the gas prices must be configured using the configuration file
func (api *API) SetGasPrice(gasPrice hexutil.Big) bool {
api.logger.Info(api.ctx.Viper.ConfigFileUsed())
appConf, err := config.ParseConfig(api.ctx.Viper)
if err != nil {
api.logger.Debug("failed to parse config file", "file", api.ctx.Viper.ConfigFileUsed(), "error", err.Error())
return false
}

var unit string
minGasPrices := appConf.GetMinGasPrices()

// fetch the base denom from the sdk Config in case it's not currently defined on the node config
if len(minGasPrices) == 0 || minGasPrices.Empty() {
unit, err = sdk.GetBaseDenom()
if err != nil {
api.logger.Debug("could not get the denom of smallest unit registered", "error", err.Error())
return false
}
} else {
unit = minGasPrices[0].Denom
}

c := sdk.NewDecCoin(unit, sdk.NewIntFromBigInt(gasPrice.ToInt()))

appConf.SetMinGasPrices(sdk.DecCoins{c})
config.WriteConfigFile(api.ctx.Viper.ConfigFileUsed(), appConf)
api.logger.Info("Your configuration file was modified. Please RESTART your node.", "gas-price", c.String())
return true
}
51 changes: 51 additions & 0 deletions ethereum/rpc/namespaces/miner/unsupported.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package miner

import (
"errors"

"github.com/ethereum/go-ethereum/common/hexutil"
)

// GetHashrate returns the current hashrate for local CPU miner and remote miner.
// Unsupported in Ethermint
func (api *API) GetHashrate() uint64 {
api.logger.Debug("miner_getHashrate")
api.logger.Debug("Unsupported rpc function: miner_getHashrate")
return 0
}

// SetExtra sets the extra data string that is included when this miner mines a block.
// Unsupported in Ethermint
func (api *API) SetExtra(extra string) (bool, error) {
api.logger.Debug("miner_setExtra")
api.logger.Debug("Unsupported rpc function: miner_setExtra")
return false, errors.New("unsupported rpc function: miner_setExtra")
}

// SetGasLimit sets the gaslimit to target towards during mining.
// Unsupported in Ethermint
func (api *API) SetGasLimit(gasLimit hexutil.Uint64) bool {
api.logger.Debug("miner_setGasLimit")
api.logger.Debug("Unsupported rpc function: miner_setGasLimit")
return false
}

// Start starts the miner with the given number of threads. If threads is nil,
// the number of workers started is equal to the number of logical CPUs that are
// usable by this process. If mining is already running, this method adjust the
// number of threads allowed to use and updates the minimum price required by the
// transaction pool.
// Unsupported in Ethermint
func (api *API) Start(threads *int) error {
api.logger.Debug("miner_start")
api.logger.Debug("Unsupported rpc function: miner_start")
return errors.New("unsupported rpc function: miner_start")
}

// Stop terminates the miner, both at the consensus engine level as well as at
// the block creation level.
// Unsupported in Ethermint
func (api *API) Stop() {
api.logger.Debug("miner_stop")
api.logger.Debug("Unsupported rpc function: miner_stop")
}
2 changes: 1 addition & 1 deletion init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ if [[ $1 == "pending" ]]; then
fi

# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --evm-rpc.api eth,txpool,personal,net,debug,web3
ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --evm-rpc.api eth,txpool,personal,net,debug,web3,miner