fix: cli: better handle sending from EthAccount actors

This will make `lotus send` mostly just "do what the user wants" in this
case:

1. The user may not explicitly specify a method number.
2. Parameters are automatically cbor-encoded where applicable.
3. The method number is automatically selected based on the
   recipient (CreateExternal if sent to the EAM, InvokeEVM otherwise).
This commit is contained in:
Steven Allen
2023-02-24 15:15:41 -08:00
parent 1ec02c5c95
commit 68b401a895
3 changed files with 105 additions and 16 deletions
+43 -13
View File
@@ -1,15 +1,18 @@
package cli
import (
"bytes"
"encoding/hex"
"fmt"
"strings"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types"
@@ -117,15 +120,51 @@ var sendCmd = &cli.Command{
params.From = faddr
}
if params.From.Protocol() == address.Delegated {
if cctx.IsSet("params-hex") {
decparams, err := hex.DecodeString(cctx.String("params-hex"))
if err != nil {
return fmt.Errorf("failed to decode hex params: %w", err)
}
params.Params = decparams
}
if ethtypes.IsEthAddress(params.From) {
// Method numbers don't make sense from eth accounts.
if cctx.IsSet("method") {
return xerrors.Errorf("messages from f410f addresses may not specify a method number")
}
// Now, figure out the correct method number from the recipient.
if params.To == builtintypes.EthereumAddressManagerActorAddr {
params.Method = builtintypes.MethodsEAM.CreateExternal
} else {
params.Method = builtintypes.MethodsEVM.InvokeContract
}
if cctx.IsSet("params-json") {
return xerrors.Errorf("may not call with json parameters from an eth account")
}
// And format the parameters, if present.
if len(params.Params) > 0 {
var buf bytes.Buffer
if err := cbg.WriteByteArray(&buf, params.Params); err != nil {
return xerrors.Errorf("failed to marshal EVM parameters")
}
params.Params = buf.Bytes()
}
// We can only send to an f410f or f0 address.
if !(params.To.Protocol() == address.ID || params.To.Protocol() == address.Delegated) {
api := srv.FullNodeAPI()
// Resolve id addr if possible.
params.To, err = api.StateLookupID(ctx, params.To, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("f4 addresses can only send to other f4 or id addresses. could not find id address for %s", params.To.String())
return xerrors.Errorf("addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for %s", params.To.String())
}
}
} else {
params.Method = abi.MethodNum(cctx.Uint64("method"))
}
if cctx.IsSet("gas-premium") {
@@ -149,22 +188,13 @@ var sendCmd = &cli.Command{
params.GasLimit = &limit
}
params.Method = abi.MethodNum(cctx.Uint64("method"))
if cctx.IsSet("params-json") {
decparams, err := srv.DecodeTypedParamsFromJSON(ctx, params.To, params.Method, cctx.String("params-json"))
if err != nil {
return fmt.Errorf("failed to decode json params: %w", err)
}
params.Params = decparams
}
if cctx.IsSet("params-hex") {
if params.Params != nil {
return fmt.Errorf("can only specify one of 'params-json' and 'params-hex'")
}
decparams, err := hex.DecodeString(cctx.String("params-hex"))
decparams, err := srv.DecodeTypedParamsFromJSON(ctx, params.To, params.Method, cctx.String("params-json"))
if err != nil {
return fmt.Errorf("failed to decode hex params: %w", err)
return fmt.Errorf("failed to decode json params: %w", err)
}
params.Params = decparams
}