package main import ( "fmt" "reflect" "github.com/urfave/cli/v2" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" lcli "github.com/filecoin-project/lotus/cli" ) var ethCmd = &cli.Command{ Name: "eth", Description: "Ethereum compatibility related commands", Flags: []cli.Flag{ &cli.StringFlag{ Name: "repo", Value: "~/.lotus", }, }, Subcommands: []*cli.Command{ checkTipsetsCmd, computeEthHashCmd, }, } var checkTipsetsCmd = &cli.Command{ Name: "check-tipsets", Description: "Check that eth_getBlockByNumber and eth_getBlockByHash consistently return tipsets", Action: func(cctx *cli.Context) error { api, closer, err := lcli.GetFullNodeAPIV1(cctx) if err != nil { return err } defer closer() ctx := lcli.ReqContext(cctx) head, err := api.ChainHead(ctx) if err != nil { return err } height := head.Height() fmt.Println("Current height:", height) for i := int64(height); i > 0; i-- { if _, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(i), types.EmptyTSK); err != nil { fmt.Printf("[FAIL] failed to get tipset @%d from Lotus: %s\n", i, err) continue } hex := fmt.Sprintf("0x%x", i) ethBlockA, err := api.EthGetBlockByNumber(ctx, hex, false) if err != nil { fmt.Printf("[FAIL] failed to get tipset @%d via eth_getBlockByNumber: %s\n", i, err) continue } ethBlockB, err := api.EthGetBlockByHash(ctx, ethBlockA.Hash, false) if err != nil { fmt.Printf("[FAIL] failed to get tipset @%d via eth_getBlockByHash: %s\n", i, err) continue } if equal := reflect.DeepEqual(ethBlockA, ethBlockB); equal { fmt.Printf("[OK] blocks received via eth_getBlockByNumber and eth_getBlockByHash for tipset @%d are identical\n", i) } else { fmt.Printf("[FAIL] blocks received via eth_getBlockByNumber and eth_getBlockByHash for tipset @%d are NOT identical\n", i) } } return nil }, } var computeEthHashCmd = &cli.Command{ Name: "compute-eth-hash", Usage: "Compute the eth hash for a given message CID", Action: func(cctx *cli.Context) error { if cctx.NArg() != 1 { return lcli.IncorrectNumArgs(cctx) } msg, err := messageFromString(cctx, cctx.Args().First()) if err != nil { return err } switch msg := msg.(type) { case *types.SignedMessage: tx, err := ethtypes.EthTxFromSignedEthMessage(msg) if err != nil { return fmt.Errorf("failed to convert from signed message: %w", err) } tx.Hash, err = tx.TxHash() if err != nil { return fmt.Errorf("failed to call TxHash: %w", err) } fmt.Println(tx.Hash) default: return fmt.Errorf("not a signed message") } return nil }, }