Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cli: Add cli to inspect Eth addresses and simulate calls #9897

Merged
merged 8 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
2 changes: 2 additions & 0 deletions chain/types/ethtypes/eth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
return addr, nil
}

// This API assumes that if an ID address is passed in, it doesn't have an equivalent
// delegated address
func TryEthAddressFromFilecoinAddress(addr address.Address, allowId bool) (EthAddress, bool, error) {
switch addr.Protocol() {
case address.ID:
Expand Down
1 change: 1 addition & 0 deletions cli/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var Commands = []*cli.Command{
WithCategory("developer", LogCmd),
WithCategory("developer", WaitApiCmd),
WithCategory("developer", FetchParamCmd),
WithCategory("developer", EthCmd),
WithCategory("network", NetCmd),
WithCategory("network", SyncCmd),
WithCategory("status", StatusCmd),
Expand Down
178 changes: 178 additions & 0 deletions cli/eth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package cli

import (
"context"
"encoding/hex"
"fmt"

"github.com/urfave/cli/v2"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-address"

"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
)

var EthCmd = &cli.Command{
Name: "eth",
Usage: "Query eth contract state",
Subcommands: []*cli.Command{
EthGetInfoCmd,
EthCallSimulateCmd,
},
}

var EthGetInfoCmd = &cli.Command{
Name: "stat",
Usage: "Print eth/filecoin addrs and code cid",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "filAddr",
Usage: "Filecoin address",
},
&cli.StringFlag{
Name: "ethAddr",
Usage: "Ethereum address",
},
},
Action: func(cctx *cli.Context) error {

shrenujbansal marked this conversation as resolved.
Show resolved Hide resolved
filAddr := cctx.String("filAddr")
ethAddr := cctx.String("ethAddr")

var faddr address.Address
var eaddr ethtypes.EthAddress

api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)

if filAddr != "" {
addr, err := address.NewFromString(filAddr)
if err != nil {
return err
}
eaddr, faddr, err = ethAddrFromFilecoinAddress(ctx, addr, api)
if err != nil {
return err
}
} else if ethAddr != "" {
if ethAddr[:2] == "0x" {
ethAddr = ethAddr[2:]
}
addr, err := hex.DecodeString(ethAddr)
if err != nil {
return err
}
copy(eaddr[:], addr)
shrenujbansal marked this conversation as resolved.
Show resolved Hide resolved
faddr, err = eaddr.ToFilecoinAddress()
if err != nil {
return err
}
} else {
return xerrors.Errorf("Neither filAddr nor ethAddr specified")
}

actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK)
if err != nil {
return err
}

fmt.Println("Filecoin address: ", faddr)
fmt.Println("Eth address: ", eaddr)
fmt.Println("Code cid: ", actor.Code.String())

return nil

},
}

var EthCallSimulateCmd = &cli.Command{
Name: "call",
Usage: "Simulate an eth contract call",
ArgsUsage: "[from] [to] [params]",
Action: func(cctx *cli.Context) error {

if cctx.NArg() != 3 {
return IncorrectNumArgs(cctx)
}

fromEthAddr, err := ethtypes.EthAddressFromHex(cctx.Args().Get(0))
if err != nil {
return err
}

toEthAddr, err := ethtypes.EthAddressFromHex(cctx.Args().Get(1))
if err != nil {
return err
}

params, err := hex.DecodeString(cctx.Args().Get(2))
if err != nil {
return err
}

api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)

res, err := api.EthCall(ctx, ethtypes.EthCall{
From: &fromEthAddr,
To: &toEthAddr,
Data: params,
}, "")
if err != nil {
fmt.Println("Eth call fails, return val: ", res)
return err
}

fmt.Println("Result: ", res)

return nil

},
}

func ethAddrFromFilecoinAddress(ctx context.Context, addr address.Address, fnapi v0api.FullNode) (ethtypes.EthAddress, address.Address, error) {
var faddr address.Address
var err error

switch addr.Protocol() {
case address.BLS, address.SECP256K1:
faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK)
if err != nil {
return ethtypes.EthAddress{}, addr, err
}
case address.Actor, address.ID:
faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK)
if err != nil {
return ethtypes.EthAddress{}, addr, err
}
fAct, err := fnapi.StateGetActor(ctx, faddr, types.EmptyTSK)
if err != nil {
return ethtypes.EthAddress{}, addr, err
}
if fAct.Address != nil && (*fAct.Address).Protocol() == address.Delegated {
faddr = *fAct.Address
}
case address.Delegated:
faddr = addr
default:
return ethtypes.EthAddress{}, addr, xerrors.Errorf("Filecoin address doesn't match known protocols")
}

ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(faddr)
if err != nil {
return ethtypes.EthAddress{}, addr, err
}

return ethAddr, faddr, nil
}
46 changes: 46 additions & 0 deletions documentation/en/cli-lotus.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ COMMANDS:
log Manage logging
wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters
eth Query eth contract state
NETWORK:
net Manage P2P Network
sync Inspect or interact with the chain syncer
Expand Down Expand Up @@ -2569,6 +2570,51 @@ OPTIONS:

```

## lotus eth
```
NAME:
lotus eth - Query eth contract state

USAGE:
lotus eth command [command options] [arguments...]

COMMANDS:
stat Print eth/filecoin addrs and code cid
call Simulate an eth contract call
help, h Shows a list of commands or help for one command

OPTIONS:
--help, -h show help (default: false)

```

### lotus eth stat
```
NAME:
lotus eth stat - Print eth/filecoin addrs and code cid

USAGE:
lotus eth stat [command options] [arguments...]

OPTIONS:
--ethaddr value Ethereum address
--filaddr value Filecoin address

```

### lotus eth call
```
NAME:
lotus eth call - Simulate an eth contract call

USAGE:
lotus eth call [command options] [from] [to] [params]

OPTIONS:
--help, -h show help (default: false)

```

## lotus net
```
NAME:
Expand Down
2 changes: 1 addition & 1 deletion node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message) (res *
return nil, xerrors.Errorf("CallWithGas failed: %w", err)
}
if res.MsgRct.ExitCode.IsError() {
return nil, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error)
return nil, xerrors.Errorf("message execution failed: exit %s, msg receipt: %s, reason: %s", res.MsgRct.ExitCode, res.MsgRct.Return, res.Error)
}
return res, nil
}
Expand Down