diff --git a/api/api_full.go b/api/api_full.go index 158590b0da6..6235e98d66b 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -630,10 +630,14 @@ type FullNode interface { // , , MsigApproveTxnHash(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (*MessagePrototype, error) //perm:sign + // MsigCancel cancels a previously-proposed multisig message + // It takes the following params: , + MsigCancel(context.Context, address.Address, uint64, address.Address) (*MessagePrototype, error) //perm:sign + // MsigCancel cancels a previously-proposed multisig message // It takes the following params: , , , , // , , - MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (*MessagePrototype, error) //perm:sign + MsigCancelTxnHash(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (*MessagePrototype, error) //perm:sign // MsigAddPropose proposes adding a signer in the multisig // It takes the following params: , , diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index a6781b0b7f8..44fe82b6095 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1428,18 +1428,33 @@ func (mr *MockFullNodeMockRecorder) MsigApproveTxnHash(arg0, arg1, arg2, arg3, a } // MsigCancel mocks base method. -func (m *MockFullNode) MsigCancel(arg0 context.Context, arg1 address.Address, arg2 uint64, arg3 address.Address, arg4 big.Int, arg5 address.Address, arg6 uint64, arg7 []byte) (*api.MessagePrototype, error) { +func (m *MockFullNode) MsigCancel(arg0 context.Context, arg1 address.Address, arg2 uint64, arg3 address.Address) (*api.MessagePrototype, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MsigCancel", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + ret := m.ctrl.Call(m, "MsigCancel", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(*api.MessagePrototype) ret1, _ := ret[1].(error) return ret0, ret1 } // MsigCancel indicates an expected call of MsigCancel. -func (mr *MockFullNodeMockRecorder) MsigCancel(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call { +func (mr *MockFullNodeMockRecorder) MsigCancel(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MsigCancel", reflect.TypeOf((*MockFullNode)(nil).MsigCancel), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MsigCancel", reflect.TypeOf((*MockFullNode)(nil).MsigCancel), arg0, arg1, arg2, arg3) +} + +// MsigCancelTxnHash mocks base method. +func (m *MockFullNode) MsigCancelTxnHash(arg0 context.Context, arg1 address.Address, arg2 uint64, arg3 address.Address, arg4 big.Int, arg5 address.Address, arg6 uint64, arg7 []byte) (*api.MessagePrototype, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MsigCancelTxnHash", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + ret0, _ := ret[0].(*api.MessagePrototype) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MsigCancelTxnHash indicates an expected call of MsigCancelTxnHash. +func (mr *MockFullNodeMockRecorder) MsigCancelTxnHash(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MsigCancelTxnHash", reflect.TypeOf((*MockFullNode)(nil).MsigCancelTxnHash), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) } // MsigCreate mocks base method. diff --git a/api/proxy_gen.go b/api/proxy_gen.go index b36f19a7e1e..02a87ff766b 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -270,7 +270,9 @@ type FullNodeStruct struct { MsigApproveTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 address.Address, p5 types.BigInt, p6 address.Address, p7 uint64, p8 []byte) (*MessagePrototype, error) `perm:"sign"` - MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) `perm:"sign"` + MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) `perm:"sign"` + + MsigCancelTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) `perm:"sign"` MsigCreate func(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (*MessagePrototype, error) `perm:"sign"` @@ -1943,14 +1945,25 @@ func (s *FullNodeStub) MsigApproveTxnHash(p0 context.Context, p1 address.Address return nil, ErrNotSupported } -func (s *FullNodeStruct) MsigCancel(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) { +func (s *FullNodeStruct) MsigCancel(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) { if s.Internal.MsigCancel == nil { return nil, ErrNotSupported } - return s.Internal.MsigCancel(p0, p1, p2, p3, p4, p5, p6, p7) + return s.Internal.MsigCancel(p0, p1, p2, p3) +} + +func (s *FullNodeStub) MsigCancel(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) MsigCancelTxnHash(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) { + if s.Internal.MsigCancelTxnHash == nil { + return nil, ErrNotSupported + } + return s.Internal.MsigCancelTxnHash(p0, p1, p2, p3, p4, p5, p6, p7) } -func (s *FullNodeStub) MsigCancel(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) { +func (s *FullNodeStub) MsigCancelTxnHash(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) { return nil, ErrNotSupported } diff --git a/api/v0api/v1_wrapper.go b/api/v0api/v1_wrapper.go index 7f729160082..e36f478f5f9 100644 --- a/api/v0api/v1_wrapper.go +++ b/api/v0api/v1_wrapper.go @@ -108,7 +108,7 @@ func (w *WrapperV1Full) MsigApproveTxnHash(ctx context.Context, msig address.Add } func (w *WrapperV1Full) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { - p, err := w.FullNode.MsigCancel(ctx, msig, txID, to, amt, src, method, params) + p, err := w.FullNode.MsigCancelTxnHash(ctx, msig, txID, to, amt, src, method, params) if err != nil { return cid.Undef, xerrors.Errorf("creating prototype: %w", err) } diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 1578d746536..901cb24bb74 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 335e47cc7c6..2d48e544bca 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 98a3986a272..6c6db8a56cd 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/cli/multisig.go b/cli/multisig.go index 7b93e55f911..980493b59dc 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -51,6 +51,7 @@ var multisigCmd = &cli.Command{ msigProposeCmd, msigRemoveProposeCmd, msigApproveCmd, + msigCancelCmd, msigAddProposeCmd, msigAddApproveCmd, msigAddCancelCmd, @@ -159,6 +160,8 @@ var msigCreateCmd = &cli.Command{ msgCid := sm.Cid() + fmt.Println("sent create in message: ", msgCid) + // wait for it to get mined into a block wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")), build.Finality, true) if err != nil { @@ -612,6 +615,131 @@ var msigApproveCmd = &cli.Command{ }, } +var msigCancelCmd = &cli.Command{ + Name: "cancel", + Usage: "Cancel a multisig message", + ArgsUsage: " [destination value [methodId methodParams]]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "account to send the cancel message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 2 { + return ShowHelp(cctx, fmt.Errorf("must pass at least multisig address and message ID")) + } + + if cctx.Args().Len() > 2 && cctx.Args().Len() < 4 { + return ShowHelp(cctx, fmt.Errorf("usage: msig cancel ")) + } + + if cctx.Args().Len() > 4 && cctx.Args().Len() != 6 { + return ShowHelp(cctx, fmt.Errorf("usage: msig cancel [ ]")) + } + + srv, err := GetFullNodeServices(cctx) + if err != nil { + return err + } + defer srv.Close() //nolint:errcheck + + api := srv.FullNodeAPI() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + var msgCid cid.Cid + if cctx.Args().Len() == 2 { + proto, err := api.MsigCancel(ctx, msig, txid, from) + if err != nil { + return err + } + + sm, err := InteractiveSend(ctx, cctx, srv, proto) + if err != nil { + return err + } + + msgCid = sm.Cid() + } else { + dest, err := address.NewFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + value, err := types.ParseFIL(cctx.Args().Get(3)) + if err != nil { + return err + } + + var method uint64 + var params []byte + if cctx.Args().Len() == 6 { + m, err := strconv.ParseUint(cctx.Args().Get(4), 10, 64) + if err != nil { + return err + } + method = m + + p, err := hex.DecodeString(cctx.Args().Get(5)) + if err != nil { + return err + } + params = p + } + + proto, err := api.MsigCancelTxnHash(ctx, msig, txid, dest, types.BigInt(value), from, method, params) + if err != nil { + return err + } + + sm, err := InteractiveSend(ctx, cctx, srv, proto) + if err != nil { + return err + } + + msgCid = sm.Cid() + } + + fmt.Println("sent cancel in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")), build.Finality, true) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("cancel returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + var msigRemoveProposeCmd = &cli.Command{ Name: "propose-remove", Usage: "Propose to remove a signer", @@ -1490,7 +1618,7 @@ var msigLockCancelCmd = &cli.Command{ return actErr } - proto, err := api.MsigCancel(ctx, msig, txid, msig, big.Zero(), from, uint64(multisig.Methods.LockBalance), params) + proto, err := api.MsigCancelTxnHash(ctx, msig, txid, msig, big.Zero(), from, uint64(multisig.Methods.LockBalance), params) if err != nil { return err } diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index b03f75e9d05..24eba2d0630 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -108,6 +108,7 @@ * [MsigApprove](#MsigApprove) * [MsigApproveTxnHash](#MsigApproveTxnHash) * [MsigCancel](#MsigCancel) + * [MsigCancelTxnHash](#MsigCancelTxnHash) * [MsigCreate](#MsigCreate) * [MsigGetAvailableBalance](#MsigGetAvailableBalance) * [MsigGetPending](#MsigGetPending) @@ -2702,6 +2703,44 @@ Response: ### MsigCancel MsigCancel cancels a previously-proposed multisig message +It takes the following params: , + + +Perms: sign + +Inputs: +```json +[ + "f01234", + 42, + "f01234" +] +``` + +Response: +```json +{ + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true +} +``` + +### MsigCancelTxnHash +MsigCancel cancels a previously-proposed multisig message It takes the following params: , , , , , , diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index b0c5739188a..d617ac68469 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -857,6 +857,7 @@ COMMANDS: propose Propose a multisig transaction propose-remove Propose to remove a signer approve Approve a multisig message + cancel Cancel a multisig message add-propose Propose to add a signer add-approve Approve a message to add a signer add-cancel Cancel a message to add a signer @@ -952,6 +953,20 @@ OPTIONS: ``` +### lotus msig cancel +``` +NAME: + lotus msig cancel - Cancel a multisig message + +USAGE: + lotus msig cancel [command options] [destination value [methodId methodParams]] + +OPTIONS: + --from value account to send the cancel message from + --help, -h show help (default: false) + +``` + ### lotus msig add-propose ``` NAME: diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 0d20c3f03ea..edc67ec9e29 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -100,7 +100,7 @@ func (a *MsigAPI) MsigAddCancel(ctx context.Context, msig address.Address, src a return nil, actErr } - return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(multisig.Methods.AddSigner), enc) + return a.MsigCancelTxnHash(ctx, msig, txID, msig, big.Zero(), src, uint64(multisig.Methods.AddSigner), enc) } func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (*api.MessagePrototype, error) { @@ -127,7 +127,7 @@ func (a *MsigAPI) MsigSwapCancel(ctx context.Context, msig address.Address, src return nil, actErr } - return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(multisig.Methods.SwapSigner), enc) + return a.MsigCancelTxnHash(ctx, msig, txID, msig, big.Zero(), src, uint64(multisig.Methods.SwapSigner), enc) } func (a *MsigAPI) MsigApprove(ctx context.Context, msig address.Address, txID uint64, src address.Address) (*api.MessagePrototype, error) { @@ -138,7 +138,11 @@ func (a *MsigAPI) MsigApproveTxnHash(ctx context.Context, msig address.Address, return a.msigApproveOrCancelTxnHash(ctx, api.MsigApprove, msig, txID, proposer, to, amt, src, method, params) } -func (a *MsigAPI) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (*api.MessagePrototype, error) { +func (a *MsigAPI) MsigCancel(ctx context.Context, msig address.Address, txID uint64, src address.Address) (*api.MessagePrototype, error) { + return a.msigApproveOrCancelSimple(ctx, api.MsigCancel, msig, txID, src) +} + +func (a *MsigAPI) MsigCancelTxnHash(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (*api.MessagePrototype, error) { return a.msigApproveOrCancelTxnHash(ctx, api.MsigCancel, msig, txID, src, to, amt, src, method, params) }